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: Miklos Szeredi <mszeredi@suse.cz>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
Miklos Szeredi 2010-08-10 11:41:39 +02:00 committed by Al Viro
parent 98dc568bc2
commit f2eb6575d5
1 changed files with 80 additions and 58 deletions

View File

@ -1904,6 +1904,74 @@ static int prepend_name(char **buffer, int *buflen, struct qstr *name)
return prepend(buffer, buflen, name->name, name->len);
}
/**
* Prepend path string to a buffer
*
* @path: the dentry/vfsmount to report
* @root: root vfsmnt/dentry (may be modified by this function)
* @buffer: pointer to the end of the buffer
* @buflen: pointer to buffer length
*
* Caller holds the dcache_lock.
*
* If path is not reachable from the supplied root, then the value of
* root is changed (without modifying refcounts).
*/
static int prepend_path(const struct path *path, struct path *root,
char **buffer, int *buflen)
{
struct dentry *dentry = path->dentry;
struct vfsmount *vfsmnt = path->mnt;
bool slash = false;
int error = 0;
spin_lock(&vfsmount_lock);
while (dentry != root->dentry || vfsmnt != root->mnt) {
struct dentry * parent;
if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
/* Global root? */
if (vfsmnt->mnt_parent == vfsmnt) {
goto global_root;
}
dentry = vfsmnt->mnt_mountpoint;
vfsmnt = vfsmnt->mnt_parent;
continue;
}
parent = dentry->d_parent;
prefetch(parent);
error = prepend_name(buffer, buflen, &dentry->d_name);
if (!error)
error = prepend(buffer, buflen, "/", 1);
if (error)
break;
slash = true;
dentry = parent;
}
out:
if (!error && !slash)
error = prepend(buffer, buflen, "/", 1);
spin_unlock(&vfsmount_lock);
return error;
global_root:
/*
* Filesystems needing to implement special "root names"
* should do so with ->d_dname()
*/
if (IS_ROOT(dentry) &&
(dentry->d_name.len != 1 || dentry->d_name.name[0] != '/')) {
WARN(1, "Root dentry has weird name <%.*s>\n",
(int) dentry->d_name.len, dentry->d_name.name);
}
root->mnt = vfsmnt;
root->dentry = dentry;
goto out;
}
/**
* __d_path - return the path of a dentry
* @path: the dentry/vfsmount to report
@ -1923,69 +1991,23 @@ static int prepend_name(char **buffer, int *buflen, struct qstr *name)
* root is changed (without modifying refcounts).
*/
char *__d_path(const struct path *path, struct path *root,
char *buffer, int buflen)
char *buf, int buflen)
{
struct dentry *dentry = path->dentry;
struct vfsmount *vfsmnt = path->mnt;
char *end = buffer + buflen;
char *retval;
char *res = buf + buflen;
int error;
spin_lock(&vfsmount_lock);
prepend(&end, &buflen, "\0", 1);
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;
if (dentry == root->dentry && vfsmnt == root->mnt)
break;
if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
/* Global root? */
if (vfsmnt->mnt_parent == vfsmnt) {
goto global_root;
}
dentry = vfsmnt->mnt_mountpoint;
vfsmnt = vfsmnt->mnt_parent;
continue;
}
parent = dentry->d_parent;
prefetch(parent);
if ((prepend_name(&end, &buflen, &dentry->d_name) != 0) ||
(prepend(&end, &buflen, "/", 1) != 0))
goto Elong;
retval = end;
dentry = parent;
prepend(&res, &buflen, "\0", 1);
if (d_unlinked(path->dentry)) {
error = prepend(&res, &buflen, " (deleted)", 10);
if (error)
return ERR_PTR(error);
}
out:
spin_unlock(&vfsmount_lock);
return retval;
error = prepend_path(path, root, &res, &buflen);
if (error)
return ERR_PTR(error);
global_root:
/*
* Filesystems needing to implement special "root names"
* should do so with ->d_dname()
*/
if (IS_ROOT(dentry) &&
(dentry->d_name.len != 1 || dentry->d_name.name[0] != '/')) {
WARN(1, "Root dentry has weird name <%.*s>\n",
(int) dentry->d_name.len, dentry->d_name.name);
}
root->mnt = vfsmnt;
root->dentry = dentry;
goto out;
Elong:
retval = ERR_PTR(-ENAMETOOLONG);
goto out;
return res;
}
/**