Merge branch 'work.misc' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
[linux-2.6-microblaze.git] / fs / namei.c
index d4a6dd7..78443a8 100644 (file)
@@ -2114,8 +2114,10 @@ static int link_path_walk(const char *name, struct nameidata *nd)
                return PTR_ERR(name);
        while (*name=='/')
                name++;
-       if (!*name)
+       if (!*name) {
+               nd->dir_mode = 0; // short-circuit the 'hardening' idiocy
                return 0;
+       }
 
        /* At this point we know we have a real path component. */
        for(;;) {
@@ -4346,8 +4348,8 @@ out:
 }
 EXPORT_SYMBOL(vfs_rename);
 
-static int do_renameat2(int olddfd, const char __user *oldname, int newdfd,
-                       const char __user *newname, unsigned int flags)
+int do_renameat2(int olddfd, struct filename *from, int newdfd,
+                struct filename *to, unsigned int flags)
 {
        struct dentry *old_dentry, *new_dentry;
        struct dentry *trap;
@@ -4355,32 +4357,30 @@ static int do_renameat2(int olddfd, const char __user *oldname, int newdfd,
        struct qstr old_last, new_last;
        int old_type, new_type;
        struct inode *delegated_inode = NULL;
-       struct filename *from;
-       struct filename *to;
        unsigned int lookup_flags = 0, target_flags = LOOKUP_RENAME_TARGET;
        bool should_retry = false;
-       int error;
+       int error = -EINVAL;
 
        if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE | RENAME_WHITEOUT))
-               return -EINVAL;
+               goto put_both;
 
        if ((flags & (RENAME_NOREPLACE | RENAME_WHITEOUT)) &&
            (flags & RENAME_EXCHANGE))
-               return -EINVAL;
+               goto put_both;
 
        if (flags & RENAME_EXCHANGE)
                target_flags = 0;
 
 retry:
-       from = filename_parentat(olddfd, getname(oldname), lookup_flags,
-                               &old_path, &old_last, &old_type);
+       from = filename_parentat(olddfd, from, lookup_flags, &old_path,
+                                       &old_last, &old_type);
        if (IS_ERR(from)) {
                error = PTR_ERR(from);
-               goto exit;
+               goto put_new;
        }
 
-       to = filename_parentat(newdfd, getname(newname), lookup_flags,
-                               &new_path, &new_last, &new_type);
+       to = filename_parentat(newdfd, to, lookup_flags, &new_path, &new_last,
+                               &new_type);
        if (IS_ERR(to)) {
                error = PTR_ERR(to);
                goto exit1;
@@ -4473,34 +4473,40 @@ exit2:
        if (retry_estale(error, lookup_flags))
                should_retry = true;
        path_put(&new_path);
-       putname(to);
 exit1:
        path_put(&old_path);
-       putname(from);
        if (should_retry) {
                should_retry = false;
                lookup_flags |= LOOKUP_REVAL;
                goto retry;
        }
-exit:
+put_both:
+       if (!IS_ERR(from))
+               putname(from);
+put_new:
+       if (!IS_ERR(to))
+               putname(to);
        return error;
 }
 
 SYSCALL_DEFINE5(renameat2, int, olddfd, const char __user *, oldname,
                int, newdfd, const char __user *, newname, unsigned int, flags)
 {
-       return do_renameat2(olddfd, oldname, newdfd, newname, flags);
+       return do_renameat2(olddfd, getname(oldname), newdfd, getname(newname),
+                               flags);
 }
 
 SYSCALL_DEFINE4(renameat, int, olddfd, const char __user *, oldname,
                int, newdfd, const char __user *, newname)
 {
-       return do_renameat2(olddfd, oldname, newdfd, newname, 0);
+       return do_renameat2(olddfd, getname(oldname), newdfd, getname(newname),
+                               0);
 }
 
 SYSCALL_DEFINE2(rename, const char __user *, oldname, const char __user *, newname)
 {
-       return do_renameat2(AT_FDCWD, oldname, AT_FDCWD, newname, 0);
+       return do_renameat2(AT_FDCWD, getname(oldname), AT_FDCWD,
+                               getname(newname), 0);
 }
 
 int readlink_copy(char __user *buffer, int buflen, const char *link)