summaryrefslogtreecommitdiff
path: root/kernel/sysfile.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/sysfile.c')
-rw-r--r--kernel/sysfile.c71
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);