mirror of
https://github.com/Mathewnd/Astral.git
synced 2026-10-29 21:58:20 +00:00
kernel: rename VOP and syscall
This commit is contained in:
@@ -39,6 +39,7 @@ extern syscall_ftruncate
|
||||
extern syscall_mount
|
||||
extern syscall_fchownat
|
||||
extern syscall_utimensat
|
||||
extern syscall_renameat
|
||||
syscalltab:
|
||||
dq syscall_print
|
||||
dq syscall_mmap
|
||||
@@ -80,7 +81,8 @@ dq syscall_ftruncate
|
||||
dq syscall_mount
|
||||
dq syscall_fchownat
|
||||
dq syscall_utimensat
|
||||
syscallcount equ 40
|
||||
dq syscall_renameat
|
||||
syscallcount equ 41
|
||||
section .text
|
||||
global arch_syscall_entry
|
||||
; on entry:
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
#ifdef SYSCALL_LOGGING
|
||||
|
||||
#define SYSCALL_COUNT 40
|
||||
#define SYSCALL_COUNT 41
|
||||
#define LOGSTR(x) arch_e9_puts(x)
|
||||
|
||||
static char *name[] = {
|
||||
@@ -48,6 +48,7 @@ static char *name[] = {
|
||||
"mount",
|
||||
"fchownat",
|
||||
"utimensat",
|
||||
"renameat"
|
||||
};
|
||||
|
||||
static char *args[] = {
|
||||
@@ -90,7 +91,8 @@ static char *args[] = {
|
||||
"fd %d size %lu", // ftruncate
|
||||
"backing %p mountpoint %s fs %s flags %d data %p", // mount
|
||||
"fd %d path %s owner %d group %d flags %x", // fchownat
|
||||
"dirfd %d path %p times %p flags %x" // utimensat
|
||||
"dirfd %d path %p times %p flags %x", // utimensat
|
||||
"olddirfd %d oldpath %s newdirfd %d newpath %s flags %d" // renameat
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -334,7 +334,8 @@ static vops_t vnops = {
|
||||
.isatty = devfs_isatty,
|
||||
.ioctl = devfs_ioctl,
|
||||
.maxseek = devfs_maxseek,
|
||||
.resize = devfs_enodev
|
||||
.resize = devfs_enodev,
|
||||
.rename = devfs_enodev
|
||||
};
|
||||
|
||||
static void ctor(scache_t *cache, void *obj) {
|
||||
|
||||
@@ -235,7 +235,8 @@ static vops_t vnops = {
|
||||
.mmap = pipefs_enodev,
|
||||
.munmap = pipefs_enodev,
|
||||
.getdents = pipefs_enodev,
|
||||
.resize = pipefs_enodev
|
||||
.resize = pipefs_enodev,
|
||||
.rename = pipefs_enodev
|
||||
};
|
||||
|
||||
static void ctor(scache_t *cache, void *obj) {
|
||||
|
||||
+65
-2
@@ -343,6 +343,68 @@ static int tmpfs_link(vnode_t *node, vnode_t *dir, char *name, cred_t *cred) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tmpfs_rename(vnode_t *source, char *oldname, vnode_t *target, char *newname, int flags) {
|
||||
if (source->vfs != target->vfs)
|
||||
return EXDEV;
|
||||
|
||||
if (source->type != V_TYPE_DIR || target->type != V_TYPE_DIR)
|
||||
return ENOTDIR;
|
||||
|
||||
tmpfsnode_t *sourcedir = (tmpfsnode_t *)source;
|
||||
tmpfsnode_t *targetdir = (tmpfsnode_t *)target;
|
||||
|
||||
size_t oldlen = strlen(oldname);
|
||||
size_t newlen = strlen(newname);
|
||||
|
||||
if (target != source) {
|
||||
VOP_LOCK(source);
|
||||
VOP_LOCK(target);
|
||||
} else {
|
||||
VOP_LOCK(target);
|
||||
}
|
||||
|
||||
// get original node
|
||||
void *v;
|
||||
int error = hashtable_get(&sourcedir->children, &v, oldname, oldlen);
|
||||
if (error)
|
||||
goto cleanup;
|
||||
|
||||
vnode_t *node = v;
|
||||
vnode_t *oldnode = NULL;
|
||||
|
||||
// get old node in target
|
||||
error = hashtable_get(&targetdir->children, &v, newname, newlen);
|
||||
if (error != ENOENT && error != 0)
|
||||
goto cleanup;
|
||||
else if (error == 0) // found
|
||||
oldnode = v;
|
||||
|
||||
// same link, rename is a no-op
|
||||
if (sourcedir == targetdir && strcmp(oldname, newname) == 0)
|
||||
goto cleanup;
|
||||
|
||||
// link node to new name
|
||||
error = hashtable_set(&targetdir->children, node, newname, newlen, true);
|
||||
if (error)
|
||||
goto cleanup;
|
||||
|
||||
// remove old link. should not fail
|
||||
__assert(hashtable_remove(&sourcedir->children, oldname, oldlen) == 0);
|
||||
|
||||
if (oldnode)
|
||||
VOP_RELEASE(oldnode);
|
||||
|
||||
cleanup:
|
||||
if (target != source) {
|
||||
VOP_UNLOCK(target);
|
||||
VOP_UNLOCK(source);
|
||||
} else {
|
||||
VOP_UNLOCK(target);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static int tmpfs_symlink(vnode_t *node, char *name, vattr_t *attr, char *path, cred_t *cred) {
|
||||
if (node->type != V_TYPE_DIR)
|
||||
return ENOTDIR;
|
||||
@@ -458,7 +520,7 @@ static int tmpfs_getdents(vnode_t *node, dent_t *buffer, size_t count, uintmax_t
|
||||
ent->d_off = offset;
|
||||
ent->d_reclen = sizeof(dent_t);
|
||||
ent->d_type = vfs_getposixtype(itmpnode->vnode.type);
|
||||
strcpy(ent->d_name, entry->key);
|
||||
memcpy(ent->d_name, entry->key, entry->keysize);
|
||||
|
||||
*readcount += 1;
|
||||
}
|
||||
@@ -505,7 +567,8 @@ static vops_t vnops = {
|
||||
.mmap = tmpfs_mmap,
|
||||
.munmap = tmpfs_munmap,
|
||||
.getdents = tmpfs_getdents,
|
||||
.resize = tmpfs_resize
|
||||
.resize = tmpfs_resize,
|
||||
.rename = tmpfs_rename
|
||||
};
|
||||
|
||||
static tmpfsnode_t *newnode(vfs_t *vfs, int type) {
|
||||
|
||||
@@ -98,6 +98,7 @@ typedef struct vops_t {
|
||||
int (*ioctl)(vnode_t *node, unsigned long request, void *arg, int *result);
|
||||
int (*maxseek)(vnode_t *node, size_t *max);
|
||||
int (*resize)(vnode_t *node, size_t newsize, cred_t *cred);
|
||||
int (*rename)(vnode_t *source, char *oldname, vnode_t *target, char *newname, int flags);
|
||||
} vops_t;
|
||||
|
||||
#define VFS_INIT(v, o, f) \
|
||||
@@ -145,6 +146,7 @@ typedef struct vops_t {
|
||||
#define VOP_IOCTL(v, r, a, rp) ((v)->ops->ioctl ? (v)->ops->ioctl(v, r, a, rp) : 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(s, o, t, n, f) (s)->ops->rename(s, o, t, n, f)
|
||||
#define VOP_HOLD(v) __atomic_add_fetch(&(v)->refcount, 1, __ATOMIC_SEQ_CST)
|
||||
#define VOP_RELEASE(v) {\
|
||||
if (__atomic_sub_fetch(&(v)->refcount, 1, __ATOMIC_SEQ_CST) == 0) {\
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
#include <kernel/syscalls.h>
|
||||
#include <kernel/alloc.h>
|
||||
#include <string.h>
|
||||
#include <logging.h>
|
||||
|
||||
syscallret_t syscall_renameat(context_t *context, int olddirfd, const char *uoldpath, int newdirfd, const char *unewpath, unsigned int flags) {
|
||||
syscallret_t ret = {
|
||||
.ret = -1
|
||||
};
|
||||
|
||||
__assert(flags == 0);
|
||||
|
||||
char *oldcomponent = NULL;
|
||||
char *newcomponent = NULL;
|
||||
char *oldpath = alloc(strlen(uoldpath) + 1);
|
||||
if (oldpath == NULL) {
|
||||
ret.errno = ENOMEM;
|
||||
return ret;
|
||||
}
|
||||
|
||||
char *newpath = alloc(strlen(unewpath) + 1);
|
||||
if (newpath == NULL) {
|
||||
free(oldpath);
|
||||
ret.errno = ENOMEM;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// TODO safe strcopy
|
||||
strcpy(oldpath, uoldpath);
|
||||
strcpy(newpath, unewpath);
|
||||
|
||||
vnode_t *olddirnode = NULL;
|
||||
file_t *oldfile = NULL;
|
||||
vnode_t *newdirnode = NULL;
|
||||
file_t *newfile = NULL;
|
||||
vnode_t *targetdirnode = NULL;
|
||||
vnode_t *sourcedirnode = NULL;
|
||||
ret.errno = dirfd_enter(oldpath, olddirfd, &oldfile, &olddirnode);
|
||||
|
||||
if (ret.errno)
|
||||
goto cleanup;
|
||||
|
||||
ret.errno = dirfd_enter(newpath, newdirfd, &newfile, &newdirnode);
|
||||
|
||||
if (ret.errno)
|
||||
goto cleanup;
|
||||
|
||||
oldcomponent = alloc(strlen(oldpath));
|
||||
newcomponent = alloc(strlen(newpath));
|
||||
|
||||
if (oldcomponent == NULL && newcomponent == NULL)
|
||||
goto cleanup;
|
||||
|
||||
ret.errno = vfs_lookup(&sourcedirnode, olddirnode, oldpath, oldcomponent, VFS_LOOKUP_NOLINK | VFS_LOOKUP_PARENT);
|
||||
if (ret.errno)
|
||||
goto cleanup;
|
||||
|
||||
ret.errno = vfs_lookup(&targetdirnode, newdirnode, newpath, newcomponent, VFS_LOOKUP_NOLINK | VFS_LOOKUP_PARENT);
|
||||
if (ret.errno)
|
||||
goto cleanup;
|
||||
|
||||
ret.errno = VOP_RENAME(sourcedirnode, oldcomponent, targetdirnode, newcomponent, flags);
|
||||
ret.ret = ret.errno ? -1 : 0;
|
||||
|
||||
cleanup:
|
||||
|
||||
if (targetdirnode)
|
||||
VOP_RELEASE(targetdirnode);
|
||||
|
||||
if (sourcedirnode)
|
||||
VOP_RELEASE(sourcedirnode);
|
||||
|
||||
if (oldcomponent)
|
||||
free(oldcomponent);
|
||||
|
||||
if (newcomponent)
|
||||
free(newcomponent);
|
||||
|
||||
if (olddirnode)
|
||||
dirfd_leave(olddirnode, oldfile);
|
||||
|
||||
if (newdirnode)
|
||||
dirfd_leave(newdirnode, newfile);
|
||||
|
||||
free(oldpath);
|
||||
free(newpath);
|
||||
|
||||
return ret;
|
||||
}
|
||||
Reference in New Issue
Block a user