Skip to content

Commit

Permalink
9pfs: fix readdir() for 9p2000.u
Browse files Browse the repository at this point in the history
If the client is using 9p2000.u, the following occurs:

$ cd ${virtfs_shared_dir}
$ mkdir -p a/b/c
$ ls a/b
ls: cannot access 'a/b/a': No such file or directory
ls: cannot access 'a/b/b': No such file or directory
a  b  c

instead of the expected:

$ ls a/b
c

This is a regression introduced by commit f57f587;
local_name_to_path() now resolves ".." and "." in paths,
and v9fs_do_readdir_with_stat()->stat_to_v9stat() then
copies the basename of the resulting path to the response.
With the example above, this means that "." and ".." are
turned into "b" and "a" respectively...

stat_to_v9stat() currently assumes it is passed a full
canonicalized path and uses it to do two different things:
1) to pass it to v9fs_co_readlink() in case the file is a symbolic
   link
2) to set the name field of the V9fsStat structure to the basename
   part of the given path

It only has two users: v9fs_stat() and v9fs_do_readdir_with_stat().

v9fs_stat() really needs 1) and 2) to be performed since it starts
with the full canonicalized path stored in the fid. It is different
for v9fs_do_readdir_with_stat() though because the name we want to
put into the V9fsStat structure is the d_name field of the dirent
actually (ie, we want to keep the "." and ".." special names). So,
we only need 1) in this case.

This patch hence adds a basename argument to stat_to_v9stat(), to
be used to set the name field of the V9fsStat structure, and moves
the basename logic to v9fs_stat().

Signed-off-by: Jan Dakinevich <jan.dakinevich@gmail.com>
(groug, renamed old name argument to path and updated changelog)
Signed-off-by: Greg Kurz <groug@kaod.org>

(cherry picked from commit 6069537)
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
  • Loading branch information
Jan Dakinevich authored and mdroth committed Sep 22, 2017
1 parent 7e1288c commit e90997d
Showing 1 changed file with 9 additions and 13 deletions.
22 changes: 9 additions & 13 deletions hw/9pfs/9p.c
Expand Up @@ -803,12 +803,12 @@ static uint32_t stat_to_v9mode(const struct stat *stbuf)
return mode;
}

static int coroutine_fn stat_to_v9stat(V9fsPDU *pdu, V9fsPath *name,
static int coroutine_fn stat_to_v9stat(V9fsPDU *pdu, V9fsPath *path,
const char *basename,
const struct stat *stbuf,
V9fsStat *v9stat)
{
int err;
const char *str;

memset(v9stat, 0, sizeof(*v9stat));

Expand All @@ -829,7 +829,7 @@ static int coroutine_fn stat_to_v9stat(V9fsPDU *pdu, V9fsPath *name,
v9fs_string_free(&v9stat->extension);

if (v9stat->mode & P9_STAT_MODE_SYMLINK) {
err = v9fs_co_readlink(pdu, name, &v9stat->extension);
err = v9fs_co_readlink(pdu, path, &v9stat->extension);
if (err < 0) {
return err;
}
Expand All @@ -842,14 +842,7 @@ static int coroutine_fn stat_to_v9stat(V9fsPDU *pdu, V9fsPath *name,
"HARDLINKCOUNT", (unsigned long)stbuf->st_nlink);
}

str = strrchr(name->data, '/');
if (str) {
str += 1;
} else {
str = name->data;
}

v9fs_string_sprintf(&v9stat->name, "%s", str);
v9fs_string_sprintf(&v9stat->name, "%s", basename);

v9stat->size = 61 +
v9fs_string_size(&v9stat->name) +
Expand Down Expand Up @@ -1058,6 +1051,7 @@ static void coroutine_fn v9fs_stat(void *opaque)
struct stat stbuf;
V9fsFidState *fidp;
V9fsPDU *pdu = opaque;
char *basename;

err = pdu_unmarshal(pdu, offset, "d", &fid);
if (err < 0) {
Expand All @@ -1074,7 +1068,9 @@ static void coroutine_fn v9fs_stat(void *opaque)
if (err < 0) {
goto out;
}
err = stat_to_v9stat(pdu, &fidp->path, &stbuf, &v9stat);
basename = g_path_get_basename(fidp->path.data);
err = stat_to_v9stat(pdu, &fidp->path, basename, &stbuf, &v9stat);
g_free(basename);
if (err < 0) {
goto out;
}
Expand Down Expand Up @@ -1750,7 +1746,7 @@ static int coroutine_fn v9fs_do_readdir_with_stat(V9fsPDU *pdu,
if (err < 0) {
break;
}
err = stat_to_v9stat(pdu, &path, &stbuf, &v9stat);
err = stat_to_v9stat(pdu, &path, dent->d_name, &stbuf, &v9stat);
if (err < 0) {
break;
}
Expand Down

0 comments on commit e90997d

Please sign in to comment.