summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMole Shang <[email protected]>2024-02-18 16:27:05 +0800
committerMole Shang <[email protected]>2024-02-18 16:27:05 +0800
commit0cf897cbe05fd8485162619db4244f4159d0eb52 (patch)
treeb18d401102a0215f979f12ec3acf709f9e7224c4
parent659b978caa5c97bbc2477d1393461c944544a1a7 (diff)
downloadxv6-labs-fs.tar.gz
xv6-labs-fs.tar.bz2
xv6-labs-fs.zip
lab fs/symlink: finishfs
-rw-r--r--Makefile1
-rw-r--r--kernel/fcntl.h1
-rw-r--r--kernel/file.h1
-rw-r--r--kernel/stat.h1
-rw-r--r--kernel/syscall.c3
-rw-r--r--kernel/sysfile.c71
-rw-r--r--user/user.h1
-rwxr-xr-xuser/usys.pl1
8 files changed, 80 insertions, 0 deletions
diff --git a/Makefile b/Makefile
index fd6e82e..8e50dfe 100644
--- a/Makefile
+++ b/Makefile
@@ -189,6 +189,7 @@ UPROGS=\
$U/_xargs\
$U/_trace\
$U/_sysinfotest\
+ $U/_symlinktest\
diff --git a/kernel/fcntl.h b/kernel/fcntl.h
index 44861b9..d7bb43b 100644
--- a/kernel/fcntl.h
+++ b/kernel/fcntl.h
@@ -1,5 +1,6 @@
#define O_RDONLY 0x000
#define O_WRONLY 0x001
#define O_RDWR 0x002
+#define O_NOFOLLOW 0x010
#define O_CREATE 0x200
#define O_TRUNC 0x400
diff --git a/kernel/file.h b/kernel/file.h
index b993cc3..05d9377 100644
--- a/kernel/file.h
+++ b/kernel/file.h
@@ -46,3 +46,4 @@ extern struct devsw devsw[];
#define CONSOLE 1
#define STATS 2
+
diff --git a/kernel/stat.h b/kernel/stat.h
index 19543af..9554d30 100644
--- a/kernel/stat.h
+++ b/kernel/stat.h
@@ -1,6 +1,7 @@
#define T_DIR 1 // Directory
#define T_FILE 2 // File
#define T_DEVICE 3 // Device
+#define T_SYMLINK 4 // Symbolic link
struct stat {
int dev; // File system's disk device
diff --git a/kernel/syscall.c b/kernel/syscall.c
index 172c5ea..c39ebd8 100644
--- a/kernel/syscall.c
+++ b/kernel/syscall.c
@@ -119,6 +119,7 @@ extern uint64 sys_connect(void);
#ifdef LAB_PGTBL
extern uint64 sys_pgaccess(void);
#endif
+extern uint64 sys_symlink(void);
// An array mapping syscall numbers from syscall.h
// to the function that handles the system call.
@@ -154,6 +155,7 @@ static uint64 (*syscalls[])(void) = {
[SYS_sysinfo] sys_sysinfo,
[SYS_sigalarm] sys_sigalarm,
[SYS_sigreturn] sys_sigreturn,
+[SYS_symlink] sys_symlink,
};
// syscall name maps for SYS_trace:
@@ -189,6 +191,7 @@ static char *syscall_names[] = {
[SYS_sysinfo] "sysinfo",
[SYS_sigalarm] "sigalarm",
[SYS_sigreturn] "sigreturn",
+[SYS_symlink] "symlink",
};
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);
diff --git a/user/user.h b/user/user.h
index 3544ac4..c1bccdd 100644
--- a/user/user.h
+++ b/user/user.h
@@ -39,6 +39,7 @@ int trace(int);
int sysinfo(struct sysinfo*);
int sigalarm(int ticks, void (*handler)());
int sigreturn(void);
+int symlink(char *, char *);
// ulib.c
int stat(const char*, struct stat*);
diff --git a/user/usys.pl b/user/usys.pl
index 33af0ad..7f07795 100755
--- a/user/usys.pl
+++ b/user/usys.pl
@@ -42,3 +42,4 @@ entry("connect");
entry("pgaccess");
entry("sigalarm");
entry("sigreturn");
+entry("symlink");