/* * This is another tricly sys_* function that you will need to write. * It's pretty similar to sys_read(), but you don't need * to allocate a whole page, just a single dirent_t. call do_getdents in a * loop until you have read getdent_args_t->count bytes (or an error * occurs). You should note that count is the number of bytes in the * buffer, not the number of dirents, which means that you'll need to loop * a max of something like count / sizeof(dirent_t) times. */ static int sys_getdents(getdents_args_t *arg) { getdents_args_t getdents; if (copy_from_user(&getdents, arg, sizeof(getdents_args_t)) < 0) /* Copy from the user the read_args_t */ { curthr->kt_errno = EFAULT; return -1; } int i=0,j=0,max_count=0; if(getdents.count<=sizeof(dirent_t)) { max_count=getdents.count; } else getdents.count=sizeof(dirent_t); while(i<max_count) { j=do_getdent(getdents.fd, getdents.dirp); if(j<0) { curthr->kt_errno = -j; return -1; } i++; } /*NOT_YET_IMPLEMENTED("VM: sys_getdents");*/ return max_count; }
/* * This is another tricly sys_* function that you will need to write. * It's pretty similar to sys_read(), but you don't need * to allocate a whole page, just a single dirent_t. call do_getdents in a * loop until you have read getdent_args_t->count bytes (or an error * occurs). You should note that count is the number of bytes in the * buffer, not the number of dirents, which means that you'll need to loop * a max of something like count / sizeof(dirent_t) times. */ static int sys_getdents(getdents_args_t *arg) { getdents_args_t karg; int err,ret; size_t offset=0; if((err=copy_from_user(&karg,arg,sizeof(getdents_args_t)))<0){ curthr->kt_errno=-err; return -1; } dirent_t dir; while(offset<karg.count){ if((ret=do_getdent(karg.fd, &dir))<0){ curthr->kt_errno=-ret; return -1; } offset+=ret; if(ret==0) break; } if((err=copy_to_user(arg->dirp,&dir,sizeof(dirent_t)))<0){ curthr->kt_errno=-err; return -1; } return offset; }
/* * This is another tricly sys_* function that you will need to write. * It's pretty similar to sys_read(), but you don't need * to allocate a whole page, just a single dirent_t. call do_getdents in a * loop until you have read getdent_args_t->count bytes (or an error * occurs). You should note that count is the number of bytes in the * buffer, not the number of dirents, which means that you'll need to loop * a max of something like count / sizeof(dirent_t) times. */ static int sys_getdents(getdents_args_t *arg) { getdents_args_t kern_args; int err; if ((err = copy_from_user(&kern_args, arg, sizeof(getdents_args_t))) < 0) { curthr->kt_errno = -err; return -1; } dirent_t dirent; size_t maxdir = kern_args.count / sizeof(dirent_t); size_t i; int total_read = 0; for (i = 0 ; i < maxdir ; i++) { int actual_read = do_getdent(kern_args.fd, &dirent); if (actual_read < 0) { curthr->kt_errno = -actual_read; return -1; } KASSERT(actual_read == 0 || actual_read == sizeof(dirent_t)); /*no more dirents, just break out*/ if (actual_read == 0) { break; } char *uaddr = (char *)kern_args.dirp + i * sizeof(dirent_t); err = copy_to_user(uaddr, &dirent, sizeof(dirent_t)); if (err < 0) { curthr->kt_errno = -err; return -1; } KASSERT(err == 0); /*only increment total_read when copy_to_user succeed*/ total_read += actual_read; } return total_read; /*NOT_YET_IMPLEMENTED("VM: sys_getdents");*/ /*return -1;*/ }
/* * This is another tricly sys_* function that you will need to write. * It's pretty similar to sys_read(), but you don't need * to allocate a whole page, just a single dirent_t. call do_getdents in a * loop until you have read getdent_args_t->count bytes (or an error * occurs). You should note that count is the number of bytes in the * buffer, not the number of dirents, which means that you'll need to loop * a max of something like count / sizeof(dirent_t) times. */ static int sys_getdents(getdents_args_t *arg) { /* NOT_YET_IMPLEMENTED("VM: sys_read");*/ dbg(DBG_PRINT,"go into sys_getdents\n"); void* readBuf = NULL; getdents_args_t k_args; int retVal,retVal_new; size_t readBytes = 0; retVal = copy_from_user(&k_args, arg, sizeof(k_args)); KASSERT(0 <= retVal); dirent_t dirent; dirent_t *tempDirp = arg->dirp; int loopBytes; while(k_args.count > readBytes) { loopBytes= do_getdent(k_args.fd, &dirent); if(loopBytes == 0) { dbg(DBG_PRINT, "(GRADING3B)\n"); break; } if(loopBytes < 0) { dbg(DBG_PRINT, "(GRADING3C)\n"); curthr->kt_errno = -loopBytes; return -1; } retVal_new = copy_to_user(tempDirp, &dirent, loopBytes); KASSERT(0<=retVal_new); tempDirp++; readBytes += loopBytes; } return readBytes; }
/* * This is another tricly sys_* function that you will need to write. * It's pretty similar to sys_read(), but you don't need * to allocate a whole page, just a single dirent_t. call do_getdents in a * loop until you have read getdent_args_t->count bytes (or an error * occurs). You should note that count is the number of bytes in the * buffer, not the number of dirents, which means that you'll need to loop * a max of something like count / sizeof(dirent_t) times. */ static int sys_getdents(getdents_args_t *arg) { /*NOT_YET_IMPLEMENTED("VM: sys_getdents"); */ getdents_args_t kern_args; uint32_t totRead = -1, readC = 0; dirent_t dirent; int err = copy_from_user(&kern_args, arg, sizeof(getdents_args_t)); dbg(DBG_PRINT, "(GRADING3F)\n"); /*if (err < 0) { dbg(DBG_ERROR, "(GRADING test 28)\n"); curthr->kt_errno = -err; return -1; }*/ if ( !(err < 0)){ totRead = 0; while (readC < (kern_args.count / sizeof(dirent_t))) { dbg(DBG_PRINT, "(GRADING3F)\n"); err = do_getdent(kern_args.fd, &dirent); if (err == 0) { dbg(DBG_PRINT, "(GRADING3F)\n"); return totRead; } if (err < 0) { dbg(DBG_PRINT, "(GRADING3D 2)\n"); curthr->kt_errno = -err; return -1; } dbg(DBG_PRINT, "(GRADING3F)\n"); copy_to_user(kern_args.dirp + readC, &dirent, err); totRead += err; readC += 1; } dbg(DBG_PRINT, "(GRADING3F)\n"); } return totRead; }
/* * This is another tricly sys_* function that you will need to write. * It's pretty similar to sys_read(), but you don't need * to allocate a whole page, just a single dirent_t. call do_getdents in a * loop until you have read getdent_args_t->count bytes (or an error * occurs). You should note that count is the number of bytes in the * buffer, not the number of dirents, which means that you'll need to loop * a max of something like count / sizeof(dirent_t) times. */ static int sys_getdents(getdents_args_t *arg) { /*NOT_YET_IMPLEMENTED("VM: sys_getdents");*/ getdents_args_t kern_args; int bytes_read, ret; if((ret = copy_from_user(&kern_args, arg, sizeof(kern_args))) < 0){ curthr->kt_errno = -ret; return -1; } size_t total_bytes_read = 0; /* dirent_t *dirp = NULL; */ dirent_t dirp; /* Note: the read operation is performed by do_getdent() */ while(total_bytes_read < kern_args.count){ if((bytes_read = do_getdent(kern_args.fd, &dirp)) < 0){ curthr->kt_errno = -bytes_read; return -1; } else { if(bytes_read == 0) { break; } } if((ret = copy_to_user((void *)((uint32_t)kern_args.dirp + total_bytes_read), &dirp, sizeof(dirent_t))) < 0){ curthr->kt_errno = -ret; return -1; } total_bytes_read += sizeof(dirent_t); } return total_bytes_read; }
int vfs_selftest(kshell_t *kshell, int argc, char **argv) { int fd1,fd2; char *y="/ab/fil"; char x[2]; int err; do_mkdir("/ab"); do_mknod("/ab/new", S_IFCHR,MKDEVID(1,1)); fd1=do_open("/ab/new",2); fd2=do_dup2(fd1,NFILES+1); if(fd2<0) { dbg(DBG_PRINT,"File not created\n"); } do_mknod("/ab/notmade",4096,MKDEVID(1,1)); do_mknod("/ab/new/not",S_IFCHR,MKDEVID(1,1)); do_mknod("/ab/new", S_IFCHR,MKDEVID(1,1)); do_mknod("", S_IFCHR,MKDEVID(1,1)); /*do_close(fd1);*/ for(fd2=1;fd2<35;fd2++) { sprintf(x,"%d",fd2); strcat(y,x); do_mknod(y,S_IFCHR,MKDEVID(1,0)); err=do_open(y,2); if(err<0) { break; } if(fd2<10) { y[strlen(y)-1]='\0'; } else { y[strlen(y)-2]='\0'; } } do_mknod("/ab/new1", S_IFCHR,MKDEVID(1,1)); err=do_dup(fd1); do_unlink("/ab/new/ab"); do_unlink("/ab/new"); do_close(fd1); for(fd2=NFILES-1;fd2>0;fd2--) { err=do_close(fd2); sprintf(x,"%d",fd2); strcat(y,x); do_unlink(y); if(err<0) { break; } if(fd2<10) { y[strlen(y)-1]='\0'; } else { y[strlen(y)-2]='\0'; } } do_link("/a","/dev"); do_link("/dev","/a"); do_link("/dev","/a"); do_rmdir("/a"); /* mkdir("/k"); do_link("/ab","/k");*/ do_rmdir("/ab"); /*do_rmdir("/k");*/ /*GS: SELF TESTS*/ dbg(DBG_PRINT,"\n*************************************************************\n"); dbg(DBG_PRINT,"\n\n\n\n(GRADING2C)(kmain.c)(selftest_proc_run) selftests begin\n"); int retVal = 0; int i = 0; /* 1. dbg(DBG_PRINT, "(GRADING2C) (vfs_syscall.c) (do_stat) strlen too long, return -ENAMETOOLONG\n");*/ char longPath[1024 + 1] = {0}; for(i = 0; i < 1025; i++) longPath[i] = 'a'; struct stat buf; retVal = do_stat(longPath, &buf); retVal=do_chdir(longPath); /*2. dbg(DBG_PRINT, "(GRADING2B) ENOTDIR or ENOENT\n");*/ retVal = do_stat("", &buf); /*3. dbg(DBG_PRINT, "(GRADING2C) (vfs_syscall.c) (do_getdent) Invalid file descriptor fd, return -EBADF\n");*/ struct dirent dirp; retVal = do_getdent(-1, &dirp); /*4. dbg(DBG_PRINT, "(GRADING2C) (vfs_syscall.c) (do_getdent) Invalid file descriptor fd, return -EBADF\n");*/ retVal = do_getdent(1, &dirp); /*5. dbg(DBG_PRINT, "(GRADING2C) (vfs_syscall.c) (do_getdent) File descriptor does not refer to a directory, return -ENOTDIR\n");*/ do_mknod("/./file", S_IFCHR,MKDEVID(1,1)); fd1 = do_open("/./file",2); retVal = do_getdent(fd1, &dirp); do_unlink("/./file"); do_close(fd1); /*6. dbg(DBG_PRINT, "(GRADING2C) (vfs_syscall.c) (do_rename) Both are valid names \n");*/ /* and */ /*7. dbg(DBG_PRINT, "(GRADING2C) (vfs_syscall.c) (do_rename) error do_link, return error\n"); \n");*/ retVal = do_rename("/./aaa", "/./bbb"); dbg(DBG_PRINT,"\n\nretVal=%d",retVal); dbg(DBG_PRINT,"\n*************************************************************\n"); return 0; }
/* * A little convenience command to clear the files from a directory (though not * the directories). Called from the kshell as cleardir <name>. */ int faber_cleardir(kshell_t *ksh, int argc, char **argv) { KASSERT(NULL != ksh); struct dirent d; /* The current directory entry */ char buf[TESTBUFLEN]; /* A buffer used to assemble the pathname */ int f = -1; /* File descriptor (dirs must be opened) */ int rv = 0; /* Return values */ int got_one = 1; /* True if this iteration deleted a file */ if ( argc < 2 ) { kprintf(ksh, "Usage: cleardir dir\n"); return -1; } /* Because unlinking a file changes the order of the directory entries * - specifically, it moves a directory entry into the spot where the * unlinked file's directory entry was - this loop starts over every * time a file is unlinked. The pseudocode is: * * repeat * open the directory. * find the first directory entry that is neither . nor .. * unlink it * close the directory * until only . and .. are left */ while ( got_one ) { got_one = 0; /* Open up the directory */ if ( (f = do_open(argv[1], O_RDONLY)) < 0 ) { kprintf(ksh, "Open failed on %s: %d %s\n", argv[1], f, strerror(-f)); return -1; } while ( ( rv = do_getdent(f, &d)) > 0 ) { /* Keep looking if d contains . or .. */ if ( strncmp(".", d.d_name, NAME_LEN) == 0 || strncmp("..", d.d_name, NAME_LEN) == 0 ) continue; /* Found a name to delete. Construct the path and delete it */ snprintf(buf, TESTBUFLEN, "%s/%s", argv[1], d.d_name); kprintf(ksh, "unlinking %s\n", buf); if ( (rv = do_unlink(buf)) < 0 ) { /* Something went wrong- d probably points to a directory. * Report the error, close f, and terminate the command. */ kprintf(ksh, "Unlink failed on %s: %d %s\n", buf, rv, strerror(-rv)); do_close(f); return rv; } got_one = 1; /* CLose the directory and restart (because it set got_one) */ break; } do_close(f); /* This branch will be taken if do_getdent fails */ if ( rv < 0 ) { kprintf(ksh, "get_dent failed on %s: %d %s\n", argv[1], rv, strerror(-rv)); return rv; } } /* OK, deleted everything we could. */ return rv; }