diff options
Diffstat (limited to 'kernel/sysfile.c')
-rw-r--r-- | kernel/sysfile.c | 71 |
1 files changed, 71 insertions, 0 deletions
diff --git a/kernel/sysfile.c b/kernel/sysfile.c index 4b2189a..9c12d44 100644 --- a/kernel/sysfile.c +++ b/kernel/sysfile.c @@ -16,6 +16,15 @@ #include "file.h" #include "fcntl.h" +// symlink +#define SYMLINK_MAXFOLLOW 254 + +struct symlink { + uint len; + char target[MAXPATH]; +}; + + // Fetch the nth word-sized system call argument as a file descriptor // and return both the descriptor and the corresponding struct file. static int @@ -258,6 +267,8 @@ create(char *path, short type, short major, short minor) ilock(ip); if(type == T_FILE && (ip->type == T_FILE || ip->type == T_DEVICE)) return ip; + if(type == T_SYMLINK) + return ip; iunlockput(ip); return 0; } @@ -301,6 +312,37 @@ create(char *path, short type, short major, short minor) return 0; } +// create a symbolic link to path +uint64 +sys_symlink(void) +{ + char path[MAXPATH]; + struct inode *ip; + struct symlink sl = {0}; + + if(argstr(0, sl.target, MAXPATH) < 0 || argstr(1, path, MAXPATH) < 0) + return -1; + + sl.len = strlen(sl.target); + + begin_op(); + if((ip = create(path, T_SYMLINK, 0, 0)) == 0){ + end_op(); + return -1; + } + + if(writei(ip, 0, (uint64)&sl.len, 0, sizeof(sl.len)) != sizeof(sl.len) || writei(ip, 0, (uint64)sl.target, sizeof(sl.len), sl.len+1) != sl.len+1){ + iunlockput(ip); + end_op(); + return -1; + } + + iupdate(ip); + iunlockput(ip); + end_op(); + return 0; +} + uint64 sys_open(void) { @@ -341,6 +383,35 @@ sys_open(void) return -1; } + if(ip->type == T_SYMLINK && !(omode & O_NOFOLLOW)){ + int len = 0; + uchar i; + for(i = 0; i < SYMLINK_MAXFOLLOW; i++){ + if(readi(ip, 0, (uint64)&len, 0, sizeof(len)) != sizeof(len) || + readi(ip, 0, (uint64)path, sizeof(len), len+1) != len+1) { + iunlockput(ip); + end_op(); + return -1; + } + iunlockput(ip); + + if((ip = namei(path)) == 0) { + end_op(); + return -1; + } + + ilock(ip); + if(ip->type != T_SYMLINK) + break; + } + + if (i >= SYMLINK_MAXFOLLOW) { + iunlockput(ip); + end_op(); + return -1; + } + } + if((f = filealloc()) == 0 || (fd = fdalloc(f)) < 0){ if(f) fileclose(f); |