summaryrefslogtreecommitdiffstats
path: root/src/fs
diff options
context:
space:
mode:
authorWe-unite <3205135446@qq.com>2025-01-23 10:41:10 +0800
committerWe-unite <3205135446@qq.com>2025-01-23 10:41:10 +0800
commite6f77b7ea3e38c9853bee60b275f3f89d252a5b3 (patch)
tree80bfbabed9d4cbcf9fa62677f78b34279d7e2f87 /src/fs
downloadlinux-0.11-master.tar.gz
linux-0.11-master.zip
Initial commit, makee it usable on newest linuxHEADmaster
Diffstat (limited to 'src/fs')
-rw-r--r--src/fs/Makefile98
-rw-r--r--src/fs/bitmap.c168
-rw-r--r--src/fs/block_dev.c73
-rw-r--r--src/fs/buffer.c384
-rw-r--r--src/fs/char_dev.c104
-rw-r--r--src/fs/exec.c353
-rw-r--r--src/fs/fcntl.c75
-rw-r--r--src/fs/file_dev.c90
-rw-r--r--src/fs/file_table.c9
-rw-r--r--src/fs/inode.c338
-rw-r--r--src/fs/ioctl.c46
-rw-r--r--src/fs/namei.c778
-rw-r--r--src/fs/open.c209
-rw-r--r--src/fs/pipe.c111
-rw-r--r--src/fs/read_write.c103
-rw-r--r--src/fs/stat.c56
-rw-r--r--src/fs/super.c281
-rw-r--r--src/fs/truncate.c65
18 files changed, 3341 insertions, 0 deletions
diff --git a/src/fs/Makefile b/src/fs/Makefile
new file mode 100644
index 0000000..dc85240
--- /dev/null
+++ b/src/fs/Makefile
@@ -0,0 +1,98 @@
1include ../Makefile.header
2
3LDFLAGS += -r
4CFLAGS += -I../include
5CPP += -I../include
6
7.c.s:
8 @$(CC) $(CFLAGS) \
9 -S -o $*.s $<
10.c.o:
11 @$(CC) $(CFLAGS) \
12 -c -o $*.o $<
13.s.o:
14 $(AS) -o $*.o $<
15
16OBJS= open.o read_write.o inode.o file_table.o buffer.o super.o \
17 block_dev.o char_dev.o file_dev.o stat.o exec.o pipe.o namei.o \
18 bitmap.o fcntl.o ioctl.o truncate.o
19
20fs.o: $(OBJS)
21 @$(LD) $(LDFLAGS) -o fs.o $(OBJS)
22
23clean:
24 @rm -f core *.o *.a tmp_make
25 @for i in *.c;do rm -f `basename $$i .c`.s;done
26
27dep:
28 @sed '/\#\#\# Dependencies/q' < Makefile > tmp_make
29 @(for i in *.c;do $(CPP) -M $$i;done) >> tmp_make
30 @cp tmp_make Makefile
31
32### Dependencies:
33bitmap.o: bitmap.c ../include/string.h ../include/linux/sched.h \
34 ../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \
35 ../include/linux/mm.h ../include/signal.h ../include/linux/kernel.h
36block_dev.o: block_dev.c ../include/errno.h ../include/linux/sched.h \
37 ../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \
38 ../include/linux/mm.h ../include/signal.h ../include/linux/kernel.h \
39 ../include/asm/segment.h ../include/asm/system.h
40buffer.o: buffer.c ../include/stdarg.h ../include/linux/config.h \
41 ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \
42 ../include/sys/types.h ../include/linux/mm.h ../include/signal.h \
43 ../include/linux/kernel.h ../include/asm/system.h ../include/asm/io.h
44char_dev.o: char_dev.c ../include/errno.h ../include/sys/types.h \
45 ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \
46 ../include/linux/mm.h ../include/signal.h ../include/linux/kernel.h \
47 ../include/asm/segment.h ../include/asm/io.h
48exec.o: exec.c ../include/errno.h ../include/string.h \
49 ../include/sys/stat.h ../include/sys/types.h ../include/a.out.h \
50 ../include/linux/fs.h ../include/linux/sched.h ../include/linux/head.h \
51 ../include/linux/mm.h ../include/signal.h ../include/linux/kernel.h \
52 ../include/asm/segment.h
53fcntl.o: fcntl.c ../include/string.h ../include/errno.h \
54 ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \
55 ../include/sys/types.h ../include/linux/mm.h ../include/signal.h \
56 ../include/linux/kernel.h ../include/asm/segment.h ../include/fcntl.h \
57 ../include/sys/stat.h
58file_dev.o: file_dev.c ../include/errno.h ../include/fcntl.h \
59 ../include/sys/types.h ../include/linux/sched.h ../include/linux/head.h \
60 ../include/linux/fs.h ../include/linux/mm.h ../include/signal.h \
61 ../include/linux/kernel.h ../include/asm/segment.h
62file_table.o: file_table.c ../include/linux/fs.h ../include/sys/types.h
63inode.o: inode.c ../include/string.h ../include/sys/stat.h \
64 ../include/sys/types.h ../include/linux/sched.h ../include/linux/head.h \
65 ../include/linux/fs.h ../include/linux/mm.h ../include/signal.h \
66 ../include/linux/kernel.h ../include/asm/system.h
67ioctl.o: ioctl.c ../include/string.h ../include/errno.h \
68 ../include/sys/stat.h ../include/sys/types.h ../include/linux/sched.h \
69 ../include/linux/head.h ../include/linux/fs.h ../include/linux/mm.h \
70 ../include/signal.h
71namei.o: namei.c ../include/linux/sched.h ../include/linux/head.h \
72 ../include/linux/fs.h ../include/sys/types.h ../include/linux/mm.h \
73 ../include/signal.h ../include/linux/kernel.h ../include/asm/segment.h \
74 ../include/string.h ../include/fcntl.h ../include/errno.h \
75 ../include/const.h ../include/sys/stat.h
76open.o: open.c ../include/string.h ../include/errno.h ../include/fcntl.h \
77 ../include/sys/types.h ../include/utime.h ../include/sys/stat.h \
78 ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \
79 ../include/linux/mm.h ../include/signal.h ../include/linux/tty.h \
80 ../include/termios.h ../include/linux/kernel.h ../include/asm/segment.h
81pipe.o: pipe.c ../include/signal.h ../include/sys/types.h \
82 ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \
83 ../include/linux/mm.h ../include/asm/segment.h
84read_write.o: read_write.c ../include/sys/stat.h ../include/sys/types.h \
85 ../include/errno.h ../include/linux/kernel.h ../include/linux/sched.h \
86 ../include/linux/head.h ../include/linux/fs.h ../include/linux/mm.h \
87 ../include/signal.h ../include/asm/segment.h
88stat.o: stat.c ../include/errno.h ../include/sys/stat.h \
89 ../include/sys/types.h ../include/linux/fs.h ../include/linux/sched.h \
90 ../include/linux/head.h ../include/linux/mm.h ../include/signal.h \
91 ../include/linux/kernel.h ../include/asm/segment.h
92super.o: super.c ../include/linux/config.h ../include/linux/sched.h \
93 ../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \
94 ../include/linux/mm.h ../include/signal.h ../include/linux/kernel.h \
95 ../include/asm/system.h ../include/errno.h ../include/sys/stat.h
96truncate.o: truncate.c ../include/linux/sched.h ../include/linux/head.h \
97 ../include/linux/fs.h ../include/sys/types.h ../include/linux/mm.h \
98 ../include/signal.h ../include/sys/stat.h
diff --git a/src/fs/bitmap.c b/src/fs/bitmap.c
new file mode 100644
index 0000000..fb0741d
--- /dev/null
+++ b/src/fs/bitmap.c
@@ -0,0 +1,168 @@
1/*
2 * linux/fs/bitmap.c
3 *
4 * (C) 1991 Linus Torvalds
5 */
6
7/* bitmap.c contains the code that handles the inode and block bitmaps */
8#include <string.h>
9
10#include <linux/sched.h>
11#include <linux/kernel.h>
12
13#define clear_block(addr) \
14__asm__ __volatile__ ("cld\n\t" \
15 "rep\n\t" \
16 "stosl" \
17 ::"a" (0),"c" (BLOCK_SIZE/4),"D" ((long) (addr)))
18
19#define set_bit(nr,addr) ({\
20register int res ; \
21__asm__ __volatile__("btsl %2,%3\n\tsetb %%al": \
22"=a" (res):"0" (0),"r" (nr),"m" (*(addr))); \
23res;})
24
25#define clear_bit(nr,addr) ({\
26register int res ; \
27__asm__ __volatile__("btrl %2,%3\n\tsetnb %%al": \
28"=a" (res):"0" (0),"r" (nr),"m" (*(addr))); \
29res;})
30
31#define find_first_zero(addr) ({ \
32int __res; \
33__asm__ __volatile__ ("cld\n" \
34 "1:\tlodsl\n\t" \
35 "notl %%eax\n\t" \
36 "bsfl %%eax,%%edx\n\t" \
37 "je 2f\n\t" \
38 "addl %%edx,%%ecx\n\t" \
39 "jmp 3f\n" \
40 "2:\taddl $32,%%ecx\n\t" \
41 "cmpl $8192,%%ecx\n\t" \
42 "jl 1b\n" \
43 "3:" \
44 :"=c" (__res):"c" (0),"S" (addr)); \
45__res;})
46
47void free_block(int dev, int block)
48{
49 struct super_block * sb;
50 struct buffer_head * bh;
51
52 if (!(sb = get_super(dev)))
53 panic("trying to free block on nonexistent device");
54 if (block < sb->s_firstdatazone || block >= sb->s_nzones)
55 panic("trying to free block not in datazone");
56 bh = get_hash_table(dev,block);
57 if (bh) {
58 if (bh->b_count != 1) {
59 printk("trying to free block (%04x:%d), count=%d\n",
60 dev,block,bh->b_count);
61 return;
62 }
63 bh->b_dirt=0;
64 bh->b_uptodate=0;
65 brelse(bh);
66 }
67 block -= sb->s_firstdatazone - 1 ;
68 if (clear_bit(block&8191,sb->s_zmap[block/8192]->b_data)) {
69 printk("block (%04x:%d) ",dev,block+sb->s_firstdatazone-1);
70 panic("free_block: bit already cleared");
71 }
72 sb->s_zmap[block/8192]->b_dirt = 1;
73}
74
75int new_block(int dev)
76{
77 struct buffer_head * bh;
78 struct super_block * sb;
79 int i,j;
80
81 if (!(sb = get_super(dev)))
82 panic("trying to get new block from nonexistant device");
83 j = 8192;
84 for (i=0 ; i<8 ; i++)
85 if ((bh=sb->s_zmap[i]))
86 if ((j=find_first_zero(bh->b_data))<8192)
87 break;
88 if (i>=8 || !bh || j>=8192)
89 return 0;
90 if (set_bit(j,bh->b_data))
91 panic("new_block: bit already set");
92 bh->b_dirt = 1;
93 j += i*8192 + sb->s_firstdatazone-1;
94 if (j >= sb->s_nzones)
95 return 0;
96 if (!(bh=getblk(dev,j)))
97 panic("new_block: cannot get block");
98 if (bh->b_count != 1)
99 panic("new block: count is != 1");
100 clear_block(bh->b_data);
101 bh->b_uptodate = 1;
102 bh->b_dirt = 1;
103 brelse(bh);
104 return j;
105}
106
107void free_inode(struct m_inode * inode)
108{
109 struct super_block * sb;
110 struct buffer_head * bh;
111
112 if (!inode)
113 return;
114 if (!inode->i_dev) {
115 memset(inode,0,sizeof(*inode));
116 return;
117 }
118 if (inode->i_count>1) {
119 printk("trying to free inode with count=%d\n",inode->i_count);
120 panic("free_inode");
121 }
122 if (inode->i_nlinks)
123 panic("trying to free inode with links");
124 if (!(sb = get_super(inode->i_dev)))
125 panic("trying to free inode on nonexistent device");
126 if (inode->i_num < 1 || inode->i_num > sb->s_ninodes)
127 panic("trying to free inode 0 or nonexistant inode");
128 if (!(bh=sb->s_imap[inode->i_num>>13]))
129 panic("nonexistent imap in superblock");
130 if (clear_bit(inode->i_num&8191,bh->b_data))
131 printk("free_inode: bit already cleared.\n\r");
132 bh->b_dirt = 1;
133 memset(inode,0,sizeof(*inode));
134}
135
136struct m_inode * new_inode(int dev)
137{
138 struct m_inode * inode;
139 struct super_block * sb;
140 struct buffer_head * bh;
141 int i,j;
142
143 if (!(inode=get_empty_inode()))
144 return NULL;
145 if (!(sb = get_super(dev)))
146 panic("new_inode with unknown device");
147 j = 8192;
148 for (i=0 ; i<8 ; i++)
149 if ((bh=sb->s_imap[i]))
150 if ((j=find_first_zero(bh->b_data))<8192)
151 break;
152 if (!bh || j >= 8192 || j+i*8192 > sb->s_ninodes) {
153 iput(inode);
154 return NULL;
155 }
156 if (set_bit(j,bh->b_data))
157 panic("new_inode: bit already set");
158 bh->b_dirt = 1;
159 inode->i_count=1;
160 inode->i_nlinks=1;
161 inode->i_dev=dev;
162 inode->i_uid=current->euid;
163 inode->i_gid=current->egid;
164 inode->i_dirt=1;
165 inode->i_num = j + i*8192;
166 inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
167 return inode;
168}
diff --git a/src/fs/block_dev.c b/src/fs/block_dev.c
new file mode 100644
index 0000000..a50ae3f
--- /dev/null
+++ b/src/fs/block_dev.c
@@ -0,0 +1,73 @@
1/*
2 * linux/fs/block_dev.c
3 *
4 * (C) 1991 Linus Torvalds
5 */
6
7#include <errno.h>
8
9#include <linux/sched.h>
10#include <linux/kernel.h>
11#include <asm/segment.h>
12#include <asm/system.h>
13
14int block_write(int dev, long * pos, char * buf, int count)
15{
16 int block = *pos >> BLOCK_SIZE_BITS;
17 int offset = *pos & (BLOCK_SIZE-1);
18 int chars;
19 int written = 0;
20 struct buffer_head * bh;
21 register char * p;
22
23 while (count>0) {
24 chars = BLOCK_SIZE - offset;
25 if (chars > count)
26 chars=count;
27 if (chars == BLOCK_SIZE)
28 bh = getblk(dev,block);
29 else
30 bh = breada(dev,block,block+1,block+2,-1);
31 block++;
32 if (!bh)
33 return written?written:-EIO;
34 p = offset + bh->b_data;
35 offset = 0;
36 *pos += chars;
37 written += chars;
38 count -= chars;
39 while (chars-->0)
40 *(p++) = get_fs_byte(buf++);
41 bh->b_dirt = 1;
42 brelse(bh);
43 }
44 return written;
45}
46
47int block_read(int dev, unsigned long * pos, char * buf, int count)
48{
49 int block = *pos >> BLOCK_SIZE_BITS;
50 int offset = *pos & (BLOCK_SIZE-1);
51 int chars;
52 int read = 0;
53 struct buffer_head * bh;
54 register char * p;
55
56 while (count>0) {
57 chars = BLOCK_SIZE-offset;
58 if (chars > count)
59 chars = count;
60 if (!(bh = breada(dev,block,block+1,block+2,-1)))
61 return read?read:-EIO;
62 block++;
63 p = offset + bh->b_data;
64 offset = 0;
65 *pos += chars;
66 read += chars;
67 count -= chars;
68 while (chars-->0)
69 put_fs_byte(*(p++),buf++);
70 brelse(bh);
71 }
72 return read;
73}
diff --git a/src/fs/buffer.c b/src/fs/buffer.c
new file mode 100644
index 0000000..89918e8
--- /dev/null
+++ b/src/fs/buffer.c
@@ -0,0 +1,384 @@
1/*
2 * linux/fs/buffer.c
3 *
4 * (C) 1991 Linus Torvalds
5 */
6
7/*
8 * 'buffer.c' implements the buffer-cache functions. Race-conditions have
9 * been avoided by NEVER letting a interrupt change a buffer (except for the
10 * data, of course), but instead letting the caller do it. NOTE! As interrupts
11 * can wake up a caller, some cli-sti sequences are needed to check for
12 * sleep-on-calls. These should be extremely quick, though (I hope).
13 */
14
15/*
16 * NOTE! There is one discordant note here: checking floppies for
17 * disk change. This is where it fits best, I think, as it should
18 * invalidate changed floppy-disk-caches.
19 */
20
21#include <stdarg.h>
22
23#include <linux/config.h>
24#include <linux/sched.h>
25#include <linux/kernel.h>
26#include <asm/system.h>
27#include <asm/io.h>
28
29extern int end;
30extern void put_super(int);
31extern void invalidate_inodes(int);
32
33struct buffer_head * start_buffer = (struct buffer_head *) &end;
34struct buffer_head * hash_table[NR_HASH];
35static struct buffer_head * free_list;
36static struct task_struct * buffer_wait = NULL;
37int NR_BUFFERS = 0;
38
39static inline void wait_on_buffer(struct buffer_head * bh)
40{
41 cli();
42 while (bh->b_lock)
43 sleep_on(&bh->b_wait);
44 sti();
45}
46
47int sys_sync(void)
48{
49 int i;
50 struct buffer_head * bh;
51
52 sync_inodes(); /* write out inodes into buffers */
53 bh = start_buffer;
54 for (i=0 ; i<NR_BUFFERS ; i++,bh++) {
55 wait_on_buffer(bh);
56 if (bh->b_dirt)
57 ll_rw_block(WRITE,bh);
58 }
59 return 0;
60}
61
62int sync_dev(int dev)
63{
64 int i;
65 struct buffer_head * bh;
66
67 bh = start_buffer;
68 for (i=0 ; i<NR_BUFFERS ; i++,bh++) {
69 if (bh->b_dev != dev)
70 continue;
71 wait_on_buffer(bh);
72 if (bh->b_dev == dev && bh->b_dirt)
73 ll_rw_block(WRITE,bh);
74 }
75 sync_inodes();
76 bh = start_buffer;
77 for (i=0 ; i<NR_BUFFERS ; i++,bh++) {
78 if (bh->b_dev != dev)
79 continue;
80 wait_on_buffer(bh);
81 if (bh->b_dev == dev && bh->b_dirt)
82 ll_rw_block(WRITE,bh);
83 }
84 return 0;
85}
86
87static void inline invalidate_buffers(int dev)
88{
89 int i;
90 struct buffer_head * bh;
91
92 bh = start_buffer;
93 for (i=0 ; i<NR_BUFFERS ; i++,bh++) {
94 if (bh->b_dev != dev)
95 continue;
96 wait_on_buffer(bh);
97 if (bh->b_dev == dev)
98 bh->b_uptodate = bh->b_dirt = 0;
99 }
100}
101
102/*
103 * This routine checks whether a floppy has been changed, and
104 * invalidates all buffer-cache-entries in that case. This
105 * is a relatively slow routine, so we have to try to minimize using
106 * it. Thus it is called only upon a 'mount' or 'open'. This
107 * is the best way of combining speed and utility, I think.
108 * People changing diskettes in the middle of an operation deserve
109 * to loose :-)
110 *
111 * NOTE! Although currently this is only for floppies, the idea is
112 * that any additional removable block-device will use this routine,
113 * and that mount/open needn't know that floppies/whatever are
114 * special.
115 */
116void check_disk_change(int dev)
117{
118 int i;
119
120 if (MAJOR(dev) != 2)
121 return;
122 if (!floppy_change(dev & 0x03))
123 return;
124 for (i=0 ; i<NR_SUPER ; i++)
125 if (super_block[i].s_dev == dev)
126 put_super(super_block[i].s_dev);
127 invalidate_inodes(dev);
128 invalidate_buffers(dev);
129}
130
131#define _hashfn(dev,block) (((unsigned)(dev^block))%NR_HASH)
132#define hash(dev,block) hash_table[_hashfn(dev,block)]
133
134static inline void remove_from_queues(struct buffer_head * bh)
135{
136/* remove from hash-queue */
137 if (bh->b_next)
138 bh->b_next->b_prev = bh->b_prev;
139 if (bh->b_prev)
140 bh->b_prev->b_next = bh->b_next;
141 if (hash(bh->b_dev,bh->b_blocknr) == bh)
142 hash(bh->b_dev,bh->b_blocknr) = bh->b_next;
143/* remove from free list */
144 if (!(bh->b_prev_free) || !(bh->b_next_free))
145 panic("Free block list corrupted");
146 bh->b_prev_free->b_next_free = bh->b_next_free;
147 bh->b_next_free->b_prev_free = bh->b_prev_free;
148 if (free_list == bh)
149 free_list = bh->b_next_free;
150}
151
152static inline void insert_into_queues(struct buffer_head * bh)
153{
154/* put at end of free list */
155 bh->b_next_free = free_list;
156 bh->b_prev_free = free_list->b_prev_free;
157 free_list->b_prev_free->b_next_free = bh;
158 free_list->b_prev_free = bh;
159/* put the buffer in new hash-queue if it has a device */
160 bh->b_prev = NULL;
161 bh->b_next = NULL;
162 if (!bh->b_dev)
163 return;
164 bh->b_next = hash(bh->b_dev,bh->b_blocknr);
165 hash(bh->b_dev,bh->b_blocknr) = bh;
166 bh->b_next->b_prev = bh;
167}
168
169static struct buffer_head * find_buffer(int dev, int block)
170{
171 struct buffer_head * tmp;
172
173 for (tmp = hash(dev,block) ; tmp != NULL ; tmp = tmp->b_next)
174 if (tmp->b_dev==dev && tmp->b_blocknr==block)
175 return tmp;
176 return NULL;
177}
178
179/*
180 * Why like this, I hear you say... The reason is race-conditions.
181 * As we don't lock buffers (unless we are readint them, that is),
182 * something might happen to it while we sleep (ie a read-error
183 * will force it bad). This shouldn't really happen currently, but
184 * the code is ready.
185 */
186struct buffer_head * get_hash_table(int dev, int block)
187{
188 struct buffer_head * bh;
189
190 for (;;) {
191 if (!(bh=find_buffer(dev,block)))
192 return NULL;
193 bh->b_count++;
194 wait_on_buffer(bh);
195 if (bh->b_dev == dev && bh->b_blocknr == block)
196 return bh;
197 bh->b_count--;
198 }
199}
200
201/*
202 * Ok, this is getblk, and it isn't very clear, again to hinder
203 * race-conditions. Most of the code is seldom used, (ie repeating),
204 * so it should be much more efficient than it looks.
205 *
206 * The algoritm is changed: hopefully better, and an elusive bug removed.
207 */
208#define BADNESS(bh) (((bh)->b_dirt<<1)+(bh)->b_lock)
209struct buffer_head * getblk(int dev,int block)
210{
211 struct buffer_head * tmp, * bh;
212
213repeat:
214 if ((bh = get_hash_table(dev,block)))
215 return bh;
216 tmp = free_list;
217 do {
218 if (tmp->b_count)
219 continue;
220 if (!bh || BADNESS(tmp)<BADNESS(bh)) {
221 bh = tmp;
222 if (!BADNESS(tmp))
223 break;
224 }
225/* and repeat until we find something good */
226 } while ((tmp = tmp->b_next_free) != free_list);
227 if (!bh) {
228 sleep_on(&buffer_wait);
229 goto repeat;
230 }
231 wait_on_buffer(bh);
232 if (bh->b_count)
233 goto repeat;
234 while (bh->b_dirt) {
235 sync_dev(bh->b_dev);
236 wait_on_buffer(bh);
237 if (bh->b_count)
238 goto repeat;
239 }
240/* NOTE!! While we slept waiting for this block, somebody else might */
241/* already have added "this" block to the cache. check it */
242 if (find_buffer(dev,block))
243 goto repeat;
244/* OK, FINALLY we know that this buffer is the only one of it's kind, */
245/* and that it's unused (b_count=0), unlocked (b_lock=0), and clean */
246 bh->b_count=1;
247 bh->b_dirt=0;
248 bh->b_uptodate=0;
249 remove_from_queues(bh);
250 bh->b_dev=dev;
251 bh->b_blocknr=block;
252 insert_into_queues(bh);
253 return bh;
254}
255
256void brelse(struct buffer_head * buf)
257{
258 if (!buf)
259 return;
260 wait_on_buffer(buf);
261 if (!(buf->b_count--))
262 panic("Trying to free free buffer");
263 wake_up(&buffer_wait);
264}
265
266/*
267 * bread() reads a specified block and returns the buffer that contains
268 * it. It returns NULL if the block was unreadable.
269 */
270struct buffer_head * bread(int dev,int block)
271{
272 struct buffer_head * bh;
273
274 if (!(bh=getblk(dev,block)))
275 panic("bread: getblk returned NULL\n");
276 if (bh->b_uptodate)
277 return bh;
278 ll_rw_block(READ,bh);
279 wait_on_buffer(bh);
280 if (bh->b_uptodate)
281 return bh;
282 brelse(bh);
283 return NULL;
284}
285
286#define COPYBLK(from,to) \
287__asm__("cld\n\t" \
288 "rep\n\t" \
289 "movsl\n\t" \
290 ::"c" (BLOCK_SIZE/4),"S" (from),"D" (to) \
291 )
292
293/*
294 * bread_page reads four buffers into memory at the desired address. It's
295 * a function of its own, as there is some speed to be got by reading them
296 * all at the same time, not waiting for one to be read, and then another
297 * etc.
298 */
299void bread_page(unsigned long address,int dev,int b[4])
300{
301 struct buffer_head * bh[4];
302 int i;
303
304 for (i=0 ; i<4 ; i++)
305 if (b[i]) {
306 if ((bh[i] = getblk(dev,b[i])))
307 if (!bh[i]->b_uptodate)
308 ll_rw_block(READ,bh[i]);
309 } else
310 bh[i] = NULL;
311 for (i=0 ; i<4 ; i++,address += BLOCK_SIZE)
312 if (bh[i]) {
313 wait_on_buffer(bh[i]);
314 if (bh[i]->b_uptodate)
315 COPYBLK((unsigned long) bh[i]->b_data,address);
316 brelse(bh[i]);
317 }
318}
319
320/*
321 * Ok, breada can be used as bread, but additionally to mark other
322 * blocks for reading as well. End the argument list with a negative
323 * number.
324 */
325struct buffer_head * breada(int dev,int first, ...)
326{
327 va_list args;
328 struct buffer_head * bh, *tmp;
329
330 va_start(args,first);
331 if (!(bh=getblk(dev,first)))
332 panic("bread: getblk returned NULL\n");
333 if (!bh->b_uptodate)
334 ll_rw_block(READ,bh);
335 while ((first=va_arg(args,int))>=0) {
336 tmp=getblk(dev,first);
337 if (tmp) {
338 if (!tmp->b_uptodate)
339 ll_rw_block(READA,bh);
340 tmp->b_count--;
341 }
342 }
343 va_end(args);
344 wait_on_buffer(bh);
345 if (bh->b_uptodate)
346 return bh;
347 brelse(bh);
348 return (NULL);
349}
350
351void buffer_init(long buffer_end)
352{
353 struct buffer_head * h = start_buffer;
354 void * b;
355 int i;
356
357 if (buffer_end == 1<<20)
358 b = (void *) (640*1024);
359 else
360 b = (void *) buffer_end;
361 while ( (b -= BLOCK_SIZE) >= ((void *) (h+1)) ) {
362 h->b_dev = 0;
363 h->b_dirt = 0;
364 h->b_count = 0;
365 h->b_lock = 0;
366 h->b_uptodate = 0;
367 h->b_wait = NULL;
368 h->b_next = NULL;
369 h->b_prev = NULL;
370 h->b_data = (char *) b;
371 h->b_prev_free = h-1;
372 h->b_next_free = h+1;
373 h++;
374 NR_BUFFERS++;
375 if (b == (void *) 0x100000)
376 b = (void *) 0xA0000;
377 }
378 h--;
379 free_list = start_buffer;
380 free_list->b_prev_free = h;
381 h->b_next_free = free_list;
382 for (i=0;i<NR_HASH;i++)
383 hash_table[i]=NULL;
384}
diff --git a/src/fs/char_dev.c b/src/fs/char_dev.c
new file mode 100644
index 0000000..6932e1e
--- /dev/null
+++ b/src/fs/char_dev.c
@@ -0,0 +1,104 @@
1/*
2 * linux/fs/char_dev.c
3 *
4 * (C) 1991 Linus Torvalds
5 */
6
7#include <errno.h>
8#include <sys/types.h>
9
10#include <linux/sched.h>
11#include <linux/kernel.h>
12
13#include <asm/segment.h>
14#include <asm/io.h>
15
16extern int tty_read(unsigned minor,char * buf,int count);
17extern int tty_write(unsigned minor,char * buf,int count);
18
19typedef int (*crw_ptr)(int rw,unsigned minor,char * buf,int count,off_t * pos);
20
21static int rw_ttyx(int rw,unsigned minor,char * buf,int count,off_t * pos)
22{
23 return ((rw==READ)?tty_read(minor,buf,count):
24 tty_write(minor,buf,count));
25}
26
27static int rw_tty(int rw,unsigned minor,char * buf,int count, off_t * pos)
28{
29 if (current->tty<0)
30 return -EPERM;
31 return rw_ttyx(rw,current->tty,buf,count,pos);
32}
33
34static int rw_ram(int rw,char * buf, int count, off_t *pos)
35{
36 return -EIO;
37}
38
39static int rw_mem(int rw,char * buf, int count, off_t * pos)
40{
41 return -EIO;
42}
43
44static int rw_kmem(int rw,char * buf, int count, off_t * pos)
45{
46 return -EIO;
47}
48
49static int rw_port(int rw,char * buf, int count, off_t * pos)
50{
51 int i=*pos;
52
53 while (count-->0 && i<65536) {
54 if (rw==READ)
55 put_fs_byte(inb(i),buf++);
56 else
57 outb(get_fs_byte(buf++),i);
58 i++;
59 }
60 i -= *pos;
61 *pos += i;
62 return i;
63}
64
65static int rw_memory(int rw, unsigned minor, char * buf, int count, off_t * pos)
66{
67 switch(minor) {
68 case 0:
69 return rw_ram(rw,buf,count,pos);
70 case 1:
71 return rw_mem(rw,buf,count,pos);
72 case 2:
73 return rw_kmem(rw,buf,count,pos);
74 case 3:
75 return (rw==READ)?0:count; /* rw_null */
76 case 4:
77 return rw_port(rw,buf,count,pos);
78 default:
79 return -EIO;
80 }
81}
82
83#define NRDEVS ((sizeof (crw_table))/(sizeof (crw_ptr)))
84
85static crw_ptr crw_table[]={
86 NULL, /* nodev */
87 rw_memory, /* /dev/mem etc */
88 NULL, /* /dev/fd */
89 NULL, /* /dev/hd */
90 rw_ttyx, /* /dev/ttyx */
91 rw_tty, /* /dev/tty */
92 NULL, /* /dev/lp */
93 NULL}; /* unnamed pipes */
94
95int rw_char(int rw,int dev, char * buf, int count, off_t * pos)
96{
97 crw_ptr call_addr;
98
99 if (MAJOR(dev)>=NRDEVS)
100 return -ENODEV;
101 if (!(call_addr=crw_table[MAJOR(dev)]))
102 return -ENODEV;
103 return call_addr(rw,MINOR(dev),buf,count,pos);
104}
diff --git a/src/fs/exec.c b/src/fs/exec.c
new file mode 100644
index 0000000..d7efa43
--- /dev/null
+++ b/src/fs/exec.c
@@ -0,0 +1,353 @@
1/*
2 * linux/fs/exec.c
3 *
4 * (C) 1991 Linus Torvalds
5 */
6
7/*
8 * #!-checking implemented by tytso.
9 */
10
11/*
12 * Demand-loading implemented 01.12.91 - no need to read anything but
13 * the header into memory. The inode of the executable is put into
14 * "current->executable", and page faults do the actual loading. Clean.
15 *
16 * Once more I can proudly say that linux stood up to being changed: it
17 * was less than 2 hours work to get demand-loading completely implemented.
18 */
19
20#include <errno.h>
21#include <string.h>
22#include <sys/stat.h>
23#include <a.out.h>
24
25#include <linux/fs.h>
26#include <linux/sched.h>
27#include <linux/kernel.h>
28#include <linux/mm.h>
29#include <asm/segment.h>
30
31extern int sys_exit(int exit_code);
32extern int sys_close(int fd);
33
34/*
35 * MAX_ARG_PAGES defines the number of pages allocated for arguments
36 * and envelope for the new program. 32 should suffice, this gives
37 * a maximum env+arg of 128kB !
38 */
39#define MAX_ARG_PAGES 32
40
41/*
42 * create_tables() parses the env- and arg-strings in new user
43 * memory and creates the pointer tables from them, and puts their
44 * addresses on the "stack", returning the new stack pointer value.
45 */
46static unsigned long * create_tables(char * p,int argc,int envc)
47{
48 unsigned long *argv,*envp;
49 unsigned long * sp;
50
51 sp = (unsigned long *) (0xfffffffc & (unsigned long) p);
52 sp -= envc+1;
53 envp = sp;
54 sp -= argc+1;
55 argv = sp;
56 put_fs_long((unsigned long)envp,--sp);
57 put_fs_long((unsigned long)argv,--sp);
58 put_fs_long((unsigned long)argc,--sp);
59 while (argc-->0) {
60 put_fs_long((unsigned long) p,argv++);
61 while (get_fs_byte(p++)) /* nothing */ ;
62 }
63 put_fs_long(0,argv);
64 while (envc-->0) {
65 put_fs_long((unsigned long) p,envp++);
66 while (get_fs_byte(p++)) /* nothing */ ;
67 }
68 put_fs_long(0,envp);
69 return sp;
70}
71
72/*
73 * count() counts the number of arguments/envelopes
74 */
75static int count(char ** argv)
76{
77 int i=0;
78 char ** tmp;
79
80 if ((tmp = argv))
81 while (get_fs_long((unsigned long *) (tmp++)))
82 i++;
83
84 return i;
85}
86
87/*
88 * 'copy_string()' copies argument/envelope strings from user
89 * memory to free pages in kernel mem. These are in a format ready
90 * to be put directly into the top of new user memory.
91 *
92 * Modified by TYT, 11/24/91 to add the from_kmem argument, which specifies
93 * whether the string and the string array are from user or kernel segments:
94 *
95 * from_kmem argv * argv **
96 * 0 user space user space
97 * 1 kernel space user space
98 * 2 kernel space kernel space
99 *
100 * We do this by playing games with the fs segment register. Since it
101 * it is expensive to load a segment register, we try to avoid calling
102 * set_fs() unless we absolutely have to.
103 */
104static unsigned long copy_strings(int argc,char ** argv,unsigned long *page,
105 unsigned long p, int from_kmem)
106{
107 char *tmp, *pag=NULL;
108 int len, offset = 0;
109 unsigned long old_fs, new_fs;
110
111 if (!p)
112 return 0; /* bullet-proofing */
113 new_fs = get_ds();
114 old_fs = get_fs();
115 if (from_kmem==2)
116 set_fs(new_fs);
117 while (argc-- > 0) {
118 if (from_kmem == 1)
119 set_fs(new_fs);
120 if (!(tmp = (char *)get_fs_long(((unsigned long *)argv)+argc)))
121 panic("argc is wrong");
122 if (from_kmem == 1)
123 set_fs(old_fs);
124 len=0; /* remember zero-padding */
125 do {
126 len++;
127 } while (get_fs_byte(tmp++));
128 if (p-len < 0) { /* this shouldn't happen - 128kB */
129 set_fs(old_fs);
130 return 0;
131 }
132 while (len) {
133 --p; --tmp; --len;
134 if (--offset < 0) {
135 offset = p % PAGE_SIZE;
136 if (from_kmem==2)
137 set_fs(old_fs);
138 if (!(pag = (char *) page[p/PAGE_SIZE]) &&
139 !(pag = (char *) (page[p/PAGE_SIZE] =
140 get_free_page())))
141 return 0;
142 if (from_kmem==2)
143 set_fs(new_fs);
144
145 }
146 *(pag + offset) = get_fs_byte(tmp);
147 }
148 }
149 if (from_kmem==2)
150 set_fs(old_fs);
151 return p;
152}
153
154static unsigned long change_ldt(unsigned long text_size,unsigned long * page)
155{
156 unsigned long code_limit,data_limit,code_base,data_base;
157 int i;
158
159 code_limit = text_size+PAGE_SIZE -1;
160 code_limit &= 0xFFFFF000;
161 data_limit = 0x4000000;
162 code_base = get_base(current->ldt[1]);
163 data_base = code_base;
164 set_base(current->ldt[1],code_base);
165 set_limit(current->ldt[1],code_limit);
166 set_base(current->ldt[2],data_base);
167 set_limit(current->ldt[2],data_limit);
168/* make sure fs points to the NEW data segment */
169 __asm__("pushl $0x17\n\tpop %%fs"::);
170 data_base += data_limit;
171 for (i=MAX_ARG_PAGES-1 ; i>=0 ; i--) {
172 data_base -= PAGE_SIZE;
173 if (page[i])
174 put_page(page[i],data_base);
175 }
176 return data_limit;
177}
178
179/*
180 * 'do_execve()' executes a new program.
181 */
182int do_execve(unsigned long * eip,long tmp,char * filename,
183 char ** argv, char ** envp)
184{
185 struct m_inode * inode;
186 struct buffer_head * bh;
187 struct exec ex;
188 unsigned long page[MAX_ARG_PAGES];
189 int i,argc,envc;
190 int e_uid, e_gid;
191 int retval;
192 int sh_bang = 0;
193 unsigned long p=PAGE_SIZE*MAX_ARG_PAGES-4;
194
195 if ((0xffff & eip[1]) != 0x000f)
196 panic("execve called from supervisor mode");
197 for (i=0 ; i<MAX_ARG_PAGES ; i++) /* clear page-table */
198 page[i]=0;
199 if (!(inode=namei(filename))) /* get executables inode */
200 return -ENOENT;
201 argc = count(argv);
202 envc = count(envp);
203
204restart_interp:
205 if (!S_ISREG(inode->i_mode)) { /* must be regular file */
206 retval = -EACCES;
207 goto exec_error2;
208 }
209 i = inode->i_mode;
210 e_uid = (i & S_ISUID) ? inode->i_uid : current->euid;
211 e_gid = (i & S_ISGID) ? inode->i_gid : current->egid;
212 if (current->euid == inode->i_uid)
213 i >>= 6;
214 else if (current->egid == inode->i_gid)
215 i >>= 3;
216 if (!(i & 1) &&
217 !((inode->i_mode & 0111) && suser())) {
218 retval = -ENOEXEC;
219 goto exec_error2;
220 }
221 if (!(bh = bread(inode->i_dev,inode->i_zone[0]))) {
222 retval = -EACCES;
223 goto exec_error2;
224 }
225 ex = *((struct exec *) bh->b_data); /* read exec-header */
226 if ((bh->b_data[0] == '#') && (bh->b_data[1] == '!') && (!sh_bang)) {
227 /*
228 * This section does the #! interpretation.
229 * Sorta complicated, but hopefully it will work. -TYT
230 */
231
232 char buf[1023], *cp, *interp, *i_name, *i_arg;
233 unsigned long old_fs;
234
235 strncpy(buf, bh->b_data+2, 1022);
236 brelse(bh);
237 iput(inode);
238 buf[1022] = '\0';
239 if ((cp = strchr(buf, '\n'))) {
240 *cp = '\0';
241 for (cp = buf; (*cp == ' ') || (*cp == '\t'); cp++);
242 }
243 if (!cp || *cp == '\0') {
244 retval = -ENOEXEC; /* No interpreter name found */
245 goto exec_error1;
246 }
247 interp = i_name = cp;
248 i_arg = 0;
249 for ( ; *cp && (*cp != ' ') && (*cp != '\t'); cp++) {
250 if (*cp == '/')
251 i_name = cp+1;
252 }
253 if (*cp) {
254 *cp++ = '\0';
255 i_arg = cp;
256 }
257 /*
258 * OK, we've parsed out the interpreter name and
259 * (optional) argument.
260 */
261 if (sh_bang++ == 0) {
262 p = copy_strings(envc, envp, page, p, 0);
263 p = copy_strings(--argc, argv+1, page, p, 0);
264 }
265 /*
266 * Splice in (1) the interpreter's name for argv[0]
267 * (2) (optional) argument to interpreter
268 * (3) filename of shell script
269 *
270 * This is done in reverse order, because of how the
271 * user environment and arguments are stored.
272 */
273 p = copy_strings(1, &filename, page, p, 1);
274 argc++;
275 if (i_arg) {
276 p = copy_strings(1, &i_arg, page, p, 2);
277 argc++;
278 }
279 p = copy_strings(1, &i_name, page, p, 2);
280 argc++;
281 if (!p) {
282 retval = -ENOMEM;
283 goto exec_error1;
284 }
285 /*
286 * OK, now restart the process with the interpreter's inode.
287 */
288 old_fs = get_fs();
289 set_fs(get_ds());
290 if (!(inode=namei(interp))) { /* get executables inode */
291 set_fs(old_fs);
292 retval = -ENOENT;
293 goto exec_error1;
294 }
295 set_fs(old_fs);
296 goto restart_interp;
297 }
298 brelse(bh);
299 if (N_MAGIC(ex) != ZMAGIC || ex.a_trsize || ex.a_drsize ||
300 ex.a_text+ex.a_data+ex.a_bss>0x3000000 ||
301 inode->i_size < ex.a_text+ex.a_data+ex.a_syms+N_TXTOFF(ex)) {
302 retval = -ENOEXEC;
303 goto exec_error2;
304 }
305 if (N_TXTOFF(ex) != BLOCK_SIZE) {
306 printk("%s: N_TXTOFF != BLOCK_SIZE. See a.out.h.", filename);
307 retval = -ENOEXEC;
308 goto exec_error2;
309 }
310 if (!sh_bang) {
311 p = copy_strings(envc,envp,page,p,0);
312 p = copy_strings(argc,argv,page,p,0);
313 if (!p) {
314 retval = -ENOMEM;
315 goto exec_error2;
316 }
317 }
318/* OK, This is the point of no return */
319 if (current->executable)
320 iput(current->executable);
321 current->executable = inode;
322 for (i=0 ; i<32 ; i++)
323 current->sigaction[i].sa_handler = NULL;
324 for (i=0 ; i<NR_OPEN ; i++)
325 if ((current->close_on_exec>>i)&1)
326 sys_close(i);
327 current->close_on_exec = 0;
328 free_page_tables(get_base(current->ldt[1]),get_limit(0x0f));
329 free_page_tables(get_base(current->ldt[2]),get_limit(0x17));
330 if (last_task_used_math == current)
331 last_task_used_math = NULL;
332 current->used_math = 0;
333 p += change_ldt(ex.a_text,page)-MAX_ARG_PAGES*PAGE_SIZE;
334 p = (unsigned long) create_tables((char *)p,argc,envc);
335 current->brk = ex.a_bss +
336 (current->end_data = ex.a_data +
337 (current->end_code = ex.a_text));
338 current->start_stack = p & 0xfffff000;
339 current->euid = e_uid;
340 current->egid = e_gid;
341 i = ex.a_text+ex.a_data;
342 while (i&0xfff)
343 put_fs_byte(0,(char *) (i++));
344 eip[0] = ex.a_entry; /* eip, magic happens :-) */
345 eip[3] = p; /* stack pointer */
346 return 0;
347exec_error2:
348 iput(inode);
349exec_error1:
350 for (i=0 ; i<MAX_ARG_PAGES ; i++)
351 free_page(page[i]);
352 return(retval);
353}
diff --git a/src/fs/fcntl.c b/src/fs/fcntl.c
new file mode 100644
index 0000000..f3a2d29
--- /dev/null
+++ b/src/fs/fcntl.c
@@ -0,0 +1,75 @@
1/*
2 * linux/fs/fcntl.c
3 *
4 * (C) 1991 Linus Torvalds
5 */
6
7/* #include <string.h> */
8#include <errno.h>
9#include <linux/sched.h>
10#include <linux/kernel.h>
11#include <asm/segment.h>
12
13#include <fcntl.h>
14#include <sys/stat.h>
15
16extern int sys_close(int fd);
17
18static int dupfd(unsigned int fd, unsigned int arg)
19{
20 if (fd >= NR_OPEN || !current->filp[fd])
21 return -EBADF;
22 if (arg >= NR_OPEN)
23 return -EINVAL;
24 while (arg < NR_OPEN)
25 if (current->filp[arg])
26 arg++;
27 else
28 break;
29 if (arg >= NR_OPEN)
30 return -EMFILE;
31 current->close_on_exec &= ~(1<<arg);
32 (current->filp[arg] = current->filp[fd])->f_count++;
33 return arg;
34}
35
36int sys_dup2(unsigned int oldfd, unsigned int newfd)
37{
38 sys_close(newfd);
39 return dupfd(oldfd,newfd);
40}
41
42int sys_dup(unsigned int fildes)
43{
44 return dupfd(fildes,0);
45}
46
47int sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg)
48{
49 struct file * filp;
50
51 if (fd >= NR_OPEN || !(filp = current->filp[fd]))
52 return -EBADF;
53 switch (cmd) {
54 case F_DUPFD:
55 return dupfd(fd,arg);
56 case F_GETFD:
57 return (current->close_on_exec>>fd)&1;
58 case F_SETFD:
59 if (arg&1)
60 current->close_on_exec |= (1<<fd);
61 else
62 current->close_on_exec &= ~(1<<fd);
63 return 0;
64 case F_GETFL:
65 return filp->f_flags;
66 case F_SETFL:
67 filp->f_flags &= ~(O_APPEND | O_NONBLOCK);
68 filp->f_flags |= arg & (O_APPEND | O_NONBLOCK);
69 return 0;
70 case F_GETLK: case F_SETLK: case F_SETLKW:
71 return -1;
72 default:
73 return -1;
74 }
75}
diff --git a/src/fs/file_dev.c b/src/fs/file_dev.c
new file mode 100644
index 0000000..4661b6f
--- /dev/null
+++ b/src/fs/file_dev.c
@@ -0,0 +1,90 @@
1/*
2 * linux/fs/file_dev.c
3 *
4 * (C) 1991 Linus Torvalds
5 */
6
7#include <errno.h>
8#include <fcntl.h>
9
10#include <linux/sched.h>
11#include <linux/kernel.h>
12#include <asm/segment.h>
13
14#define MIN(a,b) (((a)<(b))?(a):(b))
15#define MAX(a,b) (((a)>(b))?(a):(b))
16
17int file_read(struct m_inode * inode, struct file * filp, char * buf, int count)
18{
19 int left,chars,nr;
20 struct buffer_head * bh;
21
22 if ((left=count)<=0)
23 return 0;
24 while (left) {
25 if ((nr = bmap(inode,(filp->f_pos)/BLOCK_SIZE))) {
26 if (!(bh=bread(inode->i_dev,nr)))
27 break;
28 } else
29 bh = NULL;
30 nr = filp->f_pos % BLOCK_SIZE;
31 chars = MIN( BLOCK_SIZE-nr , left );
32 filp->f_pos += chars;
33 left -= chars;
34 if (bh) {
35 char * p = nr + bh->b_data;
36 while (chars-->0)
37 put_fs_byte(*(p++),buf++);
38 brelse(bh);
39 } else {
40 while (chars-->0)
41 put_fs_byte(0,buf++);
42 }
43 }
44 inode->i_atime = CURRENT_TIME;
45 return (count-left)?(count-left):-ERROR;
46}
47
48int file_write(struct m_inode * inode, struct file * filp, char * buf, int count)
49{
50 off_t pos;
51 int block,c;
52 struct buffer_head * bh;
53 char * p;
54 int i=0;
55
56/*
57 * ok, append may not work when many processes are writing at the same time
58 * but so what. That way leads to madness anyway.
59 */
60 if (filp->f_flags & O_APPEND)
61 pos = inode->i_size;
62 else
63 pos = filp->f_pos;
64 while (i<count) {
65 if (!(block = create_block(inode,pos/BLOCK_SIZE)))
66 break;
67 if (!(bh=bread(inode->i_dev,block)))
68 break;
69 c = pos % BLOCK_SIZE;
70 p = c + bh->b_data;
71 bh->b_dirt = 1;
72 c = BLOCK_SIZE-c;
73 if (c > count-i) c = count-i;
74 pos += c;
75 if (pos > inode->i_size) {
76 inode->i_size = pos;
77 inode->i_dirt = 1;
78 }
79 i += c;
80 while (c-->0)
81 *(p++) = get_fs_byte(buf++);
82 brelse(bh);
83 }
84 inode->i_mtime = CURRENT_TIME;
85 if (!(filp->f_flags & O_APPEND)) {
86 filp->f_pos = pos;
87 inode->i_ctime = CURRENT_TIME;
88 }
89 return (i?i:-1);
90}
diff --git a/src/fs/file_table.c b/src/fs/file_table.c
new file mode 100644
index 0000000..e0589ac
--- /dev/null
+++ b/src/fs/file_table.c
@@ -0,0 +1,9 @@
1/*
2 * linux/fs/file_table.c
3 *
4 * (C) 1991 Linus Torvalds
5 */
6
7#include <linux/fs.h>
8
9struct file file_table[NR_FILE];
diff --git a/src/fs/inode.c b/src/fs/inode.c
new file mode 100644
index 0000000..d0b1c32
--- /dev/null
+++ b/src/fs/inode.c
@@ -0,0 +1,338 @@
1/*
2 * linux/fs/inode.c
3 *
4 * (C) 1991 Linus Torvalds
5 */
6
7#include <string.h>
8#include <sys/stat.h>
9
10#include <linux/sched.h>
11#include <linux/kernel.h>
12#include <linux/mm.h>
13#include <asm/system.h>
14
15struct m_inode inode_table[NR_INODE]={{0,},};
16
17static void read_inode(struct m_inode * inode);
18static void write_inode(struct m_inode * inode);
19
20static inline void wait_on_inode(struct m_inode * inode)
21{
22 cli();
23 while (inode->i_lock)
24 sleep_on(&inode->i_wait);
25 sti();
26}
27
28static inline void lock_inode(struct m_inode * inode)
29{
30 cli();
31 while (inode->i_lock)
32 sleep_on(&inode->i_wait);
33 inode->i_lock=1;
34 sti();
35}
36
37static inline void unlock_inode(struct m_inode * inode)
38{
39 inode->i_lock=0;
40 wake_up(&inode->i_wait);
41}
42
43void invalidate_inodes(int dev)
44{
45 int i;
46 struct m_inode * inode;
47
48 inode = 0+inode_table;
49 for(i=0 ; i<NR_INODE ; i++,inode++) {
50 wait_on_inode(inode);
51 if (inode->i_dev == dev) {
52 if (inode->i_count)
53 printk("inode in use on removed disk\n\r");
54 inode->i_dev = inode->i_dirt = 0;
55 }
56 }
57}
58
59void sync_inodes(void)
60{
61 int i;
62 struct m_inode * inode;
63
64 inode = 0+inode_table;
65 for(i=0 ; i<NR_INODE ; i++,inode++) {
66 wait_on_inode(inode);
67 if (inode->i_dirt && !inode->i_pipe)
68 write_inode(inode);
69 }
70}
71
72static int _bmap(struct m_inode * inode,int block,int create)
73{
74 struct buffer_head * bh;
75 int i;
76
77 if (block<0)
78 panic("_bmap: block<0");
79 if (block >= 7+512+512*512)
80 panic("_bmap: block>big");
81 if (block<7) {
82 if (create && !inode->i_zone[block])
83 if ((inode->i_zone[block]=new_block(inode->i_dev))) {
84 inode->i_ctime=CURRENT_TIME;
85 inode->i_dirt=1;
86 }
87 return inode->i_zone[block];
88 }
89 block -= 7;
90 if (block<512) {
91 if (create && !inode->i_zone[7])
92 if ((inode->i_zone[7]=new_block(inode->i_dev))) {
93 inode->i_dirt=1;
94 inode->i_ctime=CURRENT_TIME;
95 }
96 if (!inode->i_zone[7])
97 return 0;
98 if (!(bh = bread(inode->i_dev,inode->i_zone[7])))
99 return 0;
100 i = ((unsigned short *) (bh->b_data))[block];
101 if (create && !i)
102 if ((i=new_block(inode->i_dev))) {
103 ((unsigned short *) (bh->b_data))[block]=i;
104 bh->b_dirt=1;
105 }
106 brelse(bh);
107 return i;
108 }
109 block -= 512;
110 if (create && !inode->i_zone[8])
111 if ((inode->i_zone[8]=new_block(inode->i_dev))) {
112 inode->i_dirt=1;
113 inode->i_ctime=CURRENT_TIME;
114 }
115 if (!inode->i_zone[8])
116 return 0;
117 if (!(bh=bread(inode->i_dev,inode->i_zone[8])))
118 return 0;
119 i = ((unsigned short *)bh->b_data)[block>>9];
120 if (create && !i)
121 if ((i=new_block(inode->i_dev))) {
122 ((unsigned short *) (bh->b_data))[block>>9]=i;
123 bh->b_dirt=1;
124 }
125 brelse(bh);
126 if (!i)
127 return 0;
128 if (!(bh=bread(inode->i_dev,i)))
129 return 0;
130 i = ((unsigned short *)bh->b_data)[block&511];
131 if (create && !i)
132 if ((i=new_block(inode->i_dev))) {
133 ((unsigned short *) (bh->b_data))[block&511]=i;
134 bh->b_dirt=1;
135 }
136 brelse(bh);
137 return i;
138}
139
140int bmap(struct m_inode * inode,int block)
141{
142 return _bmap(inode,block,0);
143}
144
145int create_block(struct m_inode * inode, int block)
146{
147 return _bmap(inode,block,1);
148}
149
150void iput(struct m_inode * inode)
151{
152 if (!inode)
153 return;
154 wait_on_inode(inode);
155 if (!inode->i_count)
156 panic("iput: trying to free free inode");
157 if (inode->i_pipe) {
158 wake_up(&inode->i_wait);
159 if (--inode->i_count)
160 return;
161 free_page(inode->i_size);
162 inode->i_count=0;
163 inode->i_dirt=0;
164 inode->i_pipe=0;
165 return;
166 }
167 if (!inode->i_dev) {
168 inode->i_count--;
169 return;
170 }
171 if (S_ISBLK(inode->i_mode)) {
172 sync_dev(inode->i_zone[0]);
173 wait_on_inode(inode);
174 }
175repeat:
176 if (inode->i_count>1) {
177 inode->i_count--;
178 return;
179 }
180 if (!inode->i_nlinks) {
181 truncate(inode);
182 free_inode(inode);
183 return;
184 }
185 if (inode->i_dirt) {
186 write_inode(inode); /* we can sleep - so do again */
187 wait_on_inode(inode);
188 goto repeat;
189 }
190 inode->i_count--;
191 return;
192}
193
194struct m_inode * get_empty_inode(void)
195{
196 struct m_inode * inode;
197 static struct m_inode * last_inode = inode_table;
198 int i;
199
200 do {
201 inode = NULL;
202 for (i = NR_INODE; i ; i--) {
203 if (++last_inode >= inode_table + NR_INODE)
204 last_inode = inode_table;
205 if (!last_inode->i_count) {
206 inode = last_inode;
207 if (!inode->i_dirt && !inode->i_lock)
208 break;
209 }
210 }
211 if (!inode) {
212 for (i=0 ; i<NR_INODE ; i++)
213 printk("%04x: %6d\t",inode_table[i].i_dev,
214 inode_table[i].i_num);
215 panic("No free inodes in mem");
216 }
217 wait_on_inode(inode);
218 while (inode->i_dirt) {
219 write_inode(inode);
220 wait_on_inode(inode);
221 }
222 } while (inode->i_count);
223 memset(inode,0,sizeof(*inode));
224 inode->i_count = 1;
225 return inode;
226}
227
228struct m_inode * get_pipe_inode(void)
229{
230 struct m_inode * inode;
231
232 if (!(inode = get_empty_inode()))
233 return NULL;
234 if (!(inode->i_size=get_free_page())) {
235 inode->i_count = 0;
236 return NULL;
237 }
238 inode->i_count = 2; /* sum of readers/writers */
239 PIPE_HEAD(*inode) = PIPE_TAIL(*inode) = 0;
240 inode->i_pipe = 1;
241 return inode;
242}
243
244struct m_inode * iget(int dev,int nr)
245{
246 struct m_inode * inode, * empty;
247
248 if (!dev)
249 panic("iget with dev==0");
250 empty = get_empty_inode();
251 inode = inode_table;
252 while (inode < NR_INODE+inode_table) {
253 if (inode->i_dev != dev || inode->i_num != nr) {
254 inode++;
255 continue;
256 }
257 wait_on_inode(inode);
258 if (inode->i_dev != dev || inode->i_num != nr) {
259 inode = inode_table;
260 continue;
261 }
262 inode->i_count++;
263 if (inode->i_mount) {
264 int i;
265
266 for (i = 0 ; i<NR_SUPER ; i++)
267 if (super_block[i].s_imount==inode)
268 break;
269 if (i >= NR_SUPER) {
270 printk("Mounted inode hasn't got sb\n");
271 if (empty)
272 iput(empty);
273 return inode;
274 }
275 iput(inode);
276 dev = super_block[i].s_dev;
277 nr = ROOT_INO;
278 inode = inode_table;
279 continue;
280 }
281 if (empty)
282 iput(empty);
283 return inode;
284 }
285 if (!empty)
286 return (NULL);
287 inode=empty;
288 inode->i_dev = dev;
289 inode->i_num = nr;
290 read_inode(inode);
291 return inode;
292}
293
294static void read_inode(struct m_inode * inode)
295{
296 struct super_block * sb;
297 struct buffer_head * bh;
298 int block;
299
300 lock_inode(inode);
301 if (!(sb=get_super(inode->i_dev)))
302 panic("trying to read inode without dev");
303 block = 2 + sb->s_imap_blocks + sb->s_zmap_blocks +
304 (inode->i_num-1)/INODES_PER_BLOCK;
305 if (!(bh=bread(inode->i_dev,block)))
306 panic("unable to read i-node block");
307 *(struct d_inode *)inode =
308 ((struct d_inode *)bh->b_data)
309 [(inode->i_num-1)%INODES_PER_BLOCK];
310 brelse(bh);
311 unlock_inode(inode);
312}
313
314static void write_inode(struct m_inode * inode)
315{
316 struct super_block * sb;
317 struct buffer_head * bh;
318 int block;
319
320 lock_inode(inode);
321 if (!inode->i_dirt || !inode->i_dev) {
322 unlock_inode(inode);
323 return;
324 }
325 if (!(sb=get_super(inode->i_dev)))
326 panic("trying to write inode without device");
327 block = 2 + sb->s_imap_blocks + sb->s_zmap_blocks +
328 (inode->i_num-1)/INODES_PER_BLOCK;
329 if (!(bh=bread(inode->i_dev,block)))
330 panic("unable to read i-node block");
331 ((struct d_inode *)bh->b_data)
332 [(inode->i_num-1)%INODES_PER_BLOCK] =
333 *(struct d_inode *)inode;
334 bh->b_dirt=1;
335 inode->i_dirt=0;
336 brelse(bh);
337 unlock_inode(inode);
338}
diff --git a/src/fs/ioctl.c b/src/fs/ioctl.c
new file mode 100644
index 0000000..47ce3cb
--- /dev/null
+++ b/src/fs/ioctl.c
@@ -0,0 +1,46 @@
1/*
2 * linux/fs/ioctl.c
3 *
4 * (C) 1991 Linus Torvalds
5 */
6
7/* #include <string.h>*/
8#include <errno.h>
9#include <sys/stat.h>
10
11#include <linux/sched.h>
12
13extern int tty_ioctl(int dev, int cmd, int arg);
14
15typedef int (*ioctl_ptr)(int dev,int cmd,int arg);
16
17#define NRDEVS ((sizeof (ioctl_table))/(sizeof (ioctl_ptr)))
18
19static ioctl_ptr ioctl_table[]={
20 NULL, /* nodev */
21 NULL, /* /dev/mem */
22 NULL, /* /dev/fd */
23 NULL, /* /dev/hd */
24 tty_ioctl, /* /dev/ttyx */
25 tty_ioctl, /* /dev/tty */
26 NULL, /* /dev/lp */
27 NULL}; /* named pipes */
28
29
30int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
31{
32 struct file * filp;
33 int dev,mode;
34
35 if (fd >= NR_OPEN || !(filp = current->filp[fd]))
36 return -EBADF;
37 mode=filp->f_inode->i_mode;
38 if (!S_ISCHR(mode) && !S_ISBLK(mode))
39 return -EINVAL;
40 dev = filp->f_inode->i_zone[0];
41 if (MAJOR(dev) >= NRDEVS)
42 return -ENODEV;
43 if (!ioctl_table[MAJOR(dev)])
44 return -ENOTTY;
45 return ioctl_table[MAJOR(dev)](dev,cmd,arg);
46}
diff --git a/src/fs/namei.c b/src/fs/namei.c
new file mode 100644
index 0000000..97d0de4
--- /dev/null
+++ b/src/fs/namei.c
@@ -0,0 +1,778 @@
1/*
2 * linux/fs/namei.c
3 *
4 * (C) 1991 Linus Torvalds
5 */
6
7/*
8 * Some corrections by tytso.
9 */
10
11#include <linux/sched.h>
12#include <linux/kernel.h>
13#include <asm/segment.h>
14
15#include <string.h>
16#include <fcntl.h>
17#include <errno.h>
18#include <const.h>
19#include <sys/stat.h>
20
21#define ACC_MODE(x) ("\004\002\006\377"[(x)&O_ACCMODE])
22
23/*
24 * comment out this line if you want names > NAME_LEN chars to be
25 * truncated. Else they will be disallowed.
26 */
27/* #define NO_TRUNCATE */
28
29#define MAY_EXEC 1
30#define MAY_WRITE 2
31#define MAY_READ 4
32
33/*
34 * permission()
35 *
36 * is used to check for read/write/execute permissions on a file.
37 * I don't know if we should look at just the euid or both euid and
38 * uid, but that should be easily changed.
39 */
40static int permission(struct m_inode * inode,int mask)
41{
42 int mode = inode->i_mode;
43
44/* special case: not even root can read/write a deleted file */
45 if (inode->i_dev && !inode->i_nlinks)
46 return 0;
47 else if (current->euid==inode->i_uid)
48 mode >>= 6;
49 else if (current->egid==inode->i_gid)
50 mode >>= 3;
51 if (((mode & mask & 0007) == mask) || suser())
52 return 1;
53 return 0;
54}
55
56/*
57 * ok, we cannot use strncmp, as the name is not in our data space.
58 * Thus we'll have to use match. No big problem. Match also makes
59 * some sanity tests.
60 *
61 * NOTE! unlike strncmp, match returns 1 for success, 0 for failure.
62 */
63static int match(int len,const char * name,struct dir_entry * de)
64{
65 register int same ;
66
67 if (!de || !de->inode || len > NAME_LEN)
68 return 0;
69 if (len < NAME_LEN && de->name[len])
70 return 0;
71 __asm__("cld\n\t"
72 "fs ; repe ; cmpsb\n\t"
73 "setz %%al"
74 :"=a" (same)
75 :"0" (0),"S" ((long) name),"D" ((long) de->name),"c" (len)
76 );
77 return same;
78}
79
80/*
81 * find_entry()
82 *
83 * finds an entry in the specified directory with the wanted name. It
84 * returns the cache buffer in which the entry was found, and the entry
85 * itself (as a parameter - res_dir). It does NOT read the inode of the
86 * entry - you'll have to do that yourself if you want to.
87 *
88 * This also takes care of the few special cases due to '..'-traversal
89 * over a pseudo-root and a mount point.
90 */
91static struct buffer_head * find_entry(struct m_inode ** dir,
92 const char * name, int namelen, struct dir_entry ** res_dir)
93{
94 int entries;
95 int block,i;
96 struct buffer_head * bh;
97 struct dir_entry * de;
98 struct super_block * sb;
99
100#ifdef NO_TRUNCATE
101 if (namelen > NAME_LEN)
102 return NULL;
103#else
104 if (namelen > NAME_LEN)
105 namelen = NAME_LEN;
106#endif
107 entries = (*dir)->i_size / (sizeof (struct dir_entry));
108 *res_dir = NULL;
109 if (!namelen)
110 return NULL;
111/* check for '..', as we might have to do some "magic" for it */
112 if (namelen==2 && get_fs_byte(name)=='.' && get_fs_byte(name+1)=='.') {
113/* '..' in a pseudo-root results in a faked '.' (just change namelen) */
114 if ((*dir) == current->root)
115 namelen=1;
116 else if ((*dir)->i_num == ROOT_INO) {
117/* '..' over a mount-point results in 'dir' being exchanged for the mounted
118 directory-inode. NOTE! We set mounted, so that we can iput the new dir */
119 sb=get_super((*dir)->i_dev);
120 if (sb->s_imount) {
121 iput(*dir);
122 (*dir)=sb->s_imount;
123 (*dir)->i_count++;
124 }
125 }
126 }
127 if (!(block = (*dir)->i_zone[0]))
128 return NULL;
129 if (!(bh = bread((*dir)->i_dev,block)))
130 return NULL;
131 i = 0;
132 de = (struct dir_entry *) bh->b_data;
133 while (i < entries) {
134 if ((char *)de >= BLOCK_SIZE+bh->b_data) {
135 brelse(bh);
136 bh = NULL;
137 if (!(block = bmap(*dir,i/DIR_ENTRIES_PER_BLOCK)) ||
138 !(bh = bread((*dir)->i_dev,block))) {
139 i += DIR_ENTRIES_PER_BLOCK;
140 continue;
141 }
142 de = (struct dir_entry *) bh->b_data;
143 }
144 if (match(namelen,name,de)) {
145 *res_dir = de;
146 return bh;
147 }
148 de++;
149 i++;
150 }
151 brelse(bh);
152 return NULL;
153}
154
155/*
156 * add_entry()
157 *
158 * adds a file entry to the specified directory, using the same
159 * semantics as find_entry(). It returns NULL if it failed.
160 *
161 * NOTE!! The inode part of 'de' is left at 0 - which means you
162 * may not sleep between calling this and putting something into
163 * the entry, as someone else might have used it while you slept.
164 */
165static struct buffer_head * add_entry(struct m_inode * dir,
166 const char * name, int namelen, struct dir_entry ** res_dir)
167{
168 int block,i;
169 struct buffer_head * bh;
170 struct dir_entry * de;
171
172 *res_dir = NULL;
173#ifdef NO_TRUNCATE
174 if (namelen > NAME_LEN)
175 return NULL;
176#else
177 if (namelen > NAME_LEN)
178 namelen = NAME_LEN;
179#endif
180 if (!namelen)
181 return NULL;
182 if (!(block = dir->i_zone[0]))
183 return NULL;
184 if (!(bh = bread(dir->i_dev,block)))
185 return NULL;
186 i = 0;
187 de = (struct dir_entry *) bh->b_data;
188 while (1) {
189 if ((char *)de >= BLOCK_SIZE+bh->b_data) {
190 brelse(bh);
191 bh = NULL;
192 block = create_block(dir,i/DIR_ENTRIES_PER_BLOCK);
193 if (!block)
194 return NULL;
195 if (!(bh = bread(dir->i_dev,block))) {
196 i += DIR_ENTRIES_PER_BLOCK;
197 continue;
198 }
199 de = (struct dir_entry *) bh->b_data;
200 }
201 if (i*sizeof(struct dir_entry) >= dir->i_size) {
202 de->inode=0;
203 dir->i_size = (i+1)*sizeof(struct dir_entry);
204 dir->i_dirt = 1;
205 dir->i_ctime = CURRENT_TIME;
206 }
207 if (!de->inode) {
208 dir->i_mtime = CURRENT_TIME;
209 for (i=0; i < NAME_LEN ; i++)
210 de->name[i]=(i<namelen)?get_fs_byte(name+i):0;
211 bh->b_dirt = 1;
212 *res_dir = de;
213 return bh;
214 }
215 de++;
216 i++;
217 }
218 brelse(bh);
219 return NULL;
220}
221
222/*
223 * get_dir()
224 *
225 * Getdir traverses the pathname until it hits the topmost directory.
226 * It returns NULL on failure.
227 */
228static struct m_inode * get_dir(const char * pathname)
229{
230 char c;
231 const char * thisname;
232 struct m_inode * inode;
233 struct buffer_head * bh;
234 int namelen,inr,idev;
235 struct dir_entry * de;
236
237 if (!current->root || !current->root->i_count)
238 panic("No root inode");
239 if (!current->pwd || !current->pwd->i_count)
240 panic("No cwd inode");
241 if ((c=get_fs_byte(pathname))=='/') {
242 inode = current->root;
243 pathname++;
244 } else if (c)
245 inode = current->pwd;
246 else
247 return NULL; /* empty name is bad */
248 inode->i_count++;
249 while (1) {
250 thisname = pathname;
251 if (!S_ISDIR(inode->i_mode) || !permission(inode,MAY_EXEC)) {
252 iput(inode);
253 return NULL;
254 }
255 for(namelen=0;(c=get_fs_byte(pathname++))&&(c!='/');namelen++)
256 /* nothing */ ;
257 if (!c)
258 return inode;
259 if (!(bh = find_entry(&inode,thisname,namelen,&de))) {
260 iput(inode);
261 return NULL;
262 }
263 inr = de->inode;
264 idev = inode->i_dev;
265 brelse(bh);
266 iput(inode);
267 if (!(inode = iget(idev,inr)))
268 return NULL;
269 }
270}
271
272/*
273 * dir_namei()
274 *
275 * dir_namei() returns the inode of the directory of the
276 * specified name, and the name within that directory.
277 */
278static struct m_inode * dir_namei(const char * pathname,
279 int * namelen, const char ** name)
280{
281 char c;
282 const char * basename;
283 struct m_inode * dir;
284
285 if (!(dir = get_dir(pathname)))
286 return NULL;
287 basename = pathname;
288 while ((c=get_fs_byte(pathname++)))
289 if (c=='/')
290 basename=pathname;
291 *namelen = pathname-basename-1;
292 *name = basename;
293 return dir;
294}
295
296/*
297 * namei()
298 *
299 * is used by most simple commands to get the inode of a specified name.
300 * Open, link etc use their own routines, but this is enough for things
301 * like 'chmod' etc.
302 */
303struct m_inode * namei(const char * pathname)
304{
305 const char * basename;
306 int inr,dev,namelen;
307 struct m_inode * dir;
308 struct buffer_head * bh;
309 struct dir_entry * de;
310
311 if (!(dir = dir_namei(pathname,&namelen,&basename)))
312 return NULL;
313 if (!namelen) /* special case: '/usr/' etc */
314 return dir;
315 bh = find_entry(&dir,basename,namelen,&de);
316 if (!bh) {
317 iput(dir);
318 return NULL;
319 }
320 inr = de->inode;
321 dev = dir->i_dev;
322 brelse(bh);
323 iput(dir);
324 dir=iget(dev,inr);
325 if (dir) {
326 dir->i_atime=CURRENT_TIME;
327 dir->i_dirt=1;
328 }
329 return dir;
330}
331
332/*
333 * open_namei()
334 *
335 * namei for open - this is in fact almost the whole open-routine.
336 */
337int open_namei(const char * pathname, int flag, int mode,
338 struct m_inode ** res_inode)
339{
340 const char * basename;
341 int inr,dev,namelen;
342 struct m_inode * dir, *inode;
343 struct buffer_head * bh;
344 struct dir_entry * de;
345
346 if ((flag & O_TRUNC) && !(flag & O_ACCMODE))
347 flag |= O_WRONLY;
348 mode &= 0777 & ~current->umask;
349 mode |= I_REGULAR;
350 if (!(dir = dir_namei(pathname,&namelen,&basename)))
351 return -ENOENT;
352 if (!namelen) { /* special case: '/usr/' etc */
353 if (!(flag & (O_ACCMODE|O_CREAT|O_TRUNC))) {
354 *res_inode=dir;
355 return 0;
356 }
357 iput(dir);
358 return -EISDIR;
359 }
360 bh = find_entry(&dir,basename,namelen,&de);
361 if (!bh) {
362 if (!(flag & O_CREAT)) {
363 iput(dir);
364 return -ENOENT;
365 }
366 if (!permission(dir,MAY_WRITE)) {
367 iput(dir);
368 return -EACCES;
369 }
370 inode = new_inode(dir->i_dev);
371 if (!inode) {
372 iput(dir);
373 return -ENOSPC;
374 }
375 inode->i_uid = current->euid;
376 inode->i_mode = mode;
377 inode->i_dirt = 1;
378 bh = add_entry(dir,basename,namelen,&de);
379 if (!bh) {
380 inode->i_nlinks--;
381 iput(inode);
382 iput(dir);
383 return -ENOSPC;
384 }
385 de->inode = inode->i_num;
386 bh->b_dirt = 1;
387 brelse(bh);
388 iput(dir);
389 *res_inode = inode;
390 return 0;
391 }
392 inr = de->inode;
393 dev = dir->i_dev;
394 brelse(bh);
395 iput(dir);
396 if (flag & O_EXCL)
397 return -EEXIST;
398 if (!(inode=iget(dev,inr)))
399 return -EACCES;
400 if ((S_ISDIR(inode->i_mode) && (flag & O_ACCMODE)) ||
401 !permission(inode,ACC_MODE(flag))) {
402 iput(inode);
403 return -EPERM;
404 }
405 inode->i_atime = CURRENT_TIME;
406 if (flag & O_TRUNC)
407 truncate(inode);
408 *res_inode = inode;
409 return 0;
410}
411
412int sys_mknod(const char * filename, int mode, int dev)
413{
414 const char * basename;
415 int namelen;
416 struct m_inode * dir, * inode;
417 struct buffer_head * bh;
418 struct dir_entry * de;
419
420 if (!suser())
421 return -EPERM;
422 if (!(dir = dir_namei(filename,&namelen,&basename)))
423 return -ENOENT;
424 if (!namelen) {
425 iput(dir);
426 return -ENOENT;
427 }
428 if (!permission(dir,MAY_WRITE)) {
429 iput(dir);
430 return -EPERM;
431 }
432 bh = find_entry(&dir,basename,namelen,&de);
433 if (bh) {
434 brelse(bh);
435 iput(dir);
436 return -EEXIST;
437 }
438 inode = new_inode(dir->i_dev);
439 if (!inode) {
440 iput(dir);
441 return -ENOSPC;
442 }
443 inode->i_mode = mode;
444 if (S_ISBLK(mode) || S_ISCHR(mode))
445 inode->i_zone[0] = dev;
446 inode->i_mtime = inode->i_atime = CURRENT_TIME;
447 inode->i_dirt = 1;
448 bh = add_entry(dir,basename,namelen,&de);
449 if (!bh) {
450 iput(dir);
451 inode->i_nlinks=0;
452 iput(inode);
453 return -ENOSPC;
454 }
455 de->inode = inode->i_num;
456 bh->b_dirt = 1;
457 iput(dir);
458 iput(inode);
459 brelse(bh);
460 return 0;
461}
462
463int sys_mkdir(const char * pathname, int mode)
464{
465 const char * basename;
466 int namelen;
467 struct m_inode * dir, * inode;
468 struct buffer_head * bh, *dir_block;
469 struct dir_entry * de;
470
471 if (!suser())
472 return -EPERM;
473 if (!(dir = dir_namei(pathname,&namelen,&basename)))
474 return -ENOENT;
475 if (!namelen) {
476 iput(dir);
477 return -ENOENT;
478 }
479 if (!permission(dir,MAY_WRITE)) {
480 iput(dir);
481 return -EPERM;
482 }
483 bh = find_entry(&dir,basename,namelen,&de);
484 if (bh) {
485 brelse(bh);
486 iput(dir);
487 return -EEXIST;
488 }
489 inode = new_inode(dir->i_dev);
490 if (!inode) {
491 iput(dir);
492 return -ENOSPC;
493 }
494 inode->i_size = 32;
495 inode->i_dirt = 1;
496 inode->i_mtime = inode->i_atime = CURRENT_TIME;
497 if (!(inode->i_zone[0]=new_block(inode->i_dev))) {
498 iput(dir);
499 inode->i_nlinks--;
500 iput(inode);
501 return -ENOSPC;
502 }
503 inode->i_dirt = 1;
504 if (!(dir_block=bread(inode->i_dev,inode->i_zone[0]))) {
505 iput(dir);
506 free_block(inode->i_dev,inode->i_zone[0]);
507 inode->i_nlinks--;
508 iput(inode);
509 return -ERROR;
510 }
511 de = (struct dir_entry *) dir_block->b_data;
512 de->inode=inode->i_num;
513 strcpy(de->name,".");
514 de++;
515 de->inode = dir->i_num;
516 strcpy(de->name,"..");
517 inode->i_nlinks = 2;
518 dir_block->b_dirt = 1;
519 brelse(dir_block);
520 inode->i_mode = I_DIRECTORY | (mode & 0777 & ~current->umask);
521 inode->i_dirt = 1;
522 bh = add_entry(dir,basename,namelen,&de);
523 if (!bh) {
524 iput(dir);
525 free_block(inode->i_dev,inode->i_zone[0]);
526 inode->i_nlinks=0;
527 iput(inode);
528 return -ENOSPC;
529 }
530 de->inode = inode->i_num;
531 bh->b_dirt = 1;
532 dir->i_nlinks++;
533 dir->i_dirt = 1;
534 iput(dir);
535 iput(inode);
536 brelse(bh);
537 return 0;
538}
539
540/*
541 * routine to check that the specified directory is empty (for rmdir)
542 */
543static int empty_dir(struct m_inode * inode)
544{
545 int nr,block;
546 int len;
547 struct buffer_head * bh;
548 struct dir_entry * de;
549
550 len = inode->i_size / sizeof (struct dir_entry);
551 if (len<2 || !inode->i_zone[0] ||
552 !(bh=bread(inode->i_dev,inode->i_zone[0]))) {
553 printk("warning - bad directory on dev %04x\n",inode->i_dev);
554 return 0;
555 }
556 de = (struct dir_entry *) bh->b_data;
557 if (de[0].inode != inode->i_num || !de[1].inode ||
558 strcmp(".",de[0].name) || strcmp("..",de[1].name)) {
559 printk("warning - bad directory on dev %04x\n",inode->i_dev);
560 return 0;
561 }
562 nr = 2;
563 de += 2;
564 while (nr<len) {
565 if ((void *) de >= (void *) (bh->b_data+BLOCK_SIZE)) {
566 brelse(bh);
567 block=bmap(inode,nr/DIR_ENTRIES_PER_BLOCK);
568 if (!block) {
569 nr += DIR_ENTRIES_PER_BLOCK;
570 continue;
571 }
572 if (!(bh=bread(inode->i_dev,block)))
573 return 0;
574 de = (struct dir_entry *) bh->b_data;
575 }
576 if (de->inode) {
577 brelse(bh);
578 return 0;
579 }
580 de++;
581 nr++;
582 }
583 brelse(bh);
584 return 1;
585}
586
587int sys_rmdir(const char * name)
588{
589 const char * basename;
590 int namelen;
591 struct m_inode * dir, * inode;
592 struct buffer_head * bh;
593 struct dir_entry * de;
594
595 if (!suser())
596 return -EPERM;
597 if (!(dir = dir_namei(name,&namelen,&basename)))
598 return -ENOENT;
599 if (!namelen) {
600 iput(dir);
601 return -ENOENT;
602 }
603 if (!permission(dir,MAY_WRITE)) {
604 iput(dir);
605 return -EPERM;
606 }
607 bh = find_entry(&dir,basename,namelen,&de);
608 if (!bh) {
609 iput(dir);
610 return -ENOENT;
611 }
612 if (!(inode = iget(dir->i_dev, de->inode))) {
613 iput(dir);
614 brelse(bh);
615 return -EPERM;
616 }
617 if ((dir->i_mode & S_ISVTX) && current->euid &&
618 inode->i_uid != current->euid) {
619 iput(dir);
620 iput(inode);
621 brelse(bh);
622 return -EPERM;
623 }
624 if (inode->i_dev != dir->i_dev || inode->i_count>1) {
625 iput(dir);
626 iput(inode);
627 brelse(bh);
628 return -EPERM;
629 }
630 if (inode == dir) { /* we may not delete ".", but "../dir" is ok */
631 iput(inode);
632 iput(dir);
633 brelse(bh);
634 return -EPERM;
635 }
636 if (!S_ISDIR(inode->i_mode)) {
637 iput(inode);
638 iput(dir);
639 brelse(bh);
640 return -ENOTDIR;
641 }
642 if (!empty_dir(inode)) {
643 iput(inode);
644 iput(dir);
645 brelse(bh);
646 return -ENOTEMPTY;
647 }
648 if (inode->i_nlinks != 2)
649 printk("empty directory has nlink!=2 (%d)",inode->i_nlinks);
650 de->inode = 0;
651 bh->b_dirt = 1;
652 brelse(bh);
653 inode->i_nlinks=0;
654 inode->i_dirt=1;
655 dir->i_nlinks--;
656 dir->i_ctime = dir->i_mtime = CURRENT_TIME;
657 dir->i_dirt=1;
658 iput(dir);
659 iput(inode);
660 return 0;
661}
662
663int sys_unlink(const char * name)
664{
665 const char * basename;
666 int namelen;
667 struct m_inode * dir, * inode;
668 struct buffer_head * bh;
669 struct dir_entry * de;
670
671 if (!(dir = dir_namei(name,&namelen,&basename)))
672 return -ENOENT;
673 if (!namelen) {
674 iput(dir);
675 return -ENOENT;
676 }
677 if (!permission(dir,MAY_WRITE)) {
678 iput(dir);
679 return -EPERM;
680 }
681 bh = find_entry(&dir,basename,namelen,&de);
682 if (!bh) {
683 iput(dir);
684 return -ENOENT;
685 }
686 if (!(inode = iget(dir->i_dev, de->inode))) {
687 iput(dir);
688 brelse(bh);
689 return -ENOENT;
690 }
691 if ((dir->i_mode & S_ISVTX) && !suser() &&
692 current->euid != inode->i_uid &&
693 current->euid != dir->i_uid) {
694 iput(dir);
695 iput(inode);
696 brelse(bh);
697 return -EPERM;
698 }
699 if (S_ISDIR(inode->i_mode)) {
700 iput(inode);
701 iput(dir);
702 brelse(bh);
703 return -EPERM;
704 }
705 if (!inode->i_nlinks) {
706 printk("Deleting nonexistent file (%04x:%d), %d\n",
707 inode->i_dev,inode->i_num,inode->i_nlinks);
708 inode->i_nlinks=1;
709 }
710 de->inode = 0;
711 bh->b_dirt = 1;
712 brelse(bh);
713 inode->i_nlinks--;
714 inode->i_dirt = 1;
715 inode->i_ctime = CURRENT_TIME;
716 iput(inode);
717 iput(dir);
718 return 0;
719}
720
721int sys_link(const char * oldname, const char * newname)
722{
723 struct dir_entry * de;
724 struct m_inode * oldinode, * dir;
725 struct buffer_head * bh;
726 const char * basename;
727 int namelen;
728
729 oldinode=namei(oldname);
730 if (!oldinode)
731 return -ENOENT;
732 if (S_ISDIR(oldinode->i_mode)) {
733 iput(oldinode);
734 return -EPERM;
735 }
736 dir = dir_namei(newname,&namelen,&basename);
737 if (!dir) {
738 iput(oldinode);
739 return -EACCES;
740 }
741 if (!namelen) {
742 iput(oldinode);
743 iput(dir);
744 return -EPERM;
745 }
746 if (dir->i_dev != oldinode->i_dev) {
747 iput(dir);
748 iput(oldinode);
749 return -EXDEV;
750 }
751 if (!permission(dir,MAY_WRITE)) {
752 iput(dir);
753 iput(oldinode);
754 return -EACCES;
755 }
756 bh = find_entry(&dir,basename,namelen,&de);
757 if (bh) {
758 brelse(bh);
759 iput(dir);
760 iput(oldinode);
761 return -EEXIST;
762 }
763 bh = add_entry(dir,basename,namelen,&de);
764 if (!bh) {
765 iput(dir);
766 iput(oldinode);
767 return -ENOSPC;
768 }
769 de->inode = oldinode->i_num;
770 bh->b_dirt = 1;
771 brelse(bh);
772 iput(dir);
773 oldinode->i_nlinks++;
774 oldinode->i_ctime = CURRENT_TIME;
775 oldinode->i_dirt = 1;
776 iput(oldinode);
777 return 0;
778}
diff --git a/src/fs/open.c b/src/fs/open.c
new file mode 100644
index 0000000..cac0082
--- /dev/null
+++ b/src/fs/open.c
@@ -0,0 +1,209 @@
1/*
2 * linux/fs/open.c
3 *
4 * (C) 1991 Linus Torvalds
5 */
6
7/* #include <string.h> */
8#include <errno.h>
9#include <fcntl.h>
10#include <sys/types.h>
11#include <utime.h>
12#include <sys/stat.h>
13
14#include <linux/sched.h>
15#include <linux/tty.h>
16#include <linux/kernel.h>
17#include <asm/segment.h>
18
19int sys_ustat(int dev, struct ustat * ubuf)
20{
21 return -ENOSYS;
22}
23
24int sys_utime(char * filename, struct utimbuf * times)
25{
26 struct m_inode * inode;
27 long actime,modtime;
28
29 if (!(inode=namei(filename)))
30 return -ENOENT;
31 if (times) {
32 actime = get_fs_long((unsigned long *) &times->actime);
33 modtime = get_fs_long((unsigned long *) &times->modtime);
34 } else
35 actime = modtime = CURRENT_TIME;
36 inode->i_atime = actime;
37 inode->i_mtime = modtime;
38 inode->i_dirt = 1;
39 iput(inode);
40 return 0;
41}
42
43/*
44 * XXX should we use the real or effective uid? BSD uses the real uid,
45 * so as to make this call useful to setuid programs.
46 */
47int sys_access(const char * filename,int mode)
48{
49 struct m_inode * inode;
50 int res, i_mode;
51
52 mode &= 0007;
53 if (!(inode=namei(filename)))
54 return -EACCES;
55 i_mode = res = inode->i_mode & 0777;
56 iput(inode);
57 if (current->uid == inode->i_uid)
58 res >>= 6;
59 else if (current->gid == inode->i_gid)
60 res >>= 6;
61 if ((res & 0007 & mode) == mode)
62 return 0;
63 /*
64 * XXX we are doing this test last because we really should be
65 * swapping the effective with the real user id (temporarily),
66 * and then calling suser() routine. If we do call the
67 * suser() routine, it needs to be called last.
68 */
69 if ((!current->uid) &&
70 (!(mode & 1) || (i_mode & 0111)))
71 return 0;
72 return -EACCES;
73}
74
75int sys_chdir(const char * filename)
76{
77 struct m_inode * inode;
78
79 if (!(inode = namei(filename)))
80 return -ENOENT;
81 if (!S_ISDIR(inode->i_mode)) {
82 iput(inode);
83 return -ENOTDIR;
84 }
85 iput(current->pwd);
86 current->pwd = inode;
87 return (0);
88}
89
90int sys_chroot(const char * filename)
91{
92 struct m_inode * inode;
93
94 if (!(inode=namei(filename)))
95 return -ENOENT;
96 if (!S_ISDIR(inode->i_mode)) {
97 iput(inode);
98 return -ENOTDIR;
99 }
100 iput(current->root);
101 current->root = inode;
102 return (0);
103}
104
105int sys_chmod(const char * filename,int mode)
106{
107 struct m_inode * inode;
108
109 if (!(inode=namei(filename)))
110 return -ENOENT;
111 if ((current->euid != inode->i_uid) && !suser()) {
112 iput(inode);
113 return -EACCES;
114 }
115 inode->i_mode = (mode & 07777) | (inode->i_mode & ~07777);
116 inode->i_dirt = 1;
117 iput(inode);
118 return 0;
119}
120
121int sys_chown(const char * filename,int uid,int gid)
122{
123 struct m_inode * inode;
124
125 if (!(inode=namei(filename)))
126 return -ENOENT;
127 if (!suser()) {
128 iput(inode);
129 return -EACCES;
130 }
131 inode->i_uid=uid;
132 inode->i_gid=gid;
133 inode->i_dirt=1;
134 iput(inode);
135 return 0;
136}
137
138int sys_open(const char * filename,int flag,int mode)
139{
140 struct m_inode * inode;
141 struct file * f;
142 int i,fd;
143
144 mode &= 0777 & ~current->umask;
145 for(fd=0 ; fd<NR_OPEN ; fd++)
146 if (!current->filp[fd])
147 break;
148 if (fd>=NR_OPEN)
149 return -EINVAL;
150 current->close_on_exec &= ~(1<<fd);
151 f=0+file_table;
152 for (i=0 ; i<NR_FILE ; i++,f++)
153 if (!f->f_count) break;
154 if (i>=NR_FILE)
155 return -EINVAL;
156 (current->filp[fd]=f)->f_count++;
157 if ((i=open_namei(filename,flag,mode,&inode))<0) {
158 current->filp[fd]=NULL;
159 f->f_count=0;
160 return i;
161 }
162/* ttys are somewhat special (ttyxx major==4, tty major==5) */
163 if (S_ISCHR(inode->i_mode)) {
164 if (MAJOR(inode->i_zone[0])==4) {
165 if (current->leader && current->tty<0) {
166 current->tty = MINOR(inode->i_zone[0]);
167 tty_table[current->tty].pgrp = current->pgrp;
168 }
169 } else if (MAJOR(inode->i_zone[0])==5)
170 if (current->tty<0) {
171 iput(inode);
172 current->filp[fd]=NULL;
173 f->f_count=0;
174 return -EPERM;
175 }
176 }
177/* Likewise with block-devices: check for floppy_change */
178 if (S_ISBLK(inode->i_mode))
179 check_disk_change(inode->i_zone[0]);
180 f->f_mode = inode->i_mode;
181 f->f_flags = flag;
182 f->f_count = 1;
183 f->f_inode = inode;
184 f->f_pos = 0;
185 return (fd);
186}
187
188int sys_creat(const char * pathname, int mode)
189{
190 return sys_open(pathname, O_CREAT | O_TRUNC, mode);
191}
192
193int sys_close(unsigned int fd)
194{
195 struct file * filp;
196
197 if (fd >= NR_OPEN)
198 return -EINVAL;
199 current->close_on_exec &= ~(1<<fd);
200 if (!(filp = current->filp[fd]))
201 return -EINVAL;
202 current->filp[fd] = NULL;
203 if (filp->f_count == 0)
204 panic("Close: file count is 0");
205 if (--filp->f_count)
206 return (0);
207 iput(filp->f_inode);
208 return (0);
209}
diff --git a/src/fs/pipe.c b/src/fs/pipe.c
new file mode 100644
index 0000000..dfc4480
--- /dev/null
+++ b/src/fs/pipe.c
@@ -0,0 +1,111 @@
1/*
2 * linux/fs/pipe.c
3 *
4 * (C) 1991 Linus Torvalds
5 */
6
7#include <signal.h>
8
9#include <linux/sched.h>
10#include <linux/mm.h> /* for get_free_page */
11#include <asm/segment.h>
12
13int read_pipe(struct m_inode * inode, char * buf, int count)
14{
15 int chars, size, read = 0;
16
17 while (count>0) {
18 while (!(size=PIPE_SIZE(*inode))) {
19 wake_up(&inode->i_wait);
20 if (inode->i_count != 2) /* are there any writers? */
21 return read;
22 sleep_on(&inode->i_wait);
23 }
24 chars = PAGE_SIZE-PIPE_TAIL(*inode);
25 if (chars > count)
26 chars = count;
27 if (chars > size)
28 chars = size;
29 count -= chars;
30 read += chars;
31 size = PIPE_TAIL(*inode);
32 PIPE_TAIL(*inode) += chars;
33 PIPE_TAIL(*inode) &= (PAGE_SIZE-1);
34 while (chars-->0)
35 put_fs_byte(((char *)inode->i_size)[size++],buf++);
36 }
37 wake_up(&inode->i_wait);
38 return read;
39}
40
41int write_pipe(struct m_inode * inode, char * buf, int count)
42{
43 int chars, size, written = 0;
44
45 while (count>0) {
46 while (!(size=(PAGE_SIZE-1)-PIPE_SIZE(*inode))) {
47 wake_up(&inode->i_wait);
48 if (inode->i_count != 2) { /* no readers */
49 current->signal |= (1<<(SIGPIPE-1));
50 return written?written:-1;
51 }
52 sleep_on(&inode->i_wait);
53 }
54 chars = PAGE_SIZE-PIPE_HEAD(*inode);
55 if (chars > count)
56 chars = count;
57 if (chars > size)
58 chars = size;
59 count -= chars;
60 written += chars;
61 size = PIPE_HEAD(*inode);
62 PIPE_HEAD(*inode) += chars;
63 PIPE_HEAD(*inode) &= (PAGE_SIZE-1);
64 while (chars-->0)
65 ((char *)inode->i_size)[size++]=get_fs_byte(buf++);
66 }
67 wake_up(&inode->i_wait);
68 return written;
69}
70
71int sys_pipe(unsigned long * fildes)
72{
73 struct m_inode * inode;
74 struct file * f[2];
75 int fd[2];
76 int i,j;
77
78 j=0;
79 for(i=0;j<2 && i<NR_FILE;i++)
80 if (!file_table[i].f_count)
81 (f[j++]=i+file_table)->f_count++;
82 if (j==1)
83 f[0]->f_count=0;
84 if (j<2)
85 return -1;
86 j=0;
87 for(i=0;j<2 && i<NR_OPEN;i++)
88 if (!current->filp[i]) {
89 current->filp[ fd[j]=i ] = f[j];
90 j++;
91 }
92 if (j==1)
93 current->filp[fd[0]]=NULL;
94 if (j<2) {
95 f[0]->f_count=f[1]->f_count=0;
96 return -1;
97 }
98 if (!(inode=get_pipe_inode())) {
99 current->filp[fd[0]] =
100 current->filp[fd[1]] = NULL;
101 f[0]->f_count = f[1]->f_count = 0;
102 return -1;
103 }
104 f[0]->f_inode = f[1]->f_inode = inode;
105 f[0]->f_pos = f[1]->f_pos = 0;
106 f[0]->f_mode = 1; /* read */
107 f[1]->f_mode = 2; /* write */
108 put_fs_long(fd[0],0+fildes);
109 put_fs_long(fd[1],1+fildes);
110 return 0;
111}
diff --git a/src/fs/read_write.c b/src/fs/read_write.c
new file mode 100644
index 0000000..341274a
--- /dev/null
+++ b/src/fs/read_write.c
@@ -0,0 +1,103 @@
1/*
2 * linux/fs/read_write.c
3 *
4 * (C) 1991 Linus Torvalds
5 */
6
7#include <sys/stat.h>
8#include <errno.h>
9#include <sys/types.h>
10
11#include <linux/kernel.h>
12#include <linux/sched.h>
13#include <asm/segment.h>
14
15extern int rw_char(int rw,int dev, char * buf, int count, off_t * pos);
16extern int read_pipe(struct m_inode * inode, char * buf, int count);
17extern int write_pipe(struct m_inode * inode, char * buf, int count);
18extern int block_read(int dev, off_t * pos, char * buf, int count);
19extern int block_write(int dev, off_t * pos, char * buf, int count);
20extern int file_read(struct m_inode * inode, struct file * filp,
21 char * buf, int count);
22extern int file_write(struct m_inode * inode, struct file * filp,
23 char * buf, int count);
24
25int sys_lseek(unsigned int fd,off_t offset, int origin)
26{
27 struct file * file;
28 int tmp;
29
30 if (fd >= NR_OPEN || !(file=current->filp[fd]) || !(file->f_inode)
31 || !IS_SEEKABLE(MAJOR(file->f_inode->i_dev)))
32 return -EBADF;
33 if (file->f_inode->i_pipe)
34 return -ESPIPE;
35 switch (origin) {
36 case 0:
37 if (offset<0) return -EINVAL;
38 file->f_pos=offset;
39 break;
40 case 1:
41 if (file->f_pos+offset<0) return -EINVAL;
42 file->f_pos += offset;
43 break;
44 case 2:
45 if ((tmp=file->f_inode->i_size+offset) < 0)
46 return -EINVAL;
47 file->f_pos = tmp;
48 break;
49 default:
50 return -EINVAL;
51 }
52 return file->f_pos;
53}
54
55int sys_read(unsigned int fd,char * buf,int count)
56{
57 struct file * file;
58 struct m_inode * inode;
59
60 if (fd>=NR_OPEN || count<0 || !(file=current->filp[fd]))
61 return -EINVAL;
62 if (!count)
63 return 0;
64 verify_area(buf,count);
65 inode = file->f_inode;
66 if (inode->i_pipe)
67 return (file->f_mode&1)?read_pipe(inode,buf,count):-EIO;
68 if (S_ISCHR(inode->i_mode))
69 return rw_char(READ,inode->i_zone[0],buf,count,&file->f_pos);
70 if (S_ISBLK(inode->i_mode))
71 return block_read(inode->i_zone[0],&file->f_pos,buf,count);
72 if (S_ISDIR(inode->i_mode) || S_ISREG(inode->i_mode)) {
73 if (count+file->f_pos > inode->i_size)
74 count = inode->i_size - file->f_pos;
75 if (count<=0)
76 return 0;
77 return file_read(inode,file,buf,count);
78 }
79 printk("(Read)inode->i_mode=%06o\n\r",inode->i_mode);
80 return -EINVAL;
81}
82
83int sys_write(unsigned int fd,char * buf,int count)
84{
85 struct file * file;
86 struct m_inode * inode;
87
88 if (fd>=NR_OPEN || count <0 || !(file=current->filp[fd]))
89 return -EINVAL;
90 if (!count)
91 return 0;
92 inode=file->f_inode;
93 if (inode->i_pipe)
94 return (file->f_mode&2)?write_pipe(inode,buf,count):-EIO;
95 if (S_ISCHR(inode->i_mode))
96 return rw_char(WRITE,inode->i_zone[0],buf,count,&file->f_pos);
97 if (S_ISBLK(inode->i_mode))
98 return block_write(inode->i_zone[0],&file->f_pos,buf,count);
99 if (S_ISREG(inode->i_mode))
100 return file_write(inode,file,buf,count);
101 printk("(Write)inode->i_mode=%06o\n\r",inode->i_mode);
102 return -EINVAL;
103}
diff --git a/src/fs/stat.c b/src/fs/stat.c
new file mode 100644
index 0000000..61a4ceb
--- /dev/null
+++ b/src/fs/stat.c
@@ -0,0 +1,56 @@
1/*
2 * linux/fs/stat.c
3 *
4 * (C) 1991 Linus Torvalds
5 */
6
7#include <errno.h>
8#include <sys/stat.h>
9
10#include <linux/fs.h>
11#include <linux/sched.h>
12#include <linux/kernel.h>
13#include <asm/segment.h>
14
15static void cp_stat(struct m_inode * inode, struct stat * statbuf)
16{
17 struct stat tmp;
18 int i;
19
20 verify_area(statbuf,sizeof (* statbuf));
21 tmp.st_dev = inode->i_dev;
22 tmp.st_ino = inode->i_num;
23 tmp.st_mode = inode->i_mode;
24 tmp.st_nlink = inode->i_nlinks;
25 tmp.st_uid = inode->i_uid;
26 tmp.st_gid = inode->i_gid;
27 tmp.st_rdev = inode->i_zone[0];
28 tmp.st_size = inode->i_size;
29 tmp.st_atime = inode->i_atime;
30 tmp.st_mtime = inode->i_mtime;
31 tmp.st_ctime = inode->i_ctime;
32 for (i=0 ; i<sizeof (tmp) ; i++)
33 put_fs_byte(((char *) &tmp)[i],&((char *) statbuf)[i]);
34}
35
36int sys_stat(char * filename, struct stat * statbuf)
37{
38 struct m_inode * inode;
39
40 if (!(inode=namei(filename)))
41 return -ENOENT;
42 cp_stat(inode,statbuf);
43 iput(inode);
44 return 0;
45}
46
47int sys_fstat(unsigned int fd, struct stat * statbuf)
48{
49 struct file * f;
50 struct m_inode * inode;
51
52 if (fd >= NR_OPEN || !(f=current->filp[fd]) || !(inode=f->f_inode))
53 return -EBADF;
54 cp_stat(inode,statbuf);
55 return 0;
56}
diff --git a/src/fs/super.c b/src/fs/super.c
new file mode 100644
index 0000000..39c4089
--- /dev/null
+++ b/src/fs/super.c
@@ -0,0 +1,281 @@
1/*
2 * linux/fs/super.c
3 *
4 * (C) 1991 Linus Torvalds
5 */
6
7/*
8 * super.c contains code to handle the super-block tables.
9 */
10#include <linux/config.h>
11#include <linux/sched.h>
12#include <linux/kernel.h>
13#include <asm/system.h>
14
15#include <errno.h>
16#include <sys/stat.h>
17
18int sync_dev(int dev);
19void wait_for_keypress(void);
20
21/* set_bit uses setb, as gas doesn't recognize setc */
22#define set_bit(bitnr,addr) ({ \
23register int __res ; \
24__asm__("bt %2,%3;setb %%al":"=a" (__res):"a" (0),"r" (bitnr),"m" (*(addr))); \
25__res; })
26
27struct super_block super_block[NR_SUPER];
28/* this is initialized in init/main.c */
29int ROOT_DEV = 0;
30
31static void lock_super(struct super_block * sb)
32{
33 cli();
34 while (sb->s_lock)
35 sleep_on(&(sb->s_wait));
36 sb->s_lock = 1;
37 sti();
38}
39
40static void free_super(struct super_block * sb)
41{
42 cli();
43 sb->s_lock = 0;
44 wake_up(&(sb->s_wait));
45 sti();
46}
47
48static void wait_on_super(struct super_block * sb)
49{
50 cli();
51 while (sb->s_lock)
52 sleep_on(&(sb->s_wait));
53 sti();
54}
55
56struct super_block * get_super(int dev)
57{
58 struct super_block * s;
59
60 if (!dev)
61 return NULL;
62 s = 0+super_block;
63 while (s < NR_SUPER+super_block)
64 if (s->s_dev == dev) {
65 wait_on_super(s);
66 if (s->s_dev == dev)
67 return s;
68 s = 0+super_block;
69 } else
70 s++;
71 return NULL;
72}
73
74void put_super(int dev)
75{
76 struct super_block * sb;
77 /* struct m_inode * inode;*/
78 int i;
79
80 if (dev == ROOT_DEV) {
81 printk("root diskette changed: prepare for armageddon\n\r");
82 return;
83 }
84 if (!(sb = get_super(dev)))
85 return;
86 if (sb->s_imount) {
87 printk("Mounted disk changed - tssk, tssk\n\r");
88 return;
89 }
90 lock_super(sb);
91 sb->s_dev = 0;
92 for(i=0;i<I_MAP_SLOTS;i++)
93 brelse(sb->s_imap[i]);
94 for(i=0;i<Z_MAP_SLOTS;i++)
95 brelse(sb->s_zmap[i]);
96 free_super(sb);
97 return;
98}
99
100static struct super_block * read_super(int dev)
101{
102 struct super_block * s;
103 struct buffer_head * bh;
104 int i,block;
105
106 if (!dev)
107 return NULL;
108 check_disk_change(dev);
109 if ((s = get_super(dev)))
110 return s;
111 for (s = 0+super_block ;; s++) {
112 if (s >= NR_SUPER+super_block)
113 return NULL;
114 if (!s->s_dev)
115 break;
116 }
117 s->s_dev = dev;
118 s->s_isup = NULL;
119 s->s_imount = NULL;
120 s->s_time = 0;
121 s->s_rd_only = 0;
122 s->s_dirt = 0;
123 lock_super(s);
124 if (!(bh = bread(dev,1))) {
125 s->s_dev=0;
126 free_super(s);
127 return NULL;
128 }
129 *((struct d_super_block *) s) =
130 *((struct d_super_block *) bh->b_data);
131 brelse(bh);
132 if (s->s_magic != SUPER_MAGIC) {
133 s->s_dev = 0;
134 free_super(s);
135 return NULL;
136 }
137 for (i=0;i<I_MAP_SLOTS;i++)
138 s->s_imap[i] = NULL;
139 for (i=0;i<Z_MAP_SLOTS;i++)
140 s->s_zmap[i] = NULL;
141 block=2;
142 for (i=0 ; i < s->s_imap_blocks ; i++)
143 if ((s->s_imap[i]=bread(dev,block)))
144 block++;
145 else
146 break;
147 for (i=0 ; i < s->s_zmap_blocks ; i++)
148 if ((s->s_zmap[i]=bread(dev,block)))
149 block++;
150 else
151 break;
152 if (block != 2+s->s_imap_blocks+s->s_zmap_blocks) {
153 for(i=0;i<I_MAP_SLOTS;i++)
154 brelse(s->s_imap[i]);
155 for(i=0;i<Z_MAP_SLOTS;i++)
156 brelse(s->s_zmap[i]);
157 s->s_dev=0;
158 free_super(s);
159 return NULL;
160 }
161 s->s_imap[0]->b_data[0] |= 1;
162 s->s_zmap[0]->b_data[0] |= 1;
163 free_super(s);
164 return s;
165}
166
167int sys_umount(char * dev_name)
168{
169 struct m_inode * inode;
170 struct super_block * sb;
171 int dev;
172
173 if (!(inode=namei(dev_name)))
174 return -ENOENT;
175 dev = inode->i_zone[0];
176 if (!S_ISBLK(inode->i_mode)) {
177 iput(inode);
178 return -ENOTBLK;
179 }
180 iput(inode);
181 if (dev==ROOT_DEV)
182 return -EBUSY;
183 if (!(sb=get_super(dev)) || !(sb->s_imount))
184 return -ENOENT;
185 if (!sb->s_imount->i_mount)
186 printk("Mounted inode has i_mount=0\n");
187 for (inode=inode_table+0 ; inode<inode_table+NR_INODE ; inode++)
188 if (inode->i_dev==dev && inode->i_count)
189 return -EBUSY;
190 sb->s_imount->i_mount=0;
191 iput(sb->s_imount);
192 sb->s_imount = NULL;
193 iput(sb->s_isup);
194 sb->s_isup = NULL;
195 put_super(dev);
196 sync_dev(dev);
197 return 0;
198}
199
200int sys_mount(char * dev_name, char * dir_name, int rw_flag)
201{
202 struct m_inode * dev_i, * dir_i;
203 struct super_block * sb;
204 int dev;
205
206 if (!(dev_i=namei(dev_name)))
207 return -ENOENT;
208 dev = dev_i->i_zone[0];
209 if (!S_ISBLK(dev_i->i_mode)) {
210 iput(dev_i);
211 return -EPERM;
212 }
213 iput(dev_i);
214 if (!(dir_i=namei(dir_name)))
215 return -ENOENT;
216 if (dir_i->i_count != 1 || dir_i->i_num == ROOT_INO) {
217 iput(dir_i);
218 return -EBUSY;
219 }
220 if (!S_ISDIR(dir_i->i_mode)) {
221 iput(dir_i);
222 return -EPERM;
223 }
224 if (!(sb=read_super(dev))) {
225 iput(dir_i);
226 return -EBUSY;
227 }
228 if (sb->s_imount) {
229 iput(dir_i);
230 return -EBUSY;
231 }
232 if (dir_i->i_mount) {
233 iput(dir_i);
234 return -EPERM;
235 }
236 sb->s_imount=dir_i;
237 dir_i->i_mount=1;
238 dir_i->i_dirt=1; /* NOTE! we don't iput(dir_i) */
239 return 0; /* we do that in umount */
240}
241
242void mount_root(void)
243{
244 int i,free;
245 struct super_block * p;
246 struct m_inode * mi;
247
248 if (32 != sizeof (struct d_inode))
249 panic("bad i-node size");
250 for(i=0;i<NR_FILE;i++)
251 file_table[i].f_count=0;
252 if (MAJOR(ROOT_DEV) == 2) {
253 printk("Insert root floppy and press ENTER");
254 wait_for_keypress();
255 }
256 for(p = &super_block[0] ; p < &super_block[NR_SUPER] ; p++) {
257 p->s_dev = 0;
258 p->s_lock = 0;
259 p->s_wait = NULL;
260 }
261 if (!(p=read_super(ROOT_DEV)))
262 panic("Unable to mount root");
263 if (!(mi=iget(ROOT_DEV,ROOT_INO)))
264 panic("Unable to read root i-node");
265 mi->i_count += 3 ; /* NOTE! it is logically used 4 times, not 1 */
266 p->s_isup = p->s_imount = mi;
267 current->pwd = mi;
268 current->root = mi;
269 free=0;
270 i=p->s_nzones;
271 while (-- i >= 0)
272 if (!set_bit(i&8191,p->s_zmap[i>>13]->b_data))
273 free++;
274 printk("%d/%d free blocks\n\r",free,p->s_nzones);
275 free=0;
276 i=p->s_ninodes+1;
277 while (-- i >= 0)
278 if (!set_bit(i&8191,p->s_imap[i>>13]->b_data))
279 free++;
280 printk("%d/%d free inodes\n\r",free,p->s_ninodes);
281}
diff --git a/src/fs/truncate.c b/src/fs/truncate.c
new file mode 100644
index 0000000..cb22d5f
--- /dev/null
+++ b/src/fs/truncate.c
@@ -0,0 +1,65 @@
1/*
2 * linux/fs/truncate.c
3 *
4 * (C) 1991 Linus Torvalds
5 */
6
7#include <linux/sched.h>
8
9#include <sys/stat.h>
10
11static void free_ind(int dev,int block)
12{
13 struct buffer_head * bh;
14 unsigned short * p;
15 int i;
16
17 if (!block)
18 return;
19 if ((bh=bread(dev,block))) {
20 p = (unsigned short *) bh->b_data;
21 for (i=0;i<512;i++,p++)
22 if (*p)
23 free_block(dev,*p);
24 brelse(bh);
25 }
26 free_block(dev,block);
27}
28
29static void free_dind(int dev,int block)
30{
31 struct buffer_head * bh;
32 unsigned short * p;
33 int i;
34
35 if (!block)
36 return;
37 if ((bh=bread(dev,block))) {
38 p = (unsigned short *) bh->b_data;
39 for (i=0;i<512;i++,p++)
40 if (*p)
41 free_ind(dev,*p);
42 brelse(bh);
43 }
44 free_block(dev,block);
45}
46
47void truncate(struct m_inode * inode)
48{
49 int i;
50
51 if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode)))
52 return;
53 for (i=0;i<7;i++)
54 if (inode->i_zone[i]) {
55 free_block(inode->i_dev,inode->i_zone[i]);
56 inode->i_zone[i]=0;
57 }
58 free_ind(inode->i_dev,inode->i_zone[7]);
59 free_dind(inode->i_dev,inode->i_zone[8]);
60 inode->i_zone[7] = inode->i_zone[8] = 0;
61 inode->i_size = 0;
62 inode->i_dirt = 1;
63 inode->i_mtime = inode->i_ctime = CURRENT_TIME;
64}
65