Merge branch 'kconfig' of git://git.kernel.org/pub/scm/linux/kernel/git/mmarek/kbuild-2.6
[deliverable/linux.git] / fs / dcache.c
index d09d93819b4d45413bb7f1e73669fba4f8225c5c..166d35d56868c7c4c2a79fb29e03404e1831172b 100644 (file)
@@ -1979,8 +1979,7 @@ global_root:
  * @buffer: buffer to return value in
  * @buflen: buffer length
  *
- * Convert a dentry into an ASCII path name. If the entry has been deleted
- * the string " (deleted)" is appended. Note that this is ambiguous.
+ * Convert a dentry into an ASCII path name.
  *
  * Returns a pointer into the buffer or an error code if the
  * path was too long.
@@ -1997,12 +1996,6 @@ char *__d_path(const struct path *path, struct path *root,
        int error;
 
        prepend(&res, &buflen, "\0", 1);
-       if (d_unlinked(path->dentry)) {
-               error = prepend(&res, &buflen, " (deleted)", 10);
-               if (error)
-                       return ERR_PTR(error);
-       }
-
        error = prepend_path(path, root, &res, &buflen);
        if (error)
                return ERR_PTR(error);
@@ -2010,6 +2003,27 @@ char *__d_path(const struct path *path, struct path *root,
        return res;
 }
 
+/*
+ * same as __d_path but appends "(deleted)" for unlinked files.
+ */
+static int path_with_deleted(const struct path *path, struct path *root,
+                                char **buf, int *buflen)
+{
+       prepend(buf, buflen, "\0", 1);
+       if (d_unlinked(path->dentry)) {
+               int error = prepend(buf, buflen, " (deleted)", 10);
+               if (error)
+                       return error;
+       }
+
+       return prepend_path(path, root, buf, buflen);
+}
+
+static int prepend_unreachable(char **buffer, int *buflen)
+{
+       return prepend(buffer, buflen, "(unreachable)", 13);
+}
+
 /**
  * d_path - return the path of a dentry
  * @path: path to report
@@ -2028,9 +2042,10 @@ char *__d_path(const struct path *path, struct path *root,
  */
 char *d_path(const struct path *path, char *buf, int buflen)
 {
-       char *res;
+       char *res = buf + buflen;
        struct path root;
        struct path tmp;
+       int error;
 
        /*
         * We have various synthetic filesystems that never get mounted.  On
@@ -2045,13 +2060,48 @@ char *d_path(const struct path *path, char *buf, int buflen)
        get_fs_root(current->fs, &root);
        spin_lock(&dcache_lock);
        tmp = root;
-       res = __d_path(path, &tmp, buf, buflen);
+       error = path_with_deleted(path, &tmp, &res, &buflen);
+       if (error)
+               res = ERR_PTR(error);
        spin_unlock(&dcache_lock);
        path_put(&root);
        return res;
 }
 EXPORT_SYMBOL(d_path);
 
+/**
+ * d_path_with_unreachable - return the path of a dentry
+ * @path: path to report
+ * @buf: buffer to return value in
+ * @buflen: buffer length
+ *
+ * The difference from d_path() is that this prepends "(unreachable)"
+ * to paths which are unreachable from the current process' root.
+ */
+char *d_path_with_unreachable(const struct path *path, char *buf, int buflen)
+{
+       char *res = buf + buflen;
+       struct path root;
+       struct path tmp;
+       int error;
+
+       if (path->dentry->d_op && path->dentry->d_op->d_dname)
+               return path->dentry->d_op->d_dname(path->dentry, buf, buflen);
+
+       get_fs_root(current->fs, &root);
+       spin_lock(&dcache_lock);
+       tmp = root;
+       error = path_with_deleted(path, &tmp, &res, &buflen);
+       if (!error && !path_equal(&tmp, &root))
+               error = prepend_unreachable(&res, &buflen);
+       spin_unlock(&dcache_lock);
+       path_put(&root);
+       if (error)
+               res =  ERR_PTR(error);
+
+       return res;
+}
+
 /*
  * Helper function for dentry_operations.d_dname() members
  */
@@ -2161,15 +2211,23 @@ SYSCALL_DEFINE2(getcwd, char __user *, buf, unsigned long, size)
        if (!d_unlinked(pwd.dentry)) {
                unsigned long len;
                struct path tmp = root;
-               char * cwd;
+               char *cwd = page + PAGE_SIZE;
+               int buflen = PAGE_SIZE;
 
-               cwd = __d_path(&pwd, &tmp, page, PAGE_SIZE);
+               prepend(&cwd, &buflen, "\0", 1);
+               error = prepend_path(&pwd, &tmp, &cwd, &buflen);
                spin_unlock(&dcache_lock);
 
-               error = PTR_ERR(cwd);
-               if (IS_ERR(cwd))
+               if (error)
                        goto out;
 
+               /* Unreachable from current root */
+               if (!path_equal(&tmp, &root)) {
+                       error = prepend_unreachable(&cwd, &buflen);
+                       if (error)
+                               goto out;
+               }
+
                error = -ERANGE;
                len = PAGE_SIZE + page - cwd;
                if (len <= size) {
This page took 0.027198 seconds and 5 git commands to generate.