New AT_... flag: AT_EMPTY_PATH
authorAl Viro <viro@zeniv.linux.org.uk>
Mon, 14 Mar 2011 22:56:51 +0000 (18:56 -0400)
committerAl Viro <viro@zeniv.linux.org.uk>
Mon, 14 Mar 2011 23:12:20 +0000 (19:12 -0400)
For name_to_handle_at(2) we'll want both ...at()-style syscall that
would be usable for non-directory descriptors (with empty relative
pathname).  Introduce new flag (AT_EMPTY_PATH) to deal with that and
corresponding LOOKUP_EMPTY; teach user_path_at() and path_init() to
deal with the latter.

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
fs/namei.c
include/linux/fcntl.h
include/linux/namei.h

index abc8d2d..83e92ba 100644 (file)
@@ -136,7 +136,7 @@ static int do_getname(const char __user *filename, char *page)
        return retval;
 }
 
-char * getname(const char __user * filename)
+static char *getname_flags(const char __user * filename, int flags)
 {
        char *tmp, *result;
 
@@ -147,14 +147,21 @@ char * getname(const char __user * filename)
 
                result = tmp;
                if (retval < 0) {
-                       __putname(tmp);
-                       result = ERR_PTR(retval);
+                       if (retval != -ENOENT || !(flags & LOOKUP_EMPTY)) {
+                               __putname(tmp);
+                               result = ERR_PTR(retval);
+                       }
                }
        }
        audit_getname(result);
        return result;
 }
 
+char *getname(const char __user * filename)
+{
+       return getname_flags(filename, 0);
+}
+
 #ifdef CONFIG_AUDITSYSCALL
 void putname(const char *name)
 {
@@ -1544,13 +1551,15 @@ static int path_init(int dfd, const char *name, unsigned int flags,
 
                dentry = file->f_path.dentry;
 
-               retval = -ENOTDIR;
-               if (!S_ISDIR(dentry->d_inode->i_mode))
-                       goto fput_fail;
+               if (*name) {
+                       retval = -ENOTDIR;
+                       if (!S_ISDIR(dentry->d_inode->i_mode))
+                               goto fput_fail;
 
-               retval = file_permission(file, MAY_EXEC);
-               if (retval)
-                       goto fput_fail;
+                       retval = file_permission(file, MAY_EXEC);
+                       if (retval)
+                               goto fput_fail;
+               }
 
                nd->path = file->f_path;
                if (flags & LOOKUP_RCU) {
@@ -1759,7 +1768,7 @@ int user_path_at(int dfd, const char __user *name, unsigned flags,
                 struct path *path)
 {
        struct nameidata nd;
-       char *tmp = getname(name);
+       char *tmp = getname_flags(name, flags);
        int err = PTR_ERR(tmp);
        if (!IS_ERR(tmp)) {
 
index a562fa5..f550f89 100644 (file)
@@ -46,6 +46,7 @@
                                            unlinking file.  */
 #define AT_SYMLINK_FOLLOW      0x400   /* Follow symbolic links.  */
 #define AT_NO_AUTOMOUNT                0x800   /* Suppress terminal automount traversal */
+#define AT_EMPTY_PATH          0x1000  /* Allow empty relative pathname */
 
 #ifdef __KERNEL__
 
index 83cd6e5..9c86038 100644 (file)
@@ -64,6 +64,7 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND};
 
 #define LOOKUP_JUMPED          0x1000
 #define LOOKUP_ROOT            0x2000
+#define LOOKUP_EMPTY           0x4000
 
 extern int user_path_at(int, const char __user *, unsigned, struct path *);