/* * 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) { vnode_t *tmp= NULL; int ret; if(buf == NULL || path==NULL) { dbg(DBG_PRINT,"(GRADING2D)\n"); return -EINVAL; } if(strlen(path)>MAXPATHLEN) { dbg(DBG_PRINT,"(GRADING2D)\n"); return -ENAMETOOLONG; } if ((ret = open_namev(path, NULL, &tmp, NULL)) < 0) { dbg(DBG_PRINT,"(GRADING2B)\n"); return ret; } ret = tmp->vn_ops->stat(tmp, buf); KASSERT(tmp->vn_ops->stat); dbg(DBG_PRINT, "(GRADING2A 3.f)\n"); vput(tmp); return ret; }
/* * 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 (path == NULL) { return -EINVAL; } vnode_t *result; int ret; ret = open_namev(path, 0, &result, NULL); if (ret){ return ret; } /* Corrected for kernel 3 */ /* vput(result); */ /* grading guideline required */ KASSERT(result->vn_ops->stat); dbg(DBG_PRINT,"(GRADING2A 3.f) The corresponding vnode has stat function. \n"); /* Corrected for kernel 3 */ int retVal = result->vn_ops->stat(result, buf); vput(result); return retVal; }
/* 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) { int ret; vnode_t *tmp; if(path == NULL || strlen(path)<1) { dbg(DBG_PRINT,"(GRADING2D)\n"); return -EINVAL; } if(strlen(path)>MAXPATHLEN) return -ENAMETOOLONG; if ((ret=open_namev(path, 0, &tmp, NULL))<0) { dbg(DBG_PRINT,"(GRADING2B)\n"); return ret; } if (!S_ISDIR(tmp->vn_mode)) { dbg(DBG_PRINT,"(GRADING2B)\n"); vput(tmp); return -ENOTDIR; } vput(curproc->p_cwd); curproc->p_cwd = tmp; 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; }
/* 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;*/ }
int do_chdir(const char *path) { /* NOT_YET_IMPLEMENTED("VFS: do_chdir"); */ /*GS: path should point to something */ KASSERT(path); dbg(DBG_PRINT, "(GRADING2C) (vfs_syscall.c) (do_chdir)\n"); /*GS: Check if a path too long. */ if(strlen(path) > MAXPATHLEN) { dbg(DBG_PRINT, "(GRADING2C 1.n) (vfs_syscall.c) (do_chdir) path too long, return -ENAMETOOLONG\n"); return -ENAMETOOLONG; } /*GS: This returns in newcwd the vnode requested by the other parameters. * and ups the refcount to the new cwd*/ vnode_t *newcwd = NULL; int retVal = open_namev(path, O_RDONLY, &newcwd, curproc->p_cwd); /* GS: NOTE! - need to confirm open_namev error values after implemented */ if( retVal < 0 ) { dbg(DBG_PRINT, "(GRADING2B) (vfs_syscall.c) (do_chdir) error open_namev, cannot open, return error\n"); return retVal; } /*GS: check if the path does not exist.*/ /*if( newcwd == NULL ) { dbg(DBG_PRINT, "(GRADING2C) (vfs_syscall.c) (do_chdir) path does not exist, return -ENOENT\n"); return -ENOENT; }*/ /*GS: Check if a component of path is not a directory.*/ if (!S_ISDIR(newcwd->vn_mode)) { /*GS: need to down the count back*/ vput(newcwd); dbg(DBG_PRINT, "(GRADING2B) component of path is not a directory, return -ENOTDIR\n"); return -ENOTDIR; } /*GS: Down the refcount to the old cwd - vput() */ vput(curproc->p_cwd); /*GS: Make the named directory the current process's cwd */ curproc->p_cwd = newcwd; vref(curproc->p_cwd); vput(newcwd); 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; }
/* 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); }
/* 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"); */ int retopen_namev=0; vnode_t *result; dbg(DBG_PRINT, "(GRADING2B)\n"); /*int retdir_namev;*/ /*if (strlen(path) > MAXPATHLEN){ dbg(DBG_ERROR, "1\n"); return -ENAMETOOLONG; }*/ /*retdir_namev =*/ /*if (strlen(name) > NAME_LEN) { dbg(DBG_ERROR, "2\n"); if (retdir_namev == 0) { dbg(DBG_ERROR, "3\n"); vput(res_vnode); } return -ENAMETOOLONG; } if (retdir_namev != 0) { dbg(DBG_ERROR, "4\n"); dbg(DBG_PRINT, "1chdir returns %d\n", retdir_namev); return retdir_namev; }*/ retopen_namev = open_namev(path, O_RDONLY, &result, NULL); if (retopen_namev < 0) { return retopen_namev; } if (!S_ISDIR(result->vn_mode)) { dbg(DBG_PRINT, "(GRADING2B)\n"); vput(result); return -ENOTDIR; } vput(curproc->p_cwd); curproc->p_cwd = result; dbg(DBG_PRINT, "(GRADING2B)\n"); return 0; }
/* 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) { if(strlen(path) > MAXPATHLEN) { dbg(DBG_PRINT,"(GRADING2B) one of the component in the path field is too long\n"); dbg(DBG_PRINT,"do_chdir(): one of the component in the path field is too long\n"); return -ENAMETOOLONG; } if(strlen(path) <= 0) { dbg(DBG_PRINT,"(GRADING2B) Invalid path name\n"); dbg(DBG_PRINT,"do_chdir(): Invalid path name\n"); return -EINVAL; } size_t namelen; char *name; vnode_t *res_vnode; int ret_val =0; ret_val = open_namev(path,0,&res_vnode,NULL); if(ret_val<0) { dbg(DBG_PRINT,"(GRADING2B) Error while accessing open_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(curproc->p_cwd); curproc->p_cwd = res_vnode; return 0; /*NOT_YET_IMPLEMENTED("VFS: do_chdir"); return -1;*/ }
/* 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) { size_t namelen=0; const char *name=NULL; vnode_t *base = NULL; vnode_t *res_vnode=NULL; KASSERT(path); int namev_ret = open_namev(path, 0, &res_vnode, NULL); if(namev_ret<0) { KASSERT(namev_ret<0); dbg(DBG_PRINT,"(GRADING2D 3.f): Path component has failed.\n"); return namev_ret; } if(!S_ISDIR(res_vnode->vn_mode)) { KASSERT(!S_ISDIR(res_vnode->vn_mode)); dbg(DBG_PRINT, "(GRADING2D 3.b): The path is not to a directory.\n"); vput(res_vnode); return -ENOTDIR; } KASSERT(res_vnode != NULL); /* Don't forget to down the refcount to the old cwd (vput()) and * up the refcount to the new cwd (open_namev() or vget()).*/ KASSERT(curproc != NULL); vput(curproc->p_cwd); curproc->p_cwd=res_vnode; /* Might need to increase the ref_count, but I think it should instead * happen inside lookup which gets called by open_namev.*/ /*vget(res_vnode->vn_fs,res_vnode->vn_vno);*/ dbg(DBG_PRINT, "(GRADING2D 3.i): Successfully changed directory.\n"); return 0; }
int do_stat(const char *path, struct stat *buf) { /* NOT_YET_IMPLEMENTED("VFS: do_stat");*/ /*GS: path should point to something */ KASSERT(path); /*GS: buf should point to something */ KASSERT(buf); int retVal = 0; /*GS: check if strlen too long*/ if( strlen(path) > MAXPATHLEN ) { dbg(DBG_PRINT, "(GRADING2C 1.l) (vfs_syscall.c) (do_stat) strlen too long, return -ENAMETOOLONG\n"); return -ENAMETOOLONG; } vnode_t *vnode; /*GS: return the vnode of the associated path */ retVal = open_namev(path, O_RDONLY, &vnode, NULL); if(retVal < 0) /*GS: NOTE! need to check what the return values are once implemented*/ { /*GS: ENOTDIR and ENOENT should both get caught here*/ dbg(DBG_PRINT, "(GRADING2B) (vfs_syscall.c) (do_stat) ENOTDIR or ENOENT\n"); return retVal; } /*GS: stat() should point to something */ KASSERT(NULL != vnode->vn_ops->stat); dbg(DBG_PRINT,"(GRADING2A 3.f) (middle) KASSERT(vnode->->vn_ops->stat)\n"); /*GS: call the stat() vnode operation*/ retVal = vnode->vn_ops->stat(vnode, buf); vput(vnode); return retVal; }
/* 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"); return -1; */ /*dbg(DBG_PRINT,"Entering do_chdir ****************************************\n"); */ int retvar; /* size_t namelen; const char *name; vnode_t *res_vnode; retvar = dir_namev(path,&namelen,&name,NULL,&res_vnode); */ /*dbg(DBG_PRINT,"(GRADING2C V41)\n"); */ vnode_t *res_vnode; retvar = open_namev(path,000,&res_vnode,NULL); if (retvar < 0) { /*vput(res_vnode); */ dbg(DBG_PRINT,"(GRADING2C)\n"); /*dbg(DBG_PRINT,"retvar %d Leaving do_chdir ****************************************\n",retvar); */ return retvar; } if(!S_ISDIR(res_vnode->vn_mode)) { vput(res_vnode); dbg(DBG_PRINT,"(GRADING2C)\n"); return -ENOTDIR; } vput(curproc->p_cwd); curproc->p_cwd = res_vnode; dbg(DBG_PRINT,"(GRADING2C)\n"); /*dbg(DBG_PRINT,"Leaving do_chdir ****************************************\n"); */ return 0; }
/* * 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"); */ vnode_t *result; int retopen_namev=0; /*size_t *namelen = (size_t) kalloc(sizeof(size_t)); const char **name = (char) kalloc(sizeof(char)); vnode_t **res_vnode = (vnode_t) kalloc(sizeof(vnode_t)); */ /*if (strlen(path) > MAXPATHLEN) { dbg(DBG_ERROR, "2\n"); return ENAMETOOLONG; }*/ /* Base passed NULL since dir_nameve can handle acccordingly */ /*if (retdir_namev != 0) { dbg(DBG_ERROR, "3\n"); return retdir_namev; } if (strlen(name) > NAME_LEN) { dbg(DBG_ERROR, "4\n"); vput(res_vnode); return -ENAMETOOLONG; }*/ if (path == NULL || buf == NULL || strlen(path) == 0) { dbg(DBG_PRINT, "(GRADING2B)\n"); return -EINVAL; } retopen_namev = open_namev(path, O_RDONLY, &result, NULL); if (retopen_namev < 0) { dbg(DBG_PRINT, "(GRADING2B)\n"); return retopen_namev; } retopen_namev = result->vn_ops->stat(result, buf); vput(result); return retopen_namev; }
/* 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"); */ int ret = 0; int flag = 0; /* Should this be 0 */ vnode_t *dir; vnode_t *temp = curproc->p_cwd; ret = open_namev(path, flag, &dir, NULL); if (ret == -ENOENT){ return -ENOENT; } if (ret == -ENOTDIR){ return -ENOTDIR; } /* ERROR!!! A component of filename was too long.*/ if (ret == -ENAMETOOLONG){ return -ENAMETOOLONG; } if (ret) { return ret; } if (dir->vn_mode != S_IFDIR) { vput(dir); return -ENOTDIR; } /*Since the change_dir has been successful, vput the old cwd.*/ vput(temp); curproc->p_cwd = dir; return 0; }
int do_open(const char *filename, int oflags) { /*NOT_YET_IMPLEMENTED("VFS: do_open");*/ if (oflags!=O_RDONLY && oflags!=O_WRONLY && oflags!=O_RDWR && oflags!=O_APPEND && oflags!= (O_RDONLY | O_CREAT) && oflags != (O_RDWR | O_CREAT) && oflags != (O_RDWR | O_APPEND)) { return -EINVAL; } int fd = get_empty_fd(curproc); if( fd == -EMFILE){ return -EMFILE; } file_t *f = fget(-1); if( f == NULL){ return -ENOMEM; } curproc->p_files[fd] = f; /*Set file_t->f_mode to OR of FMODE_(READ|WRITE|APPEND) based on * oflags, which can be O_RDONLY, O_WRONLY or O_RDWR, possibly OR'd with * O_APPEND. */ /*FIXME check the logic below*/ if(oflags == O_RDONLY){ f->f_mode = FMODE_READ; }else if(oflags == O_WRONLY){ f->f_mode = FMODE_WRITE; }else if(oflags == O_RDWR){ f->f_mode = FMODE_READ | FMODE_WRITE; }else if(oflags == O_APPEND){ f->f_mode = FMODE_WRITE | FMODE_APPEND; }else if(oflags == (O_RDONLY | O_CREAT)){ f->f_mode = FMODE_READ; }else if(oflags == (O_RDWR | O_CREAT) ){ f->f_mode = FMODE_READ | FMODE_WRITE; }else if(oflags == (O_RDWR | O_APPEND) ){ f->f_mode = FMODE_READ | FMODE_WRITE | FMODE_APPEND; } vnode_t *pVnode; int s = open_namev(filename, oflags, &pVnode, NULL); if(s != 0){ curproc->p_files[fd] = NULL; fput(f); return s; } if(S_ISDIR(pVnode->vn_mode) && ((oflags & O_WRONLY) || (oflags & O_RDWR)) ){ curproc->p_files[fd] = NULL; vput(pVnode); fput(f); return -EISDIR; } if(S_ISBLK(pVnode->vn_mode)){ if(!(pVnode->vn_bdev = blockdev_lookup(pVnode->vn_devid))){ curproc->p_files[fd] = NULL; fput(f); vput(pVnode); return -ENXIO; } } if(S_ISCHR(pVnode->vn_mode)){ if(!(pVnode->vn_cdev = bytedev_lookup(pVnode->vn_devid))){ curproc->p_files[fd] = NULL; fput(f); vput(pVnode); return -ENXIO; } } f->f_pos=0; f->f_vnode = pVnode; return fd; }
int do_open(const char *filename, int oflags) { /*NOT_YET_IMPLEMENTED("VFS: do_open");*/ /* Check validity of oflags */ int flag_write_only = oflags & O_WRONLY; int flag_readwrite = oflags & O_RDWR; int flag_append = oflags & O_APPEND; int flag_create = oflags & O_CREAT; /* oflags is Read_Only and also trying to write/append/create if( !oflags && ( flag_write_only || flag_readwrite || flag_append || flag_create) ) { dbg(DBG_PRINT, "Add self test dbg here (GRADING1C 7)\n"); return(-EINVAL); }*/ /* Trying to read from write_only */ if( flag_write_only && flag_readwrite ) { dbg(DBG_PRINT, "(GRADING2B)\n"); return(-EINVAL); } int file_mode = 0; if( oflags == 0 ) { dbg(DBG_PRINT, "(GRADING2B)\n"); file_mode = file_mode | FMODE_READ; } if( flag_write_only ) { dbg(DBG_PRINT, "(GRADING2B)\n"); file_mode = file_mode | FMODE_WRITE; } if( flag_readwrite ) { dbg(DBG_PRINT, "(GRADING2B)\n"); file_mode = file_mode | FMODE_READ | FMODE_WRITE; } if( flag_append ) { dbg(DBG_PRINT, "(GRADING2B)\n"); file_mode = file_mode | FMODE_APPEND; } vnode_t *new_vnode; int namev_ret = open_namev(filename, oflags, &new_vnode , NULL); if( namev_ret ) { dbg(DBG_PRINT, "(GRADING2B)\n"); return namev_ret; } int next_fd; next_fd = get_empty_fd(curproc); /*if ( next_fd == -EMFILE ) { vput(new_vnode); return -EMFILE; }*/ curproc->p_files[next_fd] = fget(-1); curproc->p_files[next_fd]->f_mode = file_mode; if( S_ISDIR(new_vnode->vn_mode) && (flag_write_only || flag_readwrite) ) { dbg(DBG_PRINT, "(GRADING2B)\n"); fput(curproc->p_files[next_fd]); curproc->p_files[next_fd] = NULL; vput(new_vnode); return(-EISDIR); } if( S_ISCHR(new_vnode->vn_mode) && !(new_vnode->vn_cdev) ) { dbg(DBG_PRINT, "(GRADING2B)\n"); fput( curproc->p_files[next_fd] ); curproc->p_files[next_fd] = NULL; vput(new_vnode); return(-ENXIO); } if( S_ISBLK(new_vnode->vn_mode) && !(new_vnode->vn_bdev) ) { dbg(DBG_PRINT, "(GRADING2B)\n"); fput( curproc->p_files[next_fd] ); curproc->p_files[next_fd] = NULL; vput(new_vnode); return(-ENXIO); } curproc->p_files[next_fd]->f_vnode = new_vnode; curproc->p_files[next_fd]->f_pos = 0; return next_fd; }
/* 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) { /* NOT_YET_IMPLEMENTED("VFS: do_link"); */ /* o open_namev(from)*/ int ret = 0; vnode_t *from_vnode = NULL; vnode_t *to_vnode = NULL; size_t namelen; const char *name; int flag = 0; /* Not modifying the file, so flag should be 0? */ ret = open_namev(from, flag, &from_vnode, NULL); if (ret == -ENOENT){ return -ENOENT; } if (ret == -ENOTDIR){ return -ENOTDIR; } /* ERROR!!! A component of filename was too long.*/ if (ret == -ENAMETOOLONG){ return -ENAMETOOLONG; } /* In case there are other errors */ if (ret) { return ret; } /* Remember to vput the vnodes returned from open_namev and dir_namev.*/ /* Corrected for kernel 3 */ /* vput(from_vnode); */ /* The textbook page 30 says hard link can not be made to directory */ if (from_vnode->vn_mode == S_IFDIR) { /* Corrected for kernel 3 */ vput(from_vnode); return -EISDIR; } /* o dir_namev(to)*/ ret = dir_namev(to, &namelen, &name, NULL, &to_vnode); if (ret == -ENOENT) { /* Corrected for kernel 3 */ vput(from_vnode); return -ENOENT; } if (ret == -ENOTDIR) { /* Corrected for kernel 3 */ vput(from_vnode); return -ENOTDIR; } /* ERROR!!! A component of filename was too long.*/ if (ret == -ENAMETOOLONG) { /* Corrected for kernel 3 */ vput(from_vnode); return -ENAMETOOLONG; } /* In case there are other errors */ if (ret) { /* Corrected for kernel 3 */ vput(from_vnode); return ret; } /* Remember to vput the vnodes returned from open_namev and dir_namev.*/ /* Corrected for kernel 3 */ /* vput(to_vnode); */ /*o EEXIST * to already exists. * do lookup to check if to already exists */ vnode_t *testNode; ret = lookup(to_vnode, name, namelen, &testNode); if (ret == 0) { /* Corrected for kernel 3 */ vput(from_vnode); vput(to_vnode); vput(testNode); return -EEXIST; } else if (ret == -ENOTDIR) { /* Corrected for kernel 3 */ vput(from_vnode); vput(to_vnode); return -ENOTDIR; } else { /* o call the destination dir's (to) link vn_ops.*/ ret = to_vnode->vn_ops->link(from_vnode, to_vnode, name, namelen); /* Corrected for kernel 3 */ vput(from_vnode); vput(to_vnode); /* o return the result of link, or an error*/ return ret; } }
int do_open(const char *filename, int oflags) { vnode_t *res_vnode; int status_flag = 0, access_flag = 0, fd = 0, errno = 0; dbg(DBG_PRINT | DBG_VFS,"Kernel2:SysMsg: begin do_open(), filename =%s\n",filename); /*Error cases*/ if ( strlen(filename) > MAXPATHLEN ) { dbg(DBG_ERROR | DBG_VFS,"Kernel2:SysMsg: in do_open(), filename =%s - The component of the Filename too long\n",filename); return -ENAMETOOLONG; } if ( strlen(filename) < 1 ) { dbg(DBG_ERROR | DBG_VFS,"Kernel2:SysMsg: in do_open(), filename =%s - Invalid file as length is less than 1 \n",filename); return -EINVAL; } /*set up the access and status flags*/ status_flag = oflags & 0x700; /*O_CREAT,O_TRUNC,O_APPEND*/ access_flag = oflags & 0x003; /*O_RDONLY,O_WRONLY,O_RDWR*/ if ( access_flag != O_RDONLY && access_flag != O_WRONLY && access_flag != O_RDWR ) { dbg(DBG_ERROR | DBG_VFS,"Kernel2:SysMsg: in do_open(), filename =%s - Invalid file\n",filename); return -EINVAL; } /* get empty file descriptor, open file,O_CREAT handled in open_namev */ fd = get_empty_fd(curproc); if ( fd < 0 ) { dbg(DBG_ERROR | DBG_VFS,"Kernel2:SysMsg: in do_open(), filename =%s - Maximum number of files open\n",filename); return -EMFILE; } curproc->p_files[fd] = fget(-1); if ( curproc->p_files[fd] == NULL ) { dbg(DBG_ERROR | DBG_VFS,"Kernel2:SysMsg: in do_open(), filename =%s - Insufficient Kernel memory\n",filename); return -ENOMEM; } errno = open_namev(filename,status_flag,&res_vnode,NULL); if ( errno < 0 ) { fput(curproc->p_files[fd]); return errno; } /* Check error for opening a dir for write*/ if ( S_ISDIR(res_vnode->vn_mode) && (access_flag == O_RDWR || access_flag == O_WRONLY)) { fput(curproc->p_files[fd]); vput(res_vnode); dbg(DBG_ERROR | DBG_VFS,"Kernel2:SysMsg: in do_open(), filename =%s - The pathname is a directory or the access requested requires writing\n",filename); return -EISDIR; } /* Make O_TRUNC behavior default */ if ( errno == 0 && (status_flag & O_APPEND) != O_APPEND && access_flag == O_WRONLY) { vput(res_vnode); errno = do_unlink(filename); if ( errno < 0 ) { fput(curproc->p_files[fd]); return errno; } errno = open_namev(filename,O_CREAT,&res_vnode,NULL); if ( errno < 0 ) { fput(curproc->p_files[fd]); return errno; } } curproc->p_files[fd]->f_vnode = res_vnode; /*Handle file O_APPEND or O_TRUNC*/ switch ( status_flag ) { case O_APPEND : curproc->p_files[fd]->f_mode = FMODE_APPEND; break; case O_APPEND | O_CREAT : curproc->p_files[fd]->f_mode = FMODE_APPEND; break; default : curproc->p_files[fd]->f_mode = 0; curproc->p_files[fd]->f_pos = 0; break; } /*Handle file access*/ switch ( access_flag ) { case O_RDONLY : curproc->p_files[fd]->f_mode |= FMODE_READ; break; case O_WRONLY : curproc->p_files[fd]->f_mode |= FMODE_WRITE; break; case O_RDWR : curproc->p_files[fd]->f_mode |= FMODE_WRITE | FMODE_READ; break; } dbg(DBG_PRINT | DBG_VFS,"Kernel2:SysMsg: begin do_open(), return fd \n"); return fd; }
int do_open(const char *filename, int oflags) { /* check invalid combinations */ int wr = oflags & O_WRONLY; int rdwr = oflags & O_RDWR; int rd = 0; if( (wr == 0) && (rdwr == 0)){ rd = 1; } int append = oflags & O_APPEND; int trunc = oflags &O_TRUNC; int creat = oflags & O_CREAT; if( (wr != 0) && (rdwr != 0) ){ return -EINVAL; } /* 1. Get the next empty file descriptor */ int fd = get_empty_fd(curproc); if(fd == -EMFILE){ return -EMFILE; } /* 2. Call fget to get a fresh file_t */ file_t* file = fget(-1); if(file == NULL){ /* not sure for this error */ return -ENOMEM; } /* 3. Save the file_t in curproc's file descriptor table */ curproc -> p_files[fd] = file; /* 4. Set file_t->f_mode to OR of FMODE_(READ|WRITE|APPEND) based on * oflags, which can be O_RDONLY, O_WRONLY or O_RDWR, possibly OR'd with * O_APPEND. */ int mode = -1; if( (wr != 0) ||(rd != 0) || (rdwr != 0)){ if(rd != 0){ mode = FMODE_READ; } else if(wr != 0){ mode = FMODE_WRITE; } else if(rdwr != 0){ mode = FMODE_READ | FMODE_WRITE; } /* last check append */ if( append != 0){ mode |= FMODE_APPEND; } } if(mode == -1){ /* invalid combination */ curproc -> p_files[fd] = NULL; fput(file); return -EINVAL; } file -> f_mode = mode; /* 5. Use open_namev() to get the vnode for the file_t. */ vnode_t* res_vnode = NULL; vnode_t* base = curproc -> p_cwd; int res = open_namev(filename, oflags, &res_vnode, base); if(res < 0){ curproc -> p_files[fd] = NULL; if(res_vnode) vput(res_vnode); fput(file); return res;/* including errors: ENAMETOOLONG, ENOTDIR, ENOENT */ } if( ((res_vnode -> vn_mode & S_IFDIR) != 0) && (mode != FMODE_READ)){ curproc -> p_files[fd] = NULL; vput(res_vnode); fput(file); return -EISDIR; } /* 6. Fill in the fields of the file_t */ file->f_vnode = res_vnode; file->f_pos = 0; /* 7. return new fd */ return fd; }
int do_open(const char *filename, int oflags) { /*NOT_YET_IMPLEMENTED("VFS: do_open");*/ dbg(DBG_PRINT, "Entering do_open()....%s\n", filename); int fd = get_empty_fd(curproc); if(fd == -EMFILE) { dbg(DBG_PRINT, "Exiting do_open()....\n"); return fd; } if((oflags & O_RDONLY) != O_RDONLY && (oflags & O_WRONLY) != O_WRONLY && (oflags & O_RDWR) != O_RDWR) { dbg(DBG_PRINT,"None of the access modes(O_RDONLY, O_WRONLY, O_RDWR) set......\n"); dbg(DBG_PRINT, "Exiting do_open()....\n"); return -EINVAL; } if((oflags & O_RDWR) == O_RDWR && (oflags & O_WRONLY) == O_WRONLY) { dbg(DBG_PRINT, "Invalid flags set.........\n"); dbg(DBG_PRINT, "Exiting do_open()....\n"); return -EINVAL; } if((oflags & O_TRUNC) == O_TRUNC) { if((oflags & O_RDWR) != O_RDWR && (oflags & O_WRONLY) != O_WRONLY) { dbg(DBG_PRINT, "O_TRUNC set but none of the write flags are set...\n"); dbg(DBG_PRINT, "Exiting do_open()....\n"); return -EINVAL; } } if((oflags & O_APPEND) == O_APPEND) { if((oflags & O_RDWR) != O_RDWR && (oflags & O_WRONLY) != O_WRONLY) { dbg(DBG_PRINT, "O_APPEND set but none of the write flags are set...........\n"); dbg(DBG_PRINT, "Exiting do_open()....\n"); return -EINVAL; } } int count = 0; /*const char *p = filename;*/ if(strlen(filename) > MAXPATHLEN) return -ENAMETOOLONG; file_t *sft = fget(-1); if(sft == NULL) return ENOMEM; /* not sure ..........................*/ curproc->p_files[fd] = sft; if((oflags & O_WRONLY) == O_WRONLY) { sft->f_mode = FMODE_WRITE; } else if((oflags & O_RDWR) == O_RDWR) { sft->f_mode = FMODE_WRITE | FMODE_READ; } else { sft->f_mode = FMODE_READ; } if((oflags & O_APPEND) == O_APPEND) { sft->f_mode |= FMODE_APPEND; } vnode_t *res_vnode; /*vfs_is_in_use(vfs_root_vn->vn_fs);*/ int openv_ret = open_namev(filename, oflags, &res_vnode, NULL); if(openv_ret < 0) { /*dbg(DBG_PRINT, "do_open()\n", openv_ret);*/ fput(sft); /*Not Sure................................*/ if(openv_ret == -ENOENT && (oflags & O_CREAT) != O_CREAT) { dbg(DBG_PRINT, "Exiting do_open()....\n"); return -ENOENT; } else { dbg(DBG_PRINT, "Exiting do_open()....\n"); return openv_ret; } } if(S_ISDIR(res_vnode->vn_mode) && ((oflags & O_WRONLY) == O_WRONLY || (oflags & O_RDWR) == O_RDWR)) { dbg(DBG_PRINT, "Exiting from do_open()\n"); fput(sft); vput(res_vnode); return -EISDIR; } sft->f_pos = 0; sft->f_vnode = res_vnode; /*sft->f_refcount += 1;*/ if((oflags & O_TRUNC) == O_TRUNC) { sft->f_vnode->vn_len = 0; } if(S_ISCHR(sft->f_vnode->vn_mode)) { if(sft->f_vnode->vn_cdev == NULL) { dbg(DBG_PRINT, "Exiting do_open()....\n"); /*vput(res_vnode);*/ return -ENXIO; } } if(S_ISBLK(sft->f_vnode->vn_mode)) { if(sft->f_vnode->vn_bdev == NULL) { dbg(DBG_PRINT, "Exiting do_open()....\n"); /*vput(res_vnode);*/ return -ENXIO; } } dbg(DBG_PRINT, "Exiting do_open() normally....\n"); return fd; }
int do_open(const char *filename, int oflags) { int status; file_t *f; int fd = get_empty_fd(curproc); if(fd!=EMFILE) { /* can fail if memory not allocated */ f = fget(-1); if(f==NULL) return -ENOMEM; curproc->p_files[fd] = f; if(oflags & O_RDONLY) f->f_mode = FMODE_READ; else if(oflags & O_WRONLY) f->f_mode = FMODE_WRITE; else if(oflags & O_RDWR) f->f_mode = FMODE_READ | FMODE_WRITE; else if(oflags & (O_WRONLY|O_APPEND)) f->f_mode = FMODE_WRITE|FMODE_APPEND; else if(oflags & (O_RDWR|O_APPEND)) f->f_mode = FMODE_READ|FMODE_WRITE|FMODE_APPEND; else return -EINVAL; /* not sure if other combinations should be handled */ if(S_ISDIR(f->f_vnode->vn_mode) && (O_WRONLY | O_RDWR)) { curproc->p_files[fd] = NULL; fput(f); return -EISDIR; } if( S_ISCHR(f->f_vnode->vn_mode) || S_ISBLK(f->f_vnode->vn_mode)) { curproc->p_files[fd] = NULL; fput(f); return -ENXIO; } /* returns int */ status = open_namev(filename, oflags, (vnode_t **)(&(f->f_vnode)), NULL); if(status<0) { curproc->p_files[fd] = NULL; fput(f); return status; } /* can return error codes*/ status = do_lseek(fd,0,0); /* 3rd argument SEEK_SET = 0 is not defined, not sure to do this as lseek.h not included */ if(status<0) { curproc->p_files[fd] = NULL; fput(f); return status; } return fd; } else return -EMFILE; /*NOT_YET_IMPLEMENTED("VFS: do_open"); return -1;*/ }
/* 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; }
int do_open(const char *filename, int oflags) { /* VFS {{{ */ int fd; file_t *f; vnode_t *file_vnode; int ret; if ((oflags & O_WRONLY) && (oflags & O_RDWR)) { return -EINVAL; } if ((fd = get_empty_fd(curproc)) < 0) { return fd; } if ((f = fget(-1)) == NULL) { return -ENOMEM; } curproc->p_files[fd] = f; dbg(DBG_VFS, "open on %s, file at %p\n", filename, curproc->p_files[fd]); switch (oflags & 0x3) { case O_RDONLY: f->f_mode = FMODE_READ; break; case O_WRONLY: f->f_mode = FMODE_WRITE; break; case O_RDWR: f->f_mode = FMODE_READ | FMODE_WRITE; break; default: /*kthread_cleanup_pop(1);*/ nukefd(fd); return -EINVAL; } if ((ret = open_namev(filename, oflags, &file_vnode, NULL)) < 0) { /*kthread_cleanup_pop(1);*/ nukefd(fd); return ret; } if (((oflags & O_WRONLY) || (oflags & O_RDWR)) && S_ISDIR(file_vnode->vn_mode)) { /*kthread_cleanup_pop(1);*/ nukefd(fd); vput(file_vnode); return -EISDIR; } if (S_ISBLK(file_vnode->vn_mode) && (!file_vnode->vn_bdev)) { /*kthread_cleanup_pop(1);*/ nukefd(fd); vput(file_vnode); return -ENXIO; } if (S_ISCHR(file_vnode->vn_mode) && (!file_vnode->vn_cdev)) { /*kthread_cleanup_pop(1);*/ nukefd(fd); vput(file_vnode); return -ENXIO; } f->f_vnode = file_vnode; dbg(DBG_VFS, " vnode at %p\n", file_vnode); if (oflags & O_APPEND) { f->f_mode |= FMODE_APPEND; } /*kthread_cleanup_pop(0);*/ return fd; /* VFS }}} */ return -1; }
int do_open(const char *filename, int oflags) { dbg(DBG_VFS, "calling do_open on %s\n", filename); /* step 1: get next empty file descriptor */ int fd = get_empty_fd(curproc); /* error case 2 */ if (fd == -EMFILE){ return -EMFILE; } /* step 2: Call fget to get a fresh file_t */ file_t *f = fget(-1); /* error case 3 */ if (f == NULL){ return -ENOMEM; } KASSERT(f != NULL); KASSERT(f->f_refcount == 1); /* step 3: Save file_t in curproc's file descriptor table */ KASSERT(curproc->p_files[fd] == NULL); curproc->p_files[fd] = f; /* step 4: Set the file_t->f-mode */ f->f_mode = 0; if (oflags & O_APPEND){ f->f_mode = FMODE_APPEND; } if ((oflags & O_WRONLY) && !(oflags & O_RDWR)){ f->f_mode |= FMODE_WRITE; } else if ((oflags & O_RDWR) && !(oflags & O_WRONLY)){ f->f_mode |= FMODE_READ | FMODE_WRITE; } else if (oflags == O_RDONLY || oflags == (O_RDONLY | O_CREAT) || oflags == (O_RDONLY | O_APPEND) || oflags == (O_RDONLY | O_CREAT | O_APPEND)){ f->f_mode |= FMODE_READ; } else { dbg(DBG_VFS, "oflags not valid\n"); fput(f); curproc->p_files[fd] = NULL; return -EINVAL; } /* make sure we have a valid mode */ KASSERT(f->f_mode == FMODE_READ || f->f_mode == FMODE_WRITE || f->f_mode == (FMODE_READ | FMODE_WRITE) || f->f_mode == (FMODE_WRITE | FMODE_APPEND) || f->f_mode == (FMODE_READ | FMODE_WRITE | FMODE_APPEND)); /* step 5: use open_namev to get the vnode for the file_t */ int open_result = open_namev(filename, oflags, &f->f_vnode, NULL); if (open_result < 0){ curproc->p_files[fd] = NULL; fput(f); return open_result; } dbg(DBG_VFS, "found the vnode with id %d. Current refcount is %d\n", f->f_vnode->vn_vno, f->f_vnode->vn_mmobj.mmo_refcount); /* step 6: fill in the fields of the file_t */ /* no need to call vref, since open_namev() took care of that*/ f->f_pos = 0; f->f_refcount = 1; /* step 7: return new fd */ return fd; }