/* * See the comment in vnode.h for what is expected of this function. * * When this function returns, the inode refcount of the unlinked file * should be decremented. * * You probably want to use s5_remove_dirent(). */ static int s5fs_unlink(vnode_t *dir, const char *name, size_t namelen) { KASSERT(dir->vn_ops->mkdir != NULL); kmutex_lock(&dir->vn_mutex); int ret = s5_remove_dirent(dir, name, namelen); kmutex_unlock(&dir->vn_mutex); return ret; }
/* * See the comment in vnode.h for what is expected of this function. * * When this function returns, the inode refcount on the parent should be * decremented (since ".." in the removed directory no longer references * it). Remember that the directory must be empty (except for "." and * ".."). * * You probably want to use s5_find_dirent() and s5_remove_dirent(). */ static int s5fs_rmdir(vnode_t *parent, const char *name, size_t namelen) { KASSERT(!(namelen == 1 && name[0] == '.')); KASSERT(!(namelen == 2 && name[0] == '.' && name[1] == '.')); KASSERT(parent->vn_ops->rmdir != NULL); kmutex_lock(&parent->vn_mutex); int ino = s5_find_dirent(parent, name, namelen); /* we check in do_rmdir to make sure the directory exists */ KASSERT(ino != -ENOENT); if (ino < 0){ dbg(DBG_S5FS, "error finding child dir to delete\n"); kmutex_unlock(&parent->vn_mutex); return ino; } vnode_t *child = vget(VNODE_TO_S5FS(parent)->s5f_fs, ino); kmutex_lock(&child->vn_mutex); int dot_lookup_res = s5_find_dirent(child, ".", 1); int dotdot_lookup_res = s5_find_dirent(child, "..", 2); KASSERT(dot_lookup_res != -ENOENT && dotdot_lookup_res != -ENOENT); if (dot_lookup_res < 0 || dotdot_lookup_res < 0){ dbg(DBG_S5FS, "error reading dirents of directory to delete\n"); kmutex_unlock(&child->vn_mutex); kmutex_unlock(&parent->vn_mutex); return (dot_lookup_res < 0) ? dot_lookup_res : dotdot_lookup_res; } KASSERT((unsigned) child->vn_len >= 2 * sizeof(s5_dirent_t)); if ((unsigned) child->vn_len > 2 * sizeof(s5_dirent_t)){ vput(child); kmutex_unlock(&child->vn_mutex); kmutex_unlock(&parent->vn_mutex); return -ENOTEMPTY; } vput(child); VNODE_TO_S5INODE(parent)->s5_linkcount--; s5_dirty_inode(VNODE_TO_S5FS(parent), VNODE_TO_S5INODE(parent)); kmutex_unlock(&child->vn_mutex); kmutex_unlock(&parent->vn_mutex); return s5_remove_dirent(parent, name, namelen); }
/* * s5fs_unlink: * s5fs_unlink removes the link to the vnode in dir specified by name * param *dir: the parent's vnode * param *name: name string * param namelen: the length of the name * return: 0 on success, and negative number on a variety of errors */ static int s5fs_unlink(vnode_t *dir, const char *name, size_t namelen) { dbg(DBG_S5FS, "{\n"); KASSERT(dir != NULL); KASSERT(name != NULL); KASSERT(namelen <= S5_NAME_LEN-1); kmutex_lock(&dir->vn_mutex); int ret = 0; if ((ret = s5_remove_dirent(dir, name, namelen)) < 0) { kmutex_unlock(&dir->vn_mutex); return ret; } kmutex_unlock(&dir->vn_mutex); dbg(DBG_S5FS, "}\n"); return ret; }
/* * s5fs_rmdir: * s5fs_rmdir removes the directory called name from dir. the directory * to be removed must be empty (except for . and .. of course). * param *parent: the pointer to the parent dir of the name specified * param *name: name string * param namelen: the length of the name string * return: 0 on success; negative numbers on a variety of errors */ static int s5fs_rmdir(vnode_t *parent, const char *name, size_t namelen) { dbg(DBG_S5FS, "{\n"); KASSERT(parent != NULL); KASSERT(name != NULL); KASSERT(namelen <= NAME_LEN - 1); KASSERT((uint32_t)parent->vn_len == VNODE_TO_S5INODE(parent)->s5_size); kmutex_lock(&parent->vn_mutex); int inode_number = 0; if ((inode_number = s5_find_dirent(parent, name, namelen)) < 0) { kmutex_unlock(&parent->vn_mutex); /* Need vput? */ return inode_number; } /* May block here */ vnode_t* vn = vget(parent->vn_fs, inode_number); KASSERT(vn != NULL); if (!S_ISDIR(vn->vn_mode)) { /* May block here */ vput(vn); kmutex_unlock(&parent->vn_mutex); return -ENOTDIR; } /* Check empty */ if (VNODE_TO_S5INODE(vn)->s5_size > sizeof(dirent_t)*2) { vput(vn); kmutex_unlock(&parent->vn_mutex); return -ENOTEMPTY; } int ret; if ((ret = s5_remove_dirent(parent, name, namelen)) < 0) { /* May block here */ vput(vn); kmutex_unlock(&parent->vn_mutex); return ret; } /* Decrease the linkcount because .. is removed */ s5_inode_t* parent_inode = VNODE_TO_S5INODE(parent); parent_inode->s5_linkcount--; s5_dirty_inode(VNODE_TO_S5FS(parent), parent_inode); /* May block here */ vput(vn); kmutex_unlock(&parent->vn_mutex); dbg(DBG_S5FS, "}\n"); return ret; }