linux源代码剖析之三fs

fs
bitmap.c
/* 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;

}



block_dev.c
#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);

}



buffer.c
/*

  • ‘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;

}



char_dev.c
#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);

}



exec.c
#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_SIZE6)<=0)
    return i;
    if ((i=read_ind(inode->i_dev,inode->i_zone[7],size,BLOCK_SIZE
    6)) ||
    (size -= BLOCK_SIZE512)<=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;
    }



fcntl.c
#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;
}

}



file_dev.c
#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);
    }


file_table.c
#include <linux/fs.h>

struct file file_table[NR_FILE];



inode.c
#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);

}



ioctl.c
#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);

}



Makefile
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



namei.c
#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->uidinode->i_uid || current->euidinode->i_uid)
mode >>= 6;
else if (current->gidinode->i_gid || current->egidinode->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 ©
    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;

}



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/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 *) &times->actime);
	modtime = get_fs_long((unsigned long *) &times->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 major4, tty major5) */
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);

}



pipe.c
#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;

}



read_write.c
#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;

}



stat.c
#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);

}



super.c
/*

  • 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);

}



truncate.c
#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;

}



tty_ioctl.c
#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 (arg0)
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;
}
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

低调的小哥哥

你的关注就是我为你服务的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值