9pfs: fix readdir() for 9p2000.u
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 f57f5878578a; 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>
This commit is contained in:
parent
c51700273a
commit
6069537f43
22
hw/9pfs/9p.c
22
hw/9pfs/9p.c
@ -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));
|
||||
|
||||
@ -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;
|
||||
}
|
||||
@ -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) +
|
||||
@ -1056,6 +1049,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) {
|
||||
@ -1072,7 +1066,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;
|
||||
}
|
||||
@ -1748,7 +1744,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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user