diff --git a/Makefile b/Makefile index 9b83591..0506f87 100644 --- a/Makefile +++ b/Makefile @@ -188,6 +188,7 @@ UPROGS=\ $U/_grind\ $U/_wc\ $U/_zombie\ + $U/_symlinktest\ diff --git a/kernel/fcntl.h b/kernel/fcntl.h index 44861b9..b42df18 100644 --- a/kernel/fcntl.h +++ b/kernel/fcntl.h @@ -3,3 +3,4 @@ #define O_RDWR 0x002 #define O_CREATE 0x200 #define O_TRUNC 0x400 +#define O_NOFOLLOW 0x800 \ No newline at end of file diff --git a/kernel/stat.h b/kernel/stat.h index 19543af..bd8fe00 100644 --- a/kernel/stat.h +++ b/kernel/stat.h @@ -1,7 +1,7 @@ #define T_DIR 1 // Directory #define T_FILE 2 // File #define T_DEVICE 3 // Device - +#define T_SYMLINK 4 struct stat { int dev; // File system's disk device uint ino; // Inode number diff --git a/kernel/syscall.c b/kernel/syscall.c index ed65409..22476be 100644 --- a/kernel/syscall.c +++ b/kernel/syscall.c @@ -101,6 +101,7 @@ extern uint64 sys_unlink(void); extern uint64 sys_link(void); extern uint64 sys_mkdir(void); extern uint64 sys_close(void); +extern uint64 sys_symlink(void); // An array mapping syscall numbers from syscall.h // to the function that handles the system call. @@ -126,6 +127,7 @@ static uint64 (*syscalls[])(void) = { [SYS_link] sys_link, [SYS_mkdir] sys_mkdir, [SYS_close] sys_close, +[SYS_symlink] sys_symlink, }; void diff --git a/kernel/syscall.h b/kernel/syscall.h index bc5f356..0fbf6ed 100644 --- a/kernel/syscall.h +++ b/kernel/syscall.h @@ -20,3 +20,4 @@ #define SYS_link 19 #define SYS_mkdir 20 #define SYS_close 21 +#define SYS_symlink 22 \ No newline at end of file diff --git a/kernel/sysfile.c b/kernel/sysfile.c index 16b668c..a9d87b8 100644 --- a/kernel/sysfile.c +++ b/kernel/sysfile.c @@ -335,6 +335,36 @@ sys_open(void) } } + if (ip->type == T_SYMLINK && !(omode & O_NOFOLLOW)) { + int symlink_step = 0; + while (ip->type == T_SYMLINK) { + if (symlink_step++ > 10) { + // printf("\x1b[031mFailed\x1b[0m due to deep symlink\n"); + iunlockput(ip); // on error, put inode 'cause only success open need to use the file after the syscall + end_op(); + return -1; + } + int len_target = readi(ip, 0, (uint64)path, 0, MAXPATH); + iunlockput(ip); // no more need to use this inode + if (len_target == 0) { + printf("\x1b[031mFailed\x1b[0m to read symlink %s\n", path); + end_op(); + return -1; + } + // get target's inode + if((ip = namei(path)) == 0){ + // printf("\x1b[031mFailed\x1b[0m open symlink target %s\n", path); + end_op(); + return -1; + } + ilock(ip); + if(ip->type == T_DIR && omode != O_RDONLY){ + iunlockput(ip); + end_op(); + return -1; + } + } + } if(ip->type == T_DEVICE && (ip->major < 0 || ip->major >= NDEV)){ iunlockput(ip); end_op(); @@ -503,3 +533,32 @@ sys_pipe(void) } return 0; } + +uint64 +sys_symlink(void) +{ + char target[MAXPATH], path[MAXPATH]; + int len_target, len_path; + struct inode* ip; + if ((len_target = argstr(0, target, MAXPATH)) < 0) + return -1; + if ((len_path = argstr(1, path, MAXPATH)) < 0) + return -1; + // printf("\x1b[033msys_symlink\x1b[0m %s -> %s\n", path, target); + begin_op(); + ip = create(path, T_SYMLINK, 0, 0); + if (ip == 0) { + end_op(); + // printf("\x1b[031mFailed\x1b[0m to create path %s\n", path); + return -1; + } + if (writei(ip, 0, (uint64)target, 0, len_target) != len_target) { + iunlockput(ip); + end_op(); + printf("\x1b[031mFailed\x1b[0m to write symlink target %s to %s\n", target, path); + return -1; + } + iunlockput(ip); // no need to keep this inode ref, if not put, in-RAM inode pool will run out + end_op(); + return 0; +} \ No newline at end of file diff --git a/time.txt b/time.txt new file mode 100644 index 0000000..c793025 --- /dev/null +++ b/time.txt @@ -0,0 +1 @@ +7 \ No newline at end of file diff --git a/user/bigfile.c b/user/bigfile.c index a484040..9b50719 100644 --- a/user/bigfile.c +++ b/user/bigfile.c @@ -32,11 +32,8 @@ main() printf("bigfile: file is too small\n"); exit(-1); } - printf("bef close fd\n"); close(fd); - printf("aft close fd\n"); fd = open("big.file", O_RDONLY); - printf("aft open\n"); if(fd < 0){ printf("bigfile: cannot re-open big.file for reading\n"); exit(-1); diff --git a/user/user.h b/user/user.h index 4d398d5..7b768a5 100644 --- a/user/user.h +++ b/user/user.h @@ -22,6 +22,7 @@ int getpid(void); char* sbrk(int); int sleep(int); int uptime(void); +int symlink(char* target, char* path); // ulib.c int stat(const char*, struct stat*); diff --git a/user/usys.pl b/user/usys.pl index 01e426e..bc5c22e 100755 --- a/user/usys.pl +++ b/user/usys.pl @@ -36,3 +36,4 @@ entry("getpid"); entry("sbrk"); entry("sleep"); entry("uptime"); +entry("symlink");