diff --git a/Makefile b/Makefile index 589db71..11faa01 100644 --- a/Makefile +++ b/Makefile @@ -68,7 +68,7 @@ USER_CPPS := user/*.c USER_CPPS := $(wildcard $(USER_CPPS)) USER_OBJS := $(addprefix $(OBJ_DIR)/, $(patsubst %.c,%.o,$(USER_CPPS))) -USER_TARGET := $(OBJ_DIR)/app_file +USER_TARGET := $(OBJ_DIR)/app_directory #------------------------targets------------------------ $(OBJ_DIR): @-mkdir -p $(OBJ_DIR) diff --git a/kernel/hostfs.c b/kernel/hostfs.c index 82415e9..62fc763 100644 --- a/kernel/hostfs.c +++ b/kernel/hostfs.c @@ -22,6 +22,10 @@ const struct vinode_ops hostfs_i_ops = { .viop_hook_close = hostfs_hook_close, .viop_write_back_vinode = hostfs_write_back_vinode, + + // not implemented + .viop_readdir = hostfs_readdir, + .viop_mkdir = hostfs_mkdir, }; /**** hostfs utility functions ****/ @@ -229,6 +233,16 @@ int hostfs_lseek(struct vinode *f_inode, ssize_t new_offset, int whence, return -1; } +int hostfs_readdir(struct vinode *dir_vinode, struct dir *dir, int *offset) { + panic("hostfs_readdir not implemented!\n"); + return -1; +} + +struct vinode *hostfs_mkdir(struct vinode *parent, struct dentry *sub_dentry) { + panic("hostfs_mkdir not implemented!\n"); + return NULL; +} + /**** vfs-hostfs hook interface functions ****/ // // open a hostfs file (after having its vfs inode). diff --git a/kernel/hostfs.h b/kernel/hostfs.h index 61449d3..c788463 100644 --- a/kernel/hostfs.h +++ b/kernel/hostfs.h @@ -30,6 +30,8 @@ int hostfs_lseek(struct vinode *f_inode, ssize_t new_offset, int whence, int *offset); int hostfs_hook_open(struct vinode *f_inode, struct dentry *f_dentry); int hostfs_hook_close(struct vinode *f_inode, struct dentry *dentry); +int hostfs_readdir(struct vinode *dir_vinode, struct dir *dir, int *offset); +struct vinode *hostfs_mkdir(struct vinode *parent, struct dentry *sub_dentry); struct super_block *hostfs_get_superblock(struct device *dev); extern const struct vinode_ops hostfs_node_ops; diff --git a/kernel/proc_file.c b/kernel/proc_file.c index 9c5f5fa..7575e9e 100644 --- a/kernel/proc_file.c +++ b/kernel/proc_file.c @@ -160,3 +160,50 @@ int do_close(int fd) { struct file *pfile = get_opened_file(fd); return vfs_close(pfile); } + +// +// open a directory +// return: the fd of the directory file +// +int do_opendir(char *pathname) { + struct file *opened_file = NULL; + if ((opened_file = vfs_opendir(pathname)) == NULL) return -1; + + int fd = 0; + struct file *pfile; + for (fd = 0; fd < MAX_FILES; ++fd) { + pfile = &(current->pfiles->opened_files[fd]); + if (pfile->status == FD_NONE) break; + } + if (pfile->status != FD_NONE) // no free entry + panic("do_opendir: no file entry for current process!\n"); + + // initialize this file structure + memcpy(pfile, opened_file, sizeof(struct file)); + + ++current->pfiles->nfiles; + return fd; +} + +// +// read a directory entry +// +int do_readdir(int fd, struct dir *dir) { + struct file *pfile = get_opened_file(fd); + return vfs_readdir(pfile, dir); +} + +// +// make a new directory +// +int do_mkdir(char *pathname) { + return vfs_mkdir(pathname); +} + +// +// close a directory +// +int do_closedir(int fd) { + struct file *pfile = get_opened_file(fd); + return vfs_closedir(pfile); +} diff --git a/kernel/proc_file.h b/kernel/proc_file.h index 25e8d16..e233d0c 100644 --- a/kernel/proc_file.h +++ b/kernel/proc_file.h @@ -16,6 +16,11 @@ int do_stat(int fd, struct istat *istat); int do_disk_stat(int fd, struct istat *istat); int do_close(int fd); +int do_opendir(char *pathname); +int do_readdir(int fd, struct dir *dir); +int do_mkdir(char *pathname); +int do_closedir(int fd); + void fs_init(void); // data structure that manages all openned files in a PCB diff --git a/kernel/rfs.c b/kernel/rfs.c index 753b0a2..b1f63db 100644 --- a/kernel/rfs.c +++ b/kernel/rfs.c @@ -27,7 +27,13 @@ const struct vinode_ops rfs_i_ops = { .viop_disk_stat = rfs_disk_stat, .viop_lookup = rfs_lookup, + .viop_readdir = rfs_readdir, + .viop_mkdir = rfs_mkdir, + .viop_write_back_vinode = rfs_write_back_vinode, + + .viop_hook_opendir = rfs_hook_opendir, + .viop_hook_closedir = rfs_hook_closedir, }; /**** rfs utility functions ****/ @@ -565,6 +571,137 @@ int rfs_disk_stat(struct vinode *vinode, struct istat *istat) { return 0; } +// +// when a directory is opened, the contents of the directory file are read +// into the memory for directory read operations +// +int rfs_hook_opendir(struct vinode *dir_vinode, struct dentry *dentry) { + // allocate space and read the contents of the dir block into memory + void *pdire = NULL; + void *previous = NULL; + struct rfs_device *rdev = rfs_device_list[dir_vinode->sb->s_dev->dev_id]; + + // read-in the directory file, store all direntries in dir cache. + for (int i = dir_vinode->blocks - 1; i >= 0; i--) { + previous = pdire; + pdire = alloc_page(); + + if (previous != NULL && previous - pdire != RFS_BLKSIZE) + panic("rfs_hook_opendir: memory discontinuity"); + + rfs_r1block(rdev, dir_vinode->addrs[i]); + memcpy(pdire, rdev->iobuffer, RFS_BLKSIZE); + } + + // save the pointer to the directory block in the vinode + struct rfs_dir_cache *dir_cache = (struct rfs_dir_cache *)alloc_page(); + dir_cache->block_count = dir_vinode->blocks; + dir_cache->dir_base_addr = (struct rfs_direntry *)pdire; + + dir_vinode->i_fs_info = dir_cache; + + return 0; +} + +// +// when a directory is closed, the memory space allocated for the directory +// block is freed +// +int rfs_hook_closedir(struct vinode *dir_vinode, struct dentry *dentry) { + struct rfs_dir_cache *dir_cache = + (struct rfs_dir_cache *)dir_vinode->i_fs_info; + + // reclaim the dir cache + for (int i = 0; i < dir_cache->block_count; ++i) { + free_page((char *)dir_cache->dir_base_addr + i * RFS_BLKSIZE); + } + return 0; +} + +// +// read a directory entry from the directory "dir", and the "offset" indicate +// the position of the entry to be read. if offset is 0, the first entry is read, +// if offset is 1, the second entry is read, and so on. +// return: 0 on success, -1 when there are no more entry (end of the list). +// +int rfs_readdir(struct vinode *dir_vinode, struct dir *dir, int *offset) { + int total_direntrys = dir_vinode->size / sizeof(struct rfs_direntry); + int one_block_direntrys = RFS_BLKSIZE / sizeof(struct rfs_direntry); + + int direntry_index = *offset; + if (direntry_index >= total_direntrys) { + // no more direntry + return -1; + } + + // reads a directory entry from the directory cache stored in vfs inode. + struct rfs_dir_cache *dir_cache = + (struct rfs_dir_cache *)dir_vinode->i_fs_info; + struct rfs_direntry *p_direntry = dir_cache->dir_base_addr + direntry_index; + + // TODO (lab4_2): implement the code to read a directory entry. + // hint: in the above code, we had found the directory entry that located at the + // *offset, and used p_direntry to point it. + // in the remaining processing, we need to return our discovery. + // the method of returning is to popular proper members of "dir", more specifically, + // dir->name and dir->inum. + // note: DO NOT DELETE CODE BELOW PANIC. + panic("You need to implement the code for reading a directory entry of rfs in lab4_2.\n" ); + + // DO NOT DELETE CODE BELOW. + (*offset)++; + return 0; +} + +// +// make a new direntry named "sub_dentry->name" under the directory "parent", +// return the vfs inode of subdir being created. +// +struct vinode *rfs_mkdir(struct vinode *parent, struct dentry *sub_dentry) { + struct rfs_device *rdev = rfs_device_list[parent->sb->s_dev->dev_id]; + + // ** find a free disk inode to store the file that is going to be created + struct rfs_dinode *free_dinode = NULL; + int free_inum = 0; + for (int i = 0; i < (RFS_BLKSIZE / RFS_INODESIZE * RFS_MAX_INODE_BLKNUM); i++) { + free_dinode = rfs_read_dinode(rdev, i); + if (free_dinode->type == R_FREE) { // found + free_inum = i; + break; + } + free_page(free_dinode); + } + + if (free_dinode == NULL) + panic( "rfs_mkdir: no more free disk inode, we cannot create directory.\n" ); + + // initialize the states of the file being created + free_dinode->size = 0; + free_dinode->type = R_DIR; + free_dinode->nlinks = 1; + free_dinode->blocks = 1; + // allocate a free block for the file + free_dinode->addrs[0] = rfs_alloc_block(parent->sb); + + // ** write the disk inode of file being created to disk + rfs_write_dinode(rdev, free_dinode, free_inum); + free_page(free_dinode); + + // ** add a direntry to the directory + int result = rfs_add_direntry(parent, sub_dentry->name, free_inum); + if (result == -1) { + sprint("rfs_mkdir: rfs_add_direntry failed"); + return NULL; + } + + // ** allocate a new vinode + struct vinode *sub_vinode = rfs_alloc_vinode(parent->sb); + sub_vinode->inum = free_inum; + rfs_update_vinode(sub_vinode); + + return sub_vinode; +} + /**** vfs-rfs file system type interface functions ****/ struct super_block *rfs_get_superblock(struct device *dev) { struct rfs_device *rdev = rfs_device_list[dev->dev_id]; diff --git a/kernel/rfs.h b/kernel/rfs.h index 4d118ae..5e8971b 100644 --- a/kernel/rfs.h +++ b/kernel/rfs.h @@ -80,6 +80,11 @@ struct vinode *rfs_create(struct vinode *parent, struct dentry *sub_dentry); int rfs_lseek(struct vinode *f_inode, ssize_t new_offset, int whence, int *offset); int rfs_disk_stat(struct vinode *vinode, struct istat *istat); +int rfs_hook_opendir(struct vinode *dir_vinode, struct dentry *dentry); +int rfs_hook_closedir(struct vinode *dir_vinode, struct dentry *dentry); +int rfs_readdir(struct vinode *dir_vinode, struct dir *dir, int *offset); +struct vinode *rfs_mkdir(struct vinode *parent, struct dentry *sub_dentry); + struct super_block *rfs_get_superblock(struct device *dev); extern const struct vinode_ops rfs_i_ops; diff --git a/kernel/syscall.c b/kernel/syscall.c index 3660321..0efcade 100644 --- a/kernel/syscall.c +++ b/kernel/syscall.c @@ -165,6 +165,37 @@ ssize_t sys_user_close(int fd) { return do_close(fd); } +// +// lib call to opendir +// +ssize_t sys_user_opendir(char * pathva){ + char * pathpa = (char*)user_va_to_pa((pagetable_t)(current->pagetable), pathva); + return do_opendir(pathpa); +} + +// +// lib call to readdir +// +ssize_t sys_user_readdir(int fd, struct dir *vdir){ + struct dir * pdir = (struct dir *)user_va_to_pa((pagetable_t)(current->pagetable), vdir); + return do_readdir(fd, pdir); +} + +// +// lib call to mkdir +// +ssize_t sys_user_mkdir(char * pathva){ + char * pathpa = (char*)user_va_to_pa((pagetable_t)(current->pagetable), pathva); + return do_mkdir(pathpa); +} + +// +// lib call to closedir +// +ssize_t sys_user_closedir(int fd){ + return do_closedir(fd); +} + // // [a0]: the syscall number; [a1] ... [a7]: arguments to the syscalls. // returns the code of success, (e.g., 0 means success, fail for otherwise) @@ -199,6 +230,15 @@ long do_syscall(long a0, long a1, long a2, long a3, long a4, long a5, long a6, l return sys_user_disk_stat(a1, (struct istat *)a2); case SYS_user_close: return sys_user_close(a1); + // added @lab4_2 + case SYS_user_opendir: + return sys_user_opendir((char *)a1); + case SYS_user_readdir: + return sys_user_readdir(a1, (struct dir *)a2); + case SYS_user_mkdir: + return sys_user_mkdir((char *)a1); + case SYS_user_closedir: + return sys_user_closedir(a1); default: panic("Unknown syscall %ld \n", a0); } diff --git a/kernel/syscall.h b/kernel/syscall.h index 8ac161e..886f58e 100644 --- a/kernel/syscall.h +++ b/kernel/syscall.h @@ -22,6 +22,11 @@ #define SYS_user_stat (SYS_user_base + 21) #define SYS_user_disk_stat (SYS_user_base + 22) #define SYS_user_close (SYS_user_base + 23) +// added @lab4_2 +#define SYS_user_opendir (SYS_user_base + 24) +#define SYS_user_readdir (SYS_user_base + 25) +#define SYS_user_mkdir (SYS_user_base + 26) +#define SYS_user_closedir (SYS_user_base + 27) long do_syscall(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7); diff --git a/kernel/vfs.c b/kernel/vfs.c index 5d52d11..2088fb0 100644 --- a/kernel/vfs.c +++ b/kernel/vfs.c @@ -296,6 +296,113 @@ int vfs_close(struct file *file) { return 0; } +// +// open a dir at vfs layer. the directory must exist on disk. +// +struct file *vfs_opendir(const char *path) { + struct dentry *parent = vfs_root_dentry; + char miss_name[MAX_PATH_LEN]; + + // lookup the dir + struct dentry *file_dentry = lookup_final_dentry(path, &parent, miss_name); + + if (!file_dentry || file_dentry->dentry_inode->type != DIR_I) { + sprint("vfs_opendir: cannot find the direntry!\n"); + return NULL; + } + + // allocate a vfs file with readable/non-writable flag. + struct file *file = alloc_vfs_file(file_dentry, 1, 0, 0); + + // additional open direntry operations for a specific file system + // rfs needs duild dir cache. + if (file_dentry->dentry_inode->i_ops->viop_hook_opendir) { + if (file_dentry->dentry_inode->i_ops-> + viop_hook_opendir(file_dentry->dentry_inode, file_dentry) != 0) { + sprint("vfs_opendir: hook opendir failed!\n"); + } + } + + return file; +} + +// +// read a direntry entry from a direntry specified by "file" +// the read direntry entry is stored in "dir" +// +int vfs_readdir(struct file *file, struct dir *dir) { + if (file->f_dentry->dentry_inode->type != DIR_I) { + sprint("vfs_readdir: cannot read a file!\n"); + return -1; + } + return viop_readdir(file->f_dentry->dentry_inode, dir, &(file->offset)); +} + +// +// make a new directory specified by "path" at vfs layer. +// note that only the last level directory of the path will be created, +// and its parent directory must exist. +// +int vfs_mkdir(const char *path) { + struct dentry *parent = vfs_root_dentry; + char miss_name[MAX_PATH_LEN]; + + // lookup the dir, find its parent direntry + struct dentry *file_dentry = lookup_final_dentry(path, &parent, miss_name); + if (file_dentry) { + sprint("vfs_mkdir: the directory already exists!\n"); + return -1; + } + + char basename[MAX_PATH_LEN]; + get_base_name(path, basename); + if (strcmp(miss_name, basename) != 0) { + sprint("vfs_mkdir: cannot create directory in a non-exist directory!\n"); + return -1; + } + + // do real mkdir + struct dentry *new_dentry = alloc_vfs_dentry(basename, NULL, parent); + struct vinode *new_dir_inode = viop_mkdir(parent->dentry_inode, new_dentry); + if (!new_dir_inode) { + free_page(new_dentry); + sprint("vfs_mkdir: cannot create directory!\n"); + return -1; + } + + new_dentry->dentry_inode = new_dir_inode; + new_dir_inode->ref++; + hash_put_dentry(new_dentry); + hash_put_vinode(new_dir_inode); + return 0; +} + +// +// close a directory at vfs layer +// +int vfs_closedir(struct file *file) { + if (file->f_dentry->dentry_inode->type != DIR_I) { + sprint("vfs_closedir: cannot close a file!\n"); + return -1; + } + + // even if a directory is no longer referenced, it will not be freed because + // it will serve as a cache for later lookup operations on it or its + // descendants + file->f_dentry->d_ref--; + file->status = FD_NONE; + + // additional close direntry operations for a specific file system + // rfs needs reclaim dir cache. + if (file->f_dentry->dentry_inode->i_ops->viop_hook_closedir) { + if (file->f_dentry->dentry_inode->i_ops-> + viop_hook_closedir(file->f_dentry->dentry_inode, file->f_dentry) != 0) { + sprint("vfs_closedir: hook closedir failed!\n"); + } + } + return 0; +} + // // lookup the "path" and return its dentry (or NULL if not found). // the lookup starts from parent, and stop till the full "path" is parsed. diff --git a/kernel/vfs.h b/kernel/vfs.h index b9673ce..6f030d5 100644 --- a/kernel/vfs.h +++ b/kernel/vfs.h @@ -30,6 +30,12 @@ int vfs_stat(struct file *file, struct istat *istat); int vfs_disk_stat(struct file *file, struct istat *istat); int vfs_close(struct file *file); +// directory interfaces +struct file *vfs_opendir(const char *path); +int vfs_readdir(struct file *file, struct dir *dir); +int vfs_mkdir(const char *path); +int vfs_closedir(struct file *file); + /**** vfs abstract object types ****/ // system root direntry extern struct dentry *vfs_root_dentry; @@ -137,6 +143,10 @@ struct vinode_ops { struct vinode *(*viop_lookup)(struct vinode *parent, struct dentry *sub_dentry); + // directory operations + int (*viop_readdir)(struct vinode *dir_vinode, struct dir *dir, int *offset); + struct vinode *(*viop_mkdir)(struct vinode *parent, struct dentry *sub_dentry); + // write back inode to disk int (*viop_write_back_vinode)(struct vinode *node); @@ -148,6 +158,8 @@ struct vinode_ops { // times. int (*viop_hook_open)(struct vinode *node, struct dentry *dentry); int (*viop_hook_close)(struct vinode *node, struct dentry *dentry); + int (*viop_hook_opendir)(struct vinode *node, struct dentry *dentry); + int (*viop_hook_closedir)(struct vinode *node, struct dentry *dentry); }; // vinode operation interface @@ -160,6 +172,8 @@ struct vinode_ops { #define viop_lseek(node, new_off, whence, off) (node->i_ops->viop_lseek(node, new_off, whence, off)) #define viop_disk_stat(node, istat) (node->i_ops->viop_disk_stat(node, istat)) #define viop_lookup(parent, sub_dentry) (parent->i_ops->viop_lookup(parent, sub_dentry)) +#define viop_readdir(dir_vinode, dir, offset) (dir_vinode->i_ops->viop_readdir(dir_vinode, dir, offset)) +#define viop_mkdir(dir, sub_dentry) (dir->i_ops->viop_mkdir(dir, sub_dentry)) #define viop_write_back_vinode(node) (node->i_ops->viop_write_back_vinode(node)) // vinode hash table diff --git a/user/app_directory.c b/user/app_directory.c new file mode 100644 index 0000000..8636756 --- /dev/null +++ b/user/app_directory.c @@ -0,0 +1,60 @@ +#include "user_lib.h" +#include "util/string.h" +#include "util/types.h" + +void ls(char *path) { + int dir_fd = opendir_u(path); + printu("------------------------------\n"); + printu("ls \"%s\":\n", path); + printu("[name] [inode_num]\n"); + struct dir dir; + int width = 20; + while(readdir_u(dir_fd, &dir) == 0) { + // we do not have %ms :( + char name[width + 1]; + memset(name, ' ', width + 1); + name[width] = '\0'; + if (strlen(dir.name) < width) { + strcpy(name, dir.name); + name[strlen(dir.name)] = ' '; + printu("%s %d\n", name, dir.inum); + } + else + printu("%s %d\n", dir.name, dir.inum); + } + printu("------------------------------\n"); + closedir_u(dir_fd); +} + +int main(int argc, char *argv[]) { + char str[] = "hello world"; + int fd; + + printu("\n======== Test 1: open and read dir ========\n"); + + ls("/RAMDISK0"); + + printu("\n======== Test 2: make dir ========\n"); + + mkdir_u("/RAMDISK0/sub_dir"); + printu("make: /RAMDISK0/sub_dir\n"); + + ls("/RAMDISK0"); + + // try to write a file in the new dir + printu("write: /RAMDISK0/sub_dir/ramfile\n"); + + fd = open("/RAMDISK0/sub_dir/ramfile", O_RDWR | O_CREAT); + printu("file descriptor fd: %d\n", fd); + + write_u(fd, str, strlen(str)); + printu("write content: \n%s\n", str); + + close(fd); + + ls("/RAMDISK0/sub_dir"); + + printu("\nAll tests passed!\n\n"); + exit(0); + return 0; +} diff --git a/user/app_file.c b/user/app_file.c deleted file mode 100644 index ec3acbf..0000000 --- a/user/app_file.c +++ /dev/null @@ -1,63 +0,0 @@ -#include "user_lib.h" -#include "util/string.h" -#include "util/types.h" - -int main(int argc, char *argv[]) { - int fd; - int MAXBUF = 512; - char buf[MAXBUF]; - char str[] = "hello world"; - int fd1, fd2; - - printu("\n======== Test 1: read host file ========\n"); - printu("read: /hostfile.txt\n"); - - fd = open("/hostfile.txt", O_RDONLY); - printu("file descriptor fd: %d\n", fd); - - read_u(fd, buf, MAXBUF); - printu("read content: \n%s\n", buf); - - close(fd); - - printu("\n======== Test 2: create/write rfs file ========\n"); - printu("write: /RAMDISK0/ramfile\n"); - - fd = open("/RAMDISK0/ramfile", O_RDWR | O_CREAT); - printu("file descriptor fd: %d\n", fd); - - write_u(fd, buf, strlen(buf)); - printu("write content: \n%s\n", buf); - close(fd); - - printu("\n======== Test 3: read rfs file ========\n"); - printu("read: /RAMDISK0/ramfile\n"); - - fd = open("/RAMDISK0/ramfile", O_RDWR); - printu("file descriptor fd: %d\n", fd); - - read_u(fd, buf, MAXBUF); - printu("read content: \n%s\n", buf); - close(fd); - - printu("\n======== Test 4: open twice ========\n"); - - fd1 = open("/RAMDISK0/ramfile", O_RDWR | O_CREAT); - fd2 = open("/RAMDISK0/ramfile", O_RDWR | O_CREAT); - - printu("file descriptor fd1(ramfile): %d\n", fd1); - printu("file descriptor fd2(ramfile): %d\n", fd2); - - write_u(fd1, str, strlen(str)); - printu("write content: \n%s\n", str); - - read_u(fd2, buf, MAXBUF); - printu("read content: \n%s\n", buf); - - close(fd1); - close(fd2); - - printu("\nAll tests passed!\n\n"); - exit(0); - return 0; -} diff --git a/user/user_lib.c b/user/user_lib.c index 7e59d98..ca9ba1b 100644 --- a/user/user_lib.c +++ b/user/user_lib.c @@ -119,6 +119,34 @@ int disk_stat_u(int fd, struct istat *istat) { return do_user_call(SYS_user_disk_stat, fd, (uint64)istat, 0, 0, 0, 0, 0); } +// +// lib call to open dir +// +int opendir_u(const char *dirname) { + return do_user_call(SYS_user_opendir, (uint64)dirname, 0, 0, 0, 0, 0, 0); +} + +// +// lib call to read dir +// +int readdir_u(int fd, struct dir *dir) { + return do_user_call(SYS_user_readdir, fd, (uint64)dir, 0, 0, 0, 0, 0); +} + +// +// lib call to make dir +// +int mkdir_u(const char *pathname) { + return do_user_call(SYS_user_mkdir, (uint64)pathname, 0, 0, 0, 0, 0, 0); +} + +// +// lib call to close dir +// +int closedir_u(int fd) { + return do_user_call(SYS_user_closedir, fd, 0, 0, 0, 0, 0, 0); +} + // // lib call to close // diff --git a/user/user_lib.h b/user/user_lib.h index 58fedb5..cee321f 100644 --- a/user/user_lib.h +++ b/user/user_lib.h @@ -23,4 +23,10 @@ int stat_u(int fd, struct istat *istat); int disk_stat_u(int fd, struct istat *istat); int close(int fd); +// added @ lab4_2 +int opendir_u(const char *pathname); +int readdir_u(int fd, struct dir *dir); +int mkdir_u(const char *pathname); +int closedir_u(int fd); + #endif diff --git a/util/types.h b/util/types.h index 73c12d7..c951f82 100644 --- a/util/types.h +++ b/util/types.h @@ -42,6 +42,11 @@ typedef unsigned long size_t; #define MAX_FILE_NAME_LEN 32 +struct dir { + char name[MAX_FILE_NAME_LEN]; + int inum; +}; + struct istat { int st_inum; int st_size;