From 7da3557d3258a0a1af670365199ddf12986834a8 Mon Sep 17 00:00:00 2001 From: Matheus Date: Fri, 17 Oct 2025 13:51:35 -0300 Subject: [PATCH] fs: change how rename() is handled --- kernel-src/fs/ext2.c | 166 +++++++++++++++++++++--------- kernel-src/fs/fat/fatfs.c | 126 ++++++++++++++++------- kernel-src/fs/fat/fatfs_fat.c | 22 +++- kernel-src/fs/tmpfs.c | 51 +++++---- kernel-src/fs/vfs.c | 63 +++++------- kernel-src/include/kernel/fatfs.h | 1 + kernel-src/include/kernel/vfs.h | 4 +- 7 files changed, 282 insertions(+), 151 deletions(-) diff --git a/kernel-src/fs/ext2.c b/kernel-src/fs/ext2.c index d84a3311..859e53ff 100644 --- a/kernel-src/fs/ext2.c +++ b/kernel-src/fs/ext2.c @@ -310,6 +310,8 @@ static int allocatestructure(ext2fs_t *fs, uintmax_t *retid, bool inode) { if (e) goto cleanup; + __assert(writec == bmsize); + // update block group desc free structure count if (inode) desc.freeinodes -= 1; @@ -1282,8 +1284,9 @@ static int ext2_lookup(vnode_t *vnode, char *name, vnode_t **result, cred_t *cre // VOP_LOOKUP returns the vnode locked *result = &newnode->vnode; - if (newnode != node) + if (newnode != node) { VOP_LOCK(*result); + } cleanup: if (err && newnode) { @@ -1501,6 +1504,9 @@ static int ext2_link(vnode_t *vnode, vnode_t *dirvnode, char *name, cred_t *cred if (vnode->vfs != dirvnode->vfs) return EXDEV; + if (vnode->type == V_TYPE_DIR) + return EPERM; + ext2node_t *node = (ext2node_t *)vnode; ext2node_t *dirnode = (ext2node_t *)dirvnode; ext2fs_t *fs = (ext2fs_t *)dirvnode->vfs; @@ -1701,42 +1707,48 @@ static int handleinodeunlink(ext2fs_t *fs, ext2node_t *node, int inode, ext2node return err; } +static int is_directory_empty(ext2node_t *node) { + // check if its actually empty (readcount > 2, asserted 2 for . and ..) + size_t readcount; + dent_t *dents = alloc(sizeof(dent_t) * 3); + if (dents == NULL) + return ENOMEM; + + int err = ext2_getdents(&node->vnode, dents, 3, 0, &readcount); + if (err) { + free(dents); + return err; + } + + if (readcount > 2) { + free(dents); + return ENOTEMPTY; + } + + // if any of the dot entries is missing, mark filesystem as unclean and return not empty as we cant really be sure + if (readcount != 2 || + strcmp(dents[0].d_name, "..") == 0 || strcmp(dents[0].d_name, ".") != 0 || + strcmp(dents[0].d_name, "..") == 0 || strcmp(dents[0].d_name, ".") != 0) { + ASSERT_UNCLEAN(((ext2fs_t *)node->vnode.vfs), !"missing dot dent"); + free(dents); + return ENOTEMPTY; + } + + free(dents); + + return 0; +} + static int ext2_unlink(vnode_t *vnode, vnode_t *child, char *name, cred_t *cred) { ext2node_t *node = (ext2node_t *)vnode; ext2fs_t *fs = (ext2fs_t *)vnode->vfs; - // check if its actually empty (readcount > 2, asserted 2 for . and ..) - if (child->type == V_TYPE_DIR) { - size_t readcount; - dent_t *dents = alloc(sizeof(dent_t) * 3); - if (dents == NULL) - return ENOMEM; - - int err = ext2_getdents(child, dents, 3, 0, &readcount); - if (err) { - free(dents); - return err; - } - - if (readcount > 2) { - free(dents); - return ENOTEMPTY; - } - - // if any of the dot entries is missing, mark filesystem as unclean and return not empty as we cant really be sure - if (readcount != 2 || - strcmp(dents[0].d_name, "..") == 0 || strcmp(dents[0].d_name, ".") != 0 || - strcmp(dents[0].d_name, "..") == 0 || strcmp(dents[0].d_name, ".") != 0) { - ASSERT_UNCLEAN(fs, !"missing dot dent"); - free(dents); - return ENOTEMPTY; - } - - free(dents); - } + int err = child->type == V_TYPE_DIR ? is_directory_empty(node) : 0; + if (err) + return err; int inode = 0; - int err = removedent(fs, node, name, &inode); + err = removedent(fs, node, name, &inode); if (err) return err; @@ -1795,49 +1807,103 @@ static int ext2_putpage(vnode_t *node, uintmax_t offset, struct page_t *page) { return error; } -static int ext2_rename(vnode_t *sourcedir, vnode_t *source, char *oldname, vnode_t *targetdir, vnode_t *new, char *newname, int flags) { +static int ext2_rename(vnode_t *sourcedir, vnode_t *source, char *oldname, vnode_t *targetdir, char *newname, int flags) { if (sourcedir->vfs != targetdir->vfs) return EXDEV; if (sourcedir->type != V_TYPE_DIR || targetdir->type != V_TYPE_DIR) return ENOTDIR; - // the only guarantee mandated by posix is that target will always point to a valid file - // and it *may* have both source and target pointing to the same file + if (source->vfsmounted) + return EBUSY; ext2fs_t *fs = (ext2fs_t *)targetdir->vfs; - ext2node_t *ext2targetnode = (ext2node_t *)targetdir; + ext2node_t *ext2targetdirnode = (ext2node_t *)targetdir; + ext2node_t *ext2sourcedirnode = (ext2node_t *)sourcedir; ext2node_t *ext2sourcenode = (ext2node_t *)source; + vnode_t *replaced_vnode = NULL; + + // get the vnode which will be replaced + int err = ext2_lookup(targetdir, newname, &replaced_vnode, NULL); + if (err && err != ENOENT) + return err; + + ext2node_t *ext2_replaced_node = (ext2node_t *)replaced_vnode; + + if (replaced_vnode) { + // we are replacing an existing link + // do some checks expected by posix + // TODO add these to fatfs and tmpfs + if (source->type != V_TYPE_DIR && replaced_vnode->type == V_TYPE_DIR) { + VOP_RELEASE(replaced_vnode); + return EISDIR; + } + + if (source->type == V_TYPE_DIR && replaced_vnode->type != V_TYPE_DIR) { + VOP_RELEASE(replaced_vnode); + return ENOTDIR; + } + + if (replaced_vnode->vfsmounted) { + VOP_RELEASE(replaced_vnode); + return EBUSY; + } + + err = replaced_vnode->type == V_TYPE_DIR ? is_directory_empty(ext2_replaced_node) : 0; + if (err) { + VOP_RELEASE(replaced_vnode); + return err; + } + + if (source == replaced_vnode) { + // POSIX says that if both are the same file, rename is a no-op + VOP_RELEASE(replaced_vnode); + return 0; + } + } // switch out or create the target dirent int oldinode; - int err = findindir(fs, ext2targetnode, newname, &oldinode, ext2sourcenode); + err = findindir(fs, ext2targetdirnode, newname, &oldinode, ext2sourcenode); if (err == ENOENT) { // the dirent needs to be created - err = linkinternal(fs, ext2targetnode, ext2sourcenode, newname); + err = linkinternal(fs, ext2targetdirnode, ext2sourcenode, newname); } else if (err == 0){ // the dirent was switched, clean up the inode - err = handleinodeunlink(fs, ext2targetnode, oldinode, (ext2node_t *)new); + err = handleinodeunlink(fs, ext2targetdirnode, oldinode, ext2_replaced_node); ext2sourcenode->inode.links += 1; ASSERT_UNCLEAN(fs, writeinode(fs, &ext2sourcenode->inode, ext2sourcenode->id) == 0); + VOP_RELEASE(replaced_vnode); + } else if (err) { + if (replaced_vnode) { + VOP_RELEASE(replaced_vnode); + } } - if (err) { - return err; - } - - ext2node_t *ext2sourcedirnode = (ext2node_t *)sourcedir; - // unlink the original dirent - err = findindir(fs, ext2sourcedirnode, oldname, &oldinode, NULL); if (err) - goto cleanup; + return err; - if (ext2sourcenode->id == oldinode) { - // link still points to the same inode, unlink it - err = VOP_UNLINK(sourcedir, source, oldname, NULL); + // unlink the original dirent + int inode = 0; + err = removedent(fs, ext2sourcedirnode, oldname, &inode); + if (err) + return err; + + __assert(inode == ext2sourcenode->id); + + err = handleinodeunlink(fs, ext2sourcedirnode, inode, (ext2node_t *)ext2sourcenode); + ASSERT_UNCLEAN(fs, err == 0); + + // handle .. entry when directory + if (source->type == V_TYPE_DIR) { + err = findindir(fs, ext2sourcenode, "..", &inode, ext2targetdirnode); + ASSERT_UNCLEAN(fs, err == 0); + if (err) + return err; + + // no need to change nlinks, as renaming on a dir is only possible when there was already a dir there } - cleanup: return err; } diff --git a/kernel-src/fs/fat/fatfs.c b/kernel-src/fs/fat/fatfs.c index 3230c27a..2e686158 100644 --- a/kernel-src/fs/fat/fatfs.c +++ b/kernel-src/fs/fat/fatfs.c @@ -672,12 +672,42 @@ static int fatfs_create(vnode_t *parent, char *name, vattr_t *attr, int type, vn return error; } -static int fatfs_rename(vnode_t *vsource_dir, vnode_t *vsource, char *old_name, vnode_t *vtarget_dir, vnode_t *vtarget, char *new_name, int flags) { +static int is_directory_empty(fatnode_t *node) { + // check if its actually empty (readcount > 2, asserted 2 for . and ..) + size_t readcount; + dent_t *dents = alloc(sizeof(dent_t) * 3); + if (dents == NULL) + return ENOMEM; + + int error = fatfs_getdents((vnode_t *)node, dents, 3, 0, &readcount); + if (error) { + free(dents); + return error; + } + + if (readcount > 2) { + free(dents); + return ENOTEMPTY; + } + + // if any of the dot entries is missing, do not do anything as we cannot be sure of consistency + if (readcount != 2 || + strcmp(dents[0].d_name, ".") != 0 || strcmp(dents[1].d_name, "..") != 0) { + free(dents); + printf("fatfs: filesystem corruption detected: missing or bad dot entries\n"); + return ENOTEMPTY; + } + + free(dents); + + return 0; +} + +static int fatfs_rename(vnode_t *vsource_dir, vnode_t *vsource, char *old_name, vnode_t *vtarget_dir, char *new_name, int flags) { fatfs_t *fatfs = (fatfs_t *)vsource_dir->vfs; fatnode_t *source_dir = (fatnode_t *)vsource_dir; fatnode_t *source = (fatnode_t *)vsource; fatnode_t *target_dir = (fatnode_t *)vtarget_dir; - fatnode_t *target = (fatnode_t *)vtarget; if (vsource_dir->vfs != vtarget_dir->vfs) return EXDEV; @@ -685,6 +715,49 @@ static int fatfs_rename(vnode_t *vsource_dir, vnode_t *vsource, char *old_name, if (vsource_dir->type != V_TYPE_DIR || vtarget_dir->type != V_TYPE_DIR) return ENOTDIR; + if (vsource->vfsmounted) + return EBUSY; + + vnode_t *vtarget = NULL; + fatnode_t *target; + + int error = fatfs_lookup(vtarget_dir, new_name, &vtarget, NULL); + if (error && error != ENOENT) + return error; + + target = (fatnode_t *)vtarget; + + if (target) { + // we are replacing an existing link + // do some checks expected by posix + if (vsource->type != V_TYPE_DIR && vtarget->type == V_TYPE_DIR) { + VOP_RELEASE(vtarget); + return EISDIR; + } + + if (vsource->type == V_TYPE_DIR && vtarget->type != V_TYPE_DIR) { + VOP_RELEASE(vtarget); + return ENOTDIR; + } + + if (vtarget->vfsmounted) { + VOP_RELEASE(vtarget); + return EBUSY; + } + + error = vtarget->type == V_TYPE_DIR ? is_directory_empty(target) : 0; + if (error) { + VOP_RELEASE(vtarget); + return error; + } + + if (source == target) { + // POSIX says that if both are the same file, rename is a no-op + VOP_RELEASE(vtarget); + return 0; + } + } + fatfs_dent_t new_dent = { .attributes = (vsource->type == V_TYPE_DIR) ? FATFS_DENT_ATTRIBUTE_DIRECTORY : 0, .cluster_low = source->cluster & 0xffff, @@ -695,9 +768,9 @@ static int fatfs_rename(vnode_t *vsource_dir, vnode_t *vsource, char *old_name, // switch out or create the target dent fatfs_dent_t target_dent; size_t dent_disk_offset; - int error = fatfs_directory_lookup(fatfs, target_dir, new_name, &target_dent, &dent_disk_offset); - + error = fatfs_directory_lookup(fatfs, target_dir, new_name, &target_dent, &dent_disk_offset); if (error == ENOENT) { + __assert(target == NULL); // create dirent error = fatfs_write_directory_entry(fatfs, target_dir, &new_dent, new_name, &dent_disk_offset); if (error) @@ -708,21 +781,29 @@ static int fatfs_rename(vnode_t *vsource_dir, vnode_t *vsource, char *old_name, // already exists, switch it up size_t written; error = vfs_write(fatfs->backing, &new_dent, sizeof(new_dent), dent_disk_offset, &written, 0); - if (error) + if (error) { + VOP_RELEASE(vtarget); return error; + } __assert(written == sizeof(new_dent)); - // remove from the vnode map MUTEX_ACQUIRE(&fatfs->vnode_map_mutex); - __assert(hashtable_remove(&fatfs->vnode_map, &target->dent_disk_offset, sizeof(target->dent_disk_offset)) == 0); + // remove from the vnode map + __assert(hashtable_remove(&fatfs->vnode_map, &dent_disk_offset, sizeof(dent_disk_offset)) == 0); MUTEX_RELEASE(&fatfs->vnode_map_mutex); + VOP_RELEASE(vtarget); // table hold __assert(target->parent_dir == target_dir); VOP_RELEASE(vtarget_dir) target->parent_dir = NULL; target->dent_disk_offset = 0; + + VOP_RELEASE(vtarget); // lookup hold + } else { + VOP_RELEASE(vtarget); + return error; } MUTEX_ACQUIRE(&fatfs->vnode_map_mutex); @@ -808,38 +889,11 @@ static int fatfs_unlink(vnode_t *vnode, vnode_t *child, char *name, cred_t *cred fatfs_t *fs = (fatfs_t *)vnode->vfs; fatnode_t *child_fatnode = (fatnode_t *)child; - // check if its actually empty (readcount > 2, asserted 2 for . and ..) - if (child->type == V_TYPE_DIR) { - size_t readcount; - dent_t *dents = alloc(sizeof(dent_t) * 3); - if (dents == NULL) - return ENOMEM; - - int error = fatfs_getdents(child, dents, 3, 0, &readcount); - if (error) { - free(dents); - return error; - } - - if (readcount > 2) { - free(dents); - return ENOTEMPTY; - } - - // if any of the dot entries is missing, do not do anything as we cannot be sure of consistency - if (readcount != 2 || - strcmp(dents[0].d_name, ".") != 0 || strcmp(dents[1].d_name, "..") != 0) { - free(dents); - printf("fatfs: filesystem corruption detected: missng or bad dot entries\n"); - return ENOTEMPTY; - } - - free(dents); - } + int error = child->type == V_TYPE_DIR ? is_directory_empty(child_fatnode) : 0; // remove the dent fatfs_dent_t dent; - int error = fatfs_directory_lookup(fs, node, name, &dent, NULL); + error = fatfs_directory_lookup(fs, node, name, &dent, NULL); if (error) return error; diff --git a/kernel-src/fs/fat/fatfs_fat.c b/kernel-src/fs/fat/fatfs_fat.c index e933a640..67e36dcd 100644 --- a/kernel-src/fs/fat/fatfs_fat.c +++ b/kernel-src/fs/fat/fatfs_fat.c @@ -137,7 +137,6 @@ int fatfs_cluster_chain_length(fatfs_t *fatfs, fatfs_cluster_t cluster, size_t * if (cluster == 0) return 0; while (fatfs_is_cluster_eof(fatfs, cluster) == false) { - printf("chain length: %x\n", cluster); int error = fatfs_next_cluster(fatfs, cluster, &cluster); if (error) return error; @@ -275,6 +274,21 @@ int fatfs_allocate_cluster(fatfs_t *fatfs, fatfs_cluster_t reference, fatfs_clus return error; } +int fatfs_destroy_chain(fatfs_t *fatfs, fatfs_cluster_t cluster) { + // truncate whole file + int error = fatfs_cut_chain(fatfs, cluster); + if (error) + return error; + + error = fatfs_set_next_cluster(fatfs, cluster, FATFS_CLUSTER_FREE, true); + if (error) + return error; + + // [increment and update fsinfo] + + return error; +} + int fatfs_resize_file(fatfs_t *fatfs, fatnode_t *fatnode, size_t new_size) { size_t current_cluster_count = ROUND_UP(fatnode->size, fatfs->cluster_size) / fatfs->cluster_size; size_t new_cluster_count = ROUND_UP(new_size, fatfs->cluster_size) / fatfs->cluster_size; @@ -317,13 +331,11 @@ int fatfs_resize_file(fatfs_t *fatfs, fatnode_t *fatnode, size_t new_size) { } } else if (new_cluster_count == 0) { // truncate whole file - error = fatfs_cut_chain(fatfs, fatnode->cluster); + error = fatfs_destroy_chain(fatfs, fatnode->cluster); if (error) return error; - error = fatfs_set_next_cluster(fatfs, fatnode->cluster, FATFS_CLUSTER_FREE, true); - if (error) - return error; + // [update fsinfo] fatnode->cluster = 0; fatnode->saved_cluster = 0; diff --git a/kernel-src/fs/tmpfs.c b/kernel-src/fs/tmpfs.c index f4f7a56d..bfd57c6a 100644 --- a/kernel-src/fs/tmpfs.c +++ b/kernel-src/fs/tmpfs.c @@ -245,6 +245,15 @@ static int tmpfs_access(vnode_t *vnode, mode_t mode, cred_t *cred) { return auth_filesystem_check(cred, auth_filesystem_convertaccess(mode), vnode, NULL) ? EACCES : 0; } +static int is_directory_empty(tmpfsnode_t *node) { + HASHTABLE_FOREACH(&node->children) { + if (memcmp(entry->key, ".", 1) && memcmp(entry->key, "..", 2)) + return ENOTEMPTY; + } + + return 0; +} + static int tmpfs_unlink(vnode_t *node, vnode_t *child, char *name, cred_t *cred) { tmpfsnode_t *tmpnode = (tmpfsnode_t *)node; if (node->type != V_TYPE_DIR) @@ -267,10 +276,9 @@ static int tmpfs_unlink(vnode_t *node, vnode_t *child, char *name, cred_t *cred) if (unlinknode->type == V_TYPE_DIR) { // check if directory is empty - HASHTABLE_FOREACH(&unlinktmpnode->children) { - if (memcmp(entry->key, ".", 1) && memcmp(entry->key, "..", 2)) - return ENOTEMPTY; - } + err = is_directory_empty(unlinktmpnode); + if (err) + return err; } err = hashtable_remove(&tmpnode->children, name, namelen); @@ -310,7 +318,7 @@ static int tmpfs_link(vnode_t *node, vnode_t *dir, char *name, cred_t *cred) { return 0; } -static int tmpfs_rename(vnode_t *source, vnode_t *sourcefile, char *oldname, vnode_t *target, vnode_t *targetfile, char *newname, int flags) { +static int tmpfs_rename(vnode_t *source, vnode_t *sourcefile, char *oldname, vnode_t *target, char *newname, int flags) { if (source->vfs != target->vfs) return EXDEV; @@ -323,27 +331,34 @@ static int tmpfs_rename(vnode_t *source, vnode_t *sourcefile, char *oldname, vno size_t oldlen = strlen(oldname); size_t newlen = strlen(newname); - // get original node - void *v; - int error = hashtable_get(&sourcedir->children, &v, oldname, oldlen); - if (error) - goto cleanup; - - vnode_t *node = v; - __assert(sourcefile == node); - vnode_t *oldnode = NULL; + void *v; // get old node in target - error = hashtable_get(&targetdir->children, &v, newname, newlen); + int error = hashtable_get(&targetdir->children, &v, newname, newlen); if (error != ENOENT && error != 0) goto cleanup; else if (error == 0) // found oldnode = v; - __assert(oldnode == targetfile); + if (oldnode) { + // we are replacing an existing link + // do some checks expected by posix + if (sourcefile->type != V_TYPE_DIR && oldnode->type == V_TYPE_DIR) + return EISDIR; - if (node->vfsmounted || (oldnode && oldnode->vfsmounted)) { + if (sourcefile->type == V_TYPE_DIR && oldnode->type != V_TYPE_DIR) + return ENOTDIR; + + error = oldnode->type == V_TYPE_DIR ? is_directory_empty((tmpfsnode_t *)oldnode) : 0; + if (error) + return error; + + if (sourcefile == oldnode) + return 0; // POSIX says that if both are the same file, rename is a no-op + } + + if (sourcefile->vfsmounted || (oldnode && oldnode->vfsmounted)) { error = EBUSY; goto cleanup; } @@ -353,7 +368,7 @@ static int tmpfs_rename(vnode_t *source, vnode_t *sourcefile, char *oldname, vno goto cleanup; // link node to new name - error = hashtable_set(&targetdir->children, node, newname, newlen, true); + error = hashtable_set(&targetdir->children, sourcefile, newname, newlen, true); if (error) goto cleanup; diff --git a/kernel-src/fs/vfs.c b/kernel-src/fs/vfs.c index ce57e718..f5712360 100644 --- a/kernel-src/fs/vfs.c +++ b/kernel-src/fs/vfs.c @@ -440,6 +440,8 @@ int vfs_write_iovec(vnode_t *node, iovec_iterator_t *iovec_iterator, size_t size page_t *page = NULL; if (startoffset) { + if (node->type == V_TYPE_BLKDEV) + arch_e9_puts("1\n"); // unaligned first page err = vmmcache_getpage(node, pageoffset * PAGE_SIZE, &page); if (err) @@ -469,6 +471,8 @@ int vfs_write_iovec(vnode_t *node, iovec_iterator_t *iovec_iterator, size_t size } for (uintmax_t offset = 0; offset < pagecount * PAGE_SIZE; offset += PAGE_SIZE) { + if (node->type == V_TYPE_BLKDEV) + arch_e9_puts("2\n"); // the other pages err = vmmcache_getpage(node, pageoffset * PAGE_SIZE + offset, &page); if (err) @@ -759,69 +763,48 @@ int vfs_rename(vnode_t *srcref, char *srcpath, vnode_t *dstref, char *dstpath, i if (srcdir != dstdir) VOP_LOCK(srcdir); // lock it again for the other ops if they arent the same - bool srcdotdot = strcmp(srccomp, "..") == 0; - bool dstdotdot = strcmp(dstcomp, "..") == 0; - vnode_t *src = NULL; - vnode_t *dst = NULL; - - err = VOP_LOOKUP(srcdir, srccomp, &src, getcred()); - if (err) - goto cleanup_locks; - - // srcdir is unlocked by VOP_LOOKUP if srccomp is ".." - if (srcdotdot) - VOP_LOCK(srcdir); - - VOP_UNLOCK(src); // locked by VOP_LOOKUP, unlocked here to allow the other VOP_LOOKUP to not deadlock - - err = VOP_LOOKUP(dstdir, dstcomp, &dst, getcred()); - if (err != 0 && err != ENOENT) { - VOP_RELEASE(src); + // . and .. will not be handled + if (strcmp(srccomp, "..") == 0 || strcmp(srccomp, ".") == 0) { + err = EBUSY; goto cleanup_locks; } - // dstdir is unlocked by VOP_LOOKUP if dstcomp is ".." - if (dstdotdot) - VOP_LOCK(dstdir); + if (strcmp(dstcomp, "..") == 0 || strcmp(dstcomp, ".") == 0) { + err = EEXIST; + goto cleanup_locks; + } - if (src != dst) - VOP_LOCK(src); // lock it again for the rename if they arent the same + // TODO EINVAL in case of dstdir being in a prefix of srcdir (or vice versa, forgot) + + vnode_t *src = NULL; + err = VOP_LOOKUP(srcdir, srccomp, &src, getcred()); + if (err) + goto cleanup_locks; // check if we can rename the old file err = auth_filesystem_check(getcred(), AUTH_ACTIONS_FILESYSTEM_RENAME, src, srcdir) ? EACCES : 0; if (err) goto cleanup_child; - if (dst) { - // and if we have a file, check if we can replace it - err = auth_filesystem_check(getcred(), AUTH_ACTIONS_FILESYSTEM_UNLINK, dst, dstdir) ? EACCES : 0; - if (err) - goto cleanup_child; - } + err = auth_filesystem_check(getcred(), AUTH_ACTIONS_FILESYSTEM_RENAME, src, dstdir) ? EACCES : 0; + if (err) + goto cleanup_child; // and if we can then write the new link to the directory err = VOP_ACCESS(dstdir, V_ACCESS_WRITE, getcred()); if (err) goto cleanup_child; - err = VOP_RENAME(srcdir, src, srccomp, dstdir, dst, dstcomp, flags); + err = VOP_RENAME(srcdir, src, srccomp, dstdir, dstcomp, flags); cleanup_child: - if (src != dst) - VOP_UNLOCK(src); - - if (dst) - VOP_UNLOCK(dst); - + VOP_UNLOCK(src); // locked by VOP_LOOKUP VOP_RELEASE(src); - if (dst) - VOP_RELEASE(dst); - cleanup_locks: if (srcdir != dstdir) - VOP_UNLOCK(srcdir); + VOP_UNLOCK(srcdir); // locked by vfs_lookup VOP_UNLOCK(dstdir); // locked by vfs_lookup VOP_RELEASE(srcdir); diff --git a/kernel-src/include/kernel/fatfs.h b/kernel-src/include/kernel/fatfs.h index b8af74c9..dfc927a1 100644 --- a/kernel-src/include/kernel/fatfs.h +++ b/kernel-src/include/kernel/fatfs.h @@ -114,5 +114,6 @@ int fatfs_rw_bytes_iovec(fatfs_t *fs, fatnode_t *node, iovec_iterator_t *iovec_i int fatfs_rw_bytes(fatfs_t *fs, fatnode_t *node, void *buffer, size_t count, uintmax_t offset, bool write, bool cache); int fatfs_get_file_disk_offset(fatfs_t *fatfs, fatnode_t *node, size_t byte_offset, size_t *disk_offset); int fatfs_write_directory_entry(fatfs_t *fatfs, fatnode_t *fatnode, fatfs_dent_t *dent, const char *name, size_t *disk_offset); +int fatfs_destroy_chain(fatfs_t *fatfs, fatfs_cluster_t cluster); #endif diff --git a/kernel-src/include/kernel/vfs.h b/kernel-src/include/kernel/vfs.h index 7a1d070f..12c87d0e 100644 --- a/kernel-src/include/kernel/vfs.h +++ b/kernel-src/include/kernel/vfs.h @@ -158,7 +158,7 @@ typedef struct vops_t { int (*ioctl)(vnode_t *node, unsigned long request, void *arg, int *result, cred_t *cred); int (*maxseek)(vnode_t *node, size_t *max); int (*resize)(vnode_t *node, size_t newsize, cred_t *cred); - int (*rename)(vnode_t *sourcedir, vnode_t *source, char *oldname, vnode_t *targetdir, vnode_t *target, char *newname, int flags); + int (*rename)(vnode_t *sourcedir, vnode_t *source, char *oldname, vnode_t *targetdir, char *newname, int flags); int (*getpage)(vnode_t *node, uintmax_t offset, struct page_t *page); int (*putpage)(vnode_t *node, uintmax_t offset, struct page_t *page); int (*sync)(vnode_t *node); @@ -218,7 +218,7 @@ typedef struct vops_t { #define VOP_IOCTL(v, r, a, rp, c) ((v)->ops->ioctl ? (v)->ops->ioctl(v, r, a, rp, c) : ENOTTY) #define VOP_MAXSEEK(v, rp) ((v)->ops->maxseek ? (v)->ops->maxseek(v, rp) : ENOTTY) #define VOP_RESIZE(v, s, c) (v)->ops->resize(v, s, c) -#define VOP_RENAME(sd, s, o, td, t, n, f) (s)->ops->rename(sd, s, o, td, t, n, f) +#define VOP_RENAME(sd, s, o, td, n, f) (s)->ops->rename(sd, s, o, td, n, f) #define VOP_GETPAGE(v, o, p) (v)->ops->getpage(v, o, p) #define VOP_PUTPAGE(v, o, p) (v)->ops->putpage(v, o, p) #define VOP_SYNC(v) (v)->ops->sync(v)