diff --git a/src/arch/x86_64/syscall.asm b/src/arch/x86_64/syscall.asm index 65b62b29..083b104b 100644 --- a/src/arch/x86_64/syscall.asm +++ b/src/arch/x86_64/syscall.asm @@ -30,7 +30,8 @@ extern syscall_mkdir extern syscall_munmap extern syscall_umask extern syscall_poll -func_count equ 29 +extern syscall_fchmodat +func_count equ 30 func_table: @@ -63,6 +64,7 @@ func_table: dq syscall_munmap dq syscall_umask dq syscall_poll + dq syscall_fchmodat section .text global asm_syscall_entry diff --git a/src/fs/devfs.c b/src/fs/devfs.c index aed19d1d..a7eeec75 100644 --- a/src/fs/devfs.c +++ b/src/fs/devfs.c @@ -77,8 +77,14 @@ static int devfs_getdirent(dirnode_t* node, dent_t* buff, size_t count, uintmax_ return 0; } +static int devfs_chmod(vnode_t* node, mode_t mode){ + node->st.st_mode &= ~07777; + node->st.st_mode |= mode & 07777; + return 0; +} + static fscalls_t devfscalls = { - devfs_mount, devfs_unmount, devfs_open, devfs_close, devfs_mkdir, devfs_create, devfs_write, devfs_read, devfs_getdirent + devfs_mount, devfs_unmount, devfs_open, devfs_close, devfs_mkdir, devfs_create, devfs_write, devfs_read, devfs_getdirent, devfs_chmod }; void devfs_init(){ diff --git a/src/fs/tmpfs.c b/src/fs/tmpfs.c index 18c2b901..cc4b26d2 100644 --- a/src/fs/tmpfs.c +++ b/src/fs/tmpfs.c @@ -155,8 +155,14 @@ static int tmpfs_getdirent(dirnode_t* node, dent_t* buff, size_t count, uintmax_ return 0; } +static int tmpfs_chmod(vnode_t* node, mode_t mode){ + node->st.st_mode &= ~07777; + node->st.st_mode |= mode & 07777; + return 0; +} + static fscalls_t funcs = { - tmpfs_mount, tmpfs_unmount, tmpfs_open, tmpfs_close, tmpfs_mkdir, tmpfs_create, tmpfs_write, tmpfs_read, tmpfs_getdirent + tmpfs_mount, tmpfs_unmount, tmpfs_open, tmpfs_close, tmpfs_mkdir, tmpfs_create, tmpfs_write, tmpfs_read, tmpfs_getdirent, tmpfs_chmod }; diff --git a/src/fs/vfs.c b/src/fs/vfs.c index d2059532..001fa66d 100644 --- a/src/fs/vfs.c +++ b/src/fs/vfs.c @@ -100,6 +100,21 @@ int vfs_isatty(vnode_t* node){ } +int vfs_chmod(vnode_t* node, mode_t mode){ + + if(!node->fs->calls->chmod) + return ENOSYS; + + spinlock_acquire(&lock); + + int ret = node->fs->calls->chmod(node, mode); + + spinlock_release(&lock); + + return ret; + +} + int vfs_poll(vnode_t* node, pollfd* fd){ switch(GETTYPE(node->st.st_mode)){ diff --git a/src/include/kernel/fd.h b/src/include/kernel/fd.h index 2f53cdff..73762f87 100644 --- a/src/include/kernel/fd.h +++ b/src/include/kernel/fd.h @@ -30,6 +30,7 @@ #define O_TMPFILE 020000000 #define MAX_FD 512 +#define AT_FDCWD -100 #include #include diff --git a/src/include/kernel/vfs.h b/src/include/kernel/vfs.h index 95ace7b4..3eaf517a 100644 --- a/src/include/kernel/vfs.h +++ b/src/include/kernel/vfs.h @@ -61,6 +61,8 @@ typedef struct _fscalls_t { int (*read)(int* error, vnode_t* node, void* buff, size_t count, size_t offset); // get dir ents int (*getdirent)(dirnode_t* node, dent_t* buff, size_t count, uintmax_t offset, size_t* readcount); + // change file mode + int (*chmod)(vnode_t* node, mode_t mode); } fscalls_t; @@ -76,6 +78,7 @@ int vfs_isatty(vnode_t* node); int vfs_getdirent(dirnode_t* node, dent_t* buff, size_t count, uintmax_t offset, size_t* readcount); int vfs_ioctl(vnode_t* node, unsigned long request, void* arg, int* result); int vfs_poll(vnode_t* node, pollfd* fd); +int vfs_chmod(vnode_t* node, mode_t mode); void vfs_init(); dirnode_t* vfs_root(); diff --git a/src/sys/syscalls/chmodat.c b/src/sys/syscalls/chmodat.c new file mode 100644 index 00000000..25a8fd3c --- /dev/null +++ b/src/sys/syscalls/chmodat.c @@ -0,0 +1,71 @@ +#include +#include +#include +#include +#include +#include + +// flags is ignored for now + +syscallret syscall_fchmodat(int dirfd, const char* path, mode_t mode, int flags){ + syscallret retv; + retv.ret = -1; + + + if(path > USER_SPACE_END){ + retv.errno = EFAULT; + return retv; + } + + size_t len = strlen(path); + + char buff[len+1]; + + strcpy(buff, path); + + proc_t* proc = arch_getcls()->thread->proc; + + dirnode_t* target; + fd_t* fd; + + if(dirfd != AT_FDCWD){ + + int err = fd_access(&proc->fdtable, &fd, dirfd); + + if(err){ + retv.errno = err; + return retv; + } + + if(GETTYPE(fd->mode) != TYPE_DIR){ + retv.errno = ENOTDIR; + goto _fail; + } + + target = fd->node; + } + else + target = proc->cwd; + + + vnode_t* node; + + retv.errno = vfs_open(&node, buff[0] == '/' ? proc->root : target, buff); + + if(retv.errno) + goto _fail; + + retv.errno = vfs_chmod(node, mode); + + vfs_close(node); + + _fail: + + if(dirfd != AT_FDCWD) + fd_release(fd); + + retv.ret = retv.errno ? -1 : 0; + + return retv; + +} diff --git a/src/sys/syscalls/fstatat.c b/src/sys/syscalls/fstatat.c index 55a4ee25..128dee23 100644 --- a/src/sys/syscalls/fstatat.c +++ b/src/sys/syscalls/fstatat.c @@ -6,8 +6,6 @@ #include #include -#define AT_FDCWD -100 - syscallret syscall_fstatat(int ifd, char* path, stat* st, int flags){ syscallret retv; retv.ret = -1; @@ -67,13 +65,13 @@ syscallret syscall_fstatat(int ifd, char* path, stat* st, int flags){ vfs_close(node); + retv.ret = 0; + _fail: if(ifd != AT_FDCWD) fd_release(fd); - retv.ret = 0; - return retv; }