From b58b151ff3f69422ba1d553f66455700cd3c204b Mon Sep 17 00:00:00 2001 From: Minep Date: Tue, 2 Aug 2022 15:21:36 +0100 Subject: [PATCH] feat: symlink(2) and realpathat syscall feat: symbolic link following --- lunaix-os/includes/lunaix/fctrl.h | 10 ++- lunaix-os/includes/lunaix/fs.h | 3 + lunaix-os/includes/lunaix/lunistd.h | 2 + lunaix-os/includes/lunaix/spike.h | 4 +- lunaix-os/includes/lunaix/status.h | 1 + lunaix-os/includes/lunaix/syscall.h | 2 + lunaix-os/includes/lunaix/types.h | 1 + lunaix-os/kernel/asm/x86/syscall.S | 2 + lunaix-os/kernel/demos/dir_read.c | 2 +- lunaix-os/kernel/fs/vfs.c | 122 +++++++++++++++++++++++++--- 10 files changed, 131 insertions(+), 18 deletions(-) diff --git a/lunaix-os/includes/lunaix/fctrl.h b/lunaix-os/includes/lunaix/fctrl.h index b8bb08f..dc28872 100644 --- a/lunaix-os/includes/lunaix/fctrl.h +++ b/lunaix-os/includes/lunaix/fctrl.h @@ -7,10 +7,10 @@ __LXSYSCALL2(int, open, const char*, path, int, options) -__LXSYSCALL1(int, mkdir, const char*, path); -__LXSYSCALL2(int, unlinkat, int, fd, const char*, pathname); +__LXSYSCALL1(int, mkdir, const char*, path) +__LXSYSCALL2(int, unlinkat, int, fd, const char*, pathname) -__LXSYSCALL2(int, readdir, int, fd, struct dirent*, dent); +__LXSYSCALL2(int, readdir, int, fd, struct dirent*, dent) __LXSYSCALL4(int, readlinkat, @@ -21,6 +21,8 @@ __LXSYSCALL4(int, char*, buf, size_t, - size); + size) + +__LXSYSCALL3(int, realpathat, int, fd, char*, buf, size_t, size) #endif /* __LUNAIX_FCTRL_H */ diff --git a/lunaix-os/includes/lunaix/fs.h b/lunaix-os/includes/lunaix/fs.h index 43a5cf4..bc22fd5 100644 --- a/lunaix-os/includes/lunaix/fs.h +++ b/lunaix-os/includes/lunaix/fs.h @@ -27,6 +27,7 @@ #define VFS_WALK_MKPARENT 0x1 #define VFS_WALK_FSRELATIVE 0x2 #define VFS_WALK_PARENT 0x4 +#define VFS_WALK_NOFOLLOW 0x4 #define VFS_IOBUF_FDIRTY 0x1 @@ -124,6 +125,8 @@ struct v_inode int (*rmdir)(struct v_inode* this); int (*unlink)(struct v_inode* this); int (*link)(struct v_inode* this, struct v_dnode* new_name); + int (*read_symlink)(struct v_inode* this, const char** path_out); + int (*symlink)(struct v_inode* this, const char* target); int (*dir_lookup)(struct v_inode* this, struct v_dnode* dnode); } ops; }; diff --git a/lunaix-os/includes/lunaix/lunistd.h b/lunaix-os/includes/lunaix/lunistd.h index 472f638..556f239 100644 --- a/lunaix-os/includes/lunaix/lunistd.h +++ b/lunaix-os/includes/lunaix/lunistd.h @@ -47,4 +47,6 @@ __LXSYSCALL1(int, dup, int, oldfd) __LXSYSCALL1(int, fsync, int, fildes) +__LXSYSCALL2(int, symlink, const char*, pathname, const char*, link_target) + #endif /* __LUNAIX_UNISTD_H */ diff --git a/lunaix-os/includes/lunaix/spike.h b/lunaix-os/includes/lunaix/spike.h index 4e17993..4363b41 100644 --- a/lunaix-os/includes/lunaix/spike.h +++ b/lunaix-os/includes/lunaix/spike.h @@ -3,12 +3,12 @@ // Some helper functions. As helpful as Spike the Dragon! :) -// 除法向上取整 +// 除法 v/(2^k) 向上取整 #define CEIL(v, k) (((v) + (1 << (k)) - 1) >> (k)) #define ICEIL(x, y) ((x) / (y) + ((x) % (y) != 0)) -// 除法向下取整 +// 除法 v/(2^k) 向下取整 #define FLOOR(v, k) ((v) >> (k)) // 获取v最近的最大k倍数 diff --git a/lunaix-os/includes/lunaix/status.h b/lunaix-os/includes/lunaix/status.h index df1a1d8..fe9224c 100644 --- a/lunaix-os/includes/lunaix/status.h +++ b/lunaix-os/includes/lunaix/status.h @@ -24,5 +24,6 @@ #define EISDIR -19 #define EBUSY -20 #define EXDEV -21 +#define ELOOP -22 #endif /* __LUNAIX_CODE_H */ diff --git a/lunaix-os/includes/lunaix/syscall.h b/lunaix-os/includes/lunaix/syscall.h index 30941f6..94d197a 100644 --- a/lunaix-os/includes/lunaix/syscall.h +++ b/lunaix-os/includes/lunaix/syscall.h @@ -41,6 +41,8 @@ #define __SYSCALL_fsync 33 #define __SYSCALL_dup 34 #define __SYSCALL_dup2 35 +#define __SYSCALL_realpathat 36 +#define __SYSCALL_symlink 37 #define __SYSCALL_MAX 0x100 diff --git a/lunaix-os/includes/lunaix/types.h b/lunaix-os/includes/lunaix/types.h index e91025a..4a1f275 100644 --- a/lunaix-os/includes/lunaix/types.h +++ b/lunaix-os/includes/lunaix/types.h @@ -1,6 +1,7 @@ #ifndef __LUNAIX_TYPES_H #define __LUNAIX_TYPES_H +#include #include #define PEXITTERM 0x100 diff --git a/lunaix-os/kernel/asm/x86/syscall.S b/lunaix-os/kernel/asm/x86/syscall.S index ae63117..328afbf 100644 --- a/lunaix-os/kernel/asm/x86/syscall.S +++ b/lunaix-os/kernel/asm/x86/syscall.S @@ -43,6 +43,8 @@ .long __lxsys_fsync .long __lxsys_dup .long __lxsys_dup2 + .long __lxsys_realpathat + .long __lxsys_symlink 2: .rept __SYSCALL_MAX - (2b - 1b)/4 .long 0 diff --git a/lunaix-os/kernel/demos/dir_read.c b/lunaix-os/kernel/demos/dir_read.c index bc4e024..caa88cc 100644 --- a/lunaix-os/kernel/demos/dir_read.c +++ b/lunaix-os/kernel/demos/dir_read.c @@ -16,7 +16,7 @@ _readdir_main() } char path[129]; - int len = readlinkat(fd, ".", path, 128); + int len = realpathat(fd, path, 128); if (len < 0) { kprintf(KERROR "fail to read (%d)\n", geterrno()); } else { diff --git a/lunaix-os/kernel/fs/vfs.c b/lunaix-os/kernel/fs/vfs.c index 05741d8..fcceb70 100644 --- a/lunaix-os/kernel/fs/vfs.c +++ b/lunaix-os/kernel/fs/vfs.c @@ -114,11 +114,11 @@ vfs_dcache_add(struct v_dnode* parent, struct v_dnode* dnode) } int -vfs_walk(struct v_dnode* start, - const char* path, - struct v_dnode** dentry, - struct hstr* component, - int walk_options) +__vfs_walk(struct v_dnode* start, + const char* path, + struct v_dnode** dentry, + struct hstr* component, + int walk_options) { int errno = 0; int i = 0, j = 0; @@ -218,6 +218,45 @@ error: return errno; } +#define VFS_MAX_SYMLINK 16 + +int +vfs_walk(struct v_dnode* start, + const char* path, + struct v_dnode** dentry, + struct hstr* component, + int options) +{ + struct v_dnode* interim; + char* pathname = path; + int errno = __vfs_walk(start, path, &interim, component, options); + int counter = 0; + + while (!errno) { + if (counter >= VFS_MAX_SYMLINK) { + errno = ELOOP; + continue; + } + if ((interim->inode->itype & VFS_INODE_TYPE_SYMLINK) && + !(options & VFS_WALK_NOFOLLOW) && + interim->inode->ops.read_symlink) { + errno = interim->inode->ops.read_symlink(interim->inode, &pathname); + if (errno) { + break; + } + } else { + break; + } + errno = + __vfs_walk_internal(start, pathname, &interim, component, options); + counter++; + } + + *dentry = errno ? 0 : interim; + + return errno; +} + int vfs_mount(const char* target, const char* fs_name, bdev_t device) { @@ -632,7 +671,7 @@ __DEFINE_LXSYSCALL3(int, lseek, int, fd, int, offset, int, options) } int -vfs_readlink(struct v_dnode* dnode, char* buf, size_t size, int depth) +vfs_get_path(struct v_dnode* dnode, char* buf, size_t size, int depth) { if (!dnode) { return 0; @@ -642,7 +681,7 @@ vfs_readlink(struct v_dnode* dnode, char* buf, size_t size, int depth) return ELOOP; } - size_t len = vfs_readlink(dnode->parent, buf, size, depth + 1); + size_t len = vfs_get_path(dnode->parent, buf, size, depth + 1); if (len >= size) { return len; @@ -659,12 +698,42 @@ vfs_readlink(struct v_dnode* dnode, char* buf, size_t size, int depth) return len; } +int +vfs_readlink(struct v_dnode* dnode, char* buf, size_t size) +{ + char* link; + if (dnode->inode->ops.read_symlink) { + int errno = dnode->inode->ops.read_symlink(dnode->inode, &link); + strncpy(buf, link, size); + return errno; + } + return 0; +} + +__DEFINE_LXSYSCALL3(int, realpathat, int, fd, char*, buf, size_t, size) +{ + int errno; + struct v_fd* fd_s; + if (!GET_FD(fd, fd_s)) { + errno = EBADF; + } else { + struct v_dnode* dnode; + errno = vfs_get_path(fd_s->file->dnode, buf, size, 0); + } + + if (errno >= 0) { + return errno; + } + + return DO_STATUS(errno); +} + __DEFINE_LXSYSCALL3(int, readlink, const char*, path, char*, buf, size_t, size) { int errno; struct v_dnode* dnode; - if (!(errno = vfs_walk(NULL, path, &dnode, NULL, 0))) { - errno = vfs_readlink(dnode, buf, size, 0); + if (!(errno = vfs_walk(NULL, path, &dnode, NULL, VFS_WALK_NOFOLLOW))) { + errno = vfs_readlink(dnode, buf, size); } if (errno >= 0) { @@ -691,8 +760,12 @@ __DEFINE_LXSYSCALL4(int, errno = EBADF; } else { struct v_dnode* dnode; - if (!(errno = vfs_walk(fd_s->file->dnode, pathname, &dnode, NULL, 0))) { - errno = vfs_readlink(fd_s->file->dnode, buf, size, 0); + if (!(errno = vfs_walk(fd_s->file->dnode, + pathname, + &dnode, + NULL, + VFS_WALK_NOFOLLOW))) { + errno = vfs_readlink(fd_s->file->dnode, buf, size); } } @@ -868,5 +941,32 @@ __DEFINE_LXSYSCALL1(int, dup, int, oldfd) return newfd; } + return DO_STATUS(errno); +} + +__DEFINE_LXSYSCALL2(int, + symlink, + const char*, + pathname, + const char*, + link_target) +{ + int errno; + struct v_dnode* dnode; + if ((errno = vfs_walk(NULL, pathname, &dnode, NULL, 0))) { + goto done; + } + if ((dnode->super_block->fs->types & FSTYPE_ROFS)) { + errno = EROFS; + goto done; + } + if (!dnode->inode->ops.symlink) { + errno = ENOTSUP; + goto done; + } + + errno = dnode->inode->ops.symlink(dnode->inode, link_target); + +done: return DO_STATUS(errno); } \ No newline at end of file -- 2.27.0