9ns: Add high-level support for symlinks
authorBarret Rhoden <brho@cs.berkeley.edu>
Mon, 26 Feb 2018 16:00:10 +0000 (11:00 -0500)
committerBarret Rhoden <brho@cs.berkeley.edu>
Fri, 6 Apr 2018 19:23:01 +0000 (15:23 -0400)
This creates links with SYS_symlink and extracts the info with
SYS_readlink.  You need a 9ns device that supports symlinks, such as the
yet-unmerged KFS.  Walking through symlinks doesn't work yet.

Similar to the VFS, we have various accessor-functions for stat, such as
regular stat and lstat.  Same goes for the 'dirstat' functions.  For those
not familiar, those functions are basically "stat a path and convert to a
dir."

Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
kern/include/ns.h
kern/src/ns/sysfile.c
kern/src/syscall.c

index a0e185d..f74cc69 100644 (file)
@@ -113,6 +113,7 @@ extern int parseether(uint8_t * unused_uint8_p_t, char *unused_char_p_t);
 #define QTEXCL         0x20    /* type bit for exclusive use files */
 #define QTMOUNT                0x10    /* type bit for mounted channel */
 #define QTAUTH         0x08    /* type bit for authentication file */
+#define QTSYMLINK      0x02    /* type bit for symlinks */
 #define QTFILE         0x01    /* plain file */
 
 /* bits in Dir.mode */
@@ -1015,6 +1016,7 @@ int sysfversion(int fd, unsigned int msize, char *vers, unsigned int arglen);
 int sysfwstat(int fd, uint8_t * buf, int n);
 long bindmount(struct chan *c, char *old, int flag, char *spec);
 int sysbind(char *new, char *old, int flags);
+int syssymlink(char *new_path, char *old_path);
 int sysmount(int fd, int afd, char *old, int flags, char *spec);
 int sysunmount(char *old, char *new);
 int sysopenat(int dirfd, char *path, int vfs_flags);
@@ -1027,12 +1029,14 @@ int sysremove(char *path);
 int64_t sysseek(int fd, int64_t off, int whence);
 void validstat(uint8_t * s, int n, int slashok);
 int sysstat(char *path, uint8_t*, int n);
-int sysstatakaros(char *path, struct kstat *);
+int syslstat(char *path, uint8_t*, int n);
+int sysstatakaros(char *path, struct kstat *, int flags);
 long syswrite(int fd, void *va, long n);
 long syspwrite(int fd, void *va, long n, int64_t off);
 int syswstat(char *path, uint8_t * buf, int n);
 struct dir *chandirstat(struct chan *c);
 struct dir *sysdirstat(char *name);
+struct dir *sysdirlstat(char *name);
 struct dir *sysdirfstat(int fd);
 int sysdirwstat(char *name, struct dir *dir);
 int sysdirfwstat(int fd, struct dir *dir);
index 2011281..182bb07 100644 (file)
@@ -425,6 +425,23 @@ int sysbind(char *new, char *old, int flags)
        return r;
 }
 
+int syssymlink(char *new_path, char *old_path)
+{
+       ERRSTACK(1);
+       struct chan *c;
+
+       if (waserror()) {
+               poperror();
+               return -1;
+       }
+       validname(old_path, true);
+       c = namec(new_path, Acreate, O_EXCL,
+                 DMSYMLINK | S_IRWXU | S_IRWXG | S_IRWXO, old_path);
+       cclose(c);
+       poperror();
+       return 0;
+}
+
 int sysmount(int fd, int afd, char *old, int flags, char *spec)
 {
        ERRSTACK(1);
@@ -918,7 +935,7 @@ int sysfstatakaros(int fd, struct kstat *ks)
        return n;
 }
 
-int sysstat(char *path, uint8_t *buf, int n)
+static int __stat(char *path, uint8_t *buf, int n, int flags)
 {
        ERRSTACK(2);
        struct chan *c;
@@ -928,7 +945,7 @@ int sysstat(char *path, uint8_t *buf, int n)
                return -1;
        }
 
-       c = namec(path, Aaccess, 0, 0, NULL);
+       c = namec(path, Aaccess, flags, 0, NULL);
        if (waserror()) {
                cclose(c);
                nexterror();
@@ -942,13 +959,23 @@ int sysstat(char *path, uint8_t *buf, int n)
        return n;
 }
 
-int sysstatakaros(char *path, struct kstat *ks)
+int sysstat(char *path, uint8_t *buf, int n)
+{
+       return __stat(path, buf, n, 0);
+}
+
+int syslstat(char *path, uint8_t *buf, int n)
+{
+       return __stat(path, buf, n, O_NOFOLLOW);
+}
+
+int sysstatakaros(char *path, struct kstat *ks, int flags)
 {
 
        int n = 4096;
        uint8_t *buf;
        buf = kmalloc(n, MEM_WAIT);
-       n = sysstat(path, buf, n);
+       n = __stat(path, buf, n, flags);
        if (n > 0) {
                convM2kstat(buf, n, ks);
                n = 0;
@@ -1093,7 +1120,7 @@ struct dir *chandirstat(struct chan *c)
 
 }
 
-struct dir *sysdirstat(char *name)
+static struct dir *__dir_stat(char *name, int flags)
 {
        ERRSTACK(2);
        struct chan *c;
@@ -1104,7 +1131,7 @@ struct dir *sysdirstat(char *name)
                return NULL;
        }
 
-       c = namec(name, Aaccess, 0, 0, NULL);
+       c = namec(name, Aaccess, flags, 0, NULL);
        if (waserror()) {
                cclose(c);
                nexterror();
@@ -1117,6 +1144,16 @@ struct dir *sysdirstat(char *name)
        return d;
 }
 
+struct dir *sysdirstat(char *name)
+{
+       return __dir_stat(name, 0);
+}
+
+struct dir *sysdirlstat(char *name)
+{
+       return __dir_stat(name, O_NOFOLLOW);
+}
+
 struct dir *sysdirfstat(int fd)
 {
        ERRSTACK(2);
index c7c1f87..aa3df90 100644 (file)
@@ -348,7 +348,9 @@ static void systrace_finish_trace(struct kthread *kthread, long retval)
                                break;
                        copy_tracedata_from_user(trace, trace->arg0, trace->arg1);
                        snprintf_to_trace(trace, " -> ");
-                       copy_tracedata_from_user(trace, trace->arg2, trace->arg3);
+                       copy_tracedata_from_user(trace, trace->arg2,
+                                                (int)trace->retval < 0 ? 0
+                                                                                               : trace->retval);
                        break;
                }
        }
@@ -1845,7 +1847,8 @@ static intreg_t stat_helper(struct proc *p, const char *path, size_t path_l,
        } else {
                /* VFS failed, checking 9ns */
                unset_errno();  /* Go can't handle extra errnos */
-               retval = sysstatakaros(t_path, (struct kstat *)kbuf);
+               retval = sysstatakaros(t_path, (struct kstat *)kbuf,
+                                      flags & LOOKUP_FOLLOW ? 0 : O_NOFOLLOW);
                printd("sysstat returns %d\n", retval);
                /* both VFS and 9ns failed, bail out */
                if (retval < 0)
@@ -2059,6 +2062,10 @@ intreg_t sys_symlink(struct proc *p, char *old_path, size_t old_l,
                return -1;
        }
        ret = do_symlink(t_newpath, t_oldpath, S_IRWXU | S_IRWXG | S_IRWXO);
+       if (ret && (get_errno() == ENOENT)) {
+               unset_errno();
+               ret = syssymlink(t_newpath, t_oldpath);
+       }
        free_path(p, t_oldpath);
        free_path(p, t_newpath);
        return ret;
@@ -2068,28 +2075,24 @@ intreg_t sys_readlink(struct proc *p, char *path, size_t path_l,
                       char *u_buf, size_t buf_l)
 {
        char *symname = NULL;
-       uint8_t *buf = NULL;
        ssize_t copy_amt;
        int ret = -1;
        struct dentry *path_d;
        char *t_path = copy_in_path(p, path, path_l);
+       struct dir *dir = NULL;
+
        if (t_path == NULL)
                return -1;
-       /* TODO: 9ns support */
        path_d = lookup_dentry(t_path, 0);
-       if (!path_d){
-               int n = 2048;
-               buf = kmalloc(n*2, MEM_WAIT);
-               struct dir *d = (void *)&buf[n];
-               /* try 9ns. */
-               if (sysstat(t_path, buf, n) > 0) {
-                       printk("sysstat t_path %s\n", t_path);
-                       convM2D(buf, n, d, (char *)&d[1]);
-                       /* will be NULL if things did not work out */
-                       symname = d->muid;
-               }
-       } else
+       if (!path_d) {
+               dir = sysdirlstat(t_path);
+               if (!(dir->mode & DMSYMLINK))
+                       set_error(EINVAL, "not a symlink: %s", t_path);
+               else
+                       symname = dir->ext;
+       } else {
                symname = path_d->d_inode->i_op->readlink(path_d);
+       }
 
        free_path(p, t_path);
 
@@ -2100,9 +2103,7 @@ intreg_t sys_readlink(struct proc *p, char *path, size_t path_l,
        }
        if (path_d)
                kref_put(&path_d->d_kref);
-       if (buf)
-               kfree(buf);
-       printd("READLINK returning %s\n", u_buf);
+       kfree(dir);
        return ret;
 }