From 1d13365f821bdc201d43deeaad717cab457f151a Mon Sep 17 00:00:00 2001 From: hinus Date: Fri, 16 Jul 2021 10:48:55 +0800 Subject: [PATCH 1/2] Title: mkdir & a naive shell. Issue: https://gitee.com/hinus/linux_kernel_011/issues/I40SO8 https://gitee.com/hinus/linux_kernel_011/issues/I40SHH Description: mkdir & ls & naive shell. --- fs/Makefile | 5 +- fs/bitmap.c | 71 ++++++++++++++++++++++ fs/buffer.c | 26 ++++++++ fs/inode.c | 77 ++++++++++++++++++++++++ fs/namei.c | 127 ++++++++++++++++++++++++++++++++++++++++ fs/open.c | 35 +++++++++++ fs/truncate.c | 105 +++++++++++++++++++++++++++++++++ include/linux/fs.h | 17 +++++- include/linux/sched.h | 11 ++-- include/linux/sys.h | 8 +-- include/sys/stat.h | 9 ++- include/sys/types.h | 4 ++ include/unistd.h | 13 ++++ kernel/blk_drv/floppy.c | 2 +- kernel/main.c | 17 +++++- lib/write.c | 2 + 16 files changed, 513 insertions(+), 16 deletions(-) create mode 100644 fs/truncate.c diff --git a/fs/Makefile b/fs/Makefile index 37ebe94..193ad9f 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 namei.o fcntl.o char_dev.o bitmap.o +OBJS := read_write.o buffer.o super.o open.o file_table.o inode.o namei.o fcntl.o char_dev.o bitmap.o truncate.o fs.o : $(OBJS) $(LD) -m elf_i386 -r -o $@ $^ @@ -38,6 +38,9 @@ char_dev.o : char_dev.c bitmap.o : bitmap.c $(GCC) $(CCFLAG) -o $@ $< +truncate.o : truncate.c + $(GCC) $(CCFLAG) -o $@ $< + clean : rm *.o diff --git a/fs/bitmap.c b/fs/bitmap.c index c584589..3c31ca2 100644 --- a/fs/bitmap.c +++ b/fs/bitmap.c @@ -39,7 +39,37 @@ :"=c" (__res):"c" (0),"S" (addr):"ax","dx"); \ __res;}) +int free_block(int dev, int block) { + struct super_block * sb; + struct buffer_head * bh; + + if (!(sb = get_super(dev))) { + printk("trying to free block on nonexistent device"); + } + + if (block < sb->s_firstdatazone || block >= sb->s_nzones) + printk("trying to free block not in datazone"); + bh = get_hash_table(dev,block); + if (bh) { + if (bh->b_count > 1) { + brelse(bh); + return 0; + } + bh->b_dirt=0; + bh->b_uptodate=0; + if (bh->b_count) + 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); + printk("free_block: bit already cleared\n"); + } + sb->s_zmap[block/8192]->b_dirt = 1; + return 1; +} int new_block(int dev) { struct buffer_head * bh; @@ -79,3 +109,44 @@ int new_block(int dev) { brelse(bh); return j; } + +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))) + printk("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)) + printk("new_inode: bit already set"); + + bh->b_dirt = 1; + inode->i_count = 1; + inode->i_nlinks = 1; + inode->i_dev = dev; + inode->i_uid = 0; + inode->i_gid = 0; + inode->i_dirt=1; + inode->i_num = j + i*8192; + inode->i_mtime = inode->i_atime = 0; + return inode; +} + diff --git a/fs/buffer.c b/fs/buffer.c index 3c1a26b..3d61a4c 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -21,6 +21,32 @@ inline void wait_on_buffer(struct buffer_head * bh) { sti(); } +int sync_dev(int dev) { + int i; + struct buffer_head * bh; + + bh = start_buffer; + for (i=0 ; ib_dev != dev) + continue; + wait_on_buffer(bh); + if (bh->b_dev == dev && bh->b_dirt) + ll_rw_block(WRITE,bh); + } + + sync_inodes(); + + bh = start_buffer; + for (i=0 ; ib_dev != dev) + continue; + wait_on_buffer(bh); + if (bh->b_dev == dev && 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)] diff --git a/fs/inode.c b/fs/inode.c index f62033c..e81a77a 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -35,6 +35,19 @@ static inline void unlock_inode(struct m_inode * inode) { wake_up(&inode->i_wait); } +void sync_inodes() { + int i; + struct m_inode * inode; + + inode = 0+inode_table; + for(i=0 ; ii_dirt && !inode->i_pipe) { + write_inode(inode); + } + } +} + static int _bmap(struct m_inode * inode,int block,int create) { struct buffer_head * bh; int i; @@ -116,6 +129,43 @@ 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) + printk("iput: trying to free free inode"); + if (!inode->i_dev) { + inode->i_count--; + return; + } + if (S_ISBLK(inode->i_mode)) { + sync_dev(inode->i_zone[0]); + wait_on_inode(inode); + } +repeat: + if (inode->i_count>1) { + inode->i_count--; + return; + } + if (!inode->i_nlinks) { + truncate(inode); + unlock_inode(inode); + return; + } + if (inode->i_dirt) { + write_inode(inode); + wait_on_inode(inode); + goto repeat; + } + inode->i_count--; + return; +} + struct m_inode * get_empty_inode() { struct m_inode * inode; static struct m_inode * last_inode = inode_table; @@ -211,5 +261,32 @@ static void read_inode(struct m_inode * inode) { } static void write_inode(struct m_inode * inode) { + struct super_block * sb; + struct buffer_head * bh; + int block; + + lock_inode(inode); + if (!inode->i_dirt || !inode->i_dev) { + unlock_inode(inode); + return; + } + + if (!(sb=get_super(inode->i_dev))) + printk("trying to write inode without device"); + + block = 2 + sb->s_imap_blocks + sb->s_zmap_blocks + + (inode->i_num-1)/INODES_PER_BLOCK; + + if (!(bh=bread(inode->i_dev,block))) + printk("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); } diff --git a/fs/namei.c b/fs/namei.c index ea28f9c..29ff230 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -90,6 +90,54 @@ static struct buffer_head * find_entry(struct m_inode ** dir, return NULL; } +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; + 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; + } + + if (!de->inode) { + for (i=0; i < NAME_LEN ; i++) + de->name[i]=(ib_dirt = 1; + *res_dir = de; + return bh; + } + de++; + i++; + } +} + static struct m_inode * get_dir(const char * pathname, struct m_inode * inode) { char c; const char * thisname; @@ -188,3 +236,82 @@ int open_namei(const char * pathname, int flag, int mode, 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 (!(dir = dir_namei(pathname,&namelen,&basename, NULL))) + 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; + + 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); + 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); + inode->i_nlinks--; + 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; +} + diff --git a/fs/open.c b/fs/open.c index bdb97e4..0195356 100644 --- a/fs/open.c +++ b/fs/open.c @@ -49,3 +49,38 @@ int sys_open(const char * filename,int flag,int mode) { return fd; } + +int sys_fstat() { + int block, i, j; + int entries; + struct buffer_head * bh; + struct dir_entry * de; + struct m_inode* inode = current->root; + + if (S_ISDIR(inode->i_mode)) { + entries = inode->i_size / (sizeof (struct dir_entry)); + + if (!(block = inode->i_zone[0])) { + printk("empty i_zone\n"); + return -1; + } + + if (!(bh = bread(inode->i_dev,block))) { + printk("can not read block %d\n", block); + return -1; + } + + de = (struct dir_entry *) bh->b_data; + + for (i = 0; i < entries; i++) { + for (j = 0; j < 14; j++) { + printk("%c", de->name[j]); + } + printk("\n"); + de++; + } + } + + return 0; +} + diff --git a/fs/truncate.c b/fs/truncate.c new file mode 100644 index 0000000..007bd30 --- /dev/null +++ b/fs/truncate.c @@ -0,0 +1,105 @@ +#include +#include + +static int free_ind(int dev,int block) { + struct buffer_head * bh; + unsigned short * p; + int i; + int block_busy; + + if (!block) + return 1; + + block_busy = 0; + + if ((bh=bread(dev,block))) { + p = (unsigned short *) bh->b_data; + for (i = 0; i < 512; i++,p++) { + if (*p) { + if (free_block(dev,*p)) { + *p = 0; + bh->b_dirt = 1; + } + else + block_busy = 1; + } + } + brelse(bh); + } + + if (block_busy) + return 0; + else + return free_block(dev,block); +} + +static int free_dind(int dev,int block) { + struct buffer_head * bh; + unsigned short * p; + int i; + int block_busy; + + if (!block) + return 1; + + block_busy = 0; + + if ((bh=bread(dev,block))) { + p = (unsigned short *) bh->b_data; + for (i = 0; i < 512; i++,p++) { + if (*p) { + if (free_ind(dev,*p)) { + *p = 0; + bh->b_dirt = 1; + } + else + block_busy = 1; + } + } + brelse(bh); + } + + if (block_busy) + return 0; + else + return free_block(dev,block); +} + +void truncate(struct m_inode * inode) { + int i; + int block_busy; + + if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || + S_ISLNK(inode->i_mode))) + return; + +repeat: + block_busy = 0; + for (i = 0; i < 7; i++) { + if (inode->i_zone[i]) { + if (free_block(inode->i_dev,inode->i_zone[i])) + inode->i_zone[i] = 0; + else + block_busy = 1; + } + } + + if (free_ind(inode->i_dev,inode->i_zone[7])) + inode->i_zone[7] = 0; + else + block_busy = 1; + + if (free_dind(inode->i_dev,inode->i_zone[8])) + inode->i_zone[8] = 0; + else + block_busy = 1; + + inode->i_dirt = 1; + if (block_busy) { + current->counter = 0; + schedule(); + goto repeat; + } + inode->i_size = 0; +} + diff --git a/include/linux/fs.h b/include/linux/fs.h index 575d4cf..27fb96c 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -64,7 +64,7 @@ struct m_inode { unsigned short i_mode; unsigned short i_uid; unsigned long i_size; - unsigned long i_time; + unsigned long i_mtime; unsigned char i_gid; unsigned char i_nlinks; unsigned short i_zone[9]; @@ -129,8 +129,16 @@ struct dir_entry { char name[NAME_LEN]; }; + extern struct m_inode inode_table[NR_INODE]; extern struct file file_table[NR_FILE]; + +extern void truncate(struct m_inode * inode); +extern void sync_inodes(void); +extern int bmap(struct m_inode * inode,int block); +extern int create_block(struct m_inode * inode,int block); + +extern void iput(struct m_inode * inode); extern struct m_inode * iget(int dev,int nr); extern inline void wait_on_buffer(struct buffer_head* bh); @@ -142,6 +150,13 @@ extern struct buffer_head * bread(int dev,int block); extern int open_namei(const char * pathname, int flag, int mode, struct m_inode ** res_inode); +extern struct m_inode * get_empty_inode(void); +extern struct buffer_head * get_hash_table(int dev, int block); + +extern int new_block(int dev); +extern int free_block(int dev, int block); +extern int sync_dev(int dev); + extern struct super_block * get_super(int dev); extern int ROOT_DEV; diff --git a/include/linux/sched.h b/include/linux/sched.h index 3784cd0..70817a8 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -31,6 +31,7 @@ #define NULL ((void *) 0) #endif +extern void schedule(void); extern int copy_page_tables(unsigned long from, unsigned long to, long size); extern int free_page_tables(unsigned long from, unsigned long size); @@ -165,11 +166,11 @@ __asm__("movw %%dx,%0\n\t" \ #define _get_base(addr) ({\ unsigned long __base; \ -__asm__("movb %3,%%dh\n\t" \ - "movb %2,%%dl\n\t" \ - "shll $16,%%edx\n\t" \ - "movw %1,%%dx" \ - :"=d" (__base) \ +__asm__("movb %3,%%bh\n\t" \ + "movb %2,%%bl\n\t" \ + "shll $16,%%ebx\n\t" \ + "movw %1,%%bx" \ + :"=b" (__base) \ :"m" (*((addr)+2)), \ "m" (*((addr)+4)), \ "m" (*((addr)+7))); \ diff --git a/include/linux/sys.h b/include/linux/sys.h index d460497..7355629 100644 --- a/include/linux/sys.h +++ b/include/linux/sys.h @@ -26,7 +26,7 @@ extern int sys_open(); //extern int sys_stime(); //extern int sys_ptrace(); //extern int sys_alarm(); -//extern int sys_fstat(); +extern int sys_fstat(); //extern int sys_pause(); //extern int sys_utime(); //extern int sys_stty(); @@ -37,7 +37,7 @@ extern int sys_open(); //extern int sys_sync(); //extern int sys_kill(); //extern int sys_rename(); -//extern int sys_mkdir(); +extern int sys_mkdir(); //extern int sys_rmdir(); extern int sys_dup(); //extern int sys_pipe(); @@ -119,7 +119,7 @@ fn_ptr sys_call_table[] = { 0, //sys_ptrace, 0, //sys_alarm, - 0, //sys_fstat, + sys_fstat, 0, //sys_pause, 0, //sys_utime, 0, //sys_stty, @@ -131,7 +131,7 @@ fn_ptr sys_call_table[] = { 0, //sys_sync, 0, //sys_kill, 0, //sys_rename, - 0, //sys_mkdir, + sys_mkdir, 0, //sys_rmdir, sys_dup, diff --git a/include/sys/stat.h b/include/sys/stat.h index 131cf5d..87a0247 100644 --- a/include/sys/stat.h +++ b/include/sys/stat.h @@ -4,11 +4,18 @@ #include #define S_IFMT 00170000 +#define S_IFLNK 0120000 +#define S_IFREG 0100000 #define S_IFDIR 0040000 #define S_IFCHR 0020000 +#define S_IFBLK 0060000 - +#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) +#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) #define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) +#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) + +extern int mkdir(const char *_path, mode_t mode); #endif diff --git a/include/sys/types.h b/include/sys/types.h index b667b45..ca45c4f 100644 --- a/include/sys/types.h +++ b/include/sys/types.h @@ -3,6 +3,10 @@ typedef long off_t; +typedef unsigned short mode_t; +typedef unsigned short ino_t; +typedef unsigned short dev_t; +typedef unsigned short umode_t; typedef unsigned char cc_t; typedef unsigned int speed_t; typedef unsigned long tcflag_t; diff --git a/include/unistd.h b/include/unistd.h index 92a2fd9..b12c949 100644 --- a/include/unistd.h +++ b/include/unistd.h @@ -121,6 +121,18 @@ __asm__ volatile("int $0x80\n\r"\ return -1; \ } +#define _syscall2(type, name, atype, a, btype, b) \ +type name(atype a, btype b) { \ + long __res; \ +__asm__ volatile("int $0x80\n\r"\ + : "=a"(__res) \ + : "a"(__NR_##name), "b"((long)(a)), "c"((long)(b))); \ + if (__res >= 0) \ + return (type)__res; \ + errno = -__res; \ + return -1; \ +} + #define _syscall3(type,name,atype,a,btype,b,ctype,c) \ type name(atype a, btype b, ctype c) { \ long __res; \ @@ -139,6 +151,7 @@ extern int errno; int dup(int fildes); int fork(); +int fstat(); int open(const char * filename, int flag, ...); int write(int fildes, const char * buf, off_t count); int read(int fildes, const char * buf, off_t count); diff --git a/kernel/blk_drv/floppy.c b/kernel/blk_drv/floppy.c index 154e751..4786c69 100644 --- a/kernel/blk_drv/floppy.c +++ b/kernel/blk_drv/floppy.c @@ -114,7 +114,7 @@ void setup_DMA() { immoutb_p(4|2,10); __asm__("outb %%al,$12\n\tjmp 1f\n1:\tjmp 1f\n1:\t" "outb %%al,$11\n\tjmp 1f\n1:\tjmp 1f\n1:":: - "a" ((char) ((command == FD_READ)?DMA_READ:DMA_WRITE))); + "a" ((char) ((command == FD_READ) ? DMA_READ : DMA_WRITE))); immoutb_p(addr,4); addr >>= 8; immoutb_p(addr,4); diff --git a/kernel/main.c b/kernel/main.c index 6c640e1..9159aa2 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -109,9 +109,20 @@ void init() { (void) dup(0); (void) dup(0); - i = read(0, a, 6); - a[i] = 0; - printf("%d, %s", i, a); + while (1) { + i = read(0, a, 9); + a[i - 1] = 0; + + if (strcmp(a, "mk") == 0) { + mkdir("/hinusDocs", 0); + } + else if (strcmp(a, "ls") == 0) { + fstat(); + } + else if (strcmp(a, "q") == 0) { + break; + } + } printf("Free mem: %d bytes\n\r",memory_end-main_memory_start); } diff --git a/lib/write.c b/lib/write.c index 313c7b7..1363173 100644 --- a/lib/write.c +++ b/lib/write.c @@ -3,4 +3,6 @@ _syscall3(int,write,int,fd,const char *,buf,off_t,count) _syscall3(int,read,int,fd,const char *,buf,off_t,count) +_syscall0(int, fstat) +_syscall2(int, mkdir, const char *, pathname, mode_t, mode) -- Gitee From 416ad92e3e58a6e7a7590d4f3f76d78fefc07f55 Mon Sep 17 00:00:00 2001 From: hinus Date: Sat, 17 Jul 2021 00:08:37 +0800 Subject: [PATCH 2/2] Title: system call rmdir, to remove an empty directory. Issue: https://gitee.com/hinus/linux_kernel_011/issues/I40YPY Description: mkdir & ls & naive shell. --- fs/namei.c | 122 ++++++++++++++++++++++++++++++++++++++++++++ fs/open.c | 3 ++ include/linux/sys.h | 4 +- kernel/main.c | 3 ++ lib/write.c | 1 + 5 files changed, 131 insertions(+), 2 deletions(-) diff --git a/fs/namei.c b/fs/namei.c index 29ff230..b95da94 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -315,3 +315,125 @@ int sys_mkdir(const char * pathname, int mode) { return 0; } +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= (void *) (bh->b_data+BLOCK_SIZE)) { + brelse(bh); + block=bmap(inode,nr/DIR_ENTRIES_PER_BLOCK); + if (!block) { + nr += DIR_ENTRIES_PER_BLOCK; + break; + } + 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 (!(dir = dir_namei(name,&namelen,&basename, NULL))) + 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; + } + if (!(inode = iget(dir->i_dev, de->inode))) { + iput(dir); + brelse(bh); + return -EPERM; + } + + if (inode->i_dev != dir->i_dev || inode->i_count>1) { + iput(dir); + iput(inode); + brelse(bh); + return -EPERM; + } + + if (inode == dir) { + iput(dir); + iput(inode); + brelse(bh); + return -EPERM; + } + + if (!S_ISDIR(inode->i_mode)) { + iput(dir); + iput(inode); + 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_dirt=1; + iput(dir); + iput(inode); + + return 0; +} + diff --git a/fs/open.c b/fs/open.c index 0195356..45ef762 100644 --- a/fs/open.c +++ b/fs/open.c @@ -73,6 +73,9 @@ int sys_fstat() { de = (struct dir_entry *) bh->b_data; for (i = 0; i < entries; i++) { + if (!de->inode) { + continue; + } for (j = 0; j < 14; j++) { printk("%c", de->name[j]); } diff --git a/include/linux/sys.h b/include/linux/sys.h index 7355629..052c2f5 100644 --- a/include/linux/sys.h +++ b/include/linux/sys.h @@ -38,7 +38,7 @@ extern int sys_fstat(); //extern int sys_kill(); //extern int sys_rename(); extern int sys_mkdir(); -//extern int sys_rmdir(); +extern int sys_rmdir(); extern int sys_dup(); //extern int sys_pipe(); //extern int sys_times(); @@ -133,7 +133,7 @@ fn_ptr sys_call_table[] = { 0, //sys_rename, sys_mkdir, - 0, //sys_rmdir, + sys_rmdir, sys_dup, // sys_pipe, // sys_times, diff --git a/kernel/main.c b/kernel/main.c index 9159aa2..718db9d 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -116,6 +116,9 @@ void init() { if (strcmp(a, "mk") == 0) { mkdir("/hinusDocs", 0); } + else if (strcmp(a, "rm") == 0) { + printf("%d\n", rmdir("/hinusDocs")); + } else if (strcmp(a, "ls") == 0) { fstat(); } diff --git a/lib/write.c b/lib/write.c index 1363173..c5bb1f9 100644 --- a/lib/write.c +++ b/lib/write.c @@ -5,4 +5,5 @@ _syscall3(int,write,int,fd,const char *,buf,off_t,count) _syscall3(int,read,int,fd,const char *,buf,off_t,count) _syscall0(int, fstat) _syscall2(int, mkdir, const char *, pathname, mode_t, mode) +_syscall1(int, rmdir, const char *, pathname) -- Gitee