diff --git a/Makefile b/Makefile index 38357508208d5f81a3cffb27dc6090f31911de01..1b3b33e47aeea8f799560cc7405c0d167b3d7aa8 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ linux.img : tools/build bootsect setup kernel/system tools/build : tools/build.c gcc -o $@ $< -kernel/system : kernel/head.S kernel/*.c mm/*.c kernel/blk_drv/*.c +kernel/system : kernel/head.S kernel/*.c mm/*.c kernel/blk_drv/*.c fs/*.c cd kernel; make system; cd .. bootsect : bootsect.o diff --git a/fs/Makefile b/fs/Makefile index 3b1cea3c1d2f8e8c3ec97cf56347d2da10e1b06f..bf064136bc5b906185553672c77e633ed12cccc9 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -3,7 +3,7 @@ LD := ld CCFLAG := -I../include -nostdinc -ffreestanding -Wall -fomit-frame-pointer -fno-stack-protector -fno-pic -c -m32 LDFLAG := -Ttext 0x0 -s --oformat binary -m elf_i386 INCDIR := ../include -OBJS := read_write.o buffer.o super.o open.o file_table.o inode.o +OBJS := read_write.o buffer.o super.o open.o file_table.o inode.o namei.o fs.o : $(OBJS) $(LD) -m elf_i386 -r -o $@ $^ @@ -26,6 +26,9 @@ file_table.o : file_table.c inode.o : inode.c $(GCC) $(CCFLAG) -o $@ $< +namei.o : namei.c + $(GCC) $(CCFLAG) -o $@ $< + clean : rm *.o diff --git a/fs/namei.c b/fs/namei.c new file mode 100644 index 0000000000000000000000000000000000000000..f8a513dd3885ccbcd26664b2f6f0e630857ef7db --- /dev/null +++ b/fs/namei.c @@ -0,0 +1,172 @@ +#include +#include +#include + +#include +#include +#include +#include +#include + +#define MAY_EXEC 1 +#define MAY_WRITE 2 +#define MAY_READ 4 + +static int permission(struct m_inode * inode,int mask) { + return 1; +} + +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 && (de->name[0]=='.') && (de->name[1]=='\0')) + return 1; + + if (len < NAME_LEN && de->name[len]) + return 0; + + __asm__("cld\n\t" + "fs ; repe ; cmpsb\n\t" + "setz %%al" + :"=a" (same) + :"a" (0),"S" ((long) name),"D" ((long) de->name),"c" (len):); + + return same; +} + +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; + struct super_block * psb; + + entries = (*dir)->i_size / (sizeof (struct dir_entry)); + *res_dir = NULL; + + if (namelen==2 && get_fs_byte(name)=='.' && get_fs_byte(name+1)=='.') { + if ((*dir) == current->root) + namelen=1; + } + + 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 (match(namelen,name,de)) { + *res_dir = de; + return bh; + } + de++; + i++; + } + brelse(bh); + return NULL; +} + +static struct m_inode * get_dir(const char * pathname, struct m_inode * inode) { + char c; + const char * thisname; + struct buffer_head * bh; + int namelen,inr; + struct dir_entry * de; + struct m_inode * dir; + + if (!inode) { + inode = current->pwd; + inode->i_count++; + } + if ((c=get_fs_byte(pathname))=='/') { + //iput(inode); + inode = current->root; + pathname++; + 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; + brelse(bh); + dir = inode; + if (!(inode = iget(dir->i_dev,inr))) { + //iput(dir); + return NULL; + } + } + + return NULL; +} + +static struct m_inode * dir_namei(const char * pathname, + int * namelen, const char ** name, struct m_inode * base) { + char c; + const char * basename; + struct m_inode * dir; + + if (!(dir = get_dir(pathname,base))) + return NULL; + + basename = pathname; + while ((c = get_fs_byte(pathname++))) { + if (c == '/') + basename = pathname; + } + + *namelen = pathname-basename-1; + *name = basename; + + return dir; +} + +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,NULL))) + return -ENOENT; + + bh = find_entry(&dir,basename,namelen,&de); + if (!bh) { + return -EINVAL; + } + + inr = de->inode; + dev = dir->i_dev; + brelse(bh); + + + inode = iget(dev,inr); + *res_inode = inode; + return 0; +} + diff --git a/fs/open.c b/fs/open.c index 538df2200ba8123c8ec0fa5a9a3fb037915d7f94..bdb97e4cf9edb6812c9ed187098b01158d5ee2f6 100644 --- a/fs/open.c +++ b/fs/open.c @@ -5,9 +5,47 @@ #include #include +#include + #include int sys_open(const char * filename,int flag,int mode) { - printk("try to open %s\n", filename); - return 0; + struct m_inode * inode; + struct file * f; + int i,fd; + + mode &= 0777 & ~current->umask; + for(fd=0 ; fdfilp[fd]) + break; + } + + if (fd>=NR_OPEN) + return -EINVAL; + + current->close_on_exec &= ~(1<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; + } + + if (S_ISCHR(inode->i_mode)) { + printk("open char dev %d\n", fd); + } + + f->f_mode = inode->i_mode; + f->f_flags = flag; + f->f_count = 1; + f->f_inode = inode; + f->f_pos = 0; + + return fd; } diff --git a/include/linux/fs.h b/include/linux/fs.h index 8fb66451dc0f62d92419e45f4a92c2daca7bb37e..8d045395faa62df5fbaad0e88bff6685aa474c13 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -124,6 +124,12 @@ struct d_super_block { unsigned short s_magic; }; +struct dir_entry { + unsigned short inode; + char name[NAME_LEN]; +}; + +extern struct m_inode inode_table[NR_INODE]; extern struct file file_table[NR_FILE]; extern struct m_inode * iget(int dev,int nr); diff --git a/include/sys/stat.h b/include/sys/stat.h index cf474a0d551ea9dee27970e74d870b16540531d4..131cf5dd45ff251ff26a4764e0e982a67a57d3fa 100644 --- a/include/sys/stat.h +++ b/include/sys/stat.h @@ -3,4 +3,12 @@ #include +#define S_IFMT 00170000 +#define S_IFDIR 0040000 +#define S_IFCHR 0020000 + + +#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) + #endif