All paths in the virtfs directory now start with "./" (except the virtfs root itself which is exactly ".").
We hence don't need to skip leading '/' characters anymore, nor to handle the empty path case. Also, since virtfs will only ever be supported on linux+glibc hosts, we can use strchrnul() and come up with a much simplier code to walk through the path elements. And we don't need to dup() the passed directory fd. Signed-off-by: Greg Kurz <gr...@kaod.org> --- hw/9pfs/9p-local.c | 5 ----- hw/9pfs/9p-util.c | 26 ++++++++++---------------- 2 files changed, 10 insertions(+), 21 deletions(-) diff --git a/hw/9pfs/9p-local.c b/hw/9pfs/9p-local.c index 92262f3c3e37..bb6e296df317 100644 --- a/hw/9pfs/9p-local.c +++ b/hw/9pfs/9p-local.c @@ -54,11 +54,6 @@ int local_open_nofollow(FsContext *fs_ctx, const char *path, int flags, { LocalData *data = fs_ctx->private; - /* All paths are relative to the path data->mountfd points to */ - while (*path == '/') { - path++; - } - return relative_openat_nofollow(data->mountfd, path, flags, mode); } diff --git a/hw/9pfs/9p-util.c b/hw/9pfs/9p-util.c index fdb4d5737635..e46399a9119d 100644 --- a/hw/9pfs/9p-util.c +++ b/hw/9pfs/9p-util.c @@ -17,14 +17,11 @@ int relative_openat_nofollow(int dirfd, const char *path, int flags, mode_t mode) { - int fd; + int fd = dirfd; - fd = dup(dirfd); - if (fd == -1) { - return -1; - } + assert(*path); - while (*path) { + while (*path && fd != -1) { const char *c; int next_fd; char *head; @@ -33,25 +30,22 @@ int relative_openat_nofollow(int dirfd, const char *path, int flags, assert(path[0] != '/'); head = g_strdup(path); - c = strchr(path, '/'); - if (c) { + c = strchrnul(path, '/'); + if (*c) { + /* Intermediate path element */ head[c - path] = 0; + path = c + 1; next_fd = openat_dir(fd, head); } else { + /* Rightmost path element */ next_fd = openat_file(fd, head, flags, mode); + path = c; } g_free(head); - if (next_fd == -1) { + if (dirfd != fd) { close_preserve_errno(fd); - return -1; } - close(fd); fd = next_fd; - - if (!c) { - break; - } - path = c + 1; } return fd;