Commit f2eb6575 authored by Miklos Szeredi's avatar Miklos Szeredi Committed by Al Viro

vfs: add prepend_path() helper

Split off prepend_path() from __d_path().  This new helper takes an
end-of-buffer pointer and buffer-length pointer just like the other
prepend_* functions.  Move the " (deleted)" postfix out to __d_path().

This patch doesn't change any functionality but paves the way for the
following patches.
Signed-off-by: default avatarMiklos Szeredi <mszeredi@suse.cz>
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 98dc568b
...@@ -1905,48 +1905,30 @@ static int prepend_name(char **buffer, int *buflen, struct qstr *name) ...@@ -1905,48 +1905,30 @@ static int prepend_name(char **buffer, int *buflen, struct qstr *name)
} }
/** /**
* __d_path - return the path of a dentry * Prepend path string to a buffer
*
* @path: the dentry/vfsmount to report * @path: the dentry/vfsmount to report
* @root: root vfsmnt/dentry (may be modified by this function) * @root: root vfsmnt/dentry (may be modified by this function)
* @buffer: buffer to return value in * @buffer: pointer to the end of the buffer
* @buflen: buffer length * @buflen: pointer to 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.
*
* Returns a pointer into the buffer or an error code if the
* path was too long.
* *
* "buflen" should be positive. Caller holds the dcache_lock. * Caller holds the dcache_lock.
* *
* If path is not reachable from the supplied root, then the value of * If path is not reachable from the supplied root, then the value of
* root is changed (without modifying refcounts). * root is changed (without modifying refcounts).
*/ */
char *__d_path(const struct path *path, struct path *root, static int prepend_path(const struct path *path, struct path *root,
char *buffer, int buflen) char **buffer, int *buflen)
{ {
struct dentry *dentry = path->dentry; struct dentry *dentry = path->dentry;
struct vfsmount *vfsmnt = path->mnt; struct vfsmount *vfsmnt = path->mnt;
char *end = buffer + buflen; bool slash = false;
char *retval; int error = 0;
spin_lock(&vfsmount_lock); spin_lock(&vfsmount_lock);
prepend(&end, &buflen, "\0", 1); while (dentry != root->dentry || vfsmnt != root->mnt) {
if (d_unlinked(dentry) &&
(prepend(&end, &buflen, " (deleted)", 10) != 0))
goto Elong;
if (buflen < 1)
goto Elong;
/* Get '/' right */
retval = end-1;
*retval = '/';
for (;;) {
struct dentry * parent; struct dentry * parent;
if (dentry == root->dentry && vfsmnt == root->mnt)
break;
if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) { if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
/* Global root? */ /* Global root? */
if (vfsmnt->mnt_parent == vfsmnt) { if (vfsmnt->mnt_parent == vfsmnt) {
...@@ -1958,16 +1940,22 @@ char *__d_path(const struct path *path, struct path *root, ...@@ -1958,16 +1940,22 @@ char *__d_path(const struct path *path, struct path *root,
} }
parent = dentry->d_parent; parent = dentry->d_parent;
prefetch(parent); prefetch(parent);
if ((prepend_name(&end, &buflen, &dentry->d_name) != 0) || error = prepend_name(buffer, buflen, &dentry->d_name);
(prepend(&end, &buflen, "/", 1) != 0)) if (!error)
goto Elong; error = prepend(buffer, buflen, "/", 1);
retval = end; if (error)
break;
slash = true;
dentry = parent; dentry = parent;
} }
out: out:
if (!error && !slash)
error = prepend(buffer, buflen, "/", 1);
spin_unlock(&vfsmount_lock); spin_unlock(&vfsmount_lock);
return retval; return error;
global_root: global_root:
/* /*
...@@ -1982,10 +1970,44 @@ char *__d_path(const struct path *path, struct path *root, ...@@ -1982,10 +1970,44 @@ char *__d_path(const struct path *path, struct path *root,
root->mnt = vfsmnt; root->mnt = vfsmnt;
root->dentry = dentry; root->dentry = dentry;
goto out; goto out;
}
Elong: /**
retval = ERR_PTR(-ENAMETOOLONG); * __d_path - return the path of a dentry
goto out; * @path: the dentry/vfsmount to report
* @root: root vfsmnt/dentry (may be modified by this function)
* @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.
*
* Returns a pointer into the buffer or an error code if the
* path was too long.
*
* "buflen" should be positive. Caller holds the dcache_lock.
*
* If path is not reachable from the supplied root, then the value of
* root is changed (without modifying refcounts).
*/
char *__d_path(const struct path *path, struct path *root,
char *buf, int buflen)
{
char *res = buf + buflen;
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);
return res;
} }
/** /**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment