Linux Headquarters
[ Register ]
[ About us ] [ Home Page ]

Advertisement
[ Kernel ] [ Documentation ] [ Links ] [ Books ]

Advertisement

Kernel v2.1.132 /fs/namei.c

Filename:/fs/namei.c
Lines Added:184
Lines Deleted:171
Also changed in: (Previous) 2.1.131  2.1.129  2.1.127  2.1.126  2.1.125  2.1.123 
(Following)

Location
[  2.1.132
  [  fs
     o  namei.c

Patch

diff -u --recursive --new-file v2.1.131/linux/fs/namei.c linux/fs/namei.c
--- v2.1.131/linux/fs/namei.c   Wed Dec 16 10:32:55 1998
+++ linux/fs/namei.c   Fri Dec 18 07:09:35 1998
@@ -490,6 +490,77 @@
    return dentry;
 }
 
+/*
+ * It's inline, so penalty for filesystems that don't use sticky bit is
+ * minimal.
+ */
+static inline int check_sticky(struct inode *dir, struct inode *inode)
+{
+   if (!(dir->i_mode & S_ISVTX))
+      return 0;
+   if (inode->i_uid == current->fsuid)
+      return 0;
+   if (dir->i_uid == current->fsuid)
+      return 0;
+   return !capable(CAP_FOWNER);
+}
+
+/*
+ *   Check whether we can remove a link victim from directory dir, check
+ *  whether the type of victim is right.
+ *  1. We can't do it if dir is read-only (done in permission())
+ *  2. We should have write and exec permissions on dir
+ *  3. We can't remove anything from append-only dir
+ *  4. We can't do anything with immutable dir (done in permission())
+ *  5. If the sticky bit on dir is set we should either
+ *   a. be owner of dir, or
+ *   b. be owner of victim, or
+ *   c. have CAP_FOWNER capability
+ *  6. If the victim is append-only or immutable we can't do antyhing with
+ *     links pointing to it.
+ *  7. If we were asked to remove a directory and victim isn't one - ENOTDIR.
+ *  8. If we were asked to remove a non-directory and victim isn't one - EISDIR.
+ *  9. We can't remove a root or mountpoint.
+ */
+static inline int may_delete(struct inode *dir,struct dentry *victim, int isdir)
+{
+   int error;
+   if (!victim->d_inode || victim->d_parent->d_inode != dir)
+      return -ENOENT;
+   error = permission(dir,MAY_WRITE | MAY_EXEC);
+   if (error)
+      return error;
+   if (IS_APPEND(dir))
+      return -EPERM;
+   if (check_sticky(dir, victim->d_inode)||IS_APPEND(victim->d_inode)||
+       IS_IMMUTABLE(victim->d_inode))
+      return -EPERM;
+   if (isdir) {
+      if (!S_ISDIR(victim->d_inode->i_mode))
+         return -ENOTDIR;
+      if (IS_ROOT(victim))
+         return -EBUSY;
+      if (victim->d_mounts != victim->d_covers)
+         return -EBUSY;
+   } else if (S_ISDIR(victim->d_inode->i_mode))
+      return -EISDIR;
+   return 0;
+}
+
+/*   Check whether we can create an object with dentry child in directory
+ *  dir.
+ *  1. We can't do it if child already exists (open has special treatment for
+ *     this case, but since we are inlined it's OK)
+ *  2. We can't do it if dir is read-only (done in permission())
+ *  3. We should have write and exec permissions on dir
+ *  4. We can't do it if dir is immutable (done in permission())
+ */
+static inline int may_create(struct inode *dir, struct dentry *child) {
+   if (child->d_inode)
+      return -EEXIST;
+   return permission(dir,MAY_WRITE | MAY_EXEC);
+}
+
 static inline struct dentry *get_parent(struct dentry *dentry)
 {
    return dget(dentry->d_parent);
@@ -599,16 +670,16 @@
          error = 0;
          if (flag & O_EXCL)
             error = -EEXIST;
-      } else if (IS_RDONLY(dir->d_inode))
-         error = -EROFS;
-      else if (!dir->d_inode->i_op || !dir->d_inode->i_op->create)
-         error = -EACCES;
-      else if ((error = permission(dir->d_inode,MAY_WRITE | MAY_EXEC)) == 0) {
-         DQUOT_INIT(dir->d_inode);
-         error = dir->d_inode->i_op->create(dir->d_inode, dentry, mode);
-         /* Don't check for write permission, don't truncate */
-         acc_mode = 0;
-         flag &= ~O_TRUNC;
+      } else if ((error = may_create(dir->d_inode, dentry)) == 0) {
+         if (!dir->d_inode->i_op || !dir->d_inode->i_op->create)
+            error = -EACCES;
+         else {
+            DQUOT_INIT(dir->d_inode);
+            error = dir->d_inode->i_op->create(dir->d_inode, dentry, mode);
+            /* Don't check for write permission, don't truncate */
+            acc_mode = 0;
+            flag &= ~O_TRUNC;
+         }
       }
       unlock_dir(dir);
       if (error)
@@ -705,30 +776,20 @@
    if (IS_ERR(dir))
       goto exit;
 
-   retval = ERR_PTR(-EEXIST);
-   if (dentry->d_inode)
-      goto exit_lock;
-
-   retval = ERR_PTR(-EROFS);
-   if (IS_RDONLY(dir->d_inode))
-      goto exit_lock;
-
-   error = permission(dir->d_inode,MAY_WRITE | MAY_EXEC);
-   retval = ERR_PTR(error);
+   error = may_create(dir->d_inode, dentry);
    if (error)
       goto exit_lock;
 
-   retval = ERR_PTR(-EPERM);
+   error = -EPERM;
    if (!dir->d_inode->i_op || !dir->d_inode->i_op->mknod)
       goto exit_lock;
 
    DQUOT_INIT(dir->d_inode);
    error = dir->d_inode->i_op->mknod(dir->d_inode, dentry, mode, dev);
+exit_lock:
    retval = ERR_PTR(error);
    if (!error)
       retval = dget(dentry);
-
-exit_lock:
    unlock_dir(dir);
 exit:
    dput(dentry);
@@ -790,15 +851,7 @@
    if (IS_ERR(dir))
       goto exit_dput;
 
-   error = -EEXIST;
-   if (dentry->d_inode)
-      goto exit_lock;
-
-   error = -EROFS;
-   if (IS_RDONLY(dir->d_inode))
-      goto exit_lock;
-
-   error = permission(dir->d_inode,MAY_WRITE | MAY_EXEC);
+   error = may_create(dir->d_inode, dentry);
    if (error)
       goto exit_lock;
 
@@ -865,58 +918,20 @@
    dput(d2);
 }
 
-static inline int do_rmdir(const char * name)
-{
-   int error;
-   struct dentry *dir;
-   struct dentry *dentry;
-
-   dentry = lookup_dentry(name, NULL, 0);
-   error = PTR_ERR(dentry);
-   if (IS_ERR(dentry))
-      goto exit;
-
-   dir = dget(dentry->d_parent);
 
-   error = -ENOENT;
-   if (!dentry->d_inode)
-      goto exit;
-   /*
-    * The dentry->d_count stuff confuses d_delete() enough to
-    * not kill the inode from under us while it is locked. This
-    * wouldn't be needed, except the dentry semaphore is really
-    * in the inode, not in the dentry..
-    */
-   dentry->d_count++;
-   double_lock(dir, dentry);
-   if (dentry->d_parent != dir)
-      goto exit_lock;
 
-   error = -EROFS;
-   if (IS_RDONLY(dir->d_inode))
-      goto exit_lock;
+int vfs_rmdir(struct inode *dir, struct dentry *dentry)
+{
+   int error;
 
-   error = permission(dir->d_inode,MAY_WRITE | MAY_EXEC);
+   error = may_delete(dir, dentry, 1);
    if (error)
-      goto exit_lock;
+      return error;
 
-   /*
-    * A subdirectory cannot be removed from an append-only directory.
-    */
-   error = -EPERM;
-   if (IS_APPEND(dir->d_inode))
-      goto exit_lock;
-
-   /* Disallow removals of mountpoints. */
-   error = -EBUSY;
-   if (dentry->d_mounts != dentry->d_covers)
-      goto exit_lock;
+   if (!dir->i_op || !dir->i_op->rmdir)
+      return -EPERM;
 
-   error = -EPERM;
-   if (!dir->d_inode->i_op || !dir->d_inode->i_op->rmdir)
-      goto exit_lock;
-
-   DQUOT_INIT(dir->d_inode);
+   DQUOT_INIT(dir);
 
    /*
     * We try to drop the dentry early: we should have
@@ -942,11 +957,42 @@
       d_drop(dentry);
    }
 
-   error = dir->d_inode->i_op->rmdir(dir->d_inode, dentry);
+   error = dir->i_op->rmdir(dir, dentry);
+
+   return error;
+}
+
+static inline int do_rmdir(const char * name)
+{
+   int error;
+   struct dentry *dir;
+   struct dentry *dentry;
+
+   dentry = lookup_dentry(name, NULL, 0);
+   error = PTR_ERR(dentry);
+   if (IS_ERR(dentry))
+      goto exit;
+
+   error = -ENOENT;
+   if (!dentry->d_inode)
+      goto exit_dput;
+
+   dir = dget(dentry->d_parent);
+
+   /*
+    * The dentry->d_count stuff confuses d_delete() enough to
+    * not kill the inode from under us while it is locked. This
+    * wouldn't be needed, except the dentry semaphore is really
+    * in the inode, not in the dentry..
+    */
+   dentry->d_count++;
+   double_lock(dir, dentry);
+
+   error = vfs_rmdir(dir->d_inode, dentry);
 
-exit_lock:
-   dentry->d_count--;
    double_unlock(dentry, dir);
+exit_dput:
+   dput(dentry);
 exit:
    return error;
 }
@@ -967,6 +1013,25 @@
    return error;
 }
 
+int vfs_unlink(struct inode *dir, struct dentry *dentry)
+{
+   int error;
+
+   error = may_delete(dir, dentry, 0);
+   if (error)
+      goto exit_lock;
+
+   if (!dir->i_op || !dir->i_op->unlink)
+      goto exit_lock;
+
+   DQUOT_INIT(dir);
+
+   error = dir->i_op->unlink(dir, dentry);
+
+exit_lock:
+   return error;
+}
+
 static inline int do_unlink(const char * name)
 {
    int error;
@@ -983,42 +1048,8 @@
    if (IS_ERR(dir))
       goto exit_dput;
 
-   error = -ENOENT;
-   if (!dentry->d_inode)
-      goto exit_lock;
-
-   /* Mount point? */
-   error = -EBUSY;
-   if (dentry == dir)
-      goto exit_lock;
-
-   error = -EROFS;
-   if (IS_RDONLY(dir->d_inode))
-      goto exit_lock;
-
-   error = permission(dir->d_inode,MAY_WRITE | MAY_EXEC);
-   if (error)
-      goto exit_lock;
-
-   /*
-    * A directory can't be unlink'ed.
-    * A file cannot be removed from an append-only directory.
-    */
-   error = -EPERM;
-   if (S_ISDIR(dentry->d_inode->i_mode))
-      goto exit_lock;
-
-   if (IS_APPEND(dir->d_inode))
-      goto exit_lock;
-
-   if (!dir->d_inode->i_op || !dir->d_inode->i_op->unlink)
-      goto exit_lock;
+   error = vfs_unlink(dir->d_inode, dentry);
 
-   DQUOT_INIT(dir->d_inode);
-
-   error = dir->d_inode->i_op->unlink(dir->d_inode, dentry);
-
-exit_lock:
         unlock_dir(dir);
 exit_dput:
    dput(dentry);
@@ -1059,15 +1090,7 @@
    if (IS_ERR(dir))
       goto exit_dput;
 
-   error = -EEXIST;
-   if (dentry->d_inode)
-      goto exit_lock;
-
-   error = -EROFS;
-   if (IS_RDONLY(dir->d_inode))
-      goto exit_lock;
-
-   error = permission(dir->d_inode,MAY_WRITE | MAY_EXEC);
+   error = may_create(dir->d_inode, dentry);
    if (error)
       goto exit_lock;
 
@@ -1143,22 +1166,14 @@
    if (!inode)
       goto exit_lock;
 
-   error = -EEXIST;
-   if (new_dentry->d_inode)
-      goto exit_lock;
-
-   error = -EROFS;
-   if (IS_RDONLY(dir->d_inode))
+   error = may_create(dir->d_inode, new_dentry);
+   if (error)
       goto exit_lock;
 
    error = -EXDEV;
    if (dir->d_inode->i_dev != inode->i_dev)
       goto exit_lock;
 
-   error = permission(dir->d_inode, MAY_WRITE | MAY_EXEC);
-   if (error)
-      goto exit_lock;
-
    /*
     * A link to an append-only or immutable file cannot be created.
     */
@@ -1205,6 +1220,38 @@
    return error;
 }
 
+int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
+          struct inode *new_dir, struct dentry *new_dentry)
+{
+   int error;
+   int isdir;
+
+   isdir = S_ISDIR(old_dentry->d_inode->i_mode);
+
+   error = may_delete(old_dir, old_dentry, isdir); /* XXX */
+   if (error)
+      return error;
+
+   if (new_dir->i_dev != old_dir->i_dev)
+      return -EXDEV;
+
+   if (!new_dentry->d_inode)
+      error = may_create(new_dir, new_dentry);
+   else
+      error = may_delete(new_dir, new_dentry, isdir);
+   if (error)
+      return error;
+
+   if (!old_dir->i_op || !old_dir->i_op->rename)
+      return -EPERM;
+
+   DQUOT_INIT(old_dir);
+   DQUOT_INIT(new_dir);
+   error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry);
+
+   return error;
+}
+
 static inline int do_rename(const char * oldname, const char * newname)
 {
    int error;
@@ -1237,43 +1284,9 @@
 
    double_lock(new_dir, old_dir);
 
-   error = permission(old_dir->d_inode,MAY_WRITE | MAY_EXEC);
-   if (error)
-      goto exit_lock;
-   error = permission(new_dir->d_inode,MAY_WRITE | MAY_EXEC);
-   if (error)
-      goto exit_lock;
-
-   /* Disallow moves of mountpoints. */
-   error = -EBUSY;
-   if (old_dir == old_dentry || new_dir == new_dentry)
-      goto exit_lock;
-
-   error = -EXDEV;
-   if (new_dir->d_inode->i_dev != old_dir->d_inode->i_dev)
-      goto exit_lock;
-
-   error = -EROFS;
-   if (IS_RDONLY(new_dir->d_inode) || IS_RDONLY(old_dir->d_inode))
-      goto exit_lock;
-
-   /*
-    * A file cannot be removed from an append-only directory.
-    */
-   error = -EPERM;
-   if (IS_APPEND(old_dir->d_inode))
-      goto exit_lock;
+   error = vfs_rename(old_dir->d_inode, old_dentry,
+            new_dir->d_inode, new_dentry);
 
-   error = -EPERM;
-   if (!old_dir->d_inode->i_op || !old_dir->d_inode->i_op->rename)
-      goto exit_lock;
-
-   DQUOT_INIT(old_dir->d_inode);
-   DQUOT_INIT(new_dir->d_inode);
-   error = old_dir->d_inode->i_op->rename(old_dir->d_inode, old_dentry,
-                      new_dir->d_inode, new_dentry);
-
-exit_lock:
    double_unlock(new_dir, old_dir);
    dput(new_dentry);
 exit_old:


Comments: webmaster (at) linuxhq.com.
Advertising: banners (at) linuxhq.com.
Compilation ©1998-2008 Linux Headquarters, Inc.