diff options
author | 2025-01-23 10:41:10 +0800 | |
---|---|---|
committer | 2025-01-23 10:41:10 +0800 | |
commit | e6f77b7ea3e38c9853bee60b275f3f89d252a5b3 (patch) | |
tree | 80bfbabed9d4cbcf9fa62677f78b34279d7e2f87 /src/fs | |
download | linux-0.11-master.tar.gz linux-0.11-master.zip |
Diffstat (limited to 'src/fs')
-rw-r--r-- | src/fs/Makefile | 98 | ||||
-rw-r--r-- | src/fs/bitmap.c | 168 | ||||
-rw-r--r-- | src/fs/block_dev.c | 73 | ||||
-rw-r--r-- | src/fs/buffer.c | 384 | ||||
-rw-r--r-- | src/fs/char_dev.c | 104 | ||||
-rw-r--r-- | src/fs/exec.c | 353 | ||||
-rw-r--r-- | src/fs/fcntl.c | 75 | ||||
-rw-r--r-- | src/fs/file_dev.c | 90 | ||||
-rw-r--r-- | src/fs/file_table.c | 9 | ||||
-rw-r--r-- | src/fs/inode.c | 338 | ||||
-rw-r--r-- | src/fs/ioctl.c | 46 | ||||
-rw-r--r-- | src/fs/namei.c | 778 | ||||
-rw-r--r-- | src/fs/open.c | 209 | ||||
-rw-r--r-- | src/fs/pipe.c | 111 | ||||
-rw-r--r-- | src/fs/read_write.c | 103 | ||||
-rw-r--r-- | src/fs/stat.c | 56 | ||||
-rw-r--r-- | src/fs/super.c | 281 | ||||
-rw-r--r-- | src/fs/truncate.c | 65 |
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 @@ | |||
1 | include ../Makefile.header | ||
2 | |||
3 | LDFLAGS += -r | ||
4 | CFLAGS += -I../include | ||
5 | CPP += -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 | |||
16 | OBJS= 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 | |||
20 | fs.o: $(OBJS) | ||
21 | @$(LD) $(LDFLAGS) -o fs.o $(OBJS) | ||
22 | |||
23 | clean: | ||
24 | @rm -f core *.o *.a tmp_make | ||
25 | @for i in *.c;do rm -f `basename $$i .c`.s;done | ||
26 | |||
27 | dep: | ||
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: | ||
33 | bitmap.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 | ||
36 | block_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 | ||
40 | buffer.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 | ||
44 | char_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 | ||
48 | exec.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 | ||
53 | fcntl.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 | ||
58 | file_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 | ||
62 | file_table.o: file_table.c ../include/linux/fs.h ../include/sys/types.h | ||
63 | inode.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 | ||
67 | ioctl.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 | ||
71 | namei.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 | ||
76 | open.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 | ||
81 | pipe.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 | ||
84 | read_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 | ||
88 | stat.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 | ||
92 | super.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 | ||
96 | truncate.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) ({\ | ||
20 | register int res ; \ | ||
21 | __asm__ __volatile__("btsl %2,%3\n\tsetb %%al": \ | ||
22 | "=a" (res):"0" (0),"r" (nr),"m" (*(addr))); \ | ||
23 | res;}) | ||
24 | |||
25 | #define clear_bit(nr,addr) ({\ | ||
26 | register int res ; \ | ||
27 | __asm__ __volatile__("btrl %2,%3\n\tsetnb %%al": \ | ||
28 | "=a" (res):"0" (0),"r" (nr),"m" (*(addr))); \ | ||
29 | res;}) | ||
30 | |||
31 | #define find_first_zero(addr) ({ \ | ||
32 | int __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 | |||
47 | void 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 | |||
75 | int 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 | |||
107 | void 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 | |||
136 | struct 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 | |||
14 | int 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 | |||
47 | int 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 | |||
29 | extern int end; | ||
30 | extern void put_super(int); | ||
31 | extern void invalidate_inodes(int); | ||
32 | |||
33 | struct buffer_head * start_buffer = (struct buffer_head *) &end; | ||
34 | struct buffer_head * hash_table[NR_HASH]; | ||
35 | static struct buffer_head * free_list; | ||
36 | static struct task_struct * buffer_wait = NULL; | ||
37 | int NR_BUFFERS = 0; | ||
38 | |||
39 | static 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 | |||
47 | int 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 | |||
62 | int 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 | |||
87 | static 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 | */ | ||
116 | void 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 | |||
134 | static 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 | |||
152 | static 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 | |||
169 | static 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 | */ | ||
186 | struct 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) | ||
209 | struct buffer_head * getblk(int dev,int block) | ||
210 | { | ||
211 | struct buffer_head * tmp, * bh; | ||
212 | |||
213 | repeat: | ||
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 | |||
256 | void 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 | */ | ||
270 | struct 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 | */ | ||
299 | void 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 | */ | ||
325 | struct 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 | |||
351 | void 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 | |||
16 | extern int tty_read(unsigned minor,char * buf,int count); | ||
17 | extern int tty_write(unsigned minor,char * buf,int count); | ||
18 | |||
19 | typedef int (*crw_ptr)(int rw,unsigned minor,char * buf,int count,off_t * pos); | ||
20 | |||
21 | static 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 | |||
27 | static 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 | |||
34 | static int rw_ram(int rw,char * buf, int count, off_t *pos) | ||
35 | { | ||
36 | return -EIO; | ||
37 | } | ||
38 | |||
39 | static int rw_mem(int rw,char * buf, int count, off_t * pos) | ||
40 | { | ||
41 | return -EIO; | ||
42 | } | ||
43 | |||
44 | static int rw_kmem(int rw,char * buf, int count, off_t * pos) | ||
45 | { | ||
46 | return -EIO; | ||
47 | } | ||
48 | |||
49 | static 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 | |||
65 | static 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 | |||
85 | static 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 | |||
95 | int 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 | |||
31 | extern int sys_exit(int exit_code); | ||
32 | extern 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 | */ | ||
46 | static 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 | */ | ||
75 | static 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 | */ | ||
104 | static 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 | |||
154 | static 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 | */ | ||
182 | int 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 | |||
204 | restart_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; | ||
347 | exec_error2: | ||
348 | iput(inode); | ||
349 | exec_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 | |||
16 | extern int sys_close(int fd); | ||
17 | |||
18 | static 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 | |||
36 | int sys_dup2(unsigned int oldfd, unsigned int newfd) | ||
37 | { | ||
38 | sys_close(newfd); | ||
39 | return dupfd(oldfd,newfd); | ||
40 | } | ||
41 | |||
42 | int sys_dup(unsigned int fildes) | ||
43 | { | ||
44 | return dupfd(fildes,0); | ||
45 | } | ||
46 | |||
47 | int 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 | |||
17 | int 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 | |||
48 | int 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 | |||
9 | struct 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 | |||
15 | struct m_inode inode_table[NR_INODE]={{0,},}; | ||
16 | |||
17 | static void read_inode(struct m_inode * inode); | ||
18 | static void write_inode(struct m_inode * inode); | ||
19 | |||
20 | static 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 | |||
28 | static 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 | |||
37 | static inline void unlock_inode(struct m_inode * inode) | ||
38 | { | ||
39 | inode->i_lock=0; | ||
40 | wake_up(&inode->i_wait); | ||
41 | } | ||
42 | |||
43 | void 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 | |||
59 | void 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 | |||
72 | static 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 | |||
140 | int bmap(struct m_inode * inode,int block) | ||
141 | { | ||
142 | return _bmap(inode,block,0); | ||
143 | } | ||
144 | |||
145 | int create_block(struct m_inode * inode, int block) | ||
146 | { | ||
147 | return _bmap(inode,block,1); | ||
148 | } | ||
149 | |||
150 | void 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 | } | ||
175 | repeat: | ||
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 | |||
194 | struct 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 | |||
228 | struct 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 | |||
244 | struct 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 | |||
294 | static 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 | |||
314 | static 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 | |||
13 | extern int tty_ioctl(int dev, int cmd, int arg); | ||
14 | |||
15 | typedef int (*ioctl_ptr)(int dev,int cmd,int arg); | ||
16 | |||
17 | #define NRDEVS ((sizeof (ioctl_table))/(sizeof (ioctl_ptr))) | ||
18 | |||
19 | static 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 | |||
30 | int 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 | */ | ||
40 | static 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 | */ | ||
63 | static 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 | */ | ||
91 | static 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 | */ | ||
165 | static 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 | */ | ||
228 | static 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 | */ | ||
278 | static 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 | */ | ||
303 | struct 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 | */ | ||
337 | int 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 | |||
412 | int 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 | |||
463 | int 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 | */ | ||
543 | static 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 | |||
587 | int 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 | |||
663 | int 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 | |||
721 | int 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 | |||
19 | int sys_ustat(int dev, struct ustat * ubuf) | ||
20 | { | ||
21 | return -ENOSYS; | ||
22 | } | ||
23 | |||
24 | int 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 *) ×->actime); | ||
33 | modtime = get_fs_long((unsigned long *) ×->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 | */ | ||
47 | int 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 | |||
75 | int 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 | |||
90 | int 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 | |||
105 | int 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 | |||
121 | int 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 | |||
138 | int 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 | |||
188 | int sys_creat(const char * pathname, int mode) | ||
189 | { | ||
190 | return sys_open(pathname, O_CREAT | O_TRUNC, mode); | ||
191 | } | ||
192 | |||
193 | int 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 | |||
13 | int 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 | |||
41 | int 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 | |||
71 | int 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 | |||
15 | extern int rw_char(int rw,int dev, char * buf, int count, off_t * pos); | ||
16 | extern int read_pipe(struct m_inode * inode, char * buf, int count); | ||
17 | extern int write_pipe(struct m_inode * inode, char * buf, int count); | ||
18 | extern int block_read(int dev, off_t * pos, char * buf, int count); | ||
19 | extern int block_write(int dev, off_t * pos, char * buf, int count); | ||
20 | extern int file_read(struct m_inode * inode, struct file * filp, | ||
21 | char * buf, int count); | ||
22 | extern int file_write(struct m_inode * inode, struct file * filp, | ||
23 | char * buf, int count); | ||
24 | |||
25 | int 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 | |||
55 | int 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 | |||
83 | int 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 | |||
15 | static 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 | |||
36 | int 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 | |||
47 | int 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 | |||
18 | int sync_dev(int dev); | ||
19 | void wait_for_keypress(void); | ||
20 | |||
21 | /* set_bit uses setb, as gas doesn't recognize setc */ | ||
22 | #define set_bit(bitnr,addr) ({ \ | ||
23 | register int __res ; \ | ||
24 | __asm__("bt %2,%3;setb %%al":"=a" (__res):"a" (0),"r" (bitnr),"m" (*(addr))); \ | ||
25 | __res; }) | ||
26 | |||
27 | struct super_block super_block[NR_SUPER]; | ||
28 | /* this is initialized in init/main.c */ | ||
29 | int ROOT_DEV = 0; | ||
30 | |||
31 | static 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 | |||
40 | static 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 | |||
48 | static 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 | |||
56 | struct 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 | |||
74 | void 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 | |||
100 | static 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 | |||
167 | int 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 | |||
200 | int 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 | |||
242 | void 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 | |||
11 | static 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 | |||
29 | static 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 | |||
47 | void 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 | |||