Syscalls for symlink management (XCC)
authorBarret Rhoden <brho@cs.berkeley.edu>
Tue, 17 Aug 2010 00:55:40 +0000 (17:55 -0700)
committerKevin Klues <klueska@cs.berkeley.edu>
Thu, 3 Nov 2011 00:35:51 +0000 (17:35 -0700)
Rebuild your cross compiler.

kern/include/ros/bits/syscall.h
kern/include/vfs.h
kern/src/syscall.c
kern/src/vfs.c
tests/file_test.c
tools/compilers/gcc-glibc/glibc-2.11.1-ros/sysdeps/ros/readlink.c [new file with mode: 0644]
tools/compilers/gcc-glibc/glibc-2.11.1-ros/sysdeps/ros/rename.c [new file with mode: 0644]
tools/compilers/gcc-glibc/glibc-2.11.1-ros/sysdeps/ros/symlink.c [new file with mode: 0644]

index 17ae34f..c837c1a 100644 (file)
 #define SYS_lseek                              111
 #define SYS_link                               112
 #define SYS_unlink                             113
-#define SYS_chdir                              114
-#define SYS_getcwd                             115
-#define SYS_gettimeofday               116
-#define SYS_tcgetattr                  117
-#define SYS_tcsetattr                  118
+#define SYS_symlink                            114
+#define SYS_readlink                   115
+#define SYS_chdir                              116
+#define SYS_getcwd                             117
+#define SYS_gettimeofday               118
+#define SYS_tcgetattr                  119
+#define SYS_tcsetattr                  120
 
 /* Syscalls we plan to remove someday */
 #define SYS_cache_buster        200 
index bccae40..f2af661 100644 (file)
@@ -474,6 +474,7 @@ struct dentry *get_dentry(struct super_block *sb, struct dentry *parent,
                           char *name);
 void dcache_put(struct dentry *dentry);
 void dentry_release(struct kref *kref);
+struct dentry *lookup_dentry(char *path, int flags);
 
 /* Inode Functions */
 struct inode *get_inode(struct dentry *dentry);
@@ -483,7 +484,6 @@ int create_symlink(struct inode *dir, struct dentry *dentry,
                    const char *symname, int mode);
 int check_perms(struct inode *inode, int access_mode);
 void inode_release(struct kref *kref);
-struct inode *lookup_inode(char *path, int flags);
 void stat_inode(struct inode *inode, struct kstat *kstat);
 
 /* File-ish functions */
index ca6369b..bac8834 100644 (file)
@@ -890,22 +890,22 @@ static intreg_t stat_helper(struct proc *p, const char *path, size_t path_l,
                             struct kstat *u_stat, int flags)
 {
        struct kstat *kbuf;
-       struct inode *path_i;
+       struct dentry *path_d;
        char *t_path = user_strdup_errno(p, path, path_l);
        if (!t_path)
                return -1;
-       path_i = lookup_inode(t_path, flags);
+       path_d = lookup_dentry(t_path, flags);
        user_memdup_free(p, t_path);
-       if (!path_i)
+       if (!path_d)
                return -1;
        kbuf = kmalloc(sizeof(struct kstat), 0);
        if (!kbuf) {
                set_errno(ENOMEM);
-               kref_put(&path_i->i_kref);
+               kref_put(&path_d->d_kref);
                return -1;
        }
-       stat_inode(path_i, kbuf);
-       kref_put(&path_i->i_kref);
+       stat_inode(path_d->d_inode, kbuf);
+       kref_put(&path_d->d_kref);
        /* TODO: UMEM: pin the memory, copy directly, and skip the kernel buffer */
        if (memcpy_to_user_errno(p, u_stat, kbuf, sizeof(struct kstat))) {
                kfree(kbuf);
@@ -1011,6 +1011,49 @@ intreg_t sys_unlink(struct proc *p, const char *path, size_t path_l)
        return ret;
 }
 
+intreg_t sys_symlink(struct proc *p, char *old_path, size_t old_l,
+                     char *new_path, size_t new_l)
+{
+       int ret;
+       char *t_oldpath = user_strdup_errno(p, old_path, old_l);
+       if (t_oldpath == NULL)
+               return -1;
+       char *t_newpath = user_strdup_errno(p, new_path, new_l);
+       if (t_newpath == NULL) {
+               user_memdup_free(p, t_oldpath);
+               return -1;
+       }
+       ret = do_symlink(new_path, old_path, S_IRWXU | S_IRWXG | S_IRWXO);
+       user_memdup_free(p, t_oldpath);
+       user_memdup_free(p, t_newpath);
+       return ret;
+}
+
+intreg_t sys_readlink(struct proc *p, char *path, size_t path_l,
+                      char *u_buf, size_t buf_l)
+{
+       char *symname;
+       ssize_t copy_amt;
+       struct dentry *path_d;
+       char *t_path = user_strdup_errno(p, path, path_l);
+       if (t_path == NULL)
+               return -1;
+       path_d = lookup_dentry(t_path, 0);
+       user_memdup_free(p, t_path);
+       if (!path_d)
+               return -1;
+       symname = path_d->d_inode->i_op->readlink(path_d);
+       copy_amt = strnlen(symname, buf_l - 1) + 1;
+       if (memcpy_to_user_errno(p, u_buf, symname, copy_amt)) {
+               kref_put(&path_d->d_kref);
+               set_errno(EINVAL);
+               return -1;
+       }
+       kref_put(&path_d->d_kref);
+       printd("READLINK returning %s\n", u_buf);
+       return copy_amt;
+}
+
 intreg_t sys_chdir(struct proc *p, const char *path, size_t path_l)
 {
        char* fn = user_strdup_errno(p,path,PGSIZE);
@@ -1152,6 +1195,8 @@ intreg_t syscall(struct proc *p, uintreg_t syscallno, uintreg_t a1,
                [SYS_lseek] = (syscall_t)sys_lseek,
                [SYS_link] = (syscall_t)sys_link,
                [SYS_unlink] = (syscall_t)sys_unlink,
+               [SYS_symlink] = (syscall_t)sys_symlink,
+               [SYS_readlink] = (syscall_t)sys_readlink,
                [SYS_chdir] = (syscall_t)sys_chdir,
                [SYS_getcwd] = (syscall_t)sys_getcwd,
                [SYS_gettimeofday] = (syscall_t)sys_gettimeofday,
index d72f48b..b1a2819 100644 (file)
@@ -597,6 +597,27 @@ void dentry_release(struct kref *kref)
        kmem_cache_free(dentry_kcache, dentry);
 }
 
+/* Looks up the dentry for the given path, returning a refcnt'd dentry (or 0).
+ * Permissions are applied for the current user, which is quite a broken system
+ * at the moment.  Flags are lookup flags. */
+struct dentry *lookup_dentry(char *path, int flags)
+{
+       struct dentry *dentry;
+       struct nameidata nd_r = {0}, *nd = &nd_r;
+       int error;
+
+       error = path_lookup(path, flags, nd);
+       if (error) {
+               path_release(nd);
+               set_errno(-error);
+               return 0;
+       }
+       dentry = nd->dentry;
+       kref_get(&dentry->d_kref, 1);
+       path_release(nd);
+       return dentry;
+}
+
 /* Inode Functions */
 
 /* Creates and initializes a new inode.  Generic fields are filled in.
@@ -740,27 +761,6 @@ void inode_release(struct kref *kref)
        // kref_put(inode->i_bdev->kref); /* assuming it's a bdev */
 }
 
-/* Looks up the inode for the given path, returning a refcnt'd inode (or 0).
- * Permissions are applied for the current user, which is quite a broken system
- * at the moment.  Flags are lookup flags. */
-struct inode *lookup_inode(char *path, int flags)
-{
-       struct inode *inode;
-       struct nameidata nd_r = {0}, *nd = &nd_r;
-       int error;
-
-       error = path_lookup(path, flags, nd);
-       if (error) {
-               path_release(nd);
-               set_errno(-error);
-               return 0;
-       }
-       inode = nd->dentry->d_inode;
-       kref_get(&inode->i_kref, 1);
-       path_release(nd);
-       return inode;
-}
-
 /* Fills in kstat with the stat information for the inode */
 void stat_inode(struct inode *inode, struct kstat *kstat)
 {
@@ -962,7 +962,8 @@ struct file *do_file_open(char *path, int flags, int mode)
        return file;
 }
 
-/* Path is the location of the symlink, symname is who we link to. */
+/* Path is the location of the symlink, sometimes called the "new path", and
+ * symname is who we link to, sometimes called the "old path". */
 int do_symlink(char *path, const char *symname, int mode)
 {
        struct dentry *sym_d;
index 9fe8e2e..0911272 100644 (file)
@@ -53,6 +53,15 @@ int main()
        printf("atime     : %d\n", st.st_atime);
        printf("mtime     : %d\n", st.st_mtime);
        printf("ctime     : %d\n", st.st_ctime);
-       breakpoint();
 
+       retval = symlink("/dir1/random.txt", "/dir2/sym-test");
+       if (retval < 0)
+               printf("WARNING! Symlink creation failed!\n");
+       retval = readlink("/dir2/sym-test", rbuf, 256);
+       if (retval < 0)
+               printf("WARNING! Readlink failed!\n");
+       else
+               printf("Readlink read %d bytes\n", retval);
+
+       breakpoint();
 }
diff --git a/tools/compilers/gcc-glibc/glibc-2.11.1-ros/sysdeps/ros/readlink.c b/tools/compilers/gcc-glibc/glibc-2.11.1-ros/sysdeps/ros/readlink.c
new file mode 100644 (file)
index 0000000..e1a85a9
--- /dev/null
@@ -0,0 +1,35 @@
+/* Copyright (C) 1991, 1995, 1996, 1997, 2006 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <ros/syscall.h>
+
+/* Read the contents of the symbolic link PATH into no more than
+   LEN bytes of BUF.  The contents are not null-terminated.
+   Returns the number of characters read, or -1 for errors.  */
+ssize_t
+__readlink (path, buf, len)
+     const char *path;
+     char *buf;
+     size_t len;
+{
+  return ros_syscall(SYS_readlink, path, strlen(path), buf, len, 0);
+}
+weak_alias (__readlink, readlink)
diff --git a/tools/compilers/gcc-glibc/glibc-2.11.1-ros/sysdeps/ros/rename.c b/tools/compilers/gcc-glibc/glibc-2.11.1-ros/sysdeps/ros/rename.c
new file mode 100644 (file)
index 0000000..b7d8392
--- /dev/null
@@ -0,0 +1,41 @@
+/* Copyright (C) 1991, 1995, 1996, 1997 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <stdio.h>
+#include <errno.h>
+
+
+/* Rename the file OLD to NEW.  */
+int
+rename (old, new)
+     const char *old;
+     const char *new;
+{
+  if (old == NULL || new == NULL)
+    {
+      __set_errno (EINVAL);
+      return -1;
+    }
+
+  __set_errno (ENOSYS);
+  return -1;
+}
+
+
+stub_warning (rename)
+#include <stub-tag.h>
diff --git a/tools/compilers/gcc-glibc/glibc-2.11.1-ros/sysdeps/ros/symlink.c b/tools/compilers/gcc-glibc/glibc-2.11.1-ros/sysdeps/ros/symlink.c
new file mode 100644 (file)
index 0000000..8c5f325
--- /dev/null
@@ -0,0 +1,38 @@
+/* Copyright (C) 1991, 1995, 1996, 1997 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <string.h>
+#include <ros/syscall.h>
+
+/* Make a link to FROM called TO.  */
+int
+__symlink (from, to)
+     const char *from;
+     const char *to;
+{
+  if (from == NULL || to == NULL)
+    {
+      __set_errno (EINVAL);
+      return -1;
+    }
+  return ros_syscall(SYS_symlink, from, strlen(from), to, strlen(to), 0);
+}
+weak_alias (__symlink, symlink)