add directory kernel
This commit is contained in:
95
kernel/0.00/linux-0.01/fs/Makefile
Normal file
95
kernel/0.00/linux-0.01/fs/Makefile
Normal file
@@ -0,0 +1,95 @@
|
||||
AR =gar
|
||||
AS =gas
|
||||
CC =gcc
|
||||
LD =gld
|
||||
CFLAGS =-Wall -O -fstrength-reduce -fcombine-regs -fomit-frame-pointer \
|
||||
-mstring-insns -nostdinc -I../include
|
||||
CPP =gcc -E -nostdinc -I../include
|
||||
|
||||
.c.s:
|
||||
$(CC) $(CFLAGS) \
|
||||
-S -o $*.s $<
|
||||
.c.o:
|
||||
$(CC) $(CFLAGS) \
|
||||
-c -o $*.o $<
|
||||
.s.o:
|
||||
$(AS) -o $*.o $<
|
||||
|
||||
OBJS= open.o read_write.o inode.o file_table.o buffer.o super.o \
|
||||
block_dev.o char_dev.o file_dev.o stat.o exec.o pipe.o namei.o \
|
||||
bitmap.o fcntl.o ioctl.o tty_ioctl.o truncate.o
|
||||
|
||||
fs.o: $(OBJS)
|
||||
$(LD) -r -o fs.o $(OBJS)
|
||||
|
||||
clean:
|
||||
rm -f core *.o *.a tmp_make
|
||||
for i in *.c;do rm -f `basename $$i .c`.s;done
|
||||
|
||||
dep:
|
||||
sed '/\#\#\# Dependencies/q' < Makefile > tmp_make
|
||||
(for i in *.c;do $(CPP) -M $$i;done) >> tmp_make
|
||||
cp tmp_make Makefile
|
||||
|
||||
### Dependencies:
|
||||
bitmap.o : bitmap.c ../include/string.h ../include/linux/sched.h \
|
||||
../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \
|
||||
../include/linux/mm.h ../include/linux/kernel.h
|
||||
block_dev.o : block_dev.c ../include/errno.h ../include/linux/fs.h \
|
||||
../include/sys/types.h ../include/linux/kernel.h ../include/asm/segment.h
|
||||
buffer.o : buffer.c ../include/linux/config.h ../include/linux/sched.h \
|
||||
../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \
|
||||
../include/linux/mm.h ../include/linux/kernel.h ../include/asm/system.h
|
||||
char_dev.o : char_dev.c ../include/errno.h ../include/linux/sched.h \
|
||||
../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \
|
||||
../include/linux/mm.h ../include/linux/kernel.h
|
||||
exec.o : exec.c ../include/errno.h ../include/sys/stat.h \
|
||||
../include/sys/types.h ../include/a.out.h ../include/linux/fs.h \
|
||||
../include/linux/sched.h ../include/linux/head.h ../include/linux/mm.h \
|
||||
../include/linux/kernel.h ../include/asm/segment.h
|
||||
fcntl.o : fcntl.c ../include/string.h ../include/errno.h \
|
||||
../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \
|
||||
../include/sys/types.h ../include/linux/mm.h ../include/linux/kernel.h \
|
||||
../include/asm/segment.h ../include/fcntl.h ../include/sys/stat.h
|
||||
file_dev.o : file_dev.c ../include/errno.h ../include/fcntl.h \
|
||||
../include/sys/types.h ../include/linux/sched.h ../include/linux/head.h \
|
||||
../include/linux/fs.h ../include/linux/mm.h ../include/linux/kernel.h \
|
||||
../include/asm/segment.h
|
||||
file_table.o : file_table.c ../include/linux/fs.h ../include/sys/types.h
|
||||
inode.o : inode.c ../include/string.h ../include/linux/sched.h \
|
||||
../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \
|
||||
../include/linux/mm.h ../include/linux/kernel.h ../include/asm/system.h
|
||||
ioctl.o : ioctl.c ../include/string.h ../include/errno.h \
|
||||
../include/sys/stat.h ../include/sys/types.h ../include/linux/sched.h \
|
||||
../include/linux/head.h ../include/linux/fs.h ../include/linux/mm.h
|
||||
namei.o : namei.c ../include/linux/sched.h ../include/linux/head.h \
|
||||
../include/linux/fs.h ../include/sys/types.h ../include/linux/mm.h \
|
||||
../include/linux/kernel.h ../include/asm/segment.h ../include/string.h \
|
||||
../include/fcntl.h ../include/errno.h ../include/const.h \
|
||||
../include/sys/stat.h
|
||||
open.o : open.c ../include/string.h ../include/errno.h ../include/fcntl.h \
|
||||
../include/sys/types.h ../include/utime.h ../include/sys/stat.h \
|
||||
../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \
|
||||
../include/linux/mm.h ../include/linux/tty.h ../include/termios.h \
|
||||
../include/linux/kernel.h ../include/asm/segment.h
|
||||
pipe.o : pipe.c ../include/signal.h ../include/sys/types.h \
|
||||
../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \
|
||||
../include/linux/mm.h ../include/asm/segment.h
|
||||
read_write.o : read_write.c ../include/sys/stat.h ../include/sys/types.h \
|
||||
../include/errno.h ../include/linux/kernel.h ../include/linux/sched.h \
|
||||
../include/linux/head.h ../include/linux/fs.h ../include/linux/mm.h \
|
||||
../include/asm/segment.h
|
||||
stat.o : stat.c ../include/errno.h ../include/sys/stat.h \
|
||||
../include/sys/types.h ../include/linux/fs.h ../include/linux/sched.h \
|
||||
../include/linux/head.h ../include/linux/mm.h ../include/linux/kernel.h \
|
||||
../include/asm/segment.h
|
||||
super.o : super.c ../include/linux/config.h ../include/linux/sched.h \
|
||||
../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \
|
||||
../include/linux/mm.h ../include/linux/kernel.h
|
||||
truncate.o : truncate.c ../include/linux/sched.h ../include/linux/head.h \
|
||||
../include/linux/fs.h ../include/sys/types.h ../include/linux/mm.h \
|
||||
../include/sys/stat.h
|
||||
tty_ioctl.o : tty_ioctl.c ../include/errno.h ../include/termios.h \
|
||||
../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \
|
||||
../include/sys/types.h ../include/linux/mm.h ../include/linux/kernel.h \
|
||||
../include/linux/tty.h ../include/asm/segment.h ../include/asm/system.h
|
||||
158
kernel/0.00/linux-0.01/fs/bitmap.c
Normal file
158
kernel/0.00/linux-0.01/fs/bitmap.c
Normal file
@@ -0,0 +1,158 @@
|
||||
/* bitmap.c contains the code that handles the inode and block bitmaps */
|
||||
#include <string.h>
|
||||
|
||||
#include <linux/sched.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
#define clear_block(addr) \
|
||||
__asm__("cld\n\t" \
|
||||
"rep\n\t" \
|
||||
"stosl" \
|
||||
::"a" (0),"c" (BLOCK_SIZE/4),"D" ((long) (addr)):"cx","di")
|
||||
|
||||
#define set_bit(nr,addr) ({\
|
||||
register int res __asm__("ax"); \
|
||||
__asm__("btsl %2,%3\n\tsetb %%al":"=a" (res):"0" (0),"r" (nr),"m" (*(addr))); \
|
||||
res;})
|
||||
|
||||
#define clear_bit(nr,addr) ({\
|
||||
register int res __asm__("ax"); \
|
||||
__asm__("btrl %2,%3\n\tsetnb %%al":"=a" (res):"0" (0),"r" (nr),"m" (*(addr))); \
|
||||
res;})
|
||||
|
||||
#define find_first_zero(addr) ({ \
|
||||
int __res; \
|
||||
__asm__("cld\n" \
|
||||
"1:\tlodsl\n\t" \
|
||||
"notl %%eax\n\t" \
|
||||
"bsfl %%eax,%%edx\n\t" \
|
||||
"je 2f\n\t" \
|
||||
"addl %%edx,%%ecx\n\t" \
|
||||
"jmp 3f\n" \
|
||||
"2:\taddl $32,%%ecx\n\t" \
|
||||
"cmpl $8192,%%ecx\n\t" \
|
||||
"jl 1b\n" \
|
||||
"3:" \
|
||||
:"=c" (__res):"c" (0),"S" (addr):"ax","dx","si"); \
|
||||
__res;})
|
||||
|
||||
void free_block(int dev, int block)
|
||||
{
|
||||
struct super_block * sb;
|
||||
struct buffer_head * bh;
|
||||
|
||||
if (!(sb = get_super(dev)))
|
||||
panic("trying to free block on nonexistent device");
|
||||
if (block < sb->s_firstdatazone || block >= sb->s_nzones)
|
||||
panic("trying to free block not in datazone");
|
||||
bh = get_hash_table(dev,block);
|
||||
if (bh) {
|
||||
if (bh->b_count != 1) {
|
||||
printk("trying to free block (%04x:%d), count=%d\n",
|
||||
dev,block,bh->b_count);
|
||||
return;
|
||||
}
|
||||
bh->b_dirt=0;
|
||||
bh->b_uptodate=0;
|
||||
brelse(bh);
|
||||
}
|
||||
block -= sb->s_firstdatazone - 1 ;
|
||||
if (clear_bit(block&8191,sb->s_zmap[block/8192]->b_data)) {
|
||||
printk("block (%04x:%d) ",dev,block+sb->s_firstdatazone-1);
|
||||
panic("free_block: bit already cleared");
|
||||
}
|
||||
sb->s_zmap[block/8192]->b_dirt = 1;
|
||||
}
|
||||
|
||||
int new_block(int dev)
|
||||
{
|
||||
struct buffer_head * bh;
|
||||
struct super_block * sb;
|
||||
int i,j;
|
||||
|
||||
if (!(sb = get_super(dev)))
|
||||
panic("trying to get new block from nonexistant device");
|
||||
j = 8192;
|
||||
for (i=0 ; i<8 ; i++)
|
||||
if (bh=sb->s_zmap[i])
|
||||
if ((j=find_first_zero(bh->b_data))<8192)
|
||||
break;
|
||||
if (i>=8 || !bh || j>=8192)
|
||||
return 0;
|
||||
if (set_bit(j,bh->b_data))
|
||||
panic("new_block: bit already set");
|
||||
bh->b_dirt = 1;
|
||||
j += i*8192 + sb->s_firstdatazone-1;
|
||||
if (j >= sb->s_nzones)
|
||||
return 0;
|
||||
if (!(bh=getblk(dev,j)))
|
||||
panic("new_block: cannot get block");
|
||||
if (bh->b_count != 1)
|
||||
panic("new block: count is != 1");
|
||||
clear_block(bh->b_data);
|
||||
bh->b_uptodate = 1;
|
||||
bh->b_dirt = 1;
|
||||
brelse(bh);
|
||||
return j;
|
||||
}
|
||||
|
||||
void free_inode(struct m_inode * inode)
|
||||
{
|
||||
struct super_block * sb;
|
||||
struct buffer_head * bh;
|
||||
|
||||
if (!inode)
|
||||
return;
|
||||
if (!inode->i_dev) {
|
||||
memset(inode,0,sizeof(*inode));
|
||||
return;
|
||||
}
|
||||
if (inode->i_count>1) {
|
||||
printk("trying to free inode with count=%d\n",inode->i_count);
|
||||
panic("free_inode");
|
||||
}
|
||||
if (inode->i_nlinks)
|
||||
panic("trying to free inode with links");
|
||||
if (!(sb = get_super(inode->i_dev)))
|
||||
panic("trying to free inode on nonexistent device");
|
||||
if (inode->i_num < 1 || inode->i_num > sb->s_ninodes)
|
||||
panic("trying to free inode 0 or nonexistant inode");
|
||||
if (!(bh=sb->s_imap[inode->i_num>>13]))
|
||||
panic("nonexistent imap in superblock");
|
||||
if (clear_bit(inode->i_num&8191,bh->b_data))
|
||||
panic("free_inode: bit already cleared");
|
||||
bh->b_dirt = 1;
|
||||
memset(inode,0,sizeof(*inode));
|
||||
}
|
||||
|
||||
struct m_inode * new_inode(int dev)
|
||||
{
|
||||
struct m_inode * inode;
|
||||
struct super_block * sb;
|
||||
struct buffer_head * bh;
|
||||
int i,j;
|
||||
|
||||
if (!(inode=get_empty_inode()))
|
||||
return NULL;
|
||||
if (!(sb = get_super(dev)))
|
||||
panic("new_inode with unknown device");
|
||||
j = 8192;
|
||||
for (i=0 ; i<8 ; i++)
|
||||
if (bh=sb->s_imap[i])
|
||||
if ((j=find_first_zero(bh->b_data))<8192)
|
||||
break;
|
||||
if (!bh || j >= 8192 || j+i*8192 > sb->s_ninodes) {
|
||||
iput(inode);
|
||||
return NULL;
|
||||
}
|
||||
if (set_bit(j,bh->b_data))
|
||||
panic("new_inode: bit already set");
|
||||
bh->b_dirt = 1;
|
||||
inode->i_count=1;
|
||||
inode->i_nlinks=1;
|
||||
inode->i_dev=dev;
|
||||
inode->i_dirt=1;
|
||||
inode->i_num = j + i*8192;
|
||||
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
|
||||
return inode;
|
||||
}
|
||||
86
kernel/0.00/linux-0.01/fs/block_dev.c
Normal file
86
kernel/0.00/linux-0.01/fs/block_dev.c
Normal file
@@ -0,0 +1,86 @@
|
||||
#include <errno.h>
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <asm/segment.h>
|
||||
|
||||
#define NR_BLK_DEV ((sizeof (rd_blk))/(sizeof (rd_blk[0])))
|
||||
|
||||
int block_write(int dev, long * pos, char * buf, int count)
|
||||
{
|
||||
int block = *pos / BLOCK_SIZE;
|
||||
int offset = *pos % BLOCK_SIZE;
|
||||
int chars;
|
||||
int written = 0;
|
||||
struct buffer_head * bh;
|
||||
register char * p;
|
||||
|
||||
while (count>0) {
|
||||
bh = bread(dev,block);
|
||||
if (!bh)
|
||||
return written?written:-EIO;
|
||||
chars = (count<BLOCK_SIZE) ? count : BLOCK_SIZE;
|
||||
p = offset + bh->b_data;
|
||||
offset = 0;
|
||||
block++;
|
||||
*pos += chars;
|
||||
written += chars;
|
||||
count -= chars;
|
||||
while (chars-->0)
|
||||
*(p++) = get_fs_byte(buf++);
|
||||
bh->b_dirt = 1;
|
||||
brelse(bh);
|
||||
}
|
||||
return written;
|
||||
}
|
||||
|
||||
int block_read(int dev, unsigned long * pos, char * buf, int count)
|
||||
{
|
||||
int block = *pos / BLOCK_SIZE;
|
||||
int offset = *pos % BLOCK_SIZE;
|
||||
int chars;
|
||||
int read = 0;
|
||||
struct buffer_head * bh;
|
||||
register char * p;
|
||||
|
||||
while (count>0) {
|
||||
bh = bread(dev,block);
|
||||
if (!bh)
|
||||
return read?read:-EIO;
|
||||
chars = (count<BLOCK_SIZE) ? count : BLOCK_SIZE;
|
||||
p = offset + bh->b_data;
|
||||
offset = 0;
|
||||
block++;
|
||||
*pos += chars;
|
||||
read += chars;
|
||||
count -= chars;
|
||||
while (chars-->0)
|
||||
put_fs_byte(*(p++),buf++);
|
||||
bh->b_dirt = 1;
|
||||
brelse(bh);
|
||||
}
|
||||
return read;
|
||||
}
|
||||
|
||||
extern void rw_hd(int rw, struct buffer_head * bh);
|
||||
|
||||
typedef void (*blk_fn)(int rw, struct buffer_head * bh);
|
||||
|
||||
static blk_fn rd_blk[]={
|
||||
NULL, /* nodev */
|
||||
NULL, /* dev mem */
|
||||
NULL, /* dev fd */
|
||||
rw_hd, /* dev hd */
|
||||
NULL, /* dev ttyx */
|
||||
NULL, /* dev tty */
|
||||
NULL}; /* dev lp */
|
||||
|
||||
void ll_rw_block(int rw, struct buffer_head * bh)
|
||||
{
|
||||
blk_fn blk_addr;
|
||||
unsigned int major;
|
||||
|
||||
if ((major=MAJOR(bh->b_dev)) >= NR_BLK_DEV || !(blk_addr=rd_blk[major]))
|
||||
panic("Trying to read nonexistent block-device");
|
||||
blk_addr(rw, bh);
|
||||
}
|
||||
254
kernel/0.00/linux-0.01/fs/buffer.c
Normal file
254
kernel/0.00/linux-0.01/fs/buffer.c
Normal file
@@ -0,0 +1,254 @@
|
||||
/*
|
||||
* 'buffer.c' implements the buffer-cache functions. Race-conditions have
|
||||
* been avoided by NEVER letting a interrupt change a buffer (except for the
|
||||
* data, of course), but instead letting the caller do it. NOTE! As interrupts
|
||||
* can wake up a caller, some cli-sti sequences are needed to check for
|
||||
* sleep-on-calls. These should be extremely quick, though (I hope).
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <asm/system.h>
|
||||
|
||||
#if (BUFFER_END & 0xfff)
|
||||
#error "Bad BUFFER_END value"
|
||||
#endif
|
||||
|
||||
#if (BUFFER_END > 0xA0000 && BUFFER_END <= 0x100000)
|
||||
#error "Bad BUFFER_END value"
|
||||
#endif
|
||||
|
||||
extern int end;
|
||||
struct buffer_head * start_buffer = (struct buffer_head *) &end;
|
||||
struct buffer_head * hash_table[NR_HASH];
|
||||
static struct buffer_head * free_list;
|
||||
static struct task_struct * buffer_wait = NULL;
|
||||
int NR_BUFFERS = 0;
|
||||
|
||||
static inline void wait_on_buffer(struct buffer_head * bh)
|
||||
{
|
||||
cli();
|
||||
while (bh->b_lock)
|
||||
sleep_on(&bh->b_wait);
|
||||
sti();
|
||||
}
|
||||
|
||||
int sys_sync(void)
|
||||
{
|
||||
int i;
|
||||
struct buffer_head * bh;
|
||||
|
||||
sync_inodes(); /* write out inodes into buffers */
|
||||
bh = start_buffer;
|
||||
for (i=0 ; i<NR_BUFFERS ; i++,bh++) {
|
||||
wait_on_buffer(bh);
|
||||
if (bh->b_dirt)
|
||||
ll_rw_block(WRITE,bh);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sync_dev(int dev)
|
||||
{
|
||||
int i;
|
||||
struct buffer_head * bh;
|
||||
|
||||
bh = start_buffer;
|
||||
for (i=0 ; i<NR_BUFFERS ; i++,bh++) {
|
||||
if (bh->b_dev != dev)
|
||||
continue;
|
||||
wait_on_buffer(bh);
|
||||
if (bh->b_dirt)
|
||||
ll_rw_block(WRITE,bh);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define _hashfn(dev,block) (((unsigned)(dev^block))%NR_HASH)
|
||||
#define hash(dev,block) hash_table[_hashfn(dev,block)]
|
||||
|
||||
static inline void remove_from_queues(struct buffer_head * bh)
|
||||
{
|
||||
/* remove from hash-queue */
|
||||
if (bh->b_next)
|
||||
bh->b_next->b_prev = bh->b_prev;
|
||||
if (bh->b_prev)
|
||||
bh->b_prev->b_next = bh->b_next;
|
||||
if (hash(bh->b_dev,bh->b_blocknr) == bh)
|
||||
hash(bh->b_dev,bh->b_blocknr) = bh->b_next;
|
||||
/* remove from free list */
|
||||
if (!(bh->b_prev_free) || !(bh->b_next_free))
|
||||
panic("Free block list corrupted");
|
||||
bh->b_prev_free->b_next_free = bh->b_next_free;
|
||||
bh->b_next_free->b_prev_free = bh->b_prev_free;
|
||||
if (free_list == bh)
|
||||
free_list = bh->b_next_free;
|
||||
}
|
||||
|
||||
static inline void insert_into_queues(struct buffer_head * bh)
|
||||
{
|
||||
/* put at end of free list */
|
||||
bh->b_next_free = free_list;
|
||||
bh->b_prev_free = free_list->b_prev_free;
|
||||
free_list->b_prev_free->b_next_free = bh;
|
||||
free_list->b_prev_free = bh;
|
||||
/* put the buffer in new hash-queue if it has a device */
|
||||
bh->b_prev = NULL;
|
||||
bh->b_next = NULL;
|
||||
if (!bh->b_dev)
|
||||
return;
|
||||
bh->b_next = hash(bh->b_dev,bh->b_blocknr);
|
||||
hash(bh->b_dev,bh->b_blocknr) = bh;
|
||||
bh->b_next->b_prev = bh;
|
||||
}
|
||||
|
||||
static struct buffer_head * find_buffer(int dev, int block)
|
||||
{
|
||||
struct buffer_head * tmp;
|
||||
|
||||
for (tmp = hash(dev,block) ; tmp != NULL ; tmp = tmp->b_next)
|
||||
if (tmp->b_dev==dev && tmp->b_blocknr==block)
|
||||
return tmp;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Why like this, I hear you say... The reason is race-conditions.
|
||||
* As we don't lock buffers (unless we are readint them, that is),
|
||||
* something might happen to it while we sleep (ie a read-error
|
||||
* will force it bad). This shouldn't really happen currently, but
|
||||
* the code is ready.
|
||||
*/
|
||||
struct buffer_head * get_hash_table(int dev, int block)
|
||||
{
|
||||
struct buffer_head * bh;
|
||||
|
||||
repeat:
|
||||
if (!(bh=find_buffer(dev,block)))
|
||||
return NULL;
|
||||
bh->b_count++;
|
||||
wait_on_buffer(bh);
|
||||
if (bh->b_dev != dev || bh->b_blocknr != block) {
|
||||
brelse(bh);
|
||||
goto repeat;
|
||||
}
|
||||
return bh;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ok, this is getblk, and it isn't very clear, again to hinder
|
||||
* race-conditions. Most of the code is seldom used, (ie repeating),
|
||||
* so it should be much more efficient than it looks.
|
||||
*/
|
||||
struct buffer_head * getblk(int dev,int block)
|
||||
{
|
||||
struct buffer_head * tmp;
|
||||
|
||||
repeat:
|
||||
if (tmp=get_hash_table(dev,block))
|
||||
return tmp;
|
||||
tmp = free_list;
|
||||
do {
|
||||
if (!tmp->b_count) {
|
||||
wait_on_buffer(tmp); /* we still have to wait */
|
||||
if (!tmp->b_count) /* on it, it might be dirty */
|
||||
break;
|
||||
}
|
||||
tmp = tmp->b_next_free;
|
||||
} while (tmp != free_list || (tmp=NULL));
|
||||
/* Kids, don't try THIS at home ^^^^^. Magic */
|
||||
if (!tmp) {
|
||||
printk("Sleeping on free buffer ..");
|
||||
sleep_on(&buffer_wait);
|
||||
printk("ok\n");
|
||||
goto repeat;
|
||||
}
|
||||
tmp->b_count++;
|
||||
remove_from_queues(tmp);
|
||||
/*
|
||||
* Now, when we know nobody can get to this node (as it's removed from the
|
||||
* free list), we write it out. We can sleep here without fear of race-
|
||||
* conditions.
|
||||
*/
|
||||
if (tmp->b_dirt)
|
||||
sync_dev(tmp->b_dev);
|
||||
/* update buffer contents */
|
||||
tmp->b_dev=dev;
|
||||
tmp->b_blocknr=block;
|
||||
tmp->b_dirt=0;
|
||||
tmp->b_uptodate=0;
|
||||
/* NOTE!! While we possibly slept in sync_dev(), somebody else might have
|
||||
* added "this" block already, so check for that. Thank God for goto's.
|
||||
*/
|
||||
if (find_buffer(dev,block)) {
|
||||
tmp->b_dev=0; /* ok, someone else has beaten us */
|
||||
tmp->b_blocknr=0; /* to it - free this block and */
|
||||
tmp->b_count=0; /* try again */
|
||||
insert_into_queues(tmp);
|
||||
goto repeat;
|
||||
}
|
||||
/* and then insert into correct position */
|
||||
insert_into_queues(tmp);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
void brelse(struct buffer_head * buf)
|
||||
{
|
||||
if (!buf)
|
||||
return;
|
||||
wait_on_buffer(buf);
|
||||
if (!(buf->b_count--))
|
||||
panic("Trying to free free buffer");
|
||||
wake_up(&buffer_wait);
|
||||
}
|
||||
|
||||
/*
|
||||
* bread() reads a specified block and returns the buffer that contains
|
||||
* it. It returns NULL if the block was unreadable.
|
||||
*/
|
||||
struct buffer_head * bread(int dev,int block)
|
||||
{
|
||||
struct buffer_head * bh;
|
||||
|
||||
if (!(bh=getblk(dev,block)))
|
||||
panic("bread: getblk returned NULL\n");
|
||||
if (bh->b_uptodate)
|
||||
return bh;
|
||||
ll_rw_block(READ,bh);
|
||||
if (bh->b_uptodate)
|
||||
return bh;
|
||||
brelse(bh);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
void buffer_init(void)
|
||||
{
|
||||
struct buffer_head * h = start_buffer;
|
||||
void * b = (void *) BUFFER_END;
|
||||
int i;
|
||||
|
||||
while ( (b -= BLOCK_SIZE) >= ((void *) (h+1)) ) {
|
||||
h->b_dev = 0;
|
||||
h->b_dirt = 0;
|
||||
h->b_count = 0;
|
||||
h->b_lock = 0;
|
||||
h->b_uptodate = 0;
|
||||
h->b_wait = NULL;
|
||||
h->b_next = NULL;
|
||||
h->b_prev = NULL;
|
||||
h->b_data = (char *) b;
|
||||
h->b_prev_free = h-1;
|
||||
h->b_next_free = h+1;
|
||||
h++;
|
||||
NR_BUFFERS++;
|
||||
if (b == (void *) 0x100000)
|
||||
b = (void *) 0xA0000;
|
||||
}
|
||||
h--;
|
||||
free_list = start_buffer;
|
||||
free_list->b_prev_free = h;
|
||||
h->b_next_free = free_list;
|
||||
for (i=0;i<NR_HASH;i++)
|
||||
hash_table[i]=NULL;
|
||||
}
|
||||
50
kernel/0.00/linux-0.01/fs/char_dev.c
Normal file
50
kernel/0.00/linux-0.01/fs/char_dev.c
Normal file
@@ -0,0 +1,50 @@
|
||||
#include <errno.h>
|
||||
|
||||
#include <linux/sched.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
extern int tty_read(unsigned minor,char * buf,int count);
|
||||
extern int tty_write(unsigned minor,char * buf,int count);
|
||||
|
||||
static int rw_ttyx(int rw,unsigned minor,char * buf,int count);
|
||||
static int rw_tty(int rw,unsigned minor,char * buf,int count);
|
||||
|
||||
typedef (*crw_ptr)(int rw,unsigned minor,char * buf,int count);
|
||||
|
||||
#define NRDEVS ((sizeof (crw_table))/(sizeof (crw_ptr)))
|
||||
|
||||
static crw_ptr crw_table[]={
|
||||
NULL, /* nodev */
|
||||
NULL, /* /dev/mem */
|
||||
NULL, /* /dev/fd */
|
||||
NULL, /* /dev/hd */
|
||||
rw_ttyx, /* /dev/ttyx */
|
||||
rw_tty, /* /dev/tty */
|
||||
NULL, /* /dev/lp */
|
||||
NULL}; /* unnamed pipes */
|
||||
|
||||
static int rw_ttyx(int rw,unsigned minor,char * buf,int count)
|
||||
{
|
||||
return ((rw==READ)?tty_read(minor,buf,count):
|
||||
tty_write(minor,buf,count));
|
||||
}
|
||||
|
||||
static int rw_tty(int rw,unsigned minor,char * buf,int count)
|
||||
{
|
||||
if (current->tty<0)
|
||||
return -EPERM;
|
||||
return rw_ttyx(rw,current->tty,buf,count);
|
||||
}
|
||||
|
||||
int rw_char(int rw,int dev, char * buf, int count)
|
||||
{
|
||||
crw_ptr call_addr;
|
||||
|
||||
if (MAJOR(dev)>=NRDEVS)
|
||||
panic("rw_char: dev>NRDEV");
|
||||
if (!(call_addr=crw_table[MAJOR(dev)])) {
|
||||
printk("dev: %04x\n",dev);
|
||||
panic("Trying to r/w from/to nonexistent character device");
|
||||
}
|
||||
return call_addr(rw,MINOR(dev),buf,count);
|
||||
}
|
||||
306
kernel/0.00/linux-0.01/fs/exec.c
Normal file
306
kernel/0.00/linux-0.01/fs/exec.c
Normal file
@@ -0,0 +1,306 @@
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include <a.out.h>
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mm.h>
|
||||
#include <asm/segment.h>
|
||||
|
||||
extern int sys_exit(int exit_code);
|
||||
extern int sys_close(int fd);
|
||||
|
||||
/*
|
||||
* MAX_ARG_PAGES defines the number of pages allocated for arguments
|
||||
* and envelope for the new program. 32 should suffice, this gives
|
||||
* a maximum env+arg of 128kB !
|
||||
*/
|
||||
#define MAX_ARG_PAGES 32
|
||||
|
||||
#define cp_block(from,to) \
|
||||
__asm__("pushl $0x10\n\t" \
|
||||
"pushl $0x17\n\t" \
|
||||
"pop %%es\n\t" \
|
||||
"cld\n\t" \
|
||||
"rep\n\t" \
|
||||
"movsl\n\t" \
|
||||
"pop %%es" \
|
||||
::"c" (BLOCK_SIZE/4),"S" (from),"D" (to) \
|
||||
:"cx","di","si")
|
||||
|
||||
/*
|
||||
* read_head() reads blocks 1-6 (not 0). Block 0 has already been
|
||||
* read for header information.
|
||||
*/
|
||||
int read_head(struct m_inode * inode,int blocks)
|
||||
{
|
||||
struct buffer_head * bh;
|
||||
int count;
|
||||
|
||||
if (blocks>6)
|
||||
blocks=6;
|
||||
for(count = 0 ; count<blocks ; count++) {
|
||||
if (!inode->i_zone[count+1])
|
||||
continue;
|
||||
if (!(bh=bread(inode->i_dev,inode->i_zone[count+1])))
|
||||
return -1;
|
||||
cp_block(bh->b_data,count*BLOCK_SIZE);
|
||||
brelse(bh);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int read_ind(int dev,int ind,long size,unsigned long offset)
|
||||
{
|
||||
struct buffer_head * ih, * bh;
|
||||
unsigned short * table,block;
|
||||
|
||||
if (size<=0)
|
||||
panic("size<=0 in read_ind");
|
||||
if (size>512*BLOCK_SIZE)
|
||||
size=512*BLOCK_SIZE;
|
||||
if (!ind)
|
||||
return 0;
|
||||
if (!(ih=bread(dev,ind)))
|
||||
return -1;
|
||||
table = (unsigned short *) ih->b_data;
|
||||
while (size>0) {
|
||||
if (block=*(table++))
|
||||
if (!(bh=bread(dev,block))) {
|
||||
brelse(ih);
|
||||
return -1;
|
||||
} else {
|
||||
cp_block(bh->b_data,offset);
|
||||
brelse(bh);
|
||||
}
|
||||
size -= BLOCK_SIZE;
|
||||
offset += BLOCK_SIZE;
|
||||
}
|
||||
brelse(ih);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* read_area() reads an area into %fs:mem.
|
||||
*/
|
||||
int read_area(struct m_inode * inode,long size)
|
||||
{
|
||||
struct buffer_head * dind;
|
||||
unsigned short * table;
|
||||
int i,count;
|
||||
|
||||
if ((i=read_head(inode,(size+BLOCK_SIZE-1)/BLOCK_SIZE)) ||
|
||||
(size -= BLOCK_SIZE*6)<=0)
|
||||
return i;
|
||||
if ((i=read_ind(inode->i_dev,inode->i_zone[7],size,BLOCK_SIZE*6)) ||
|
||||
(size -= BLOCK_SIZE*512)<=0)
|
||||
return i;
|
||||
if (!(i=inode->i_zone[8]))
|
||||
return 0;
|
||||
if (!(dind = bread(inode->i_dev,i)))
|
||||
return -1;
|
||||
table = (unsigned short *) dind->b_data;
|
||||
for(count=0 ; count<512 ; count++)
|
||||
if ((i=read_ind(inode->i_dev,*(table++),size,
|
||||
BLOCK_SIZE*(518+count))) || (size -= BLOCK_SIZE*512)<=0)
|
||||
return i;
|
||||
panic("Impossibly long executable");
|
||||
}
|
||||
|
||||
/*
|
||||
* create_tables() parses the env- and arg-strings in new user
|
||||
* memory and creates the pointer tables from them, and puts their
|
||||
* addresses on the "stack", returning the new stack pointer value.
|
||||
*/
|
||||
static unsigned long * create_tables(char * p,int argc,int envc)
|
||||
{
|
||||
unsigned long *argv,*envp;
|
||||
unsigned long * sp;
|
||||
|
||||
sp = (unsigned long *) (0xfffffffc & (unsigned long) p);
|
||||
sp -= envc+1;
|
||||
envp = sp;
|
||||
sp -= argc+1;
|
||||
argv = sp;
|
||||
put_fs_long((unsigned long)envp,--sp);
|
||||
put_fs_long((unsigned long)argv,--sp);
|
||||
put_fs_long((unsigned long)argc,--sp);
|
||||
while (argc-->0) {
|
||||
put_fs_long((unsigned long) p,argv++);
|
||||
while (get_fs_byte(p++)) /* nothing */ ;
|
||||
}
|
||||
put_fs_long(0,argv);
|
||||
while (envc-->0) {
|
||||
put_fs_long((unsigned long) p,envp++);
|
||||
while (get_fs_byte(p++)) /* nothing */ ;
|
||||
}
|
||||
put_fs_long(0,envp);
|
||||
return sp;
|
||||
}
|
||||
|
||||
/*
|
||||
* count() counts the number of arguments/envelopes
|
||||
*/
|
||||
static int count(char ** argv)
|
||||
{
|
||||
int i=0;
|
||||
char ** tmp;
|
||||
|
||||
if (tmp = argv)
|
||||
while (get_fs_long((unsigned long *) (tmp++)))
|
||||
i++;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
/*
|
||||
* 'copy_string()' copies argument/envelope strings from user
|
||||
* memory to free pages in kernel mem. These are in a format ready
|
||||
* to be put directly into the top of new user memory.
|
||||
*/
|
||||
static unsigned long copy_strings(int argc,char ** argv,unsigned long *page,
|
||||
unsigned long p)
|
||||
{
|
||||
int len,i;
|
||||
char *tmp;
|
||||
|
||||
while (argc-- > 0) {
|
||||
if (!(tmp = (char *)get_fs_long(((unsigned long *) argv)+argc)))
|
||||
panic("argc is wrong");
|
||||
len=0; /* remember zero-padding */
|
||||
do {
|
||||
len++;
|
||||
} while (get_fs_byte(tmp++));
|
||||
if (p-len < 0) /* this shouldn't happen - 128kB */
|
||||
return 0;
|
||||
i = ((unsigned) (p-len)) >> 12;
|
||||
while (i<MAX_ARG_PAGES && !page[i]) {
|
||||
if (!(page[i]=get_free_page()))
|
||||
return 0;
|
||||
i++;
|
||||
}
|
||||
do {
|
||||
--p;
|
||||
if (!page[p/PAGE_SIZE])
|
||||
panic("nonexistent page in exec.c");
|
||||
((char *) page[p/PAGE_SIZE])[p%PAGE_SIZE] =
|
||||
get_fs_byte(--tmp);
|
||||
} while (--len);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
static unsigned long change_ldt(unsigned long text_size,unsigned long * page)
|
||||
{
|
||||
unsigned long code_limit,data_limit,code_base,data_base;
|
||||
int i;
|
||||
|
||||
code_limit = text_size+PAGE_SIZE -1;
|
||||
code_limit &= 0xFFFFF000;
|
||||
data_limit = 0x4000000;
|
||||
code_base = get_base(current->ldt[1]);
|
||||
data_base = code_base;
|
||||
set_base(current->ldt[1],code_base);
|
||||
set_limit(current->ldt[1],code_limit);
|
||||
set_base(current->ldt[2],data_base);
|
||||
set_limit(current->ldt[2],data_limit);
|
||||
/* make sure fs points to the NEW data segment */
|
||||
__asm__("pushl $0x17\n\tpop %%fs"::);
|
||||
data_base += data_limit;
|
||||
for (i=MAX_ARG_PAGES-1 ; i>=0 ; i--) {
|
||||
data_base -= PAGE_SIZE;
|
||||
if (page[i])
|
||||
put_page(page[i],data_base);
|
||||
}
|
||||
return data_limit;
|
||||
}
|
||||
|
||||
/*
|
||||
* 'do_execve()' executes a new program.
|
||||
*/
|
||||
int do_execve(unsigned long * eip,long tmp,char * filename,
|
||||
char ** argv, char ** envp)
|
||||
{
|
||||
struct m_inode * inode;
|
||||
struct buffer_head * bh;
|
||||
struct exec ex;
|
||||
unsigned long page[MAX_ARG_PAGES];
|
||||
int i,argc,envc;
|
||||
unsigned long p;
|
||||
|
||||
if ((0xffff & eip[1]) != 0x000f)
|
||||
panic("execve called from supervisor mode");
|
||||
for (i=0 ; i<MAX_ARG_PAGES ; i++) /* clear page-table */
|
||||
page[i]=0;
|
||||
if (!(inode=namei(filename))) /* get executables inode */
|
||||
return -ENOENT;
|
||||
if (!S_ISREG(inode->i_mode)) { /* must be regular file */
|
||||
iput(inode);
|
||||
return -EACCES;
|
||||
}
|
||||
i = inode->i_mode;
|
||||
if (current->uid && current->euid) {
|
||||
if (current->euid == inode->i_uid)
|
||||
i >>= 6;
|
||||
else if (current->egid == inode->i_gid)
|
||||
i >>= 3;
|
||||
} else if (i & 0111)
|
||||
i=1;
|
||||
if (!(i & 1)) {
|
||||
iput(inode);
|
||||
return -ENOEXEC;
|
||||
}
|
||||
if (!(bh = bread(inode->i_dev,inode->i_zone[0]))) {
|
||||
iput(inode);
|
||||
return -EACCES;
|
||||
}
|
||||
ex = *((struct exec *) bh->b_data); /* read exec-header */
|
||||
brelse(bh);
|
||||
if (N_MAGIC(ex) != ZMAGIC || ex.a_trsize || ex.a_drsize ||
|
||||
ex.a_text+ex.a_data+ex.a_bss>0x3000000 ||
|
||||
inode->i_size < ex.a_text+ex.a_data+ex.a_syms+N_TXTOFF(ex)) {
|
||||
iput(inode);
|
||||
return -ENOEXEC;
|
||||
}
|
||||
if (N_TXTOFF(ex) != BLOCK_SIZE)
|
||||
panic("N_TXTOFF != BLOCK_SIZE. See a.out.h.");
|
||||
argc = count(argv);
|
||||
envc = count(envp);
|
||||
p = copy_strings(envc,envp,page,PAGE_SIZE*MAX_ARG_PAGES-4);
|
||||
p = copy_strings(argc,argv,page,p);
|
||||
if (!p) {
|
||||
for (i=0 ; i<MAX_ARG_PAGES ; i++)
|
||||
free_page(page[i]);
|
||||
iput(inode);
|
||||
return -1;
|
||||
}
|
||||
/* OK, This is the point of no return */
|
||||
for (i=0 ; i<32 ; i++)
|
||||
current->sig_fn[i] = NULL;
|
||||
for (i=0 ; i<NR_OPEN ; i++)
|
||||
if ((current->close_on_exec>>i)&1)
|
||||
sys_close(i);
|
||||
current->close_on_exec = 0;
|
||||
free_page_tables(get_base(current->ldt[1]),get_limit(0x0f));
|
||||
free_page_tables(get_base(current->ldt[2]),get_limit(0x17));
|
||||
if (last_task_used_math == current)
|
||||
last_task_used_math = NULL;
|
||||
current->used_math = 0;
|
||||
p += change_ldt(ex.a_text,page)-MAX_ARG_PAGES*PAGE_SIZE;
|
||||
p = (unsigned long) create_tables((char *)p,argc,envc);
|
||||
current->brk = ex.a_bss +
|
||||
(current->end_data = ex.a_data +
|
||||
(current->end_code = ex.a_text));
|
||||
current->start_stack = p & 0xfffff000;
|
||||
i = read_area(inode,ex.a_text+ex.a_data);
|
||||
iput(inode);
|
||||
if (i<0)
|
||||
sys_exit(-1);
|
||||
i = ex.a_text+ex.a_data;
|
||||
while (i&0xfff)
|
||||
put_fs_byte(0,(char *) (i++));
|
||||
eip[0] = ex.a_entry; /* eip, magic happens :-) */
|
||||
eip[3] = p; /* stack pointer */
|
||||
return 0;
|
||||
}
|
||||
69
kernel/0.00/linux-0.01/fs/fcntl.c
Normal file
69
kernel/0.00/linux-0.01/fs/fcntl.c
Normal file
@@ -0,0 +1,69 @@
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <asm/segment.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
extern int sys_close(int fd);
|
||||
|
||||
static int dupfd(unsigned int fd, unsigned int arg)
|
||||
{
|
||||
if (fd >= NR_OPEN || !current->filp[fd])
|
||||
return -EBADF;
|
||||
if (arg >= NR_OPEN)
|
||||
return -EINVAL;
|
||||
while (arg < NR_OPEN)
|
||||
if (current->filp[arg])
|
||||
arg++;
|
||||
else
|
||||
break;
|
||||
if (arg >= NR_OPEN)
|
||||
return -EMFILE;
|
||||
current->close_on_exec &= ~(1<<arg);
|
||||
(current->filp[arg] = current->filp[fd])->f_count++;
|
||||
return arg;
|
||||
}
|
||||
|
||||
int sys_dup2(unsigned int oldfd, unsigned int newfd)
|
||||
{
|
||||
sys_close(newfd);
|
||||
return dupfd(oldfd,newfd);
|
||||
}
|
||||
|
||||
int sys_dup(unsigned int fildes)
|
||||
{
|
||||
return dupfd(fildes,0);
|
||||
}
|
||||
|
||||
int sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct file * filp;
|
||||
|
||||
if (fd >= NR_OPEN || !(filp = current->filp[fd]))
|
||||
return -EBADF;
|
||||
switch (cmd) {
|
||||
case F_DUPFD:
|
||||
return dupfd(fd,arg);
|
||||
case F_GETFD:
|
||||
return (current->close_on_exec>>fd)&1;
|
||||
case F_SETFD:
|
||||
if (arg&1)
|
||||
current->close_on_exec |= (1<<fd);
|
||||
else
|
||||
current->close_on_exec &= ~(1<<fd);
|
||||
return 0;
|
||||
case F_GETFL:
|
||||
return filp->f_flags;
|
||||
case F_SETFL:
|
||||
filp->f_flags &= ~(O_APPEND | O_NONBLOCK);
|
||||
filp->f_flags |= arg & (O_APPEND | O_NONBLOCK);
|
||||
return 0;
|
||||
case F_GETLK: case F_SETLK: case F_SETLKW:
|
||||
return -1;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
84
kernel/0.00/linux-0.01/fs/file_dev.c
Normal file
84
kernel/0.00/linux-0.01/fs/file_dev.c
Normal file
@@ -0,0 +1,84 @@
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <linux/sched.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <asm/segment.h>
|
||||
|
||||
#define MIN(a,b) (((a)<(b))?(a):(b))
|
||||
#define MAX(a,b) (((a)>(b))?(a):(b))
|
||||
|
||||
int file_read(struct m_inode * inode, struct file * filp, char * buf, int count)
|
||||
{
|
||||
int left,chars,nr;
|
||||
struct buffer_head * bh;
|
||||
|
||||
if ((left=count)<=0)
|
||||
return 0;
|
||||
while (left) {
|
||||
if (nr = bmap(inode,(filp->f_pos)/BLOCK_SIZE)) {
|
||||
if (!(bh=bread(inode->i_dev,nr)))
|
||||
break;
|
||||
} else
|
||||
bh = NULL;
|
||||
nr = filp->f_pos % BLOCK_SIZE;
|
||||
chars = MIN( BLOCK_SIZE-nr , left );
|
||||
filp->f_pos += chars;
|
||||
left -= chars;
|
||||
if (bh) {
|
||||
char * p = nr + bh->b_data;
|
||||
while (chars-->0)
|
||||
put_fs_byte(*(p++),buf++);
|
||||
brelse(bh);
|
||||
} else {
|
||||
while (chars-->0)
|
||||
put_fs_byte(0,buf++);
|
||||
}
|
||||
}
|
||||
inode->i_atime = CURRENT_TIME;
|
||||
return (count-left)?(count-left):-ERROR;
|
||||
}
|
||||
|
||||
int file_write(struct m_inode * inode, struct file * filp, char * buf, int count)
|
||||
{
|
||||
off_t pos;
|
||||
int block,c;
|
||||
struct buffer_head * bh;
|
||||
char * p;
|
||||
int i=0;
|
||||
|
||||
/*
|
||||
* ok, append may not work when many processes are writing at the same time
|
||||
* but so what. That way leads to madness anyway.
|
||||
*/
|
||||
if (filp->f_flags & O_APPEND)
|
||||
pos = inode->i_size;
|
||||
else
|
||||
pos = filp->f_pos;
|
||||
while (i<count) {
|
||||
if (!(block = create_block(inode,pos/BLOCK_SIZE)))
|
||||
break;
|
||||
if (!(bh=bread(inode->i_dev,block)))
|
||||
break;
|
||||
c = pos % BLOCK_SIZE;
|
||||
p = c + bh->b_data;
|
||||
bh->b_dirt = 1;
|
||||
c = BLOCK_SIZE-c;
|
||||
if (c > count-i) c = count-i;
|
||||
pos += c;
|
||||
if (pos > inode->i_size) {
|
||||
inode->i_size = pos;
|
||||
inode->i_dirt = 1;
|
||||
}
|
||||
i += c;
|
||||
while (c-->0)
|
||||
*(p++) = get_fs_byte(buf++);
|
||||
brelse(bh);
|
||||
}
|
||||
inode->i_mtime = CURRENT_TIME;
|
||||
if (!(filp->f_flags & O_APPEND)) {
|
||||
filp->f_pos = pos;
|
||||
inode->i_ctime = CURRENT_TIME;
|
||||
}
|
||||
return (i?i:-1);
|
||||
}
|
||||
3
kernel/0.00/linux-0.01/fs/file_table.c
Normal file
3
kernel/0.00/linux-0.01/fs/file_table.c
Normal file
@@ -0,0 +1,3 @@
|
||||
#include <linux/fs.h>
|
||||
|
||||
struct file file_table[NR_FILE];
|
||||
288
kernel/0.00/linux-0.01/fs/inode.c
Normal file
288
kernel/0.00/linux-0.01/fs/inode.c
Normal file
@@ -0,0 +1,288 @@
|
||||
#include <string.h>
|
||||
|
||||
#include <linux/sched.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mm.h>
|
||||
#include <asm/system.h>
|
||||
|
||||
struct m_inode inode_table[NR_INODE]={{0,},};
|
||||
|
||||
static void read_inode(struct m_inode * inode);
|
||||
static void write_inode(struct m_inode * inode);
|
||||
|
||||
static inline void wait_on_inode(struct m_inode * inode)
|
||||
{
|
||||
cli();
|
||||
while (inode->i_lock)
|
||||
sleep_on(&inode->i_wait);
|
||||
sti();
|
||||
}
|
||||
|
||||
static inline void lock_inode(struct m_inode * inode)
|
||||
{
|
||||
cli();
|
||||
while (inode->i_lock)
|
||||
sleep_on(&inode->i_wait);
|
||||
inode->i_lock=1;
|
||||
sti();
|
||||
}
|
||||
|
||||
static inline void unlock_inode(struct m_inode * inode)
|
||||
{
|
||||
inode->i_lock=0;
|
||||
wake_up(&inode->i_wait);
|
||||
}
|
||||
|
||||
void sync_inodes(void)
|
||||
{
|
||||
int i;
|
||||
struct m_inode * inode;
|
||||
|
||||
inode = 0+inode_table;
|
||||
for(i=0 ; i<NR_INODE ; i++,inode++) {
|
||||
wait_on_inode(inode);
|
||||
if (inode->i_dirt && !inode->i_pipe)
|
||||
write_inode(inode);
|
||||
}
|
||||
}
|
||||
|
||||
static int _bmap(struct m_inode * inode,int block,int create)
|
||||
{
|
||||
struct buffer_head * bh;
|
||||
int i;
|
||||
|
||||
if (block<0)
|
||||
panic("_bmap: block<0");
|
||||
if (block >= 7+512+512*512)
|
||||
panic("_bmap: block>big");
|
||||
if (block<7) {
|
||||
if (create && !inode->i_zone[block])
|
||||
if (inode->i_zone[block]=new_block(inode->i_dev)) {
|
||||
inode->i_ctime=CURRENT_TIME;
|
||||
inode->i_dirt=1;
|
||||
}
|
||||
return inode->i_zone[block];
|
||||
}
|
||||
block -= 7;
|
||||
if (block<512) {
|
||||
if (create && !inode->i_zone[7])
|
||||
if (inode->i_zone[7]=new_block(inode->i_dev)) {
|
||||
inode->i_dirt=1;
|
||||
inode->i_ctime=CURRENT_TIME;
|
||||
}
|
||||
if (!inode->i_zone[7])
|
||||
return 0;
|
||||
if (!(bh = bread(inode->i_dev,inode->i_zone[7])))
|
||||
return 0;
|
||||
i = ((unsigned short *) (bh->b_data))[block];
|
||||
if (create && !i)
|
||||
if (i=new_block(inode->i_dev)) {
|
||||
((unsigned short *) (bh->b_data))[block]=i;
|
||||
bh->b_dirt=1;
|
||||
}
|
||||
brelse(bh);
|
||||
return i;
|
||||
}
|
||||
block -= 512;
|
||||
if (create && !inode->i_zone[8])
|
||||
if (inode->i_zone[8]=new_block(inode->i_dev)) {
|
||||
inode->i_dirt=1;
|
||||
inode->i_ctime=CURRENT_TIME;
|
||||
}
|
||||
if (!inode->i_zone[8])
|
||||
return 0;
|
||||
if (!(bh=bread(inode->i_dev,inode->i_zone[8])))
|
||||
return 0;
|
||||
i = ((unsigned short *)bh->b_data)[block>>9];
|
||||
if (create && !i)
|
||||
if (i=new_block(inode->i_dev)) {
|
||||
((unsigned short *) (bh->b_data))[block>>9]=i;
|
||||
bh->b_dirt=1;
|
||||
}
|
||||
brelse(bh);
|
||||
if (!i)
|
||||
return 0;
|
||||
if (!(bh=bread(inode->i_dev,i)))
|
||||
return 0;
|
||||
i = ((unsigned short *)bh->b_data)[block&511];
|
||||
if (create && !i)
|
||||
if (i=new_block(inode->i_dev)) {
|
||||
((unsigned short *) (bh->b_data))[block&511]=i;
|
||||
bh->b_dirt=1;
|
||||
}
|
||||
brelse(bh);
|
||||
return i;
|
||||
}
|
||||
|
||||
int bmap(struct m_inode * inode,int block)
|
||||
{
|
||||
return _bmap(inode,block,0);
|
||||
}
|
||||
|
||||
int create_block(struct m_inode * inode, int block)
|
||||
{
|
||||
return _bmap(inode,block,1);
|
||||
}
|
||||
|
||||
void iput(struct m_inode * inode)
|
||||
{
|
||||
if (!inode)
|
||||
return;
|
||||
wait_on_inode(inode);
|
||||
if (!inode->i_count)
|
||||
panic("iput: trying to free free inode");
|
||||
if (inode->i_pipe) {
|
||||
wake_up(&inode->i_wait);
|
||||
if (--inode->i_count)
|
||||
return;
|
||||
free_page(inode->i_size);
|
||||
inode->i_count=0;
|
||||
inode->i_dirt=0;
|
||||
inode->i_pipe=0;
|
||||
return;
|
||||
}
|
||||
if (!inode->i_dev || inode->i_count>1) {
|
||||
inode->i_count--;
|
||||
return;
|
||||
}
|
||||
repeat:
|
||||
if (!inode->i_nlinks) {
|
||||
truncate(inode);
|
||||
free_inode(inode);
|
||||
return;
|
||||
}
|
||||
if (inode->i_dirt) {
|
||||
write_inode(inode); /* we can sleep - so do again */
|
||||
wait_on_inode(inode);
|
||||
goto repeat;
|
||||
}
|
||||
inode->i_count--;
|
||||
return;
|
||||
}
|
||||
|
||||
static volatile int last_allocated_inode = 0;
|
||||
|
||||
struct m_inode * get_empty_inode(void)
|
||||
{
|
||||
struct m_inode * inode;
|
||||
int inr;
|
||||
|
||||
while (1) {
|
||||
inode = NULL;
|
||||
inr = last_allocated_inode;
|
||||
do {
|
||||
if (!inode_table[inr].i_count) {
|
||||
inode = inr + inode_table;
|
||||
break;
|
||||
}
|
||||
inr++;
|
||||
if (inr>=NR_INODE)
|
||||
inr=0;
|
||||
} while (inr != last_allocated_inode);
|
||||
if (!inode) {
|
||||
for (inr=0 ; inr<NR_INODE ; inr++)
|
||||
printk("%04x: %6d\t",inode_table[inr].i_dev,
|
||||
inode_table[inr].i_num);
|
||||
panic("No free inodes in mem");
|
||||
}
|
||||
last_allocated_inode = inr;
|
||||
wait_on_inode(inode);
|
||||
while (inode->i_dirt) {
|
||||
write_inode(inode);
|
||||
wait_on_inode(inode);
|
||||
}
|
||||
if (!inode->i_count)
|
||||
break;
|
||||
}
|
||||
memset(inode,0,sizeof(*inode));
|
||||
inode->i_count = 1;
|
||||
return inode;
|
||||
}
|
||||
|
||||
struct m_inode * get_pipe_inode(void)
|
||||
{
|
||||
struct m_inode * inode;
|
||||
|
||||
if (!(inode = get_empty_inode()))
|
||||
return NULL;
|
||||
if (!(inode->i_size=get_free_page())) {
|
||||
inode->i_count = 0;
|
||||
return NULL;
|
||||
}
|
||||
inode->i_count = 2; /* sum of readers/writers */
|
||||
PIPE_HEAD(*inode) = PIPE_TAIL(*inode) = 0;
|
||||
inode->i_pipe = 1;
|
||||
return inode;
|
||||
}
|
||||
|
||||
struct m_inode * iget(int dev,int nr)
|
||||
{
|
||||
struct m_inode * inode, * empty;
|
||||
|
||||
if (!dev)
|
||||
panic("iget with dev==0");
|
||||
empty = get_empty_inode();
|
||||
inode = inode_table;
|
||||
while (inode < NR_INODE+inode_table) {
|
||||
if (inode->i_dev != dev || inode->i_num != nr) {
|
||||
inode++;
|
||||
continue;
|
||||
}
|
||||
wait_on_inode(inode);
|
||||
if (inode->i_dev != dev || inode->i_num != nr) {
|
||||
inode = inode_table;
|
||||
continue;
|
||||
}
|
||||
inode->i_count++;
|
||||
if (empty)
|
||||
iput(empty);
|
||||
return inode;
|
||||
}
|
||||
if (!empty)
|
||||
return (NULL);
|
||||
inode=empty;
|
||||
inode->i_dev = dev;
|
||||
inode->i_num = nr;
|
||||
read_inode(inode);
|
||||
return inode;
|
||||
}
|
||||
|
||||
static void read_inode(struct m_inode * inode)
|
||||
{
|
||||
struct super_block * sb;
|
||||
struct buffer_head * bh;
|
||||
int block;
|
||||
|
||||
lock_inode(inode);
|
||||
sb=get_super(inode->i_dev);
|
||||
block = 2 + sb->s_imap_blocks + sb->s_zmap_blocks +
|
||||
(inode->i_num-1)/INODES_PER_BLOCK;
|
||||
if (!(bh=bread(inode->i_dev,block)))
|
||||
panic("unable to read i-node block");
|
||||
*(struct d_inode *)inode =
|
||||
((struct d_inode *)bh->b_data)
|
||||
[(inode->i_num-1)%INODES_PER_BLOCK];
|
||||
brelse(bh);
|
||||
unlock_inode(inode);
|
||||
}
|
||||
|
||||
static void write_inode(struct m_inode * inode)
|
||||
{
|
||||
struct super_block * sb;
|
||||
struct buffer_head * bh;
|
||||
int block;
|
||||
|
||||
lock_inode(inode);
|
||||
sb=get_super(inode->i_dev);
|
||||
block = 2 + sb->s_imap_blocks + sb->s_zmap_blocks +
|
||||
(inode->i_num-1)/INODES_PER_BLOCK;
|
||||
if (!(bh=bread(inode->i_dev,block)))
|
||||
panic("unable to read i-node block");
|
||||
((struct d_inode *)bh->b_data)
|
||||
[(inode->i_num-1)%INODES_PER_BLOCK] =
|
||||
*(struct d_inode *)inode;
|
||||
bh->b_dirt=1;
|
||||
inode->i_dirt=0;
|
||||
brelse(bh);
|
||||
unlock_inode(inode);
|
||||
}
|
||||
40
kernel/0.00/linux-0.01/fs/ioctl.c
Normal file
40
kernel/0.00/linux-0.01/fs/ioctl.c
Normal file
@@ -0,0 +1,40 @@
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <linux/sched.h>
|
||||
|
||||
extern int tty_ioctl(int dev, int cmd, int arg);
|
||||
|
||||
typedef int (*ioctl_ptr)(int dev,int cmd,int arg);
|
||||
|
||||
#define NRDEVS ((sizeof (ioctl_table))/(sizeof (ioctl_ptr)))
|
||||
|
||||
static ioctl_ptr ioctl_table[]={
|
||||
NULL, /* nodev */
|
||||
NULL, /* /dev/mem */
|
||||
NULL, /* /dev/fd */
|
||||
NULL, /* /dev/hd */
|
||||
tty_ioctl, /* /dev/ttyx */
|
||||
tty_ioctl, /* /dev/tty */
|
||||
NULL, /* /dev/lp */
|
||||
NULL}; /* named pipes */
|
||||
|
||||
|
||||
int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct file * filp;
|
||||
int dev,mode;
|
||||
|
||||
if (fd >= NR_OPEN || !(filp = current->filp[fd]))
|
||||
return -EBADF;
|
||||
mode=filp->f_inode->i_mode;
|
||||
if (!S_ISCHR(mode) && !S_ISBLK(mode))
|
||||
return -EINVAL;
|
||||
dev = filp->f_inode->i_zone[0];
|
||||
if (MAJOR(dev) >= NRDEVS)
|
||||
panic("unknown device for ioctl");
|
||||
if (!ioctl_table[MAJOR(dev)])
|
||||
return -ENOTTY;
|
||||
return ioctl_table[MAJOR(dev)](dev,cmd,arg);
|
||||
}
|
||||
678
kernel/0.00/linux-0.01/fs/namei.c
Normal file
678
kernel/0.00/linux-0.01/fs/namei.c
Normal file
@@ -0,0 +1,678 @@
|
||||
#include <linux/sched.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <asm/segment.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <const.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#define ACC_MODE(x) ("\004\002\006\377"[(x)&O_ACCMODE])
|
||||
|
||||
/*
|
||||
* comment out this line if you want names > NAME_LEN chars to be
|
||||
* truncated. Else they will be disallowed.
|
||||
*/
|
||||
/* #define NO_TRUNCATE */
|
||||
|
||||
#define MAY_EXEC 1
|
||||
#define MAY_WRITE 2
|
||||
#define MAY_READ 4
|
||||
|
||||
/*
|
||||
* permission()
|
||||
*
|
||||
* is used to check for read/write/execute permissions on a file.
|
||||
* I don't know if we should look at just the euid or both euid and
|
||||
* uid, but that should be easily changed.
|
||||
*/
|
||||
static int permission(struct m_inode * inode,int mask)
|
||||
{
|
||||
int mode = inode->i_mode;
|
||||
|
||||
/* special case: not even root can read/write a deleted file */
|
||||
if (inode->i_dev && !inode->i_nlinks)
|
||||
return 0;
|
||||
if (!(current->uid && current->euid))
|
||||
mode=0777;
|
||||
else if (current->uid==inode->i_uid || current->euid==inode->i_uid)
|
||||
mode >>= 6;
|
||||
else if (current->gid==inode->i_gid || current->egid==inode->i_gid)
|
||||
mode >>= 3;
|
||||
return mode & mask & 0007;
|
||||
}
|
||||
|
||||
/*
|
||||
* ok, we cannot use strncmp, as the name is not in our data space.
|
||||
* Thus we'll have to use match. No big problem. Match also makes
|
||||
* some sanity tests.
|
||||
*
|
||||
* NOTE! unlike strncmp, match returns 1 for success, 0 for failure.
|
||||
*/
|
||||
static int match(int len,const char * name,struct dir_entry * de)
|
||||
{
|
||||
register int same __asm__("ax");
|
||||
|
||||
if (!de || !de->inode || len > NAME_LEN)
|
||||
return 0;
|
||||
if (len < NAME_LEN && de->name[len])
|
||||
return 0;
|
||||
__asm__("cld\n\t"
|
||||
"fs ; repe ; cmpsb\n\t"
|
||||
"setz %%al"
|
||||
:"=a" (same)
|
||||
:"0" (0),"S" ((long) name),"D" ((long) de->name),"c" (len)
|
||||
:"cx","di","si");
|
||||
return same;
|
||||
}
|
||||
|
||||
/*
|
||||
* find_entry()
|
||||
*
|
||||
* finds and entry in the specified directory with the wanted name. It
|
||||
* returns the cache buffer in which the entry was found, and the entry
|
||||
* itself (as a parameter - res_dir). It does NOT read the inode of the
|
||||
* entry - you'll have to do that yourself if you want to.
|
||||
*/
|
||||
static struct buffer_head * find_entry(struct m_inode * dir,
|
||||
const char * name, int namelen, struct dir_entry ** res_dir)
|
||||
{
|
||||
int entries;
|
||||
int block,i;
|
||||
struct buffer_head * bh;
|
||||
struct dir_entry * de;
|
||||
|
||||
#ifdef NO_TRUNCATE
|
||||
if (namelen > NAME_LEN)
|
||||
return NULL;
|
||||
#else
|
||||
if (namelen > NAME_LEN)
|
||||
namelen = NAME_LEN;
|
||||
#endif
|
||||
entries = dir->i_size / (sizeof (struct dir_entry));
|
||||
*res_dir = NULL;
|
||||
if (!namelen)
|
||||
return NULL;
|
||||
if (!(block = dir->i_zone[0]))
|
||||
return NULL;
|
||||
if (!(bh = bread(dir->i_dev,block)))
|
||||
return NULL;
|
||||
i = 0;
|
||||
de = (struct dir_entry *) bh->b_data;
|
||||
while (i < entries) {
|
||||
if ((char *)de >= BLOCK_SIZE+bh->b_data) {
|
||||
brelse(bh);
|
||||
bh = NULL;
|
||||
if (!(block = bmap(dir,i/DIR_ENTRIES_PER_BLOCK)) ||
|
||||
!(bh = bread(dir->i_dev,block))) {
|
||||
i += DIR_ENTRIES_PER_BLOCK;
|
||||
continue;
|
||||
}
|
||||
de = (struct dir_entry *) bh->b_data;
|
||||
}
|
||||
if (match(namelen,name,de)) {
|
||||
*res_dir = de;
|
||||
return bh;
|
||||
}
|
||||
de++;
|
||||
i++;
|
||||
}
|
||||
brelse(bh);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* add_entry()
|
||||
*
|
||||
* adds a file entry to the specified directory, using the same
|
||||
* semantics as find_entry(). It returns NULL if it failed.
|
||||
*
|
||||
* NOTE!! The inode part of 'de' is left at 0 - which means you
|
||||
* may not sleep between calling this and putting something into
|
||||
* the entry, as someone else might have used it while you slept.
|
||||
*/
|
||||
static struct buffer_head * add_entry(struct m_inode * dir,
|
||||
const char * name, int namelen, struct dir_entry ** res_dir)
|
||||
{
|
||||
int block,i;
|
||||
struct buffer_head * bh;
|
||||
struct dir_entry * de;
|
||||
|
||||
*res_dir = NULL;
|
||||
#ifdef NO_TRUNCATE
|
||||
if (namelen > NAME_LEN)
|
||||
return NULL;
|
||||
#else
|
||||
if (namelen > NAME_LEN)
|
||||
namelen = NAME_LEN;
|
||||
#endif
|
||||
if (!namelen)
|
||||
return NULL;
|
||||
if (!(block = dir->i_zone[0]))
|
||||
return NULL;
|
||||
if (!(bh = bread(dir->i_dev,block)))
|
||||
return NULL;
|
||||
i = 0;
|
||||
de = (struct dir_entry *) bh->b_data;
|
||||
while (1) {
|
||||
if ((char *)de >= BLOCK_SIZE+bh->b_data) {
|
||||
brelse(bh);
|
||||
bh = NULL;
|
||||
block = create_block(dir,i/DIR_ENTRIES_PER_BLOCK);
|
||||
if (!block)
|
||||
return NULL;
|
||||
if (!(bh = bread(dir->i_dev,block))) {
|
||||
i += DIR_ENTRIES_PER_BLOCK;
|
||||
continue;
|
||||
}
|
||||
de = (struct dir_entry *) bh->b_data;
|
||||
}
|
||||
if (i*sizeof(struct dir_entry) >= dir->i_size) {
|
||||
de->inode=0;
|
||||
dir->i_size = (i+1)*sizeof(struct dir_entry);
|
||||
dir->i_dirt = 1;
|
||||
dir->i_ctime = CURRENT_TIME;
|
||||
}
|
||||
if (!de->inode) {
|
||||
dir->i_mtime = CURRENT_TIME;
|
||||
for (i=0; i < NAME_LEN ; i++)
|
||||
de->name[i]=(i<namelen)?get_fs_byte(name+i):0;
|
||||
bh->b_dirt = 1;
|
||||
*res_dir = de;
|
||||
return bh;
|
||||
}
|
||||
de++;
|
||||
i++;
|
||||
}
|
||||
brelse(bh);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* get_dir()
|
||||
*
|
||||
* Getdir traverses the pathname until it hits the topmost directory.
|
||||
* It returns NULL on failure.
|
||||
*/
|
||||
static struct m_inode * get_dir(const char * pathname)
|
||||
{
|
||||
char c;
|
||||
const char * thisname;
|
||||
struct m_inode * inode;
|
||||
struct buffer_head * bh;
|
||||
int namelen,inr,idev;
|
||||
struct dir_entry * de;
|
||||
|
||||
if (!current->root || !current->root->i_count)
|
||||
panic("No root inode");
|
||||
if (!current->pwd || !current->pwd->i_count)
|
||||
panic("No cwd inode");
|
||||
if ((c=get_fs_byte(pathname))=='/') {
|
||||
inode = current->root;
|
||||
pathname++;
|
||||
} else if (c)
|
||||
inode = current->pwd;
|
||||
else
|
||||
return NULL; /* empty name is bad */
|
||||
inode->i_count++;
|
||||
while (1) {
|
||||
thisname = pathname;
|
||||
if (!S_ISDIR(inode->i_mode) || !permission(inode,MAY_EXEC)) {
|
||||
iput(inode);
|
||||
return NULL;
|
||||
}
|
||||
for(namelen=0;(c=get_fs_byte(pathname++))&&(c!='/');namelen++)
|
||||
/* nothing */ ;
|
||||
if (!c)
|
||||
return inode;
|
||||
if (!(bh = find_entry(inode,thisname,namelen,&de))) {
|
||||
iput(inode);
|
||||
return NULL;
|
||||
}
|
||||
inr = de->inode;
|
||||
idev = inode->i_dev;
|
||||
brelse(bh);
|
||||
iput(inode);
|
||||
if (!(inode = iget(idev,inr)))
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* dir_namei()
|
||||
*
|
||||
* dir_namei() returns the inode of the directory of the
|
||||
* specified name, and the name within that directory.
|
||||
*/
|
||||
static struct m_inode * dir_namei(const char * pathname,
|
||||
int * namelen, const char ** name)
|
||||
{
|
||||
char c;
|
||||
const char * basename;
|
||||
struct m_inode * dir;
|
||||
|
||||
if (!(dir = get_dir(pathname)))
|
||||
return NULL;
|
||||
basename = pathname;
|
||||
while (c=get_fs_byte(pathname++))
|
||||
if (c=='/')
|
||||
basename=pathname;
|
||||
*namelen = pathname-basename-1;
|
||||
*name = basename;
|
||||
return dir;
|
||||
}
|
||||
|
||||
/*
|
||||
* namei()
|
||||
*
|
||||
* is used by most simple commands to get the inode of a specified name.
|
||||
* Open, link etc use their own routines, but this is enough for things
|
||||
* like 'chmod' etc.
|
||||
*/
|
||||
struct m_inode * namei(const char * pathname)
|
||||
{
|
||||
const char * basename;
|
||||
int inr,dev,namelen;
|
||||
struct m_inode * dir;
|
||||
struct buffer_head * bh;
|
||||
struct dir_entry * de;
|
||||
|
||||
if (!(dir = dir_namei(pathname,&namelen,&basename)))
|
||||
return NULL;
|
||||
if (!namelen) /* special case: '/usr/' etc */
|
||||
return dir;
|
||||
bh = find_entry(dir,basename,namelen,&de);
|
||||
if (!bh) {
|
||||
iput(dir);
|
||||
return NULL;
|
||||
}
|
||||
inr = de->inode;
|
||||
dev = dir->i_dev;
|
||||
brelse(bh);
|
||||
iput(dir);
|
||||
dir=iget(dev,inr);
|
||||
if (dir) {
|
||||
dir->i_atime=CURRENT_TIME;
|
||||
dir->i_dirt=1;
|
||||
}
|
||||
return dir;
|
||||
}
|
||||
|
||||
/*
|
||||
* open_namei()
|
||||
*
|
||||
* namei for open - this is in fact almost the whole open-routine.
|
||||
*/
|
||||
int open_namei(const char * pathname, int flag, int mode,
|
||||
struct m_inode ** res_inode)
|
||||
{
|
||||
const char * basename;
|
||||
int inr,dev,namelen;
|
||||
struct m_inode * dir, *inode;
|
||||
struct buffer_head * bh;
|
||||
struct dir_entry * de;
|
||||
|
||||
if ((flag & O_TRUNC) && !(flag & O_ACCMODE))
|
||||
flag |= O_WRONLY;
|
||||
mode &= 0777 & ~current->umask;
|
||||
mode |= I_REGULAR;
|
||||
if (!(dir = dir_namei(pathname,&namelen,&basename)))
|
||||
return -ENOENT;
|
||||
if (!namelen) { /* special case: '/usr/' etc */
|
||||
if (!(flag & (O_ACCMODE|O_CREAT|O_TRUNC))) {
|
||||
*res_inode=dir;
|
||||
return 0;
|
||||
}
|
||||
iput(dir);
|
||||
return -EISDIR;
|
||||
}
|
||||
bh = find_entry(dir,basename,namelen,&de);
|
||||
if (!bh) {
|
||||
if (!(flag & O_CREAT)) {
|
||||
iput(dir);
|
||||
return -ENOENT;
|
||||
}
|
||||
if (!permission(dir,MAY_WRITE)) {
|
||||
iput(dir);
|
||||
return -EACCES;
|
||||
}
|
||||
inode = new_inode(dir->i_dev);
|
||||
if (!inode) {
|
||||
iput(dir);
|
||||
return -ENOSPC;
|
||||
}
|
||||
inode->i_mode = mode;
|
||||
inode->i_dirt = 1;
|
||||
bh = add_entry(dir,basename,namelen,&de);
|
||||
if (!bh) {
|
||||
inode->i_nlinks--;
|
||||
iput(inode);
|
||||
iput(dir);
|
||||
return -ENOSPC;
|
||||
}
|
||||
de->inode = inode->i_num;
|
||||
bh->b_dirt = 1;
|
||||
brelse(bh);
|
||||
iput(dir);
|
||||
*res_inode = inode;
|
||||
return 0;
|
||||
}
|
||||
inr = de->inode;
|
||||
dev = dir->i_dev;
|
||||
brelse(bh);
|
||||
iput(dir);
|
||||
if (flag & O_EXCL)
|
||||
return -EEXIST;
|
||||
if (!(inode=iget(dev,inr)))
|
||||
return -EACCES;
|
||||
if ((S_ISDIR(inode->i_mode) && (flag & O_ACCMODE)) ||
|
||||
permission(inode,ACC_MODE(flag))!=ACC_MODE(flag)) {
|
||||
iput(inode);
|
||||
return -EPERM;
|
||||
}
|
||||
inode->i_atime = CURRENT_TIME;
|
||||
if (flag & O_TRUNC)
|
||||
truncate(inode);
|
||||
*res_inode = inode;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sys_mkdir(const char * pathname, int mode)
|
||||
{
|
||||
const char * basename;
|
||||
int namelen;
|
||||
struct m_inode * dir, * inode;
|
||||
struct buffer_head * bh, *dir_block;
|
||||
struct dir_entry * de;
|
||||
|
||||
if (current->euid && current->uid)
|
||||
return -EPERM;
|
||||
if (!(dir = dir_namei(pathname,&namelen,&basename)))
|
||||
return -ENOENT;
|
||||
if (!namelen) {
|
||||
iput(dir);
|
||||
return -ENOENT;
|
||||
}
|
||||
if (!permission(dir,MAY_WRITE)) {
|
||||
iput(dir);
|
||||
return -EPERM;
|
||||
}
|
||||
bh = find_entry(dir,basename,namelen,&de);
|
||||
if (bh) {
|
||||
brelse(bh);
|
||||
iput(dir);
|
||||
return -EEXIST;
|
||||
}
|
||||
inode = new_inode(dir->i_dev);
|
||||
if (!inode) {
|
||||
iput(dir);
|
||||
return -ENOSPC;
|
||||
}
|
||||
inode->i_size = 32;
|
||||
inode->i_dirt = 1;
|
||||
inode->i_mtime = inode->i_atime = CURRENT_TIME;
|
||||
if (!(inode->i_zone[0]=new_block(inode->i_dev))) {
|
||||
iput(dir);
|
||||
inode->i_nlinks--;
|
||||
iput(inode);
|
||||
return -ENOSPC;
|
||||
}
|
||||
inode->i_dirt = 1;
|
||||
if (!(dir_block=bread(inode->i_dev,inode->i_zone[0]))) {
|
||||
iput(dir);
|
||||
free_block(inode->i_dev,inode->i_zone[0]);
|
||||
inode->i_nlinks--;
|
||||
iput(inode);
|
||||
return -ERROR;
|
||||
}
|
||||
de = (struct dir_entry *) dir_block->b_data;
|
||||
de->inode=inode->i_num;
|
||||
strcpy(de->name,".");
|
||||
de++;
|
||||
de->inode = dir->i_num;
|
||||
strcpy(de->name,"..");
|
||||
inode->i_nlinks = 2;
|
||||
dir_block->b_dirt = 1;
|
||||
brelse(dir_block);
|
||||
inode->i_mode = I_DIRECTORY | (mode & 0777 & ~current->umask);
|
||||
inode->i_dirt = 1;
|
||||
bh = add_entry(dir,basename,namelen,&de);
|
||||
if (!bh) {
|
||||
iput(dir);
|
||||
free_block(inode->i_dev,inode->i_zone[0]);
|
||||
inode->i_nlinks=0;
|
||||
iput(inode);
|
||||
return -ENOSPC;
|
||||
}
|
||||
de->inode = inode->i_num;
|
||||
bh->b_dirt = 1;
|
||||
dir->i_nlinks++;
|
||||
dir->i_dirt = 1;
|
||||
iput(dir);
|
||||
iput(inode);
|
||||
brelse(bh);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* routine to check that the specified directory is empty (for rmdir)
|
||||
*/
|
||||
static int empty_dir(struct m_inode * inode)
|
||||
{
|
||||
int nr,block;
|
||||
int len;
|
||||
struct buffer_head * bh;
|
||||
struct dir_entry * de;
|
||||
|
||||
len = inode->i_size / sizeof (struct dir_entry);
|
||||
if (len<2 || !inode->i_zone[0] ||
|
||||
!(bh=bread(inode->i_dev,inode->i_zone[0]))) {
|
||||
printk("warning - bad directory on dev %04x\n",inode->i_dev);
|
||||
return 0;
|
||||
}
|
||||
de = (struct dir_entry *) bh->b_data;
|
||||
if (de[0].inode != inode->i_num || !de[1].inode ||
|
||||
strcmp(".",de[0].name) || strcmp("..",de[1].name)) {
|
||||
printk("warning - bad directory on dev %04x\n",inode->i_dev);
|
||||
return 0;
|
||||
}
|
||||
nr = 2;
|
||||
de += 2;
|
||||
while (nr<len) {
|
||||
if ((void *) de >= (void *) (bh->b_data+BLOCK_SIZE)) {
|
||||
brelse(bh);
|
||||
block=bmap(inode,nr/DIR_ENTRIES_PER_BLOCK);
|
||||
if (!block) {
|
||||
nr += DIR_ENTRIES_PER_BLOCK;
|
||||
continue;
|
||||
}
|
||||
if (!(bh=bread(inode->i_dev,block)))
|
||||
return 0;
|
||||
de = (struct dir_entry *) bh->b_data;
|
||||
}
|
||||
if (de->inode) {
|
||||
brelse(bh);
|
||||
return 0;
|
||||
}
|
||||
de++;
|
||||
nr++;
|
||||
}
|
||||
brelse(bh);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int sys_rmdir(const char * name)
|
||||
{
|
||||
const char * basename;
|
||||
int namelen;
|
||||
struct m_inode * dir, * inode;
|
||||
struct buffer_head * bh;
|
||||
struct dir_entry * de;
|
||||
|
||||
if (current->euid && current->uid)
|
||||
return -EPERM;
|
||||
if (!(dir = dir_namei(name,&namelen,&basename)))
|
||||
return -ENOENT;
|
||||
if (!namelen) {
|
||||
iput(dir);
|
||||
return -ENOENT;
|
||||
}
|
||||
bh = find_entry(dir,basename,namelen,&de);
|
||||
if (!bh) {
|
||||
iput(dir);
|
||||
return -ENOENT;
|
||||
}
|
||||
if (!permission(dir,MAY_WRITE)) {
|
||||
iput(dir);
|
||||
brelse(bh);
|
||||
return -EPERM;
|
||||
}
|
||||
if (!(inode = iget(dir->i_dev, de->inode))) {
|
||||
iput(dir);
|
||||
brelse(bh);
|
||||
return -EPERM;
|
||||
}
|
||||
if (inode == dir) { /* we may not delete ".", but "../dir" is ok */
|
||||
iput(inode);
|
||||
iput(dir);
|
||||
brelse(bh);
|
||||
return -EPERM;
|
||||
}
|
||||
if (!S_ISDIR(inode->i_mode)) {
|
||||
iput(inode);
|
||||
iput(dir);
|
||||
brelse(bh);
|
||||
return -ENOTDIR;
|
||||
}
|
||||
if (!empty_dir(inode)) {
|
||||
iput(inode);
|
||||
iput(dir);
|
||||
brelse(bh);
|
||||
return -ENOTEMPTY;
|
||||
}
|
||||
if (inode->i_nlinks != 2)
|
||||
printk("empty directory has nlink!=2 (%d)",inode->i_nlinks);
|
||||
de->inode = 0;
|
||||
bh->b_dirt = 1;
|
||||
brelse(bh);
|
||||
inode->i_nlinks=0;
|
||||
inode->i_dirt=1;
|
||||
dir->i_nlinks--;
|
||||
dir->i_ctime = dir->i_mtime = CURRENT_TIME;
|
||||
dir->i_dirt=1;
|
||||
iput(dir);
|
||||
iput(inode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sys_unlink(const char * name)
|
||||
{
|
||||
const char * basename;
|
||||
int namelen;
|
||||
struct m_inode * dir, * inode;
|
||||
struct buffer_head * bh;
|
||||
struct dir_entry * de;
|
||||
|
||||
if (!(dir = dir_namei(name,&namelen,&basename)))
|
||||
return -ENOENT;
|
||||
if (!namelen) {
|
||||
iput(dir);
|
||||
return -ENOENT;
|
||||
}
|
||||
if (!permission(dir,MAY_WRITE)) {
|
||||
iput(dir);
|
||||
return -EPERM;
|
||||
}
|
||||
bh = find_entry(dir,basename,namelen,&de);
|
||||
if (!bh) {
|
||||
iput(dir);
|
||||
return -ENOENT;
|
||||
}
|
||||
inode = iget(dir->i_dev, de->inode);
|
||||
if (!inode) {
|
||||
printk("iget failed in delete (%04x:%d)",dir->i_dev,de->inode);
|
||||
iput(dir);
|
||||
brelse(bh);
|
||||
return -ENOENT;
|
||||
}
|
||||
if (!S_ISREG(inode->i_mode)) {
|
||||
iput(inode);
|
||||
iput(dir);
|
||||
brelse(bh);
|
||||
return -EPERM;
|
||||
}
|
||||
if (!inode->i_nlinks) {
|
||||
printk("Deleting nonexistent file (%04x:%d), %d\n",
|
||||
inode->i_dev,inode->i_num,inode->i_nlinks);
|
||||
inode->i_nlinks=1;
|
||||
}
|
||||
de->inode = 0;
|
||||
bh->b_dirt = 1;
|
||||
brelse(bh);
|
||||
inode->i_nlinks--;
|
||||
inode->i_dirt = 1;
|
||||
inode->i_ctime = CURRENT_TIME;
|
||||
iput(inode);
|
||||
iput(dir);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sys_link(const char * oldname, const char * newname)
|
||||
{
|
||||
struct dir_entry * de;
|
||||
struct m_inode * oldinode, * dir;
|
||||
struct buffer_head * bh;
|
||||
const char * basename;
|
||||
int namelen;
|
||||
|
||||
oldinode=namei(oldname);
|
||||
if (!oldinode)
|
||||
return -ENOENT;
|
||||
if (!S_ISREG(oldinode->i_mode)) {
|
||||
iput(oldinode);
|
||||
return -EPERM;
|
||||
}
|
||||
dir = dir_namei(newname,&namelen,&basename);
|
||||
if (!dir) {
|
||||
iput(oldinode);
|
||||
return -EACCES;
|
||||
}
|
||||
if (!namelen) {
|
||||
iput(oldinode);
|
||||
iput(dir);
|
||||
return -EPERM;
|
||||
}
|
||||
if (dir->i_dev != oldinode->i_dev) {
|
||||
iput(dir);
|
||||
iput(oldinode);
|
||||
return -EXDEV;
|
||||
}
|
||||
if (!permission(dir,MAY_WRITE)) {
|
||||
iput(dir);
|
||||
iput(oldinode);
|
||||
return -EACCES;
|
||||
}
|
||||
bh = find_entry(dir,basename,namelen,&de);
|
||||
if (bh) {
|
||||
brelse(bh);
|
||||
iput(dir);
|
||||
iput(oldinode);
|
||||
return -EEXIST;
|
||||
}
|
||||
bh = add_entry(dir,basename,namelen,&de);
|
||||
if (!bh) {
|
||||
iput(dir);
|
||||
iput(oldinode);
|
||||
return -ENOSPC;
|
||||
}
|
||||
de->inode = oldinode->i_num;
|
||||
bh->b_dirt = 1;
|
||||
brelse(bh);
|
||||
iput(dir);
|
||||
oldinode->i_nlinks++;
|
||||
oldinode->i_ctime = CURRENT_TIME;
|
||||
oldinode->i_dirt = 1;
|
||||
iput(oldinode);
|
||||
return 0;
|
||||
}
|
||||
188
kernel/0.00/linux-0.01/fs/open.c
Normal file
188
kernel/0.00/linux-0.01/fs/open.c
Normal file
@@ -0,0 +1,188 @@
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <utime.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <linux/sched.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <asm/segment.h>
|
||||
|
||||
int sys_utime(char * filename, struct utimbuf * times)
|
||||
{
|
||||
struct m_inode * inode;
|
||||
long actime,modtime;
|
||||
|
||||
if (!(inode=namei(filename)))
|
||||
return -ENOENT;
|
||||
if (times) {
|
||||
actime = get_fs_long((unsigned long *) ×->actime);
|
||||
modtime = get_fs_long((unsigned long *) ×->modtime);
|
||||
} else
|
||||
actime = modtime = CURRENT_TIME;
|
||||
inode->i_atime = actime;
|
||||
inode->i_mtime = modtime;
|
||||
inode->i_dirt = 1;
|
||||
iput(inode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sys_access(const char * filename,int mode)
|
||||
{
|
||||
struct m_inode * inode;
|
||||
int res;
|
||||
|
||||
mode &= 0007;
|
||||
if (!(inode=namei(filename)))
|
||||
return -EACCES;
|
||||
res = inode->i_mode & 0777;
|
||||
iput(inode);
|
||||
if (!(current->euid && current->uid))
|
||||
if (res & 0111)
|
||||
res = 0777;
|
||||
else
|
||||
res = 0666;
|
||||
if (current->euid == inode->i_uid)
|
||||
res >>= 6;
|
||||
else if (current->egid == inode->i_gid)
|
||||
res >>= 6;
|
||||
if ((res & 0007 & mode) == mode)
|
||||
return 0;
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
int sys_chdir(const char * filename)
|
||||
{
|
||||
struct m_inode * inode;
|
||||
|
||||
if (!(inode = namei(filename)))
|
||||
return -ENOENT;
|
||||
if (!S_ISDIR(inode->i_mode)) {
|
||||
iput(inode);
|
||||
return -ENOTDIR;
|
||||
}
|
||||
iput(current->pwd);
|
||||
current->pwd = inode;
|
||||
return (0);
|
||||
}
|
||||
|
||||
int sys_chroot(const char * filename)
|
||||
{
|
||||
struct m_inode * inode;
|
||||
|
||||
if (!(inode=namei(filename)))
|
||||
return -ENOENT;
|
||||
if (!S_ISDIR(inode->i_mode)) {
|
||||
iput(inode);
|
||||
return -ENOTDIR;
|
||||
}
|
||||
iput(current->root);
|
||||
current->root = inode;
|
||||
return (0);
|
||||
}
|
||||
|
||||
int sys_chmod(const char * filename,int mode)
|
||||
{
|
||||
struct m_inode * inode;
|
||||
|
||||
if (!(inode=namei(filename)))
|
||||
return -ENOENT;
|
||||
if (current->uid && current->euid)
|
||||
if (current->uid!=inode->i_uid && current->euid!=inode->i_uid) {
|
||||
iput(inode);
|
||||
return -EACCES;
|
||||
} else
|
||||
mode = (mode & 0777) | (inode->i_mode & 07000);
|
||||
inode->i_mode = (mode & 07777) | (inode->i_mode & ~07777);
|
||||
inode->i_dirt = 1;
|
||||
iput(inode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sys_chown(const char * filename,int uid,int gid)
|
||||
{
|
||||
struct m_inode * inode;
|
||||
|
||||
if (!(inode=namei(filename)))
|
||||
return -ENOENT;
|
||||
if (current->uid && current->euid) {
|
||||
iput(inode);
|
||||
return -EACCES;
|
||||
}
|
||||
inode->i_uid=uid;
|
||||
inode->i_gid=gid;
|
||||
inode->i_dirt=1;
|
||||
iput(inode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sys_open(const char * filename,int flag,int mode)
|
||||
{
|
||||
struct m_inode * inode;
|
||||
struct file * f;
|
||||
int i,fd;
|
||||
|
||||
mode &= 0777 & ~current->umask;
|
||||
for(fd=0 ; fd<NR_OPEN ; fd++)
|
||||
if (!current->filp[fd])
|
||||
break;
|
||||
if (fd>=NR_OPEN)
|
||||
return -EINVAL;
|
||||
current->close_on_exec &= ~(1<<fd);
|
||||
f=0+file_table;
|
||||
for (i=0 ; i<NR_FILE ; i++,f++)
|
||||
if (!f->f_count) break;
|
||||
if (i>=NR_FILE)
|
||||
return -EINVAL;
|
||||
(current->filp[fd]=f)->f_count++;
|
||||
if ((i=open_namei(filename,flag,mode,&inode))<0) {
|
||||
current->filp[fd]=NULL;
|
||||
f->f_count=0;
|
||||
return i;
|
||||
}
|
||||
/* ttys are somewhat special (ttyxx major==4, tty major==5) */
|
||||
if (S_ISCHR(inode->i_mode))
|
||||
if (MAJOR(inode->i_zone[0])==4) {
|
||||
if (current->leader && current->tty<0) {
|
||||
current->tty = MINOR(inode->i_zone[0]);
|
||||
tty_table[current->tty].pgrp = current->pgrp;
|
||||
}
|
||||
} else if (MAJOR(inode->i_zone[0])==5)
|
||||
if (current->tty<0) {
|
||||
iput(inode);
|
||||
current->filp[fd]=NULL;
|
||||
f->f_count=0;
|
||||
return -EPERM;
|
||||
}
|
||||
f->f_mode = inode->i_mode;
|
||||
f->f_flags = flag;
|
||||
f->f_count = 1;
|
||||
f->f_inode = inode;
|
||||
f->f_pos = 0;
|
||||
return (fd);
|
||||
}
|
||||
|
||||
int sys_creat(const char * pathname, int mode)
|
||||
{
|
||||
return sys_open(pathname, O_CREAT | O_TRUNC, mode);
|
||||
}
|
||||
|
||||
int sys_close(unsigned int fd)
|
||||
{
|
||||
struct file * filp;
|
||||
|
||||
if (fd >= NR_OPEN)
|
||||
return -EINVAL;
|
||||
current->close_on_exec &= ~(1<<fd);
|
||||
if (!(filp = current->filp[fd]))
|
||||
return -EINVAL;
|
||||
current->filp[fd] = NULL;
|
||||
if (filp->f_count == 0)
|
||||
panic("Close: file count is 0");
|
||||
if (--filp->f_count)
|
||||
return (0);
|
||||
iput(filp->f_inode);
|
||||
return (0);
|
||||
}
|
||||
92
kernel/0.00/linux-0.01/fs/pipe.c
Normal file
92
kernel/0.00/linux-0.01/fs/pipe.c
Normal file
@@ -0,0 +1,92 @@
|
||||
#include <signal.h>
|
||||
|
||||
#include <linux/sched.h>
|
||||
#include <linux/mm.h> /* for get_free_page */
|
||||
#include <asm/segment.h>
|
||||
|
||||
int read_pipe(struct m_inode * inode, char * buf, int count)
|
||||
{
|
||||
char * b=buf;
|
||||
|
||||
while (PIPE_EMPTY(*inode)) {
|
||||
wake_up(&inode->i_wait);
|
||||
if (inode->i_count != 2) /* are there any writers left? */
|
||||
return 0;
|
||||
sleep_on(&inode->i_wait);
|
||||
}
|
||||
while (count>0 && !(PIPE_EMPTY(*inode))) {
|
||||
count --;
|
||||
put_fs_byte(((char *)inode->i_size)[PIPE_TAIL(*inode)],b++);
|
||||
INC_PIPE( PIPE_TAIL(*inode) );
|
||||
}
|
||||
wake_up(&inode->i_wait);
|
||||
return b-buf;
|
||||
}
|
||||
|
||||
int write_pipe(struct m_inode * inode, char * buf, int count)
|
||||
{
|
||||
char * b=buf;
|
||||
|
||||
wake_up(&inode->i_wait);
|
||||
if (inode->i_count != 2) { /* no readers */
|
||||
current->signal |= (1<<(SIGPIPE-1));
|
||||
return -1;
|
||||
}
|
||||
while (count-->0) {
|
||||
while (PIPE_FULL(*inode)) {
|
||||
wake_up(&inode->i_wait);
|
||||
if (inode->i_count != 2) {
|
||||
current->signal |= (1<<(SIGPIPE-1));
|
||||
return b-buf;
|
||||
}
|
||||
sleep_on(&inode->i_wait);
|
||||
}
|
||||
((char *)inode->i_size)[PIPE_HEAD(*inode)] = get_fs_byte(b++);
|
||||
INC_PIPE( PIPE_HEAD(*inode) );
|
||||
wake_up(&inode->i_wait);
|
||||
}
|
||||
wake_up(&inode->i_wait);
|
||||
return b-buf;
|
||||
}
|
||||
|
||||
int sys_pipe(unsigned long * fildes)
|
||||
{
|
||||
struct m_inode * inode;
|
||||
struct file * f[2];
|
||||
int fd[2];
|
||||
int i,j;
|
||||
|
||||
j=0;
|
||||
for(i=0;j<2 && i<NR_FILE;i++)
|
||||
if (!file_table[i].f_count)
|
||||
(f[j++]=i+file_table)->f_count++;
|
||||
if (j==1)
|
||||
f[0]->f_count=0;
|
||||
if (j<2)
|
||||
return -1;
|
||||
j=0;
|
||||
for(i=0;j<2 && i<NR_OPEN;i++)
|
||||
if (!current->filp[i]) {
|
||||
current->filp[ fd[j]=i ] = f[j];
|
||||
j++;
|
||||
}
|
||||
if (j==1)
|
||||
current->filp[fd[0]]=NULL;
|
||||
if (j<2) {
|
||||
f[0]->f_count=f[1]->f_count=0;
|
||||
return -1;
|
||||
}
|
||||
if (!(inode=get_pipe_inode())) {
|
||||
current->filp[fd[0]] =
|
||||
current->filp[fd[1]] = NULL;
|
||||
f[0]->f_count = f[1]->f_count = 0;
|
||||
return -1;
|
||||
}
|
||||
f[0]->f_inode = f[1]->f_inode = inode;
|
||||
f[0]->f_pos = f[1]->f_pos = 0;
|
||||
f[0]->f_mode = 1; /* read */
|
||||
f[1]->f_mode = 2; /* write */
|
||||
put_fs_long(fd[0],0+fildes);
|
||||
put_fs_long(fd[1],1+fildes);
|
||||
return 0;
|
||||
}
|
||||
97
kernel/0.00/linux-0.01/fs/read_write.c
Normal file
97
kernel/0.00/linux-0.01/fs/read_write.c
Normal file
@@ -0,0 +1,97 @@
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/sched.h>
|
||||
#include <asm/segment.h>
|
||||
|
||||
extern int rw_char(int rw,int dev, char * buf, int count);
|
||||
extern int read_pipe(struct m_inode * inode, char * buf, int count);
|
||||
extern int write_pipe(struct m_inode * inode, char * buf, int count);
|
||||
extern int block_read(int dev, off_t * pos, char * buf, int count);
|
||||
extern int block_write(int dev, off_t * pos, char * buf, int count);
|
||||
extern int file_read(struct m_inode * inode, struct file * filp,
|
||||
char * buf, int count);
|
||||
extern int file_write(struct m_inode * inode, struct file * filp,
|
||||
char * buf, int count);
|
||||
|
||||
int sys_lseek(unsigned int fd,off_t offset, int origin)
|
||||
{
|
||||
struct file * file;
|
||||
int tmp;
|
||||
|
||||
if (fd >= NR_OPEN || !(file=current->filp[fd]) || !(file->f_inode)
|
||||
|| !IS_BLOCKDEV(MAJOR(file->f_inode->i_dev)))
|
||||
return -EBADF;
|
||||
if (file->f_inode->i_pipe)
|
||||
return -ESPIPE;
|
||||
switch (origin) {
|
||||
case 0:
|
||||
if (offset<0) return -EINVAL;
|
||||
file->f_pos=offset;
|
||||
break;
|
||||
case 1:
|
||||
if (file->f_pos+offset<0) return -EINVAL;
|
||||
file->f_pos += offset;
|
||||
break;
|
||||
case 2:
|
||||
if ((tmp=file->f_inode->i_size+offset) < 0)
|
||||
return -EINVAL;
|
||||
file->f_pos = tmp;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
return file->f_pos;
|
||||
}
|
||||
|
||||
int sys_read(unsigned int fd,char * buf,int count)
|
||||
{
|
||||
struct file * file;
|
||||
struct m_inode * inode;
|
||||
|
||||
if (fd>=NR_OPEN || count<0 || !(file=current->filp[fd]))
|
||||
return -EINVAL;
|
||||
if (!count)
|
||||
return 0;
|
||||
verify_area(buf,count);
|
||||
inode = file->f_inode;
|
||||
if (inode->i_pipe)
|
||||
return (file->f_mode&1)?read_pipe(inode,buf,count):-1;
|
||||
if (S_ISCHR(inode->i_mode))
|
||||
return rw_char(READ,inode->i_zone[0],buf,count);
|
||||
if (S_ISBLK(inode->i_mode))
|
||||
return block_read(inode->i_zone[0],&file->f_pos,buf,count);
|
||||
if (S_ISDIR(inode->i_mode) || S_ISREG(inode->i_mode)) {
|
||||
if (count+file->f_pos > inode->i_size)
|
||||
count = inode->i_size - file->f_pos;
|
||||
if (count<=0)
|
||||
return 0;
|
||||
return file_read(inode,file,buf,count);
|
||||
}
|
||||
printk("(Read)inode->i_mode=%06o\n\r",inode->i_mode);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int sys_write(unsigned int fd,char * buf,int count)
|
||||
{
|
||||
struct file * file;
|
||||
struct m_inode * inode;
|
||||
|
||||
if (fd>=NR_OPEN || count <0 || !(file=current->filp[fd]))
|
||||
return -EINVAL;
|
||||
if (!count)
|
||||
return 0;
|
||||
inode=file->f_inode;
|
||||
if (inode->i_pipe)
|
||||
return (file->f_mode&2)?write_pipe(inode,buf,count):-1;
|
||||
if (S_ISCHR(inode->i_mode))
|
||||
return rw_char(WRITE,inode->i_zone[0],buf,count);
|
||||
if (S_ISBLK(inode->i_mode))
|
||||
return block_write(inode->i_zone[0],&file->f_pos,buf,count);
|
||||
if (S_ISREG(inode->i_mode))
|
||||
return file_write(inode,file,buf,count);
|
||||
printk("(Write)inode->i_mode=%06o\n\r",inode->i_mode);
|
||||
return -EINVAL;
|
||||
}
|
||||
51
kernel/0.00/linux-0.01/fs/stat.c
Normal file
51
kernel/0.00/linux-0.01/fs/stat.c
Normal file
@@ -0,0 +1,51 @@
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <asm/segment.h>
|
||||
|
||||
static int cp_stat(struct m_inode * inode, struct stat * statbuf)
|
||||
{
|
||||
struct stat tmp;
|
||||
int i;
|
||||
|
||||
verify_area(statbuf,sizeof (* statbuf));
|
||||
tmp.st_dev = inode->i_dev;
|
||||
tmp.st_ino = inode->i_num;
|
||||
tmp.st_mode = inode->i_mode;
|
||||
tmp.st_nlink = inode->i_nlinks;
|
||||
tmp.st_uid = inode->i_uid;
|
||||
tmp.st_gid = inode->i_gid;
|
||||
tmp.st_rdev = inode->i_zone[0];
|
||||
tmp.st_size = inode->i_size;
|
||||
tmp.st_atime = inode->i_atime;
|
||||
tmp.st_mtime = inode->i_mtime;
|
||||
tmp.st_ctime = inode->i_ctime;
|
||||
for (i=0 ; i<sizeof (tmp) ; i++)
|
||||
put_fs_byte(((char *) &tmp)[i],&((char *) statbuf)[i]);
|
||||
return (0);
|
||||
}
|
||||
|
||||
int sys_stat(char * filename, struct stat * statbuf)
|
||||
{
|
||||
int i;
|
||||
struct m_inode * inode;
|
||||
|
||||
if (!(inode=namei(filename)))
|
||||
return -ENOENT;
|
||||
i=cp_stat(inode,statbuf);
|
||||
iput(inode);
|
||||
return i;
|
||||
}
|
||||
|
||||
int sys_fstat(unsigned int fd, struct stat * statbuf)
|
||||
{
|
||||
struct file * f;
|
||||
struct m_inode * inode;
|
||||
|
||||
if (fd >= NR_OPEN || !(f=current->filp[fd]) || !(inode=f->f_inode))
|
||||
return -ENOENT;
|
||||
return cp_stat(inode,statbuf);
|
||||
}
|
||||
102
kernel/0.00/linux-0.01/fs/super.c
Normal file
102
kernel/0.00/linux-0.01/fs/super.c
Normal file
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* super.c contains code to handle the super-block tables.
|
||||
*/
|
||||
#include <linux/config.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
/* set_bit uses setb, as gas doesn't recognize setc */
|
||||
#define set_bit(bitnr,addr) ({ \
|
||||
register int __res __asm__("ax"); \
|
||||
__asm__("bt %2,%3;setb %%al":"=a" (__res):"a" (0),"r" (bitnr),"m" (*(addr))); \
|
||||
__res; })
|
||||
|
||||
struct super_block super_block[NR_SUPER];
|
||||
|
||||
struct super_block * do_mount(int dev)
|
||||
{
|
||||
struct super_block * p;
|
||||
struct buffer_head * bh;
|
||||
int i,block;
|
||||
|
||||
for(p = &super_block[0] ; p < &super_block[NR_SUPER] ; p++ )
|
||||
if (!(p->s_dev))
|
||||
break;
|
||||
p->s_dev = -1; /* mark it in use */
|
||||
if (p >= &super_block[NR_SUPER])
|
||||
return NULL;
|
||||
if (!(bh = bread(dev,1)))
|
||||
return NULL;
|
||||
*p = *((struct super_block *) bh->b_data);
|
||||
brelse(bh);
|
||||
if (p->s_magic != SUPER_MAGIC) {
|
||||
p->s_dev = 0;
|
||||
return NULL;
|
||||
}
|
||||
for (i=0;i<I_MAP_SLOTS;i++)
|
||||
p->s_imap[i] = NULL;
|
||||
for (i=0;i<Z_MAP_SLOTS;i++)
|
||||
p->s_zmap[i] = NULL;
|
||||
block=2;
|
||||
for (i=0 ; i < p->s_imap_blocks ; i++)
|
||||
if (p->s_imap[i]=bread(dev,block))
|
||||
block++;
|
||||
else
|
||||
break;
|
||||
for (i=0 ; i < p->s_zmap_blocks ; i++)
|
||||
if (p->s_zmap[i]=bread(dev,block))
|
||||
block++;
|
||||
else
|
||||
break;
|
||||
if (block != 2+p->s_imap_blocks+p->s_zmap_blocks) {
|
||||
for(i=0;i<I_MAP_SLOTS;i++)
|
||||
brelse(p->s_imap[i]);
|
||||
for(i=0;i<Z_MAP_SLOTS;i++)
|
||||
brelse(p->s_zmap[i]);
|
||||
p->s_dev=0;
|
||||
return NULL;
|
||||
}
|
||||
p->s_imap[0]->b_data[0] |= 1;
|
||||
p->s_zmap[0]->b_data[0] |= 1;
|
||||
p->s_dev = dev;
|
||||
p->s_isup = NULL;
|
||||
p->s_imount = NULL;
|
||||
p->s_time = 0;
|
||||
p->s_rd_only = 0;
|
||||
p->s_dirt = 0;
|
||||
return p;
|
||||
}
|
||||
|
||||
void mount_root(void)
|
||||
{
|
||||
int i,free;
|
||||
struct super_block * p;
|
||||
struct m_inode * mi;
|
||||
|
||||
if (32 != sizeof (struct d_inode))
|
||||
panic("bad i-node size");
|
||||
for(i=0;i<NR_FILE;i++)
|
||||
file_table[i].f_count=0;
|
||||
for(p = &super_block[0] ; p < &super_block[NR_SUPER] ; p++)
|
||||
p->s_dev = 0;
|
||||
if (!(p=do_mount(ROOT_DEV)))
|
||||
panic("Unable to mount root");
|
||||
if (!(mi=iget(ROOT_DEV,1)))
|
||||
panic("Unable to read root i-node");
|
||||
mi->i_count += 3 ; /* NOTE! it is logically used 4 times, not 1 */
|
||||
p->s_isup = p->s_imount = mi;
|
||||
current->pwd = mi;
|
||||
current->root = mi;
|
||||
free=0;
|
||||
i=p->s_nzones;
|
||||
while (-- i >= 0)
|
||||
if (!set_bit(i&8191,p->s_zmap[i>>13]->b_data))
|
||||
free++;
|
||||
printk("%d/%d free blocks\n\r",free,p->s_nzones);
|
||||
free=0;
|
||||
i=p->s_ninodes+1;
|
||||
while (-- i >= 0)
|
||||
if (!set_bit(i&8191,p->s_imap[i>>13]->b_data))
|
||||
free++;
|
||||
printk("%d/%d free inodes\n\r",free,p->s_ninodes);
|
||||
}
|
||||
59
kernel/0.00/linux-0.01/fs/truncate.c
Normal file
59
kernel/0.00/linux-0.01/fs/truncate.c
Normal file
@@ -0,0 +1,59 @@
|
||||
#include <linux/sched.h>
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
static void free_ind(int dev,int block)
|
||||
{
|
||||
struct buffer_head * bh;
|
||||
unsigned short * p;
|
||||
int i;
|
||||
|
||||
if (!block)
|
||||
return;
|
||||
if (bh=bread(dev,block)) {
|
||||
p = (unsigned short *) bh->b_data;
|
||||
for (i=0;i<512;i++,p++)
|
||||
if (*p)
|
||||
free_block(dev,*p);
|
||||
brelse(bh);
|
||||
}
|
||||
free_block(dev,block);
|
||||
}
|
||||
|
||||
static void free_dind(int dev,int block)
|
||||
{
|
||||
struct buffer_head * bh;
|
||||
unsigned short * p;
|
||||
int i;
|
||||
|
||||
if (!block)
|
||||
return;
|
||||
if (bh=bread(dev,block)) {
|
||||
p = (unsigned short *) bh->b_data;
|
||||
for (i=0;i<512;i++,p++)
|
||||
if (*p)
|
||||
free_ind(dev,*p);
|
||||
brelse(bh);
|
||||
}
|
||||
free_block(dev,block);
|
||||
}
|
||||
|
||||
void truncate(struct m_inode * inode)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode)))
|
||||
return;
|
||||
for (i=0;i<7;i++)
|
||||
if (inode->i_zone[i]) {
|
||||
free_block(inode->i_dev,inode->i_zone[i]);
|
||||
inode->i_zone[i]=0;
|
||||
}
|
||||
free_ind(inode->i_dev,inode->i_zone[7]);
|
||||
free_dind(inode->i_dev,inode->i_zone[8]);
|
||||
inode->i_zone[7] = inode->i_zone[8] = 0;
|
||||
inode->i_size = 0;
|
||||
inode->i_dirt = 1;
|
||||
inode->i_mtime = inode->i_ctime = CURRENT_TIME;
|
||||
}
|
||||
|
||||
166
kernel/0.00/linux-0.01/fs/tty_ioctl.c
Normal file
166
kernel/0.00/linux-0.01/fs/tty_ioctl.c
Normal file
@@ -0,0 +1,166 @@
|
||||
#include <errno.h>
|
||||
#include <termios.h>
|
||||
|
||||
#include <linux/sched.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/tty.h>
|
||||
|
||||
#include <asm/segment.h>
|
||||
#include <asm/system.h>
|
||||
|
||||
static void flush(struct tty_queue * queue)
|
||||
{
|
||||
cli();
|
||||
queue->head = queue->tail;
|
||||
sti();
|
||||
}
|
||||
|
||||
static void wait_until_sent(struct tty_struct * tty)
|
||||
{
|
||||
/* do nothing - not implemented */
|
||||
}
|
||||
|
||||
static void send_break(struct tty_struct * tty)
|
||||
{
|
||||
/* do nothing - not implemented */
|
||||
}
|
||||
|
||||
static int get_termios(struct tty_struct * tty, struct termios * termios)
|
||||
{
|
||||
int i;
|
||||
|
||||
verify_area(termios, sizeof (*termios));
|
||||
for (i=0 ; i< (sizeof (*termios)) ; i++)
|
||||
put_fs_byte( ((char *)&tty->termios)[i] , i+(char *)termios );
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_termios(struct tty_struct * tty, struct termios * termios)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0 ; i< (sizeof (*termios)) ; i++)
|
||||
((char *)&tty->termios)[i]=get_fs_byte(i+(char *)termios);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_termio(struct tty_struct * tty, struct termio * termio)
|
||||
{
|
||||
int i;
|
||||
struct termio tmp_termio;
|
||||
|
||||
verify_area(termio, sizeof (*termio));
|
||||
tmp_termio.c_iflag = tty->termios.c_iflag;
|
||||
tmp_termio.c_oflag = tty->termios.c_oflag;
|
||||
tmp_termio.c_cflag = tty->termios.c_cflag;
|
||||
tmp_termio.c_lflag = tty->termios.c_lflag;
|
||||
tmp_termio.c_line = tty->termios.c_line;
|
||||
for(i=0 ; i < NCC ; i++)
|
||||
tmp_termio.c_cc[i] = tty->termios.c_cc[i];
|
||||
for (i=0 ; i< (sizeof (*termio)) ; i++)
|
||||
put_fs_byte( ((char *)&tmp_termio)[i] , i+(char *)termio );
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_termio(struct tty_struct * tty, struct termio * termio)
|
||||
{
|
||||
int i;
|
||||
struct termio tmp_termio;
|
||||
|
||||
for (i=0 ; i< (sizeof (*termio)) ; i++)
|
||||
((char *)&tmp_termio)[i]=get_fs_byte(i+(char *)termio);
|
||||
*(unsigned short *)&tty->termios.c_iflag = tmp_termio.c_iflag;
|
||||
*(unsigned short *)&tty->termios.c_oflag = tmp_termio.c_oflag;
|
||||
*(unsigned short *)&tty->termios.c_cflag = tmp_termio.c_cflag;
|
||||
*(unsigned short *)&tty->termios.c_lflag = tmp_termio.c_lflag;
|
||||
tty->termios.c_line = tmp_termio.c_line;
|
||||
for(i=0 ; i < NCC ; i++)
|
||||
tty->termios.c_cc[i] = tmp_termio.c_cc[i];
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tty_ioctl(int dev, int cmd, int arg)
|
||||
{
|
||||
struct tty_struct * tty;
|
||||
if (MAJOR(dev) == 5) {
|
||||
dev=current->tty;
|
||||
if (dev<0)
|
||||
panic("tty_ioctl: dev<0");
|
||||
} else
|
||||
dev=MINOR(dev);
|
||||
tty = dev + tty_table;
|
||||
switch (cmd) {
|
||||
case TCGETS:
|
||||
return get_termios(tty,(struct termios *) arg);
|
||||
case TCSETSF:
|
||||
flush(&tty->read_q); /* fallthrough */
|
||||
case TCSETSW:
|
||||
wait_until_sent(tty); /* fallthrough */
|
||||
case TCSETS:
|
||||
return set_termios(tty,(struct termios *) arg);
|
||||
case TCGETA:
|
||||
return get_termio(tty,(struct termio *) arg);
|
||||
case TCSETAF:
|
||||
flush(&tty->read_q); /* fallthrough */
|
||||
case TCSETAW:
|
||||
wait_until_sent(tty); /* fallthrough */
|
||||
case TCSETA:
|
||||
return set_termio(tty,(struct termio *) arg);
|
||||
case TCSBRK:
|
||||
if (!arg) {
|
||||
wait_until_sent(tty);
|
||||
send_break(tty);
|
||||
}
|
||||
return 0;
|
||||
case TCXONC:
|
||||
return -EINVAL; /* not implemented */
|
||||
case TCFLSH:
|
||||
if (arg==0)
|
||||
flush(&tty->read_q);
|
||||
else if (arg==1)
|
||||
flush(&tty->write_q);
|
||||
else if (arg==2) {
|
||||
flush(&tty->read_q);
|
||||
flush(&tty->write_q);
|
||||
} else
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
case TIOCEXCL:
|
||||
return -EINVAL; /* not implemented */
|
||||
case TIOCNXCL:
|
||||
return -EINVAL; /* not implemented */
|
||||
case TIOCSCTTY:
|
||||
return -EINVAL; /* set controlling term NI */
|
||||
case TIOCGPGRP:
|
||||
verify_area((void *) arg,4);
|
||||
put_fs_long(tty->pgrp,(unsigned long *) arg);
|
||||
return 0;
|
||||
case TIOCSPGRP:
|
||||
tty->pgrp=get_fs_long((unsigned long *) arg);
|
||||
return 0;
|
||||
case TIOCOUTQ:
|
||||
verify_area((void *) arg,4);
|
||||
put_fs_long(CHARS(tty->write_q),(unsigned long *) arg);
|
||||
return 0;
|
||||
case TIOCSTI:
|
||||
return -EINVAL; /* not implemented */
|
||||
case TIOCGWINSZ:
|
||||
return -EINVAL; /* not implemented */
|
||||
case TIOCSWINSZ:
|
||||
return -EINVAL; /* not implemented */
|
||||
case TIOCMGET:
|
||||
return -EINVAL; /* not implemented */
|
||||
case TIOCMBIS:
|
||||
return -EINVAL; /* not implemented */
|
||||
case TIOCMBIC:
|
||||
return -EINVAL; /* not implemented */
|
||||
case TIOCMSET:
|
||||
return -EINVAL; /* not implemented */
|
||||
case TIOCGSOFTCAR:
|
||||
return -EINVAL; /* not implemented */
|
||||
case TIOCSSOFTCAR:
|
||||
return -EINVAL; /* not implemented */
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user