fs: change how rename() is handled

This commit is contained in:
Matheus
2025-10-17 13:51:35 -03:00
parent 36c3976c05
commit 7da3557d32
7 changed files with 282 additions and 151 deletions
+116 -50
View File
@@ -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;
}
+90 -36
View File
@@ -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;
+17 -5
View File
@@ -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;
+33 -18
View File
@@ -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;
+23 -40
View File
@@ -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);
+1
View File
@@ -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
+2 -2
View File
@@ -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)