Properly convert open mode flags to rwx [3/7]
authorBarret Rhoden <brho@cs.berkeley.edu>
Thu, 3 Sep 2015 22:32:03 +0000 (18:32 -0400)
committerBarret Rhoden <brho@cs.berkeley.edu>
Mon, 28 Sep 2015 19:14:00 +0000 (15:14 -0400)
Plan 9's devpermcheck hard-coded the fact that O_RDONLY was 0 into its
"access" array.  It also didn't seem to deal with O_EXEC being OR-ed
into the flags, such that you could only have an 'x', not anything else.

The helper for this conversion is also useful in the VFS.

kern/include/ns.h
kern/src/ns/dev.c
kern/src/ns/util.c
kern/src/vfs.c

index b4e5556..6612e9a 100644 (file)
@@ -769,6 +769,7 @@ void notkilled(void);
 int nrand(int);
 uint64_t ns2fastticks(uint64_t);
 int okaddr(uint32_t, uint32_t, int);
+int omode_to_rwx(int);
 struct block *packblock(struct block *);
 struct block *padblock(struct block *, int);
 
index 4228e6d..68fc981 100644 (file)
@@ -333,18 +333,20 @@ devdirread(struct chan *c, char *d, long n,
  */
 void devpermcheck(char *fileuid, uint32_t perm, int omode)
 {
-       uint32_t t;
-       static int access[] = { 0400, 0200, 0600, 0100 };
-
+       int rwx;
+       /* select user, group, or other from the traditional rwxrwxrwx, shifting
+        * into the upper-most position */
        if (strcmp(current->user, fileuid) == 0)
                perm <<= 0;
        else if (strcmp(current->user, eve) == 0)
                perm <<= 3;
        else
                perm <<= 6;
-
-       t = access[omode & 3];
-       if ((t & perm) != t)
+       /* translate omode into things like S_IRUSR (just one set of rwx------).
+        * Plan 9 originally only returned 0400 0200 0600 and 0100 here; it didn't
+        * seem to handle O_EXEC being mixed readable or writable. */
+       rwx = omode_to_rwx(omode);
+       if ((rwx & perm) != rwx)
                error("%s: devpermcheck(%s,0x%x,0x%x) failed", Eperm, fileuid, perm,
                          omode);
 }
index 227cfce..9bf0a01 100644 (file)
@@ -35,3 +35,16 @@ int readstr(unsigned long offset, char *buf, unsigned long n, char *str)
        /* always include the \0 */
        return readmem(offset, buf, n, str, strlen(str) + 1);
 }
+
+/* Converts open mode flags, e.g. O_RDWR, to a rwx------ value, e.g. S_IRUSR */
+int omode_to_rwx(int open_flags)
+{
+       static int rwx_opts[] = { [O_RDWR | O_EXEC] = 0700,
+                                 [O_RDWR] = 0600,
+                                 [O_READ | O_EXEC] = 0500,
+                                 [O_READ] = 0400,
+                                 [O_WRITE | O_EXEC] = 0300,
+                                 [O_WRITE] = 0200,
+                                 [O_EXEC] = 0100 };
+       return rwx_opts[open_flags & O_ACCMODE];
+}
index 649fc97..516c12b 100644 (file)
@@ -2232,21 +2232,9 @@ struct file *dentry_open(struct dentry *dentry, int flags)
        struct file *file;
        int desired_mode;
        inode = dentry->d_inode;
-       /* Do the mode first, since we can still error out.  f_mode stores how the
-        * OS file is open, which can be more restrictive than the i_mode */
-       switch (flags & (O_RDONLY | O_WRONLY | O_RDWR)) {
-               case O_RDONLY:
-                       desired_mode = S_IRUSR;
-                       break;
-               case O_WRONLY:
-                       desired_mode = S_IWUSR;
-                       break;
-               case O_RDWR:
-                       desired_mode = S_IRUSR | S_IWUSR;
-                       break;
-               default:
-                       goto error_access;
-       }
+       /* f_mode stores how the OS file is open, which can be more restrictive than
+        * the i_mode */
+       desired_mode = omode_to_rwx(flags & O_ACCMODE);
        if (check_perms(inode, desired_mode))
                goto error_access;
        file = alloc_file();