This commit was manufactured by cvs2svn to create tag
[linux-2.6.git] / fs / namei.c
index 3f170ce..44262f3 100644 (file)
@@ -27,6 +27,8 @@
 #include <linux/security.h>
 #include <linux/mount.h>
 #include <linux/audit.h>
+#include <linux/vs_base.h>
+
 #include <asm/namei.h>
 #include <asm/uaccess.h>
 
@@ -208,6 +210,20 @@ int vfs_permission(struct inode * inode, int mask)
        return -EACCES;
 }
 
+static inline int xid_permission(struct inode *inode, int mask, struct nameidata *nd)
+{
+       if (inode->i_xid == 0)
+               return 0;
+       if (vx_check(inode->i_xid, VX_ADMIN|VX_WATCH|VX_IDENT))
+               return 0;
+/*
+       printk("VSW: xid=%d denied access to %p[#%d,%lu] »%*s«.\n",
+               vx_current_xid(), inode, inode->i_xid, inode->i_ino,
+               nd->dentry->d_name.len, nd->dentry->d_name.name);
+*/
+       return -EACCES;
+}
+
 int permission(struct inode * inode,int mask, struct nameidata *nd)
 {
        int retval;
@@ -216,6 +232,8 @@ int permission(struct inode * inode,int mask, struct nameidata *nd)
        /* Ordinary permission routines do not understand MAY_APPEND. */
        submask = mask & ~MAY_APPEND;
 
+       if ((retval = xid_permission(inode, mask, nd)))
+               return retval;
        if (inode->i_op && inode->i_op->permission)
                retval = inode->i_op->permission(inode, submask, nd);
        else
@@ -658,9 +676,11 @@ int fastcall link_path_walk(const char * name, struct nameidata *nd)
 {
        struct path next;
        struct inode *inode;
-       int err;
+       int err, atomic;
        unsigned int lookup_flags = nd->flags;
-       
+
+       atomic = (lookup_flags & LOOKUP_ATOMIC);
+
        while (*name=='/')
                name++;
        if (!*name)
@@ -728,6 +748,9 @@ int fastcall link_path_walk(const char * name, struct nameidata *nd)
                        if (err < 0)
                                break;
                }
+               err = -EWOULDBLOCKIO;
+               if (atomic)
+                       break;
                nd->flags |= LOOKUP_CONTINUE;
                /* This does the actual lookups.. */
                err = do_lookup(nd, &this, &next);
@@ -792,6 +815,9 @@ last_component:
                        if (err < 0)
                                break;
                }
+               err = -EWOULDBLOCKIO;
+               if (atomic)
+                       break;
                err = do_lookup(nd, &this, &next);
                if (err)
                        break;
@@ -868,29 +894,31 @@ static int __emul_lookup_dentry(const char *name, struct nameidata *nd)
                return 0;               /* something went wrong... */
 
        if (!nd->dentry->d_inode || S_ISDIR(nd->dentry->d_inode->i_mode)) {
-               struct nameidata nd_root;
+               struct dentry *old_dentry = nd->dentry;
+               struct vfsmount *old_mnt = nd->mnt;
+               struct qstr last = nd->last;
+               int last_type = nd->last_type;
                /*
                 * NAME was not found in alternate root or it's a directory.  Try to find
                 * it in the normal root:
                 */
-               nd_root.last_type = LAST_ROOT;
-               nd_root.flags = nd->flags;
-               nd_root.depth = 0;
-               memcpy(&nd_root.intent, &nd->intent, sizeof(nd_root.intent));
+               nd->last_type = LAST_ROOT;
                read_lock(&current->fs->lock);
-               nd_root.mnt = mntget(current->fs->rootmnt);
-               nd_root.dentry = dget(current->fs->root);
+               nd->mnt = mntget(current->fs->rootmnt);
+               nd->dentry = dget(current->fs->root);
                read_unlock(&current->fs->lock);
-               if (path_walk(name, &nd_root))
-                       return 1;
-               if (nd_root.dentry->d_inode) {
+               if (path_walk(name, nd) == 0) {
+                       if (nd->dentry->d_inode) {
+                               dput(old_dentry);
+                               mntput(old_mnt);
+                               return 1;
+                       }
                        path_release(nd);
-                       nd->dentry = nd_root.dentry;
-                       nd->mnt = nd_root.mnt;
-                       nd->last = nd_root.last;
-                       return 1;
                }
-               path_release(&nd_root);
+               nd->dentry = old_dentry;
+               nd->mnt = old_mnt;
+               nd->last = last;
+               nd->last_type = last_type;
        }
        return 1;
 }
@@ -943,8 +971,7 @@ int fastcall path_lookup(const char *name, unsigned int flags, struct nameidata
                }
                nd->mnt = mntget(current->fs->rootmnt);
                nd->dentry = dget(current->fs->root);
-       }
-       else{
+       } else {
                nd->mnt = mntget(current->fs->pwdmnt);
                nd->dentry = dget(current->fs->pwd);
        }
@@ -1094,15 +1121,18 @@ static inline int check_sticky(struct inode *dir, struct inode *inode)
 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)
+       if (!victim->d_inode)
                return -ENOENT;
+       if (victim->d_parent->d_inode != dir)
+               BUG();
+                       
        error = permission(dir,MAY_WRITE | MAY_EXEC, NULL);
        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))
+               IS_IXORUNLINK(victim->d_inode))
                return -EPERM;
        if (isdir) {
                if (!S_ISDIR(victim->d_inode->i_mode))
@@ -1154,6 +1184,8 @@ static inline int lookup_flags(unsigned int f)
        
        if (f & O_DIRECTORY)
                retval |= LOOKUP_DIRECTORY;
+       if (f & O_ATOMICLOOKUP)
+               retval |= LOOKUP_ATOMIC;
 
        return retval;
 }
@@ -1909,7 +1941,7 @@ int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_de
        /*
         * A link to an append-only or immutable file cannot be created.
         */
-       if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
+       if (IS_APPEND(inode) || IS_IXORUNLINK(inode))
                return -EPERM;
        if (!dir->i_op || !dir->i_op->link)
                return -EPERM;
@@ -2299,12 +2331,8 @@ int page_readlink(struct dentry *dentry, char __user *buffer, int buflen)
 int page_follow_link_light(struct dentry *dentry, struct nameidata *nd)
 {
        struct page *page;
-       char *s = page_getlink(dentry, &page);
-       if (!IS_ERR(s)) {
-               nd_set_link(nd, s);
-               s = NULL;
-       }
-       return PTR_ERR(s);
+       nd_set_link(nd, page_getlink(dentry, &page));
+       return 0;
 }
 
 void page_put_link(struct dentry *dentry, struct nameidata *nd)