/* Use dir_namev() to find the vnode of the directory containing the dir to be * removed. Then call the containing dir's rmdir v_op. The rmdir v_op will * return an error if the dir to be removed does not exist or is not empty, so * you don't need to worry about that here. Return the value of the v_op, * or an error. * * Error cases you must handle for this function at the VFS level: * o EINVAL * path has "." as its final component. * o ENOTEMPTY * path has ".." as its final component. * o ENOENT * A directory component in path does not exist. * o ENOTDIR * A component used as a directory in path is not, in fact, a directory. * o ENAMETOOLONG * A component of path was too long. */ int do_rmdir(const char *path) { if (strlen(path) > MAXPATHLEN) { dbg(DBG_PRINT,"(GRADING2B) Path length exceeding maximum path length\n"); dbg(DBG_ERROR, "Path length exceeding maximum path length\n"); return -ENAMETOOLONG; } size_t namelen; const char *name; vnode_t *res_vnode; int dir_value = dir_namev(path, &namelen, &name, NULL, &res_vnode); if (dir_value<0) { dbg(DBG_PRINT,"(GRADING2B) Error in calling dir_namev function\n"); dbg(DBG_ERROR, "Error in calling dir_namev function\n"); return dir_value; } /*int result=lookup(res_vnode,name, namelen, &res_vnode);*/ KASSERT(NULL != res_vnode->vn_ops->rmdir); dbg(DBG_PRINT,"\n(GRADING2A 3.d) res_vnode->vn_ops is not NULL"); /* if (result==-ENOTDIR) { dbg(DBG_ERROR, "\n A component used as a directory in path is not, in fact, a directory."); return -ENOTDIR; }*/ if(strcmp(name,".")==0) { vput(res_vnode); dbg(DBG_PRINT,"(GRADING2B) do_rmdir(): path has '.' as final component\n"); dbg(DBG_ERROR, "do_rmdir(): path has '.' as final component\n"); return -EINVAL; } if(strcmp(name,"..")==0) { vput(res_vnode); dbg(DBG_PRINT,"(GRADING2B) do_rmdir(): path has '..' as final component\n"); dbg(DBG_ERROR, "do_rmdir(): path has '..' as final component\n"); return -ENOTEMPTY; } int res_val = res_vnode->vn_ops->rmdir(res_vnode,name,namelen); vput(res_vnode); return res_val; /*NOT_YET_IMPLEMENTED("VFS: do_rmdir"); return -1;*/ }
/* * Same as do_rmdir, but for files. * * Error cases you must handle for this function at the VFS level: * o EISDIR * path refers to a directory. * o ENOENT * A component in path does not exist. * o ENOTDIR * A component used as a directory in path is not, in fact, a directory. * o ENAMETOOLONG * A component of path was too long. */ int do_unlink(const char *path) { if(strlen(path) > MAXPATHLEN) { dbg(DBG_PRINT,"(GRADING2B) do_unlink(): path name Provided is too long\n"); dbg(DBG_ERROR, "do_unlink(): path name Provided is too long\n"); return -ENAMETOOLONG; } if(strlen(path) <=0) { dbg(DBG_PRINT,"(GRADING2B) do_link(): given path name is not valid\n"); dbg(DBG_ERROR, "do_link(): path name is not valid\n"); return -EINVAL; } size_t namelen; const char *name; vnode_t *res_vnode; vnode_t *check_vnode; int ret_val =0; int val=0; int unlinking = 0; ret_val = dir_namev(path,&namelen,&name,NULL,&res_vnode); if(ret_val<0) { dbg(DBG_PRINT,"(GRADING2B) Error while calling dir_namev function\n"); return ret_val; } val = lookup(res_vnode,name,namelen,&check_vnode); if(val<0) { vput(res_vnode); dbg(DBG_PRINT,"(GRADING2B) Error while calling lookup function\n"); return val; } if(S_ISDIR(check_vnode->vn_mode)) { vput(res_vnode); vput(check_vnode); dbg(DBG_PRINT,"(GRADING2B) The given path is a directory\n"); dbg(DBG_ERROR, "do_unlink(): path is directory\n"); return -EISDIR; } KASSERT(NULL != res_vnode->vn_ops->unlink); dbg(DBG_PRINT, "(GRADING2A 3.e) do_unlink(): corresponding vn_ops no NULL\n"); unlinking = res_vnode->vn_ops->unlink(res_vnode, name, namelen); vput(res_vnode); vput(check_vnode); return unlinking; /*NOT_YET_IMPLEMENTED("VFS: do_unlink"); return -1;*/ }
/* * This routine creates a special file of the type specified by 'mode' at * the location specified by 'path'. 'mode' should be one of S_IFCHR or * S_IFBLK (you might note that mknod(2) normally allows one to create * regular files as well-- for simplicity this is not the case in Weenix). * 'devid', as you might expect, is the device identifier of the device * that the new special file should represent. * * You might use a combination of dir_namev, lookup, and the fs-specific * mknod (that is, the containing directory's 'mknod' vnode operation). * Return the result of the fs-specific mknod, or an error. * * Error cases you must handle for this function at the VFS level: * o EINVAL * mode requested creation of something other than a device special * file. * o EEXIST * path already exists. * o ENOENT * A directory component in path does not exist. * o ENOTDIR * A component used as a directory in path is not, in fact, a directory. * o ENAMETOOLONG * A component of path was too long. */ int do_mknod(const char *path, int mode, unsigned devid) { /* NOT_YET_IMPLEMENTED("VFS: do_mknod"); */ if (mode != S_IFCHR && mode != S_IFBLK) { dbg(DBG_ERROR, "1\n"); return -EINVAL; } dbg(DBG_PRINT, "(GRADING2B)\n"); size_t namelen = NULL; const char *name = NULL; vnode_t *base; vnode_t *res_vnode = NULL, *result = NULL; /*if (strlen(path) > MAXPATHLEN){ dbg(DBG_ERROR,"2\n"); return -ENAMETOOLONG; }*/ /* Base passed NULL since dir_namev can handle accordingly */ int retdir_namev = dir_namev(path, &namelen, &name, NULL, &res_vnode); /*dbg(DBG_PRINT,"culprit is %s",path);*/ /* if (strlen(name) > NAME_LEN) { dbg(DBG_ERROR,"3\n"); if (retdir_namev == 0) { dbg(DBG_ERROR,"4\n"); vput(res_vnode); } return -ENAMETOOLONG; }*/ if (retdir_namev == 0) { dbg(DBG_PRINT, "(GRADING2B)\n"); int retlookup = lookup(res_vnode, name, namelen, &result); if (result != NULL) { dbg(DBG_ERROR, "6\n"); vput(result); return -EEXIST; } else if (result == NULL) { dbg(DBG_PRINT, "(GRADING2B)\n"); KASSERT(NULL != (res_vnode)->vn_ops->mknod); dbg(DBG_PRINT, "(GRADING2A 3.b)\n"); int ramfs_ret = (res_vnode)->vn_ops->mknod(res_vnode, name, namelen, mode, devid); /*lookup(res_vnode, name, namelen, &result);*/ /*dbg(DBG_PRINT, "Created special file %s ref=%d\n", path, result->vn_refcount);*/ return ramfs_ret; } return retlookup; } /*else { dbg(DBG_ERROR,"8\n"); return retdir_namev; }*/ /*dbg(DBG_ERROR,"9\n");*/ return 0; }
/* * Same as do_rmdir, but for files. * * Error cases you must handle for this function at the VFS level: * o EISDIR * path refers to a directory. * o ENOENT * A component in path does not exist. * o ENOTDIR * A component used as a directory in path is not, in fact, a directory. * o ENAMETOOLONG * A component of path was too long. */ int do_unlink(const char *path) { /* NOT_YET_IMPLEMENTED("VFS: do_unlink"); */ size_t namelen; const char *name; vnode_t *base; vnode_t *res_vnode, *result; dbg(DBG_PRINT, "(GRADING2B)\n"); /*if (strlen(path) > MAXPATHLEN) { dbg(DBG_ERROR, "2\n"); return -ENAMETOOLONG; }*/ /* Base passed NULL since dir_namev can handle accordingly */ int retdir_namev = dir_namev(path, &namelen, &name, NULL, &res_vnode); /*if (strlen(name) > NAME_LEN) { dbg(DBG_ERROR, "3\n"); if (retdir_namev == 0) { dbg(DBG_ERROR, "4\n"); vput(res_vnode); } return -ENAMETOOLONG; }*/ /*dbg(DBG_ERROR, "name is %s\n", name);*/ if (0 == retdir_namev) { dbg(DBG_PRINT, "(GRADING2B)\n"); vput(res_vnode); int retlookup = lookup(res_vnode, name, namelen, &result); if (retlookup == 0) { dbg(DBG_PRINT, "(GRADING2B)\n"); if (NULL != result) { dbg(DBG_PRINT, "(GRADING2B)\n"); if (S_ISDIR((result)->vn_mode)) { dbg(DBG_PRINT, "(GRADING2B)\n"); vput(result); return -EISDIR; } vput(result); KASSERT(NULL != (res_vnode)->vn_ops->unlink); dbg(DBG_PRINT, "(GRADING2A 3.e)\n"); int ret_unlink = (res_vnode)->vn_ops->unlink(res_vnode, name, namelen); } } else { dbg(DBG_PRINT, "(GRADING2B)\n"); return retlookup; } } /*else { dbg(DBG_ERROR, "10\n"); return retdir_namev; }*/ dbg(DBG_PRINT, "(GRADING2B)\n"); return 0; }
/* To link: * o open_namev(from) * o dir_namev(to) * o call the destination dir's (to) link vn_ops. * o return the result of link, or an error * * Remember to vput the vnodes returned from open_namev and dir_namev. * * Error cases you must handle for this function at the VFS level: * o EEXIST * to already exists. * o ENOENT * A directory component in from or to does not exist. * o ENOTDIR * A component used as a directory in from or to is not, in fact, a * directory. * o ENAMETOOLONG * A component of from or to was too long. * o EISDIR * from is a directory. */ int do_link(const char *from, const char *to) { /*NOT_YET_IMPLEMENTED("VFS: do_link"); return 0;*/ if ((strlen(from) > MAXPATHLEN) || (strlen(to) > MAXPATHLEN)){ return -ENAMETOOLONG; } vnode_t *from_vnode,*to_vnode,*to_vnodeFile; int from_retVal,to_retVal; size_t namelen; const char *name; from_retVal = open_namev(from,0,&from_vnode,NULL); if (from_retVal){ return from_retVal; } if (S_ISDIR(from_vnode->vn_mode)){ vput(from_vnode); return -EISDIR; } to_retVal = dir_namev(to,&namelen,&name,NULL,&to_vnode); if (to_retVal){ vput(from_vnode); return to_retVal; } if (!S_ISDIR(to_vnode->vn_mode)){ vput(from_vnode); vput(to_vnode); return -ENOTDIR; } to_retVal = lookup(to_vnode,name,namelen,&to_vnodeFile); if (!to_retVal){ vput(from_vnode); vput(to_vnode); vput(to_vnodeFile); return -EEXIST; } else { if (to_retVal == -ENOENT){ vput(from_vnode); vput(to_vnode); return from_vnode->vn_ops->link(from_vnode,to_vnode,name,namelen); } } vput(from_vnode); vput(to_vnode); return to_retVal; }
/* Use dir_namev() to find the vnode of the dir we want to make the new * directory in. Then use lookup() to make sure it doesn't already exist. * Finally call the dir's mkdir vn_ops. Return what it returns. * * Error cases you must handle for this function at the VFS level: * o EEXIST * path already exists. * o ENOENT * A directory component in path does not exist. * o ENOTDIR * A component used as a directory in path is not, in fact, a directory. * o ENAMETOOLONG * A component of path was too long. */ int do_mkdir(const char *path) { size_t len; const char *name; vnode_t *rest; struct vnode *result=NULL; int ent,dir_name_out,made; /*Alekhya: If the component of the path was too long*/ /*Add a self check test for this*/ /* if(strlen(path)>MAXPATHLEN) { dbg(DBG_PRINT,"(GRADING2C) (vfs_syscall.c) (do_mkdir) Name too long\n"); return -ENAMETOOLONG; }*/ /*Note: return error numbers in this function so can be used directly*/ dir_name_out=dir_namev(path,&len,&name,NULL,&rest); if (strlen(name) > NAME_LEN) { vput(rest); dbg(DBG_PRINT,"(GRADING2B) Part of Name too long(greater than NAME_LEN) (for LONGNAME test), return -ENAMETOOLONG\n"); return -ENAMETOOLONG; } if(dir_name_out<0) { dbg(DBG_PRINT,"(GRADING2B) error returned from dir_namev, return error \n"); return dir_name_out; } /*Alekhya: If the vnode itself does not exist, or the vnode does not refer to a directory*/ if(rest==NULL || !(S_ISDIR(rest->vn_mode))) { vput(rest); dbg(DBG_PRINT,"(GRADING2B) It is not a directory return -ENOTDIR"); return -ENOTDIR; } vput(rest); /*Alekhya: Calling lookup function to make sure the path does not already exist*/ ent=lookup(rest,name,len,&result); if(ent==0) { vput(result); dbg(DBG_PRINT,"(GRADING2B) Path already exists as lookup return 0, return -EEXIST\n"); return -EEXIST; } KASSERT(NULL != rest->vn_ops->mkdir); dbg(DBG_PRINT,"(GRADING2A 3.c) KASSERT(NULL != pointer to corresponding vnode->vn_ops->mkdir);"); made=rest->vn_ops->mkdir(rest,name,len); /*vput(rest);*/ return made; /* NOT_YET_IMPLEMENTED("VFS: do_mkdir"); return -1;*/ }
/* * Find the vnode associated with the path, and call the stat() vnode operation. * * Error cases you must handle for this function at the VFS level: * o ENOENT * A component of path does not exist. * o ENOTDIR * A component of the path prefix of path is not a directory. * o ENAMETOOLONG * A component of path was too long. */ int do_stat(const char *path, struct stat *buf) { if(*path == '\0') { KASSERT(*path == '\0'); dbg(DBG_PRINT,"(GRADING2D 3.f): Path component empty!\n"); return -EINVAL; } size_t namelen=0; const char *name=NULL; vnode_t *temp_vnode = NULL; vnode_t *res_vnode=NULL; KASSERT(path); KASSERT(buf); int namev_ret = dir_namev(path,&namelen,&name,NULL,&res_vnode); /*if(namev_ret<0){ KASSERT(namev_ret<0); dbg(DBG_PRINT,"(GRADING2D 3.f): Path component has failed.\n");*/ /* this should take care of ENAMETOOLONG*/ /* return namev_ret; }*/ /*if(res_vnode == NULL)*/ /*because dirnamev doesnt return ENOENT*/ /*{ dbg(DBG_PRINT," Directory component in path does not exist\n"); return -ENOENT; }*/ /*if(!S_ISDIR(res_vnode->vn_mode)) { dbg(DBG_PRINT,"A component of the path prefix of path is not a directory.\n"); vput(res_vnode); return -ENOTDIR; }*/ /* All return codes taken care off */ namev_ret = lookup(res_vnode,name,namelen,&temp_vnode); if (namev_ret<0) { dbg(DBG_PRINT,"Lookup failed, name is not in directory\n"); vput(res_vnode); return namev_ret; } KASSERT(res_vnode->vn_ops->stat); dbg(DBG_PRINT, "(GRADING2A 3.f): The stat function exists !!!.\n"); int stat_ret=(res_vnode->vn_ops->stat)(temp_vnode,buf); vput(res_vnode); vput(temp_vnode); dbg(DBG_PRINT,"(GRADING2D 3.l): Successfully Found the vnode associated with the path"); return stat_ret; }
/* This returns in res_vnode the vnode requested by the other parameters. * It makes use of dir_namev and lookup to find the specified vnode (if it * exists). flag is right out of the parameters to open(2); see * <weenix/fnctl.h>. If the O_CREAT flag is specified, and the file does * not exist call create() in the parent directory vnode. * * Note: Increments vnode refcount on *res_vnode. */ int open_namev(const char *pathname, int flag, vnode_t **res_vnode, vnode_t *base) { /* VFS {{{ */ int ret; const char *name; size_t namelen; vnode_t *dir; vnode_t *file = NULL; if ((ret = dir_namev(pathname, &namelen, &name, base, &dir)) < 0) { /* the directory itself doesn't exist */ return ret; } /*kthread_cleanup_push(vput,dir);*/ if ((ret = lookup(dir, name, namelen, &file)) == -ENOENT) { /* file doesn't exist. create it if need be */ if (flag & O_CREAT) { int ret2; KASSERT(NULL != dir->vn_ops->create); /* We're making a file, check name length */ if (namelen >= NAME_LEN) { vput(dir); return -ENAMETOOLONG; } if ((ret2 = dir->vn_ops->create(dir, name, namelen, &file)) < 0) { /* if we can't create it just give up */ /*kthread_cleanup_pop(1);*/ vput(dir); return ret2; } else { /*kthread_cleanup_pop(1);*/ vput(dir); *res_vnode = file; return 0; } } else { /* otherwise return error. */ /*kthread_cleanup_pop(1);*/ vput(dir); return ret; } } else { /* note that we may be in error here, it don't matter */ *res_vnode = file; /*kthread_cleanup_pop(1);*/ vput(dir); return ret; } /* VFS }}} */ return 0; }
/* To link: * o open_namev(from) * o dir_namev(to) * o call the destination dir's (to) link vn_ops. * o return the result of link, or an error * * Remember to vput the vnodes returned from open_namev and dir_namev. * * Error cases you must handle for this function at the VFS level: * o EEXIST * to already exists. * o ENOENT * A directory component in from or to does not exist. * o ENOTDIR * A component used as a directory in from or to is not, in fact, a * directory. * o ENAMETOOLONG * A component of from or to was too long. */ int do_link(const char *from, const char *to) { int err,err2,err3,ent; vnode_t *res_vnode,base,*res_vnode2,base2,*result; size_t len; const char *name; if(strlen(from)>NAME_LEN || strlen(to)>NAME_LEN) { dbg(DBG_PRINT,"(GRADING2C) (vfs_syscall.c) (do_link) Path greater than MAXPATHLEN, return -ENAMETOOLONG\n"); return -ENAMETOOLONG; } err=open_namev(from,0,&res_vnode,NULL); if(err<0) { /*vput(res_vnode);*/ dbg(DBG_PRINT,"(GRADING2C 1.j) (vfs_syscall.c) (do_link) error returned from open_namev so cannot open to link, return error \n"); return err; } if(S_ISDIR(res_vnode->vn_mode)) { vput(res_vnode); dbg(DBG_PRINT,"(GRADING2C 1.h) (vfs_syscall.c) (do_link) Link already exists, return -EEXIST \n"); return -EISDIR; } err2=dir_namev(to,&len,&name,NULL,&res_vnode2); if(err2<0) { vput(res_vnode); dbg(DBG_PRINT,"(GRADING2C) (vfs_syscall.c) (do_link) error returned from dir_namev so cannot open to link, return error \n"); return err2; } ent=lookup(res_vnode2,name,len,&result); if(ent==0) { vput(res_vnode); dbg(DBG_PRINT,"(GRADING2C 1.i) (vfs_syscall.c) (do_link) file of new Link already exists, return -EEXIST and dec ref count \n"); vput(res_vnode2); vput(res_vnode); return -EEXIST; } /*vput(res_vnode2);*/ err3=res_vnode2->vn_ops->link(res_vnode,res_vnode2,name,len); dbg(DBG_PRINT,"(GRADING2C 1.h) (vfs_syscall.c) (do_link) Link created\n"); vput(res_vnode2); vput(res_vnode); return err3; /* NOT_YET_IMPLEMENTED("VFS: do_link"); return -1;*/ }
/* Use dir_namev() to find the vnode of the dir we want to make the new * directory in. Then use lookup() to make sure it doesn't already exist. * Finally call the dir's mkdir vn_ops. Return what it returns. * * Error cases you must handle for this function at the VFS level: * o EEXIST * path already exists. * o ENOENT * A directory component in path does not exist. * o ENOTDIR * A component used as a directory in path is not, in fact, a directory. * o ENAMETOOLONG * A component of path was too long. */ int do_mkdir(const char *path) { /*NOT_YET_IMPLEMENTED("VFS: do_mkdir");*/ dbg(DBG_PRINT, "(GRADING2B)\n"); size_t namelen = 0; const char *name; vnode_t *base; vnode_t *res_vnode, *result; /* if (strlen(path) > MAXPATHLEN){ dbg(DBG_ERROR,"1\n"); return -ENAMETOOLONG; }*/ /* Base passed NULL since dir_namev can handle accordingly */ int retdir_namev = dir_namev(path, &namelen, &name, NULL, &res_vnode); if (strlen(name) > NAME_LEN) { dbg(DBG_PRINT, "(GRADING2B)\n"); if (retdir_namev == 0) { dbg(DBG_PRINT, "(GRADING2B)\n"); } return -ENAMETOOLONG; } if (retdir_namev == 0) { dbg(DBG_PRINT, "(GRADING2B)\n"); int retlookup = lookup(res_vnode, name, namelen, &result); if (retlookup == 0) { dbg(DBG_PRINT, "(GRADING2B)\n"); vput(result); vput(res_vnode); return -EEXIST; } if (retlookup == -ENOENT) { dbg(DBG_PRINT, "(GRADING2B)\n"); KASSERT(NULL != (res_vnode)->vn_ops->mkdir); dbg(DBG_PRINT, "(GRADING2A 3.c)\n"); int ramfs_ret = (res_vnode)->vn_ops->mkdir(res_vnode, name, namelen); vput(res_vnode); return ramfs_ret; } if (retlookup == -ENOTDIR) { vput(res_vnode); return -ENOTDIR; } } else { dbg(DBG_PRINT, "(GRADING2B)\n"); return retdir_namev; } return 0; }
/* * This routine creates a special file of the type specified by 'mode' at * the location specified by 'path'. 'mode' should be one of S_IFCHR or * S_IFBLK (you might note that mknod(2) normally allows one to create * regular files as well-- for simplicity this is not the case in Weenix). * 'devid', as you might expect, is the device identifier of the device * that the new special file should represent. * * You might use a combination of dir_namev, lookup, and the fs-specific * mknod (that is, the containing directory's 'mknod' vnode operation). * Return the result of the fs-specific mknod, or an error. * * Error cases you must handle for this function at the VFS level: * o EINVAL * mode requested creation of something other than a device special * file. * o EEXIST * path already exists. * o ENOENT * A directory component in path does not exist. * o ENOTDIR * A component used as a directory in path is not, in fact, a directory. * o ENAMETOOLONG * A component of path was too long. */ int do_mknod(const char *path, int mode, unsigned devid) { if (mode !=S_IFBLK && mode !=S_IFCHR) { dbg(DBG_PRINT,"(GRADING2B) The special file is neither Block device nor character device\n"); dbg(DBG_ERROR, "Mode specified is wrong\n"); return -EINVAL; } if (strlen(path) > MAXPATHLEN) { dbg(DBG_PRINT,"(GRADING2B) Path length exceeds maximum path length that is allowed\n"); dbg(DBG_ERROR, "Path length exceeding maximum path length\n"); return -ENAMETOOLONG; } size_t namelen =0; const char *name = NULL; vnode_t *res_vnode = NULL; int dir_value = dir_namev(path, &namelen, &name, NULL, &res_vnode); if (dir_value<0) { dbg(DBG_PRINT,"(GRADING2B) Error in acquiring the vnode, name and name length of the path specified\n"); dbg(DBG_ERROR, "Error in calling dir_namev function\n"); return dir_value; } vput(res_vnode); int result=lookup(res_vnode,name, namelen, &res_vnode); KASSERT(NULL != res_vnode->vn_ops->mknod); dbg(DBG_PRINT,"(GRADING2A 3.b) res_vnode->vn_ops is not NULL\n"); if (result==0) { dbg(DBG_PRINT,"(GRADING2B) The given path already exists\n"); dbg(DBG_ERROR, "Path already exists\n"); vput(res_vnode); return -EEXIST; } if (result == -ENOENT) { dbg(DBG_PRINT,"(GRADING2B) There is no entry for the particular file\n"); dbg(DBG_PRINT, "No entry for that particular file\n"); /*vput(res_vnode);*/ int res = res_vnode->vn_ops->mknod(res_vnode,name,namelen,mode,devid); return res; } return 0; /*NOT_YET_IMPLEMENTED("VFS: do_mknod"); return -1;*/ }
/* Use dir_namev() to find the vnode of the directory containing the dir to be * removed. Then call the containing dir's rmdir v_op. The rmdir v_op will * return an error if the dir to be removed does not exist or is not empty, so * you don't need to worry about that here. Return the value of the v_op, * or an error. * * Error cases you must handle for this function at the VFS level: * o EINVAL * path has "." as its final component. * o ENOTEMPTY * path has ".." as its final component. * o ENOENT * A directory component in path does not exist. * o ENOTDIR * A component used as a directory in path is not, in fact, a directory. * o ENAMETOOLONG * A component of path was too long. */ int do_rmdir(const char *path) { /* NOT_YET_IMPLEMENTED("VFS: do_rmdir"); */ size_t namelen; const char *name; vnode_t *base; vnode_t *res_vnode, *result; int tempLookup = 0; dbg(DBG_PRINT, "(GRADING2B)\n"); /* if (strlen(path) > MAXPATHLEN) { dbg(DBG_ERROR, "1\n"); return -ENAMETOOLONG; }*/ /* Base passed NULL since dir_namev can handle accordingly */ int retdir_namev = dir_namev(path, &namelen, &name, NULL, &res_vnode); if (retdir_namev != 0) { dbg(DBG_PRINT, "(GRADING2B)\n"); return retdir_namev; } if (name_match(".", name, namelen)) { dbg(DBG_PRINT, "(GRADING2B)\n"); vput(res_vnode); return -EINVAL; } if (name_match("..", name, namelen)) { dbg(DBG_PRINT, "(GRADING2B)\n"); vput(res_vnode); return -ENOTEMPTY; } if (strlen(name) > NAME_LEN) { dbg(DBG_ERROR, "5\n"); vput(res_vnode); return -ENAMETOOLONG; } if (0 == retdir_namev) { dbg(DBG_PRINT, "(GRADING2B)\n"); vput(res_vnode); tempLookup = lookup(res_vnode, name, namelen, &result); KASSERT(NULL != (res_vnode)->vn_ops->rmdir); dbg(DBG_PRINT, "(GRADING2A 3.d)\n"); int ret_rmdir = (res_vnode)->vn_ops->rmdir(res_vnode, name, namelen); if (ret_rmdir == 0 && result != NULL) { dbg(DBG_PRINT, "(GRADING2B)\n"); vput(result); } else if (tempLookup == 0 && result != NULL) { dbg(DBG_PRINT, "(GRADING2B)\n"); vput(result); } return ret_rmdir; } return 0; }
/* * Same as do_rmdir, but for files. * * Error cases you must handle for this function at the VFS level: * o EISDIR * path refers to a directory. * o ENOENT * A component in path does not exist. * o ENOTDIR * A component used as a directory in path is not, in fact, a directory. * o ENAMETOOLONG * A component of path was too long. */ int do_unlink(const char *path) { /*NOT_YET_IMPLEMENTED("VFS: do_unlink");*/ if (strlen(path) > MAXPATHLEN){ return -ENAMETOOLONG; } vnode_t *parent_vnode,*child_vnode; int child_retVal,parent_retVal; size_t namelen; const char *name; dir_namev(path,&namelen,&name,NULL,&parent_vnode); parent_retVal = dir_namev(path,&namelen,&name,NULL,&parent_vnode); if (parent_retVal) { return parent_retVal; } child_retVal = lookup(parent_vnode,name,namelen,&child_vnode); if (child_retVal){ vput(parent_vnode); dbg(DBG_PRINT,"(GRADING2B)\n"); return child_retVal; } if (S_ISDIR(child_vnode->vn_mode)){ vput(parent_vnode); vput(child_vnode); dbg(DBG_PRINT,"(GRADING2B)\n"); return -EISDIR; } KASSERT(NULL != parent_vnode->vn_ops->unlink); dbg(DBG_PRINT,"(GRADING2A 3.e)\n"); vput(parent_vnode); vput(child_vnode); return parent_vnode->vn_ops->unlink(parent_vnode,name,namelen); }
/* * Same as do_rmdir, but for files. * * Error cases you must handle for this function at the VFS level: * o EISDIR * path refers to a directory. * o ENOENT * A component in path does not exist. * o ENOTDIR * A component used as a directory in path is not, in fact, a directory. * o ENAMETOOLONG * A component of path was too long. */ int do_unlink(const char *path) { size_t len=0; const char *name=NULL; vnode_t *rest=NULL,*result=NULL; int dir_name_out,rem,ent; /*if(strlen(path)>MAXPATHLEN) { dbg(DBG_PRINT,"(GRADING2C) (vfs_syscall.c) (do_unlink) Path greater than MAXPATHLEN, return -ENAMETOOLONG\n"); return -ENAMETOOLONG; }*/ dir_name_out=dir_namev(path,&len,&name,NULL,&rest); if(dir_name_out<0) { dbg(DBG_PRINT,"(GRADING2B) error returned from dir_namev, return error \n"); return dir_name_out; } /*Alekhya: If the vnode itself does not exist, or the vnode does not refer to a directory*/ if(rest==NULL || !(S_ISDIR(rest->vn_mode))) { vput(rest); dbg(DBG_PRINT,"(GRADING2C 1.f) It is not a directory, return -ENOTDIR"); return -ENOTDIR; } ent=lookup(rest,name,len,&result); if(ent<0) { dbg(DBG_PRINT,"(GRADING2B)error returned from lookup(cannot find it) so dec ref count, return error \n"); vput(rest); return ent; } if(S_ISDIR(result->vn_mode)) { vput(rest); vput(result); dbg(DBG_PRINT,"(GRADING2B)Is a directory cannot link directory, decrease ref count, return -EISDIR\n"); return -EISDIR; } /*Alekhya: If error free, call rmdir*/ KASSERT(NULL != rest->vn_ops->unlink); dbg(DBG_PRINT,"(GRADING2A 3.e)(middle)KASSERT(NULL != /* pointer to corresponding vnode */->vn_ops->unlink);\n"); rem=rest->vn_ops->unlink(rest,name,len); vput(rest); vput(result); return rem; /* NOT_YET_IMPLEMENTED("VFS: do_unlink"); return -1;*/ }
/* Use dir_namev() to find the vnode of the directory containing the dir to be * removed. Then call the containing dir's rmdir v_op. The rmdir v_op will * return an error if the dir to be removed does not exist or is not empty, so * you don't need to worry about that here. Return the value of the v_op, * or an error. * * Error cases you must handle for this function at the VFS level: * o EINVAL * path has "." as its final component. * o ENOTEMPTY * path has ".." as its final component. * o ENOENT * A directory component in path does not exist. * o ENOTDIR * A component used as a directory in path is not, in fact, a directory. * o ENAMETOOLONG * A component of path was too long. */ int do_rmdir(const char *path) { size_t len=0; const char *name=NULL; vnode_t *rest=NULL; int dir_name_out,rem; /*Note: return error numbers in this function so can be used directly*/ dir_name_out=dir_namev(path,&len,&name,NULL,&rest); /*Andy:path has "." as its final component. */ if(dir_name_out<0) { dbg(DBG_PRINT,"(GRADING2B) error returned from dir_namev, return error \n"); return dir_name_out; } if(strcmp(name,".")==0){ dbg(DBG_PRINT,"(GRADING2B) name is . ,cannot remove, return -EINVAL\n"); vput(rest); return -EINVAL; } /*Andy:path has ".." as its final component. */ if(strcmp(name,"..")==0){ dbg(DBG_PRINT,"(GRADING2B) name is .. ,cannot remove, return -ENOTEMPTY\n"); vput(rest); return -ENOTEMPTY; } /*Add a self check test for this*/ /*if(strlen(path)>MAXPATHLEN) { dbg(DBG_PRINT,"(GRADING2C) (vfs_syscall.c) (do_rmdir) Path is greater than max path length, return -ENAMETOOLONG\n"); vput(rest); return -ENAMETOOLONG; }*/ /*Alekhya: The rest of the errors are handled inside this function*/ /*Alekhya: If the vnode itself does not exist, or the vnode does not refer to a directory*/ if(rest==NULL || !(S_ISDIR(rest->vn_mode))) { vput(rest); dbg(DBG_PRINT,"(GRADING2B) It is not a directory can only remove directory, return -ENOTDIR"); return -ENOTDIR; } /*Alekhya: If error free, call rmdir*/ KASSERT(NULL != rest->vn_ops->rmdir); dbg(DBG_PRINT,"(GRADING2A 3.d)(middle)KASSERT(NULL != /* pointer to corresponding vnode */->vn_ops->rmdir);\n"); rem=rest->vn_ops->rmdir(rest,name,len); vput(rest); return rem; /* NOT_YET_IMPLEMENTED("VFS: do_rmdir"); return -1;*/ }
/* Use dir_namev() to find the vnode of the dir we want to make the new * directory in. Then use lookup() to make sure it doesn't already exist. * Finally call the dir's mkdir vn_ops. Return what it returns. * * Error cases you must handle for this function at the VFS level: * o EEXIST * path already exists. * o ENOENT * A directory component in path does not exist. * on ENOTDIR * A component used as a directory in path is not, in fact, a directory. * o ENAMETOOLONG * A component of path was too long. */ int do_mkdir(const char *path) { if (strlen(path) > MAXPATHLEN) { dbg(DBG_PRINT,"(GRADING2B) path length exceeds the maximum path length limit\n"); dbg(DBG_ERROR, "Path length exceeding maximum path length\n"); return -ENAMETOOLONG; } size_t namelen; const char *name; vnode_t *res_vnode; int dir_value = dir_namev(path, &namelen, &name, NULL, &res_vnode); if (dir_value<0 ) { dbg(DBG_PRINT,"(GRADING2B) Error in calling dir_namev function\n"); dbg(DBG_ERROR, "Error in calling dir_namev function\n"); return dir_value; } vput(res_vnode); int result=lookup(res_vnode,name, namelen, &res_vnode); dbg(DBG_PRINT,"(GRADING2A 3.c) res_vnode->vn_ops is not NULL\n"); if (result==-ENOTDIR) { dbg(DBG_PRINT,"(GRADING2B) A component used as a directory in path is not, in fact, a directory\n"); dbg(DBG_ERROR, "A component used as a directory in path is not, in fact, a directory\n"); return -ENOTDIR; } if (result==0) { dbg(DBG_PRINT,"(GRADING2B) Specified path already exists\n"); dbg(DBG_ERROR, "Path already exists\n"); vput(res_vnode); return -EEXIST; } if (result == -ENOENT) { KASSERT(NULL != res_vnode->vn_ops->mkdir); dbg(DBG_PRINT,"(GRADING2B) No entry for this file\n"); dbg(DBG_PRINT,"No entry for that particular file\n"); /*vput(res_vnode);*/ return res_vnode->vn_ops->mkdir(res_vnode,name,namelen); } return 0; /*NOT_YET_IMPLEMENTED("VFS: do_mkdir"); return -1;*/ }
/* * This routine creates a special file of the type specified by 'mode' at * the location specified by 'path'. 'mode' should be one of S_IFCHR or * S_IFBLK (you might note that mknod(2) normally allows one to create * regular files as well-- for simplicity this is not the case in Weenix). * 'devid', as you might expect, is the device identifier of the device * that the new special file should represent. * * You might use a combination of dir_namev, lookup, and the fs-specific * mknod (that is, the containing directory's 'mknod' vnode operation). * Return the result of the fs-specific mknod, or an error. * * Error cases you must handle for this function at the VFS level: * o EINVAL * mode requested creation of something other than a device special * file. * o EEXIST * path already exists. * o ENOENT * A directory component in path does not exist. * o ENOTDIR * A component used as a directory in path is not, in fact, a directory. * o ENAMETOOLONG * A component of path was too long. */ int do_mknod(const char *path, int mode, unsigned devid) { /*NOT_YET_IMPLEMENTED("VFS: do_mknod");*/ if (strlen(path) > MAXPATHLEN){ return -ENAMETOOLONG; } if ((mode != S_IFCHR) && (mode != S_IFBLK)){ return -EINVAL; } vnode_t *parent_vnode,*child_vnode; int parent_retVal,child_retVal; size_t namelen; const char *name; parent_retVal = dir_namev(path,&namelen,&name,NULL,&parent_vnode); if (parent_retVal){ return parent_retVal; } child_retVal = lookup(parent_vnode,name,namelen,&child_vnode); if (!child_retVal){ vput(parent_vnode); vput(child_vnode); return -EEXIST; } else { if (child_retVal == -ENOENT){ if (!S_ISDIR(parent_vnode->vn_mode)){ vput(parent_vnode); return -ENOTDIR; } KASSERT(NULL != parent_vnode->vn_ops->mknod); dbg(DBG_PRINT,"(GRADING2A 3.b)\n"); vput(parent_vnode); return parent_vnode->vn_ops->mknod(parent_vnode,name,namelen,mode,devid); } } vput(parent_vnode); return child_retVal; /*Comment the code below if any of the above code is uncommented - AS*/ /*dir_namev(path,&namelen,&name,NULL,&parent_vnode); KASSERT(NULL != parent_vnode->vn_ops->mknod); lookup(parent_vnode,name,namelen,&child_vnode); dbg(DBG_PRINT,"(GRADING2A 3.b)\n"); vput(parent_vnode); return parent_vnode->vn_ops->mknod(parent_vnode,name,namelen,mode,devid);*/ }
/* Make the named directory the current process's cwd (current working * directory). Don't forget to down the refcount to the old cwd (vput()) and * up the refcount to the new cwd (open_namev() or vget()). Return 0 on * success. * * Error cases you must handle for this function at the VFS level: * o ENOENT * path does not exist. * o ENAMETOOLONG * A component of path was too long. * o ENOTDIR * A component of path is not a directory. */ int do_chdir(const char *path) { /*NOT_YET_IMPLEMENTED("VFS: do_chdir");*/ if (strlen(path) > MAXPATHLEN){ return -ENAMETOOLONG; } int child_retVal,parent_retVal; vnode_t *parent_vnode,*child_vnode; size_t namelen; const char *name; dir_namev(path,&namelen,&name,NULL,&parent_vnode); parent_retVal = dir_namev(path,&namelen,&name,NULL,&parent_vnode); if (parent_retVal){ return parent_retVal; } child_retVal = lookup(parent_vnode,name,namelen,&child_vnode); if (child_retVal){ vput(parent_vnode); dbg(DBG_PRINT,"(GRADING2B)\n"); return child_retVal; } if (!S_ISDIR(child_vnode->vn_mode)){ vput(parent_vnode); vput(child_vnode); dbg(DBG_PRINT,"(GRADING2B)\n"); return -ENOTDIR; } vput(parent_vnode); vput(curproc->p_cwd); curproc->p_cwd = child_vnode; return 0; }
/* To link: * o open_namev(from) * o dir_namev(to) * o call the destination dir's (to) link vn_ops. * o return the result of link, or an error * * Remember to vput the vnodes returned from open_namev and dir_namev. * * Error cases you must handle for this function at the VFS level: * o EEXIST * to already exists. * o ENOENT * A directory component in from or to does not exist. * o ENOTDIR * A component used as a directory in from or to is not, in fact, a * directory. * o ENAMETOOLONG * A component of from or to was too long. * o EISDIR * from is a directory. */ int do_link(const char *from, const char *to) { /*NOT_YET_IMPLEMENTED("VFS: do_link");*/ vnode_t *from_vn, *to_result; size_t to_namelen; const char *to_name; vnode_t *to_vn; int to_retdir_namev, to_retlookup; open_namev(from, O_RDONLY, &from_vn, NULL); dbg(DBG_PRINT, "(GRADING3D 2)\n"); /*if (ret_namev < 0) { dbg(DBG_ERROR, "2\n"); return ret_namev; }*/ if (S_ISDIR((from_vn)->vn_mode)) { dbg(DBG_PRINT, "(GRADING3D 2)\n"); vput(from_vn); return -EISDIR; } to_retdir_namev = dir_namev(to, &to_namelen, &to_name, NULL, &to_vn); if (to_retdir_namev < 0) { dbg(DBG_PRINT, "(GRADING3D 2)\n"); vput(from_vn); return to_retdir_namev; } /*if (to_vn->vn_ops->link == NULL) { dbg(DBG_ERROR, "5\n"); return -ENOTDIR; }*/ to_retlookup = lookup(to_vn, to_name, to_namelen, &to_result); if (to_retlookup == 0) { dbg(DBG_PRINT, "(GRADING3D 2)\n"); vput(to_result); return -EEXIST; } else { dbg(DBG_PRINT, "(GRADING3D 2)\n"); int to_retlink = to_vn->vn_ops->link(from_vn, to_vn, to_name, to_namelen); vput(to_vn); vput(from_vn); return to_retlink; } return -1; }
/* * Find the vnode associated with the path, and call the stat() vnode operation. * * Error cases you must handle for this function at the VFS level: * o ENOENT * A component of path does not exist. * o ENOTDIR * A component of the path prefix of path is not a directory. * o ENAMETOOLONG * A component of path was too long. */ int do_stat(const char *path, struct stat *buf) { if(strlen(path) > MAXPATHLEN) { dbg(DBG_PRINT,"(GRADING2B) A component in the path specified is too long\n"); return -ENAMETOOLONG; } if(strlen(path) <= 0) { dbg(DBG_PRINT, "(GRADING2B) do_stat(): Path specified is not a valid path\n"); return -EINVAL; } size_t namelen; const char *name; vnode_t *res_vnode; int ret_val =0; ret_val = dir_namev(path,&namelen,&name,NULL,&res_vnode); if(ret_val<0) { dbg(DBG_PRINT, "(GRADING2B) Error accessing dir_namev\n"); return ret_val; } if(!S_ISDIR(res_vnode->vn_mode)) { vput(res_vnode); dbg(DBG_PRINT, "(GRADING2B) given Path is not a directory\n"); return -ENOTDIR; } vput(res_vnode); ret_val = lookup(res_vnode,name,namelen,&res_vnode); if(ret_val < 0) { dbg(DBG_PRINT, "(GRADING2B) Error in Lookup function\n"); dbg(DBG_ERROR, "do_stat(): Error while returning from lookup()\n"); return ret_val; } KASSERT(NULL != res_vnode->vn_ops->stat); dbg(DBG_PRINT, "(GRADING2A 3.f) do_stat(): function pointer to stat exists\n"); vput(res_vnode); return res_vnode->vn_ops->stat(res_vnode,buf); /*NOT_YET_IMPLEMENTED("VFS: do_stat"); return -1;*/ }
/* This returns in res_vnode the vnode requested by the other parameters. * It makes use of dir_namev and lookup to find the specified vnode (if it * exists). flag is right out of the parameters to open(2); see * <weenix/fcntl.h>. If the O_CREAT flag is specified, and the file does * not exist call create() in the parent directory vnode. * * Note: Increments vnode refcount on *res_vnode. */ int open_namev(const char *pathname, int flag, vnode_t **res_vnode, vnode_t *base) { /* TODO: Kernel#2 open_namev done NOT_YET_IMPLEMENTED("VFS: open_namev done"); */ dbg(DBG_PRINT,"(GRADING2B)\n"); size_t length; char *name; vnode_t *parentDir; int retval = dir_namev(pathname, &length, (const char**)&name, base, &parentDir); if(retval >= 0){ dbg(DBG_PRINT,"(GRADING2B)\n"); retval = lookup(parentDir, name, length, res_vnode); if(retval >= 0){/* found file, open successfully. */ vput(parentDir); dbg(DBG_PRINT,"(GRADING2B)\n"); return retval; }else{ dbg(DBG_PRINT,"(GRADING2B)\n"); if((retval == -ENOENT)){/* create file */ dbg(DBG_PRINT,"(GRADING2B)\n"); if(!(flag & O_CREAT)){ dbg(DBG_PRINT,"(GRADING2B)\n"); vput(parentDir); return -ENOENT; } if((retval == -ENOENT) && (flag & O_CREAT)){ KASSERT(NULL != parentDir->vn_ops->create); dbg(DBG_PRINT,"(GRADING2A 2.c)\n"); dbg(DBG_PRINT,"(GRADING2B)\n"); } dbg(DBG_PRINT,"(GRADING2B)\n"); retval = parentDir->vn_ops->create(parentDir, name, length, res_vnode); vput(parentDir); return retval; }else{/* failed */ dbg(DBG_PRINT,"(GRADING2B)\n"); vput(parentDir); return retval; } } }else{ dbg(DBG_PRINT,"(GRADING2B)\n"); return retval; } }
/* To link: * o open_namev(from) * o dir_namev(to) * o call the destination dir's (to) link vn_ops. * o return the result of link, or an error * * Remember to vput the vnodes returned from open_namev and dir_namev. * * Error cases you must handle for this function at the VFS level: * o EEXIST * to already exists. * o ENOENT * A directory component in from or to does not exist. * o ENOTDIR * A component used as a directory in from or to is not, in fact, a * directory. * o ENAMETOOLONG * A component of from or to was too long. * o EISDIR * from is a directory. */ int do_link(const char *from, const char *to) { /*NOT_YET_IMPLEMENTED("VFS: do_link"); return -1;*/ const char *name; size_t name_len; int ret; vnode_t *from_vnode,*to_p_vnode,*to_vnode; if(from == NULL || to == NULL) { dbg(DBG_PRINT,"(GRADING2D)\n"); return -EINVAL; } if(strlen(from)>MAXPATHLEN || strlen(to)>MAXPATHLEN) { dbg(DBG_PRINT,"(GRADING2D)\n"); return -ENAMETOOLONG; } if ((ret = open_namev(from,NULL,&from_vnode,NULL))<0) { dbg(DBG_PRINT,"(GRADING2D)\n"); return ret; } vput(from_vnode); if ((ret = dir_namev(to,&name_len,&name,NULL,&to_p_vnode))<0) { dbg(DBG_PRINT,"(GRADING2D)\n"); return ret; } vput(to_p_vnode); if (S_ISDIR(from_vnode->vn_mode)) { dbg(DBG_PRINT,"(GRADING2D)\n"); return -EISDIR; } if ((ret = lookup(to_p_vnode,name,name_len,&to_vnode) )== 0) { dbg(DBG_PRINT,"(GRADING2D)\n"); vput(to_vnode); return -EEXIST; } return to_p_vnode->vn_ops->link(from_vnode,to_p_vnode,name,name_len); }
/* Use dir_namev() to find the vnode of the dir we want to make the new * directory in. Then use lookup() to make sure it doesn't already exist. * Finally call the dir's mkdir vn_ops. Return what it returns. * * Error cases you must handle for this function at the VFS level: * o EEXIST * path already exists. * o ENOENT * A directory component in path does not exist. * o ENOTDIR * A component used as a directory in path is not, in fact, a directory. * o ENAMETOOLONG * A component of path was too long. */ int do_mkdir(const char *path) { /*NOT_YET_IMPLEMENTED("VFS: do_mkdir");*/ if (strlen(path) > MAXPATHLEN){ return -ENAMETOOLONG; } vnode_t *parent_vnode,*child_vnode; int parent_retVal,child_retVal; size_t namelen; const char *name; parent_retVal = dir_namev(path,&namelen,&name,NULL,&parent_vnode); if (parent_retVal) { dbg(DBG_PRINT,"(GRADING2B)\n"); return parent_retVal; } child_retVal = lookup(parent_vnode,name,namelen,&child_vnode); if (!child_retVal){ vput(parent_vnode); vput(child_vnode); dbg(DBG_PRINT,"(GRADING2B)\n"); return -EEXIST; } else { if (child_retVal == -ENOENT){ if (!S_ISDIR(parent_vnode->vn_mode)){ vput(parent_vnode); return -ENOTDIR; } KASSERT(NULL != parent_vnode->vn_ops->mkdir); dbg(DBG_PRINT,"(GRADING2A 3.c)\n"); vput(parent_vnode); return parent_vnode->vn_ops->mkdir(parent_vnode,name,namelen); } } dbg(DBG_PRINT,"(GRADING2B)\n"); vput(parent_vnode); return child_retVal; }
/* This returns in res_vnode the vnode requested by the other parameters. * It makes use of dir_namev and lookup to find the specified vnode (if it * exists). flag is right out of the parameters to open(2); see * <weenix/fcntl.h>. If the O_CREAT flag is specified, and the file does * not exist call create() in the parent directory vnode. * * Note: Increments vnode refcount on *res_vnode. */ int open_namev(const char *pathname, int flag, vnode_t **res_vnode, vnode_t *base) { /* NOT_YET_IMPLEMENTED("VFS: open_namev"); */ const char *named = NULL; size_t len = 0; vnode_t *res_vnode1; int ret_val = dir_namev(pathname, &len,&named,base, &res_vnode1); if (ret_val != 0) { dbg(DBG_ERROR, "dir not found\n"); dbg(DBG_PRINT,"(GRADING2B) dir not found \n"); return ret_val; } int ret_val1 = lookup(res_vnode1,named,len,res_vnode); if (ret_val1 < 0) { if (flag & O_CREAT) { dbg(DBG_ERROR,"file not found but O_CREAT flag is on \n"); dbg(DBG_PRINT,"(GRADING2B) file not found but O_CREAT flag is on \n"); KASSERT(NULL != res_vnode1->vn_ops->create); dbg(DBG_PRINT,"(GRADING2A 2.c) new file can be created\n"); int ret_val2 = res_vnode1->vn_ops->create(res_vnode1,named,len,res_vnode); if (ret_val2 < 0) { dbg(DBG_PRINT, "(GRADING2C) Cannot create the file\n"); vput(res_vnode1); return ret_val2; } } else { dbg(DBG_PRINT, "(GRADING2B) Could not find the file \n"); vput(res_vnode1); return ret_val1; } } dbg(DBG_PRINT, "(GRADING2B) File with the given name alredy exists\n"); vput(res_vnode1); return 0; }
/* Use dir_namev() to find the vnode of the directory containing the dir to be * removed. Then call the containing dir's rmdir v_op. The rmdir v_op will * return an error if the dir to be removed does not exist or is not empty, so * you don't need to worry about that here. Return the value of the v_op, * or an error. * * Error cases you must handle for this function at the VFS level: * o EINVAL * path has "." as its final component. * o ENOTEMPTY * path has ".." as its final component. * o ENOENT * A directory component in path does not exist. * o ENOTDIR * A component used as a directory in path is not, in fact, a directory. * o ENAMETOOLONG * A component of path was too long. */ int do_rmdir(const char *path) { /*NOT_YET_IMPLEMENTED("VFS: do_rmdir");*/ if (strlen(path) > MAXPATHLEN){ return -ENAMETOOLONG; } vnode_t *parent_vnode; int parent_retVal; size_t namelen; const char *name; parent_retVal = dir_namev(path,&namelen,&name,NULL,&parent_vnode); if (parent_retVal) { dbg(DBG_PRINT,"(GRADING2B)\n"); return parent_retVal; } if (!strcmp(name,".")){ vput(parent_vnode); dbg(DBG_PRINT,"(GRADING2B)\n"); return -EINVAL; } if (!strcmp(name,"..")){ vput(parent_vnode); dbg(DBG_PRINT,"(GRADING2B)\n"); return -ENOTEMPTY; } if (!S_ISDIR(parent_vnode->vn_mode)){ vput(parent_vnode); dbg(DBG_PRINT,"(GRADING2B)\n"); return -ENOTDIR; } KASSERT(NULL != parent_vnode->vn_ops->rmdir); dbg(DBG_PRINT,"(GRADING2A 3.d)\n"); vput(parent_vnode); return parent_vnode->vn_ops->rmdir(parent_vnode,name,namelen); }
/* * Find the vnode associated with the path, and call the stat() vnode operation. * * Error cases you must handle for this function at the VFS level: * o ENOENT * A component of path does not exist. * o ENOTDIR * A component of the path prefix of path is not a directory. * o ENAMETOOLONG * A component of path was too long. */ int do_stat(const char *path, struct stat *buf) { /*NOT_YET_IMPLEMENTED("VFS: do_stat");*/ if (strlen(path) > MAXPATHLEN){ return -ENAMETOOLONG; } int parent_retVal,file_retVal,retVal; vnode_t *parent_vnode,*file_vnode; size_t namelen; const char *name; parent_retVal = dir_namev(path,&namelen,&name,NULL,&parent_vnode); if (parent_retVal){ dbg(DBG_PRINT,"(GRADING2B)\n"); return parent_retVal; } file_retVal = lookup(parent_vnode,name,namelen,&file_vnode); if (file_retVal){ vput(parent_vnode); dbg(DBG_PRINT,"(GRADING2B)\n"); return file_retVal; } dbg(DBG_PRINT,"(GRADING2A 3.f)\n"); KASSERT(file_vnode->vn_ops->stat); retVal = file_vnode->vn_ops->stat(file_vnode,buf); vput(parent_vnode); vput(file_vnode); return retVal; }
/* To link: * o open_namev(from) * o dir_namev(to) * o call the destination dir's (to) link vn_ops. * o return the result of link, or an error * * Remember to vput the vnodes returned from open_namev and dir_namev. * * Error cases you must handle for this function at the VFS level: * o EEXIST * to already exists. * o ENOENT * A directory component in from or to does not exist. * o ENOTDIR * A component used as a directory in from or to is not, in fact, a * directory. * o ENAMETOOLONG * A component of from or to was too long. * o EISDIR * from is a directory. */ int do_link(const char *from, const char *to) { if((strlen(from) > MAXPATHLEN) || (strlen(to) > MAXPATHLEN)) { dbg(DBG_PRINT,"(GRADING2B) A component of from or to is too long\n"); dbg(DBG_ERROR, "do_link(): A component of from or to is too long\n"); return -ENAMETOOLONG; } if((strlen(from)) <= 0 || (strlen(to) <=0)) { dbg(DBG_PRINT,"(GRADING2B) A component of from or to is not valid\n"); dbg(DBG_ERROR, "do_link(): A component of from or to is not valid\n"); return -EINVAL; } size_t namelen; int dir_val; int open_val; const char *name; int res=0; int res_val =0; int val=0; vnode_t *old_vnode; vnode_t *res_vnode; /*old_vnode (from), res_vnode(to)*/ open_val= open_namev(from,0,&old_vnode,NULL); if(open_val < 0) { dbg(DBG_PRINT,"(GRADING2B) open_namev failed\n"); return open_val; } res_val = dir_namev(to,&namelen,&name,NULL,&res_vnode); if(res_val < 0) { vput(old_vnode); dbg(DBG_PRINT,"(GRADING2B) Error calling dir_namev\n"); dbg(DBG_ERROR, "do_link(): dir_namev failed\n"); return res_val; } vput(old_vnode); if(res_vnode->vn_ops->link == NULL) { dbg(DBG_PRINT,"(GRADING2B) open_namev failed\n"); return -ENOTDIR; } else if(lookup(res_vnode,name,namelen, &res_vnode) == 0) { dbg(DBG_PRINT,"(GRADING2B) given path already exists\n"); vput(res_vnode); return -EEXIST; } else { dbg(DBG_PRINT,"(GRADING2B) calling link function\n"); res = res_vnode->vn_ops->link(old_vnode,res_vnode,name,strlen(name)); vput(res_vnode); return res; } /*NOT_YET_IMPLEMENTED("VFS: do_link");*/ return -1; }
/* Use dir_namev() to find the vnode of the directory containing the dir to be * removed. Then call the containing dir's rmdir v_op. The rmdir v_op will * return an error if the dir to be removed does not exist or is not empty, so * you don't need to worry about that here. Return the value of the v_op, * or an error. * * Error cases you must handle for this function at the VFS level: * o EINVAL * path has "." as its final component. * o ENOTEMPTY * path has ".." as its final component. * o ENOENT * A directory component in path does not exist. * o ENOTDIR * A component used as a directory in path is not, in fact, a directory. * o ENAMETOOLONG * A component of path was too long. */ int do_rmdir(const char *path) { /*NOT_YET_IMPLEMENTED("VFS: do_rmdir"); return -1;*/ if(strlen(path)>MAXPATHLEN) { dbg(DBG_PRINT,"(GRADING2D)\n"); dbg(DBG_PRINT,"ERROR: do_rmkdir: ENAMETOOLONG. A component of path was too long.\n"); return -ENAMETOOLONG; } if(path == NULL) { dbg(DBG_PRINT,"(GRADING2D)\n"); dbg(DBG_PRINT,"ERROR: do_rmkdir: EINVAL. Mode requested creation of something other than a device special file.\n"); return -EINVAL; } size_t namelen=0; const char *name=NULL; vnode_t *res_vnode; vnode_t *result; int i=dir_namev(path, &namelen,&name,NULL,&res_vnode); if(i<0) { dbg(DBG_PRINT,"(GRADING2B)\n"); dbg(DBG_PRINT,"ERROR: do_rmkdir: Unable to resolve file path\n"); return i; } if(strlen(name)>NAME_LEN) { dbg(DBG_PRINT,"(GRADING2D)\n"); dbg(DBG_PRINT, "ERROR: do_rmkdir: A component of name was too long\n"); vput(res_vnode); return -ENAMETOOLONG; } if(res_vnode==NULL) { dbg(DBG_PRINT,"(GRADING2D)\n"); dbg(DBG_PRINT,"ERROR: do_rmkdir: A directory component in path does not exist.\n"); return -ENOENT; } else { dbg(DBG_PRINT,"(GRADING2B)\n"); if(!S_ISDIR(res_vnode->vn_mode)) { dbg(DBG_PRINT,"(GRADING2D)\n"); dbg(DBG_PRINT,"ERROR: do_rmkdir: A component used as a directory in path is not, in fact, a directory.\n"); vput(res_vnode); return -ENOTDIR; } } if(strcmp(name,".")==0) { dbg(DBG_PRINT,"(GRADING2B)\n"); dbg(DBG_PRINT,"ERROR: do_rmdir: Path has \'.\'as final component\n"); vput(res_vnode); return -EINVAL; } if(strcmp(name,"..")==0) { dbg(DBG_PRINT,"(GRADING2B)\n"); dbg(DBG_PRINT,"ERROR: do_rmdir: Path had \'..\' as final component\n"); vput(res_vnode); return -ENOTEMPTY; } KASSERT(NULL!=res_vnode->vn_ops->rmdir); i=(res_vnode->vn_ops->rmdir)(res_vnode,name,namelen); vput(res_vnode); dbg(DBG_VFS,"Directory remove successful. Path=%s\n",path); return i; }
/* * This routine creates a special file of the type specified by 'mode' at * the location specified by 'path'. 'mode' should be one of S_IFCHR or * S_IFBLK (you might note that mknod(2) normally allows one to create * regular files as well-- for simplicity this is not the case in Weenix). * 'devid', as you might expect, is the device identifier of the device * that the new special file should represent. * * You might use a combination of dir_namev, lookup, and the fs-specific * mknod (that is, the containing directory's 'mknod' vnode operation). * Return the result of the fs-specific mknod, or an error. * * Error cases you must handle for this function at the VFS level: * o EINVAL * mode requested creation of something other than a device special * file. * o EEXIST * path already exists. * o ENOENT * A directory component in path does not exist. * o ENOTDIR * A component used as a directory in path is not, in fact, a directory. * o ENAMETOOLONG * A component of path was too long. */ int do_mknod(const char *path, int mode, unsigned devid) { /*NOT_YET_IMPLEMENTED("VFS: do_mknod"); return -1;*/ if(strlen(path)>MAXPATHLEN) { dbg(DBG_PRINT,"(GRADING2D)\n"); dbg(DBG_PRINT,"ERROR: do_mknod: ENAMETOOLONG. A component of path was too long.\n"); return -ENAMETOOLONG; } if(path == NULL) { dbg(DBG_PRINT,"(GRADING2D)\n"); dbg(DBG_PRINT,"ERROR: do_mknod: EINVAL. Mode requested creation of something other than a device special file.\n"); return -EINVAL; } if(mode!=S_IFCHR&&mode!=S_IFBLK) { dbg(DBG_PRINT,"(GRADING2D)\n"); dbg(DBG_PRINT,"ERROR: do_mknod: EINVAL. Invalid mode.Mode requested creation of something other than a device special file.\n"); return -EINVAL; } size_t namelen=0; const char *name=NULL; vnode_t *res_vnode; vnode_t *result; int i=dir_namev(path, &namelen,&name,NULL,&res_vnode); if(i<0) { dbg(DBG_PRINT,"(GRADING2D)\n"); dbg(DBG_PRINT,"ERROR: do_mknod: Unable to resolve file path\n"); return i; } if(strlen(name)>NAME_LEN) { dbg(DBG_PRINT,"(GRADING2D)\n"); dbg(DBG_PRINT, "ERROR: do_mknod: A component of name was too long\n"); vput(res_vnode); return -ENAMETOOLONG; } if(res_vnode==NULL) { dbg(DBG_PRINT,"(GRADING2D)\n"); dbg(DBG_PRINT,"ERROR: do_mknod: A directory component in path does not exist.\n"); return -ENOENT; } else { dbg(DBG_PRINT,"(GRADING2B)\n"); if(!S_ISDIR(res_vnode->vn_mode)) { dbg(DBG_PRINT,"(GRADING2D)\n"); dbg(DBG_PRINT,"ERROR: do_mknod: A component used as a directory in path is not, in fact, a directory.\n"); vput(res_vnode); return -ENOTDIR; } } if(name!=NULL) { dbg(DBG_PRINT,"(GRADING2B)\n"); int j=lookup(res_vnode,name,namelen,&result); if(j==0) { dbg(DBG_PRINT,"(GRADING2D)\n"); dbg(DBG_PRINT, "ERROR: do_mknod: Path already exists\n"); vput(res_vnode); vput(result); return -EEXIST; } } vput(res_vnode); KASSERT(NULL!=res_vnode->vn_ops->mknod); dbg(DBG_PRINT,"(GRADING2A 3.b)\n"); i=(res_vnode->vn_ops->mknod)(res_vnode,name,namelen,mode,devid); return i; }
/* * Same as do_rmdir, but for files. * * Error cases you must handle for this function at the VFS level: * o EISDIR * path refers to a directory. * o ENOENT * A component in path does not exist. * o ENOTDIR * A component used as a directory in path is not, in fact, a directory. * o ENAMETOOLONG * A component of path was too long. */ int do_unlink(const char *path) { /*NOT_YET_IMPLEMENTED("VFS: do_unlink"); return -1;*/ if(strlen(path)>MAXPATHLEN) { dbg(DBG_PRINT,"(GRADING2D)\n"); dbg(DBG_PRINT,"ERROR: do_unlink: Path is too long\n"); return -ENAMETOOLONG; } size_t namelen=0; const char *name=NULL; vnode_t *res_vnode; vnode_t *result; if(path == NULL) { dbg(DBG_PRINT,"(GRADING2D)\n"); dbg(DBG_PRINT,"ERROR: do_unlink: missing operand\n"); return -EINVAL; } int i=dir_namev(path, &namelen,&name,NULL,&res_vnode); if(i<0) { dbg(DBG_PRINT,"(GRADING2D)\n"); dbg(DBG_PRINT,"ERROR: do_unlink: Unable to resolve the path\n"); return i; } if(res_vnode==NULL) { dbg(DBG_PRINT,"(GRADING2D)\n"); dbg(DBG_PRINT,"ERROR: do_unlink: A component in path doesn't exist\n"); return -ENOENT; } else { dbg(DBG_PRINT,"(GRADING2B)\n"); if(!S_ISDIR(res_vnode->vn_mode)) { dbg(DBG_PRINT,"(GRADING2D)\n"); dbg(DBG_PRINT,"ERROR: do_unlink: A component in the path is not directory\n"); vput(res_vnode); return -ENOTDIR; } } if(strlen(name)>NAME_LEN) { dbg(DBG_PRINT,"(GRADING2D)\n"); dbg(DBG_PRINT, "ERROR: do_unlink: A component of name was too long\n"); vput(res_vnode); return -ENAMETOOLONG; } if(name!=NULL) { dbg(DBG_PRINT,"(GRADING2B)\n"); int j=lookup(res_vnode,name,namelen,&result); if(j!=0) { dbg(DBG_PRINT,"(GRADING2B)\n"); dbg(DBG_PRINT,"ERROR: do_unlink: Lookup for final component in the path fails\n"); vput(res_vnode); return j; } } if(result==NULL) { dbg(DBG_PRINT,"(GRADING2D)\n"); dbg(DBG_PRINT,"ERROR: do_unlink: Component in the path doesn't exist\n"); vput(res_vnode); return -ENOENT; } if(S_ISDIR(result->vn_mode)) { dbg(DBG_PRINT,"(GRADING2B)\n"); dbg(DBG_PRINT,"ERROR: do_unlink: Path refers to a directory\n"); vput(res_vnode); vput(result); return -EISDIR; } KASSERT(NULL!=res_vnode->vn_ops->unlink); dbg(DBG_PRINT,"(GRADING2A 3.e)\n"); i=(res_vnode->vn_ops->unlink)(res_vnode,name,namelen); vput(res_vnode); vput(result); return i; }