chmod() and fchmod(), implemented with wstat (XCC)
authorBarret Rhoden <brho@cs.berkeley.edu>
Wed, 16 Jul 2014 05:21:34 +0000 (22:21 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Wed, 16 Jul 2014 05:21:34 +0000 (22:21 -0700)
Removes SYS_chmod, using SYS_wstat for it instead.  While I was at it,
wstat and fwstat work for 9ns completely.  For the VFS, it only supports
changing the mode.

Rebuild glibc.  Either copy over the two new files or just make clean.
If you chmod and get "invalid" or something similar, either you didn't
rebuild glibc properly or you didn't fill kfs again.

kern/include/ros/bits/syscall.h
kern/include/vfs.h
kern/src/syscall.c
kern/src/vfs.c
tools/compilers/gcc-glibc/glibc-2.14.1-ros/sysdeps/ros/chmod.c
tools/compilers/gcc-glibc/glibc-2.14.1-ros/sysdeps/ros/fchmod.c [new file with mode: 0644]

index 83de5ae..699313c 100644 (file)
@@ -56,7 +56,7 @@
 #define SYS_fcntl                              107
 #define SYS_access                             108
 #define SYS_umask                              109
-#define SYS_chmod                              110
+/* was SYS_chmod                               110 */
 #define SYS_llseek                             111
 #define SYS_link                               112
 #define SYS_unlink                             113
index 7d3967b..8eb9a20 100644 (file)
@@ -469,7 +469,7 @@ int do_symlink(char *path, const char *symname, int mode);
 int do_link(char *old_path, char *new_path);
 int do_unlink(char *path);
 int do_access(char *path, int mode);
-int do_chmod(char *path, int mode);
+int do_file_chmod(struct file *file, int mode);
 int do_mkdir(char *path, int mode);
 int do_rmdir(char *path);
 int do_pipe(struct file **pipe_files, int flags);
index 963792f..4857a19 100644 (file)
@@ -1355,55 +1355,6 @@ intreg_t sys_umask(struct proc *p, int mask)
        return old_mask;
 }
 
-static void init_dir_for_wstat(struct dir *d)
-{
-       d->type = ~0;
-       d->dev = ~0;
-       d->qid.path = ~0;
-       d->qid.vers = ~0;
-       d->qid.type = ~0;
-       d->mode = ~0;
-       d->atime = ~0;
-       d->mtime = ~0;
-       d->length = ~0;
-       d->name = "";
-       d->uid = "";
-       d->gid = "";
-       d->muid = "";
-}
-
-intreg_t sys_chmod(struct proc *p, const char *path, size_t path_l, int mode)
-{
-       int retval;
-       char *t_path = user_strdup_errno(p, path, path_l);
-       if (!t_path)
-               return -1;
-       /* busybox sends in the upper bits as 37777777 (-1), perhaps trying to get
-        * the 'default' setting? */
-       if (mode & ~S_PMASK)
-               printd("[kernel] sys_chmod ignoring upper bits %o\n", mode & ~S_PMASK);
-       mode &= S_PMASK;
-       retval = do_chmod(t_path, mode);
-       /* let's try 9ns */
-       if (retval < 0) {
-               unset_errno();
-               uint8_t *buf;
-               int size;
-               struct dir d;
-               init_dir_for_wstat(&d);
-               d.mode = mode;
-               size = sizeD2M(&d);
-               buf = kmalloc(size, KMALLOC_WAIT);
-               convD2M(&d, buf, size);
-               /* wstat returns the number of bytes written */
-               retval = syswstat(t_path, buf, size);
-               retval = (retval > 0 ? 0 : -1);
-               kfree(buf);
-       }
-       user_memdup_free(p, t_path);
-       return retval;
-}
-
 /* 64 bit seek, with the off64_t passed in via two (potentially 32 bit) off_ts.
  * We're supporting both 32 and 64 bit kernels/userspaces, but both use the
  * llseek syscall with 64 bit parameters. */
@@ -1804,16 +1755,78 @@ intreg_t sys_fd2path(struct proc *p, int fd, void *u_buf, size_t len)
        return ret;
 }
 
+/* Helper, interprets the wstat and performs the VFS action.  Returns stat_sz on
+ * success for all ops, -1 or 0 o/w.  If one op fails, it'll skip the remaining
+ * ones. */
+static int vfs_wstat(struct file *file, uint8_t *stat_m, size_t stat_sz,
+                     int flags)
+{
+       struct dir *dir;
+       int m_sz;
+       int retval = 0;
+
+       dir = kzmalloc(sizeof(struct dir) + stat_sz, KMALLOC_WAIT);
+       m_sz = convM2D(stat_m, stat_sz, &dir[0], (char*)&dir[1]);
+       if (m_sz != stat_sz) {
+               set_errstr(Eshortstat);
+               set_errno(EINVAL);
+               kfree(dir);
+               return -1;
+       }
+       if (flags & WSTAT_MODE) {
+               retval = do_file_chmod(file, dir->mode);
+               if (retval < 0)
+                       goto out;
+       }
+
+out:
+       kfree(dir);
+       /* convert vfs retval to wstat retval */
+       if (retval >= 0)
+               retval = stat_sz;
+       return retval;
+}
+
 intreg_t sys_wstat(struct proc *p, char *path, size_t path_l,
                    uint8_t *stat_m, size_t stat_sz, int flags)
 {
-       return -1;
+       int retval = 0;
+       char *t_path = user_strdup_errno(p, path, path_l);
+       struct file *file;
+
+       if (!t_path)
+               return -1;
+       retval = syswstat(t_path, stat_m, stat_sz);
+       if (retval == stat_sz) {
+               user_memdup_free(p, t_path);
+               return stat_sz;
+       }
+       /* 9ns failed, we'll need to check the VFS */
+       file = do_file_open(t_path, 0, 0);
+       user_memdup_free(p, t_path);
+       if (!file)
+               return -1;
+       retval = vfs_wstat(file, stat_m, stat_sz, flags);
+       kref_put(&file->f_kref);
+       return retval;
 }
 
 intreg_t sys_fwstat(struct proc *p, int fd, uint8_t *stat_m, size_t stat_sz,
                     int flags)
 {
-       return -1;
+       int retval = 0;
+       struct file *file;
+
+       retval = sysfwstat(fd, stat_m, stat_sz);
+       if (retval == stat_sz)
+               return stat_sz;
+       /* 9ns failed, we'll need to check the VFS */
+       file = get_file_from_fd(&p->open_files, fd);
+       if (!file)
+               return -1;
+       retval = vfs_wstat(file, stat_m, stat_sz, flags);
+       kref_put(&file->f_kref);
+       return retval;
 }
 
 intreg_t sys_rename(struct proc *p, char *old_path, size_t old_path_l,
@@ -1874,7 +1887,6 @@ const struct sys_table_entry syscall_table[] = {
        [SYS_fcntl] = {(syscall_t)sys_fcntl, "fcntl"},
        [SYS_access] = {(syscall_t)sys_access, "access"},
        [SYS_umask] = {(syscall_t)sys_umask, "umask"},
-       [SYS_chmod] = {(syscall_t)sys_chmod, "chmod"},
        [SYS_llseek] = {(syscall_t)sys_llseek, "llseek"},
        [SYS_link] = {(syscall_t)sys_link, "link"},
        [SYS_unlink] = {(syscall_t)sys_unlink, "unlink"},
index 495eaf4..96638e7 100644 (file)
@@ -1552,24 +1552,17 @@ int do_access(char *path, int mode)
        return retval;
 }
 
-int do_chmod(char *path, int mode)
-{
-       struct nameidata nd_r = {0}, *nd = &nd_r;
-       int retval = 0;
-       int old_mode_ftype;
-       retval = path_lookup(path, 0, nd);
-       if (!retval) {
-               old_mode_ftype = nd->dentry->d_inode->i_mode & __S_IFMT;
-               #if 0
-               /* TODO: when we have notions of uid, check for the proc's uid */
-               if (nd->dentry->d_inode->i_uid != UID_OF_ME)
-                       retval = -EPERM;
-               else
-               #endif
-                       nd->dentry->d_inode->i_mode = (mode & S_PMASK) | old_mode_ftype;
-       }
-       path_release(nd);       
-       return retval;
+int do_file_chmod(struct file *file, int mode)
+{
+       int old_mode_ftype = file->f_dentry->d_inode->i_mode & __S_IFMT;
+       #if 0
+       /* TODO: when we have notions of uid, check for the proc's uid */
+       if (file->f_dentry->d_inode->i_uid != UID_OF_ME)
+               retval = -EPERM;
+       else
+       #endif
+               file->f_dentry->d_inode->i_mode = (mode & S_PMASK) | old_mode_ftype;
+       return 0;
 }
 
 /* Make a directory at path with mode.  Returns -1 and sets errno on errors */
index eacb5a8..a707190 100644 (file)
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <ros/syscall.h>
+#include <fcall.h>
 
 /* Change the protections of FILE to MODE.  */
 int
 __chmod (const char* file, mode_t mode)
 {
+  struct dir dir;
+  size_t mlen;
+  char mbuf[STATFIXLEN];
+  int ret;
+
   if (file == NULL)
   {
     __set_errno (EINVAL);
     return -1;
   }
 
-  return ros_syscall(SYS_chmod, file, strlen(file), mode, 0, 0, 0);
+  init_empty_dir(&dir);
+  dir.mode = mode;
+  mlen = convD2M(&dir, mbuf, STATFIXLEN);
+  ret = ros_syscall(SYS_wstat, file, strlen(file), mbuf, mlen, WSTAT_MODE, 0);
+  return (ret == mlen ? 0 : -1);
 }
 weak_alias (__chmod, chmod)
diff --git a/tools/compilers/gcc-glibc/glibc-2.14.1-ros/sysdeps/ros/fchmod.c b/tools/compilers/gcc-glibc/glibc-2.14.1-ros/sysdeps/ros/fchmod.c
new file mode 100644 (file)
index 0000000..b2cbe48
--- /dev/null
@@ -0,0 +1,48 @@
+/* Copyright (C) 1991, 1992, 1995, 1996, 1997, 2011 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 <sys/stat.h>
+#include <sys/types.h>
+#include <fcall.h>
+
+/* Change the permissions of the file referenced by FD to MODE.  */
+int
+__fchmod (fd, mode)
+     int fd;
+     mode_t mode;
+{
+  struct dir dir;
+  size_t mlen;
+  char mbuf[STATFIXLEN];
+  int ret;
+
+  if (fd < 0)
+    {
+      __set_errno (EINVAL);
+      return -1;
+    }
+
+  init_empty_dir(&dir);
+  dir.mode = mode;
+  mlen = convD2M(&dir, mbuf, STATFIXLEN);
+  ret = ros_syscall(SYS_fwstat, fd, mbuf, mlen, WSTAT_MODE, 0, 0);
+  return (ret == mlen ? 0 : -1);
+}
+weak_alias (__fchmod, fchmod)