[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PATCH v2] [WIP] [RFC ]Add initial 9pfs support for Win
From: |
Michael Fritscher |
Subject: |
Re: [Qemu-devel] [PATCH v2] [WIP] [RFC ]Add initial 9pfs support for Windows hosts v2 |
Date: |
Mon, 9 May 2016 11:12:51 +0200 |
User-agent: |
SquirrelMail/1.4.23 [SVN] |
Hello Greg,
I commented your comments :-)
To summerize:
* I didn't know where to put the win32 specific functions/wrappers -
thanks showing me the locations!
* Binary mode is needed by Windows - else newlines are screwed up.
* Windows is way more picky than Linux regarding paths.
* Which looking mechanism should I use?
Best regards,
Michael
P.S. is there a nice tool to edit / split patchfiles?
> More comments.
>
> On Tue, 12 Apr 2016 09:52:00 +0200
> Michael Fritscher <address@hidden> wrote:
>
>> It was tested on Windows & Linux hosts, on the later no obvious
>> regressions could be found. The guest was a Knoppix 7.6.0 live cd.
>>
>> This is WIP and a RFC - it isn't meant to be upstreamed yet. The
>> error_printf are only for debugging and will be deleted in the final
>> patch.
>>
>> There are some comments with "mifritscher" - I'm not quite sure how to
>> handle these problems (e.g. on mingw, this in 32 bit, while on Linux
>> this is 16 bit and so on). Additionally, some places from which I
>> suspect problems are marked with a #warning.
>>
>> Changes against v1:
>> * fixed open (added binary flag) -> read/write is fine now, file
>> creation was fixed as well
>> * added inode calculation using own crude hash algorithm
>> * fixed xattr returning -1 + EOPNOTSUP -> fixes e.g. executing files
>> * fixed unlinkat / remove für directories by trying rmdir as well
>> * prepend 777 mode on files (for executing)
>>
>> What does work:
>> * reading/writing "big" files (5MB, verified with md5sum)
>> * creating files
>> * executing files
>> * mkdir
>> * rm / rmdir
>> * cp files
>> * running gcc
>> * cp first 250 files & directories from /etc
>> * tar it from and to the 9p mount
>> * create a 100 MB swap file and do a mkswap on it
>>
>> What does not work:
>> * swapon - no real surprise (doesn't work on Linux as well - with the
>> same error message) ;-) (swapon returns -1 EINVAL)
>> * link / symlink (there is no real aequivalent for this on windows)
>> * mknod (dito)
>> * chown (dito - prepend success for compatibility)
>>
>> State of v1:
>> What works:
>> * mount
>> * stat
>> * chdir
>> * readdir (aka ls)
>> * read of small files (<10k)
>> * overwrite
>>
>> What does not work:
>> * create new files (in 90% problems with path handling (old path
>> occurs)
>> * read / probably write big files
>>
>>
>> Signed-off-by: Michael Fritscher <address@hidden>
>> ---
>> On https://github.com/mifritscher/qemu/tree/9pfs_windows is a git tree
>> with the patch.
>>
>> I gave a shot at xattr (try to include xattr stuff) but it ended up even
>> more #ifdefs. So I gave up at this.
>> Now I'm waiting on comments etc. If there are no big objections, I'll
>> remove the debug output and make a patch which is meant for upstreaming.
>>
>> Thanks to everybody which helped me!
>>
>> Makefile.objs | 1 +
>> configure | 15 ++-
>> fsdev/9p-iov-marshal.c | 2 +
>> fsdev/9p-marshal.c | 4 +-
>> fsdev/file-op-9p.h | 35 ++++-
>> fsdev/qemu-fsdev.c | 2 +
>> hw/9pfs/9p-local.c | 326
>> +++++++++++++++++++++++++++++++++++++++++----
>> hw/9pfs/9p-synth.c | 10 +-
>> hw/9pfs/9p.c | 102 +++++++++++++-
>> hw/9pfs/9p.h | 70 +++++++++-
>> hw/9pfs/Makefile.objs | 7 +-
>> hw/9pfs/codir.c | 31 +++++
>> hw/9pfs/cofile.c | 15 +++
>> hw/9pfs/cofs.c | 15 +++
>> hw/9pfs/coxattr.c | 6 +
>> hw/9pfs/virtio-9p-device.c | 4 +-
>> 16 files changed, 600 insertions(+), 45 deletions(-)
>>
>> diff --git a/Makefile.objs b/Makefile.objs
>> index 8f705f6..6fd02bc 100644
>> --- a/Makefile.objs
>> +++ b/Makefile.objs
>> @@ -48,6 +48,7 @@ common-obj-$(CONFIG_WIN32) += os-win32.o
>> common-obj-$(CONFIG_POSIX) += os-posix.o
>>
>> common-obj-$(CONFIG_LINUX) += fsdev/
>> +common-obj-$(CONFIG_WIN32) += fsdev/
>>
>> common-obj-y += migration/
>> common-obj-y += qemu-char.o #aio.o
>> diff --git a/configure b/configure
>> index 5db29f0..a4797c3 100755
>> --- a/configure
>> +++ b/configure
>> @@ -4566,12 +4566,21 @@ if test "$want_tools" = "yes" ; then
>> fi
>> if test "$softmmu" = yes ; then
>> if test "$virtfs" != no ; then
>> - if test "$cap" = yes && test "$linux" = yes && test "$attr" = yes ;
>> then
>> + if test "$linux" = yes ; then
>> + if test "$cap" = yes && test "$attr" = yes ; then
>> + virtfs=yes
>> + tools="$tools fsdev/virtfs-proxy-helper\$(EXESUF)"
>> + else
>> + if test "$virtfs" = yes; then
>> + error_exit "VirtFS requires libcap-devel and libattr-devel on
>> Linux"
>> + fi
>> + virtfs=no
>> + fi
>> + elif test "$mingw32" = yes; then
>> virtfs=yes
>> - tools="$tools fsdev/virtfs-proxy-helper\$(EXESUF)"
>> else
>> if test "$virtfs" = yes; then
>> - error_exit "VirtFS is supported only on Linux and requires
>> libcap-devel and libattr-devel"
>> + error_exit "VirtFS is only supported on Linux or Windows"
>> fi
>> virtfs=no
>> fi
>> diff --git a/fsdev/9p-iov-marshal.c b/fsdev/9p-iov-marshal.c
>> index fb40bdf..1a292c6 100644
>> --- a/fsdev/9p-iov-marshal.c
>> +++ b/fsdev/9p-iov-marshal.c
>> @@ -15,7 +15,9 @@
>> #include <glib.h>
>> #include <glib/gprintf.h>
>> #include <utime.h>
>> +#ifndef _WIN32
>> #include <sys/uio.h>
>> +#endif
>>
>> #include "9p-iov-marshal.h"
>> #include "qemu/bswap.h"
>> diff --git a/fsdev/9p-marshal.c b/fsdev/9p-marshal.c
>> index 183d366..081cb88 100644
>> --- a/fsdev/9p-marshal.c
>> +++ b/fsdev/9p-marshal.c
>> @@ -16,7 +16,9 @@
>> #include <glib/gprintf.h>
>> #include <dirent.h>
>> #include <utime.h>
>> -#include <sys/uio.h>
>> +#ifndef WIN32
>> + #include <sys/uio.h>
>> +#endif
>>
>> #include "9p-marshal.h"
>>
>> diff --git a/fsdev/file-op-9p.h b/fsdev/file-op-9p.h
>> index b8c2602..446c6a5 100644
>> --- a/fsdev/file-op-9p.h
>> +++ b/fsdev/file-op-9p.h
>> @@ -14,12 +14,43 @@
>> #define _FILEOP_H
>> #include <dirent.h>
>> #include <utime.h>
>> -#include <sys/uio.h>
>> -#include <sys/vfs.h>
>> +#ifndef _WIN32
>> + #include <sys/uio.h>
>> + #include <sys/vfs.h>
>> +#endif
>>
>> #define SM_LOCAL_MODE_BITS 0600
>> #define SM_LOCAL_DIR_MODE_BITS 0700
>>
>> +#ifdef _WIN32
>> +typedef uint32_t uid_t;
>> +typedef uint32_t gid_t;
>> +
>> +/* from http://man7.org/linux/man-pages/man2/statfs.2.html */
>> +typedef uint32_t __fsword_t;
>> +typedef uint32_t fsblkcnt_t;
>> +typedef uint32_t fsfilcnt_t;
>> +
>> +/* from linux/include/uapi/asm-generic/posix_types.h */
>> +typedef struct {
>> + long __val[2];
>> +} fsid_t;
>> +
>> +struct statfs {
>> + __fsword_t f_type;
>> + __fsword_t f_bsize;
>> + fsblkcnt_t f_blocks;
>> + fsblkcnt_t f_bfree;
>> + fsblkcnt_t f_bavail;
>> + fsfilcnt_t f_files;
>> + fsfilcnt_t f_ffree;
>> + fsid_t f_fsid;
>> + __fsword_t f_namelen;
>> + __fsword_t f_frsize;
>> + __fsword_t f_flags;
>> +};
>> +#endif
>> +
>> typedef struct FsCred
>> {
>> uid_t fc_uid;
>> diff --git a/fsdev/qemu-fsdev.c b/fsdev/qemu-fsdev.c
>> index bf7f0b0..384d72e 100644
>> --- a/fsdev/qemu-fsdev.c
>> +++ b/fsdev/qemu-fsdev.c
>> @@ -26,7 +26,9 @@ static FsDriverTable FsDrivers[] = {
>> { .name = "handle", .ops = &handle_ops},
>> #endif
>> { .name = "synth", .ops = &synth_ops},
>> +#ifndef WIN32
>> { .name = "proxy", .ops = &proxy_ops},
>> +#endif
>> };
>>
>> int qemu_fsdev_add(QemuOpts *opts)
>> diff --git a/hw/9pfs/9p-local.c b/hw/9pfs/9p-local.c
>> index 16f45f4..710ab5f 100644
>> --- a/hw/9pfs/9p-local.c
>> +++ b/hw/9pfs/9p-local.c
>> @@ -12,23 +12,174 @@
>> */
>>
>> #include "qemu/osdep.h"
>> +/* mifritscher: after killing the debug printf, kill this as well! */
>> +#include "qemu/error-report.h"
>> #include "9p.h"
>> -#include "9p-xattr.h"
>> +#ifdef _WIN32
>> +/* idea from
>> http://mingw-users.1079350.n2.nabble.com/Undefined-reference-to-quot-lstat-quot-and-quot-S-ISLNK-quot-td5450984.html
>> */
>> +# define lstat(path, buffer) stat(path, buffer)
>> +
>> +# define mkdir(path, mode) mkdir(path)
>
> Maybe these definitions can go to include/sysemu/os-win32.h ?
I didn't know that we have this file - in fact, I wanted to provoke a
reaction on this how to handle this properly ;-) Yes, good idea.
>
>> +# define getxattr(buffer, name, pointer, length) 0
>> +
>> +/* pretend success */
>> +static int setxattr(const char *path, const char *name,
>> + const void *value, size_t size, int flags)
>> +{
>> + return 0;
>> +}
>> +
>> +static ssize_t fgetxattr(int fd, const char *name,
>> + void *value, size_t size)
>> +{
>> + return 0;
>> +}
>> +
>
> and these xattr definitions to include/qemu/xattr.h ?
Yes - or perhaps a xattr-win32.h (I think there was some problem including
xattr.h)
>
>> +# define lchown(buffer, uid, gid) 0
>> +# define readlink(buffer, buf, bufsz) 0
>> +# define mknod(buffer, mode, u) 0
>> +# define link(buffer, buffer1) 0
>> +# define symlink(buffer, buffer1) 0
>> +
>> +static ssize_t v9fs_get_xattr(FsContext *ctx, const char *path,
>> + const char *name, void *value, size_t
>> size)
>> +{
>> + errno = 95; /* EOPNOTSUP - wrong definition in mingw(130); */
>
> This is ENOTSUP actually.
Aahhh - thanks :-)
>
>> + return -1;
>> +}
>> +
>> +static ssize_t v9fs_list_xattr(FsContext *ctx, const char *path,
>> + void *value, size_t vsize)
>> +{
>> + errno = 95; /* EOPNOTSUP - wrong definition in mingw(130); */
>> + return -1;
>> +}
>> +
>> +static int v9fs_set_xattr(FsContext *ctx, const char *path,
>> + const char *name, void *value, size_t size,
>> + int flags)
>> +{
>> + errno = 95; /* EOPNOTSUP - wrong definition in mingw(130); */
>> + return -1;
>> +}
>> +
>> +static int v9fs_remove_xattr(FsContext *ctx, const char *path,
>> + const char *name)
>> +{
>> + errno = 95; /* EOPNOTSUP - wrong definition in mingw(130); */
>> + return -1;
>> +}
>> +
>> +static int readdir_r(DIR *dirp, struct dirent *entry,
>> + struct dirent **result)
>> +{
>> + struct dirent *temp;
>> + errno = 0;
>> + temp = readdir(dirp);
>
> readdir() isn't expected to be thread safe... I believe we need some
> locking here.
>
> Also this function should probably be in os-win32.c.
@locking: Yes, I stumbled over that. Which locking mechanism do you prefer?
@os-win32.c: Yes :-)
>
>> + if (temp == 0) {
>> + error_printf("readdir_r: End of directory reached -> returning
>> NULL\n");
>> + *result = 0;
>> + } else {
>> + /* Copy it from the stack to the buffer got from the caller */
>> + memcpy(entry, temp, sizeof(struct dirent));
>> + error_printf("readdir_r: Name: %hu %s\n",
>> + temp->d_namlen, temp->d_name);
>> + error_printf("readdir_r: Name: %hu %s\n",
>> + entry->d_namlen, entry->d_name);
>> + *result = entry;
>> + }
>> + return errno;
>> +}
>> +
>> +/* Can be done better... */
>> +static int statfs(const char *file, struct statfs *buf)
>> +{
>> + memset(buf, 0, sizeof(struct statfs));
>> + buf->f_type = 0x01021997; /* V9FS_MAGIC */
>> + buf->f_bsize = 4096;
>> + buf->f_blocks = 4000000;
>> + buf->f_bfree = 3000000;
>> + buf->f_bavail = 2999000;
>> + buf->f_files = 1000000;
>> + buf->f_ffree = 800000;
>> + buf->f_namelen = NAME_MAX;
>> + return 0;
>> +}
>> +
>> +/* a crude hash function (needed for fake inodes) */
>> +static ino_t hash(const char *path)
>> +{
>> + ino_t result = (ino_t)41021998;
>> + int len = strlen(path);
>> + if (!len) {
>> + return result;
>> + }
>> +
>> + /* Q&D canolizement of the path */
>> + if (path[len - 1] == '\\' || path[len - 1] == '/') {
>> + len--;
>> + }
>> + if (!len) {
>> + return result;
>> + }
>> +
>> + if (path[len - 1] == '.') {
>> + if (len == 1) {
>> + return result;
>> + }
>> + len--;
>> + if (path[len - 1] == '\\' || path[len - 1] == '/') {
>> + len--;
>> + /* .. -> kill last part */
>> + } else if (path[len - 1] == '.') {
>> + len--;
>> + while (len) {
>> + if (path[len - 1] == '\\' || path[len - 1] == '/') {
>> + len--;
>> + break;
>> + }
>> + len--;
>> + }
>> + }
>> + }
>> +
>> + if (!len) {
>> + return result;
>> + }
>> +
>> + for (int i = 0; i < len; i++) {
>> + result += path[i] << (i % 7);
>> + result += path[i] << ((i + 11) % 17);
>> + result += path[i] << ((i + 19) % 23);
>> + }
>> +
>> + return result;
>> +}
>> +
>> +#else
>> +# include "9p-xattr.h"
>> +#endif
>
> I'd prefer the missing xattr bits to be added to win32... and
> if we really need different implementations, then maybe add
> 9p-xattr-posix.c and 9p-xattr-win32.c...
Yes.
>
>> #include "fsdev/qemu-fsdev.h" /* local_ops */
>> +#ifndef _WIN32
>> #include <arpa/inet.h>
>> #include <pwd.h>
>> #include <grp.h>
>> #include <sys/socket.h>
>> #include <sys/un.h>
>> #include "qemu/xattr.h"
>> +#endif
>> #include "qemu/cutils.h"
>> #include "qemu/error-report.h"
>> #include <libgen.h>
>> -#include <linux/fs.h>
>> +#ifndef _WIN32
>> + #include <linux/fs.h>
>> +#endif
>> #ifdef CONFIG_LINUX_MAGIC_H
>> #include <linux/magic.h>
>> #endif
>> +#ifndef _WIN32
>> #include <sys/ioctl.h>
>> +#endif
>>
>> #ifndef XFS_SUPER_MAGIC
>> #define XFS_SUPER_MAGIC 0x58465342
>> @@ -76,7 +227,7 @@ static FILE *local_fopen(const char *path, const char
>> *mode)
>> } else {
>> return NULL;
>> }
>> - fd = open(path, flags, o_mode);
>> + fd = open(path, flags | O_BINARY, o_mode);
>
> Why is this needed ?
Because on Windows, the files are opened in textmode - which screws up
line endings. Stephan Weil told me that this flag is ignored on other
OSes, which open files in binary mode by default.
>
>> if (fd == -1) {
>> return NULL;
>> }
>> @@ -124,10 +275,20 @@ static int local_lstat(FsContext *fs_ctx, V9fsPath
>> *fs_path, struct stat *stbuf)
>> char *path = fs_path->data;
>>
>> buffer = rpath(fs_ctx, path);
>> - err = lstat(buffer, stbuf);
>> + error_printf("\nrpath %s + %s -> %s\n\n", fs_ctx->fs_root, path,
>> buffer);
>> + err = lstat(buffer, stbuf);
>> if (err) {
>> goto err_out;
>> }
>> +#ifdef _WIN32
>> + /* This way, all files are executable
>> + (MingW seems to do 777 on dirs, but 666 on files) */
>> + stbuf->st_mode |= S_IXUSR | S_IXGRP | S_IXOTH;
>> +
>> + /* Under WIN32 (MingW), st_ino seems to be always 2,
>> + which leads to confusion */
>> + stbuf->st_ino = hash(path);
>> +#endif
>> if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
>> /* Actual credentials are part of extended attrs */
>> uid_t tmp_uid;
>> @@ -162,7 +323,7 @@ static int local_create_mapped_attr_dir(FsContext
>> *ctx, const char *path)
>> char *attr_dir;
>> char *tmp_path = g_strdup(path);
>>
>> - attr_dir = g_strdup_printf("%s/%s/%s",
>> + attr_dir = g_strdup_printf(DELIMITER_IN_PATH2,
>> ctx->fs_root, dirname(tmp_path), VIRTFS_META_DIR);
>>
>> err = mkdir(attr_dir, 0700);
>> @@ -223,7 +384,8 @@ update_map_file:
>> if (credp->fc_gid != -1) {
>> gid = credp->fc_gid;
>> }
>> - if (credp->fc_mode != -1) {
>> + /* mifritscher: is normally unsigned... */
>> + if ((int16_t)(credp->fc_mode) != -1) {
>> mode = credp->fc_mode;
>> }
>> if (credp->fc_rdev != -1) {
>> @@ -268,7 +430,8 @@ static int local_set_xattr(const char *path, FsCred
>> *credp)
>> return err;
>> }
>> }
>> - if (credp->fc_mode != -1) {
>> + /* mifritscher: is normally unsigned... */
>> + if ((int16_t)(credp->fc_mode) != -1) {
>> uint32_t tmp_mode = cpu_to_le32(credp->fc_mode);
>> err = setxattr(path, "user.virtfs.mode", &tmp_mode,
>> sizeof(mode_t), 0);
>> if (err) {
>> @@ -323,7 +486,7 @@ static ssize_t local_readlink(FsContext *fs_ctx,
>> V9fsPath *fs_path,
>> (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE)) {
>> int fd;
>> buffer = rpath(fs_ctx, path);
>> - fd = open(buffer, O_RDONLY | O_NOFOLLOW);
>> + fd = open(buffer, O_RDONLY | O_NOFOLLOW | O_BINARY);
>> g_free(buffer);
>> if (fd == -1) {
>> return -1;
>> @@ -358,7 +521,8 @@ static int local_open(FsContext *ctx, V9fsPath
>> *fs_path,
>> char *path = fs_path->data;
>>
>> buffer = rpath(ctx, path);
>> - fs->fd = open(buffer, flags | O_NOFOLLOW);
>> + error_printf("File which should be opened: %s\n", buffer);
>> + fs->fd = open(buffer, flags | O_NOFOLLOW | O_BINARY);
>
> I see you add O_BINARY on all open() call sites ? Does this mean we
> need a helper ?
I could make a helper function if you want, which wraps open() and adds
O_BINARY to the flag. Where should I add this helper?
>
>> g_free(buffer);
>> return fs->fd;
>> }
>> @@ -370,6 +534,7 @@ static int local_opendir(FsContext *ctx,
>> char *path = fs_path->data;
>>
>> buffer = rpath(ctx, path);
>> + error_printf("Directory (opendir) which should be opened: %s\n",
>> buffer);
>> fs->dir = opendir(buffer);
>> g_free(buffer);
>> if (!fs->dir) {
>> @@ -395,17 +560,36 @@ static int local_readdir_r(FsContext *ctx,
>> V9fsFidOpenState *fs,
>> int ret;
>>
>> again:
>> +#ifdef _WIN32
>> + error_printf("local_readdir_r: Directory which should be
>> read:%s\n",
>> + fs->dir->dd_name);
>> +#endif
>> ret = readdir_r(fs->dir, entry, result);
>> if (ctx->export_flags & V9FS_SM_MAPPED) {
>> +#ifndef _WIN32
>> entry->d_type = DT_UNKNOWN;
>> +#endif
>> } else if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
>> if (!ret && *result != NULL &&
>> !strcmp(entry->d_name, VIRTFS_META_DIR)) {
>> /* skp the meta data directory */
>> goto again;
>> }
>> +#ifndef _WIN32
>> entry->d_type = DT_UNKNOWN;
>> +#endif
>> }
>> + if (*result == NULL) {
>> + error_printf("local_readdir_r: End of directory -> returning
>> NULL\n");
>> + } else {
>> +#ifdef _WIN32
>> + error_printf("local_readdir_r: Name: %hu %s\n",
>> + entry->d_namlen, entry->d_name);
>> +#else
>> + error_printf("local_readdir_r: Name: %s\n", entry->d_name);
>> +#endif
>> + }
>> + error_printf("local_readdir_r: return %d\n", ret);
>> return ret;
>> }
>>
>> @@ -418,10 +602,15 @@ static ssize_t local_preadv(FsContext *ctx,
>> V9fsFidOpenState *fs,
>> const struct iovec *iov,
>> int iovcnt, off_t offset)
>> {
>> + error_printf("local_preadv: #iov: %u, addr: %p, #bytes: %u, offset:
>> %llu\n",
>> + iovcnt, iov->iov_base, iov->iov_len, offset);
>> #ifdef CONFIG_PREADV
>> + error_printf("local_preadv: using preadv\n");
>> return preadv(fs->fd, iov, iovcnt, offset);
>> #else
>> + error_printf("local_preadv: not using preadv\n");
>> int err = lseek(fs->fd, offset, SEEK_SET);
>> + error_printf("local_preadv: lseek returned %d\n", err);
>> if (err == -1) {
>> return err;
>> } else {
>> @@ -491,7 +680,7 @@ static int local_mknod(FsContext *fs_ctx, V9fsPath
>> *dir_path,
>> char *buffer = NULL;
>>
>> v9fs_string_init(&fullname);
>> - v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
>> + v9fs_string_sprintf(&fullname, DELIMITER_IN_PATH, dir_path->data,
>> name);
>> path = fullname.data;
>>
>> /* Determine the security model */
>> @@ -552,7 +741,7 @@ static int local_mkdir(FsContext *fs_ctx, V9fsPath
>> *dir_path,
>> char *buffer = NULL;
>>
>> v9fs_string_init(&fullname);
>> - v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
>> + v9fs_string_sprintf(&fullname, DELIMITER_IN_PATH, dir_path->data,
>> name);
>> path = fullname.data;
>>
>> /* Determine the security model */
>> @@ -610,7 +799,14 @@ static int local_fstat(FsContext *fs_ctx, int
>> fid_type,
>> int err, fd;
>>
>> if (fid_type == P9_FID_DIR) {
>> + /* Don't know if that's right...
>> + (on WIN32/mingw, DIR has no fd entry) */
>> +#ifdef _WIN32
>> + #warning "Could cause problems!"
>> + fd = fs->fd;
>> +#else
>> fd = dirfd(fs->dir);
>> +#endif
>> } else {
>> fd = fs->fd;
>> }
>> @@ -619,6 +815,13 @@ static int local_fstat(FsContext *fs_ctx, int
>> fid_type,
>> if (err) {
>> return err;
>> }
>> +#ifdef _WIN32
>> + /* This way, all files are executable
>> + (MingW seems to do 777 on dirs, but 666 on files) */
>> + stbuf->st_mode |= S_IXUSR | S_IXGRP | S_IXOTH;
>> +
>> + /* mifritscher: TODO: fake inode? */
>> +#endif
>> if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
>> /* Actual credentials are part of extended attrs */
>> uid_t tmp_uid;
>> @@ -661,13 +864,16 @@ static int local_open2(FsContext *fs_ctx, V9fsPath
>> *dir_path, const char *name,
>> flags |= O_NOFOLLOW;
>>
>> v9fs_string_init(&fullname);
>> - v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
>> + v9fs_string_sprintf(&fullname, DELIMITER_IN_PATH, dir_path->data,
>> name);
>> path = fullname.data;
>>
>> + error_printf("local_open2: got %s %s\n", dir_path->data, name);
>> + error_printf("local_open2: full path: %s\n", path);
>> +
>> /* Determine the security model */
>> if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
>> buffer = rpath(fs_ctx, path);
>> - fd = open(buffer, flags, SM_LOCAL_MODE_BITS);
>> + fd = open(buffer, flags | O_BINARY, SM_LOCAL_MODE_BITS);
>> if (fd == -1) {
>> err = fd;
>> goto out;
>> @@ -681,7 +887,7 @@ static int local_open2(FsContext *fs_ctx, V9fsPath
>> *dir_path, const char *name,
>> }
>> } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
>> buffer = rpath(fs_ctx, path);
>> - fd = open(buffer, flags, SM_LOCAL_MODE_BITS);
>> + fd = open(buffer, flags | O_BINARY, SM_LOCAL_MODE_BITS);
>> if (fd == -1) {
>> err = fd;
>> goto out;
>> @@ -696,12 +902,17 @@ static int local_open2(FsContext *fs_ctx, V9fsPath
>> *dir_path, const char *name,
>> } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
>> (fs_ctx->export_flags & V9FS_SM_NONE)) {
>> buffer = rpath(fs_ctx, path);
>> - fd = open(buffer, flags, credp->fc_mode);
>> + error_printf("local_open2: File which should be opened (open2):
>> %s\n",
>> + buffer);
>> + fd = open(buffer, flags | O_BINARY, credp->fc_mode);
>> + error_printf("local_open2: open returned %d\n", fd);
>> if (fd == -1) {
>> err = fd;
>> goto out;
>> }
>> err = local_post_create_passthrough(fs_ctx, path, credp);
>> + error_printf("local_open2: local_post_create_passthrough
>> returned %u\n",
>> + err);
>> if (err == -1) {
>> serrno = errno;
>> goto err_end;
>> @@ -732,7 +943,7 @@ static int local_symlink(FsContext *fs_ctx, const
>> char *oldpath,
>> char *buffer = NULL;
>>
>> v9fs_string_init(&fullname);
>> - v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
>> + v9fs_string_sprintf(&fullname, DELIMITER_IN_PATH, dir_path->data,
>> name);
>> newpath = fullname.data;
>>
>> /* Determine the security model */
>> @@ -740,7 +951,9 @@ static int local_symlink(FsContext *fs_ctx, const
>> char *oldpath,
>> int fd;
>> ssize_t oldpath_size, write_size;
>> buffer = rpath(fs_ctx, newpath);
>> - fd = open(buffer, O_CREAT|O_EXCL|O_RDWR|O_NOFOLLOW,
>> SM_LOCAL_MODE_BITS);
>> + fd = open(buffer,
>> + O_CREAT | O_EXCL | O_RDWR | O_NOFOLLOW | O_BINARY,
>> + SM_LOCAL_MODE_BITS);
>> if (fd == -1) {
>> err = fd;
>> goto out;
>> @@ -758,8 +971,10 @@ static int local_symlink(FsContext *fs_ctx, const
>> char *oldpath,
>> goto err_end;
>> }
>> close(fd);
>> - /* Set cleint credentials in symlink's xattr */
>> + /* Set client credentials in symlink's xattr */
>> +#ifndef _WIN32
>> credp->fc_mode = credp->fc_mode|S_IFLNK;
>> +#endif
>> err = local_set_xattr(buffer, credp);
>> if (err == -1) {
>> serrno = errno;
>> @@ -769,7 +984,9 @@ static int local_symlink(FsContext *fs_ctx, const
>> char *oldpath,
>> int fd;
>> ssize_t oldpath_size, write_size;
>> buffer = rpath(fs_ctx, newpath);
>> - fd = open(buffer, O_CREAT|O_EXCL|O_RDWR|O_NOFOLLOW,
>> SM_LOCAL_MODE_BITS);
>> + fd = open(buffer,
>> + O_CREAT | O_EXCL | O_RDWR | O_NOFOLLOW | O_BINARY,
>> + SM_LOCAL_MODE_BITS);
>> if (fd == -1) {
>> err = fd;
>> goto out;
>> @@ -788,7 +1005,9 @@ static int local_symlink(FsContext *fs_ctx, const
>> char *oldpath,
>> }
>> close(fd);
>> /* Set cleint credentials in symlink's xattr */
>> +#ifndef _WIN32
>> credp->fc_mode = credp->fc_mode|S_IFLNK;
>> +#endif
>> err = local_set_mapped_file_attr(fs_ctx, newpath, credp);
>> if (err == -1) {
>> serrno = errno;
>> @@ -833,7 +1052,7 @@ static int local_link(FsContext *ctx, V9fsPath
>> *oldpath,
>> char *buffer, *buffer1;
>>
>> v9fs_string_init(&newpath);
>> - v9fs_string_sprintf(&newpath, "%s/%s", dirpath->data, name);
>> + v9fs_string_sprintf(&newpath, DELIMITER_IN_PATH, dirpath->data,
>> name);
>>
>> buffer = rpath(ctx, oldpath->data);
>> buffer1 = rpath(ctx, newpath.data);
>> @@ -934,7 +1153,12 @@ static int local_utimensat(FsContext *s, V9fsPath
>> *fs_path,
>> char *path = fs_path->data;
>>
>> buffer = rpath(s, path);
>> +#ifdef _WIN32
>> + #warning "Could cause problems!"
>> + ret = 0;
>> +#else
>> ret = qemu_utimens(buffer, buf);
>> +#endif
>> g_free(buffer);
>> return ret;
>> }
>> @@ -949,6 +1173,7 @@ static int local_remove(FsContext *ctx, const char
>> *path)
>> buffer = rpath(ctx, path);
>> err = lstat(buffer, &stbuf);
>> g_free(buffer);
>> + error_printf("local_remove: stat %d %d\n", err, errno);
>> if (err) {
>> goto err_out;
>> }
>> @@ -957,10 +1182,12 @@ static int local_remove(FsContext *ctx, const
>> char *path)
>> * directory
>> */
>> if (S_ISDIR(stbuf.st_mode)) {
>> - buffer = g_strdup_printf("%s/%s/%s", ctx->fs_root,
>> + buffer = g_strdup_printf(DELIMITER_IN_PATH2, ctx->fs_root,
>> path, VIRTFS_META_DIR);
>> err = remove(buffer);
>> g_free(buffer);
>> + error_printf("local_remove: .virtfs_metdata remove %d
>> %d\n",
>> + err, errno);
>> if (err < 0 && errno != ENOENT) {
>> /*
>> * We didn't had the .virtfs_metadata file. May be file
>> created
>> @@ -976,6 +1203,8 @@ static int local_remove(FsContext *ctx, const char
>> *path)
>> buffer = local_mapped_attr_path(ctx, path);
>> err = remove(buffer);
>> g_free(buffer);
>> + error_printf("local_remove: local_mapped_attr_path remove %d
>> %d\n",
>> + err, errno);
>> if (err < 0 && errno != ENOENT) {
>> /*
>> * We didn't had the .virtfs_metadata file. May be file
>> created
>> @@ -986,7 +1215,14 @@ static int local_remove(FsContext *ctx, const char
>> *path)
>> }
>>
>> buffer = rpath(ctx, path);
>> - err = remove(buffer);
>> + /* mifritscher: posix remove can delete directories as well,
>> windows not */
>> + if (S_ISDIR(stbuf.st_mode)) {
>> + err = rmdir(buffer);
>> + } else {
>> + err = remove(buffer);
>> + }
>> + error_printf("local_remove: final remove %d %d\n",
>> + err, errno);
>> g_free(buffer);
>> err_out:
>> return err;
>> @@ -998,7 +1234,12 @@ static int local_fsync(FsContext *ctx, int
>> fid_type,
>> int fd;
>>
>> if (fid_type == P9_FID_DIR) {
>> +#ifdef _WIN32
>> + #warning "Could cause problems!"
>> + fd = fs->fd;
>> +#else
>> fd = dirfd(fs->dir);
>> +#endif
>> } else {
>> fd = fs->fd;
>> }
>> @@ -1058,10 +1299,14 @@ static int local_name_to_path(FsContext *ctx,
>> V9fsPath *dir_path,
>> const char *name, V9fsPath *target)
>> {
>> if (dir_path) {
>> - v9fs_string_sprintf((V9fsString *)target, "%s/%s",
>> + v9fs_string_sprintf((V9fsString *)target, DELIMITER_IN_PATH,
>> dir_path->data, name);
>> + error_printf("local_name_to_path: ");
>> + error_printf(DELIMITER_IN_PATH, dir_path->data, name);
>> + error_printf("\n");
>> } else {
>> v9fs_string_sprintf((V9fsString *)target, "%s", name);
>> + error_printf("local_name_to_path: %s\n", name);
>> }
>> /* Bump the size for including terminating NULL */
>> target->size++;
>> @@ -1078,8 +1323,10 @@ static int local_renameat(FsContext *ctx,
>> V9fsPath *olddir,
>> v9fs_string_init(&old_full_name);
>> v9fs_string_init(&new_full_name);
>>
>> - v9fs_string_sprintf(&old_full_name, "%s/%s", olddir->data,
>> old_name);
>> - v9fs_string_sprintf(&new_full_name, "%s/%s", newdir->data,
>> new_name);
>> + v9fs_string_sprintf(&old_full_name,
>> + DELIMITER_IN_PATH, olddir->data, old_name);
>> + v9fs_string_sprintf(&new_full_name,
>> + DELIMITER_IN_PATH, newdir->data, new_name);
>>
>> ret = local_rename(ctx, old_full_name.data, new_full_name.data);
>> v9fs_string_free(&old_full_name);
>> @@ -1096,17 +1343,19 @@ static int local_unlinkat(FsContext *ctx,
>> V9fsPath *dir,
>>
>> v9fs_string_init(&fullname);
>>
>> - v9fs_string_sprintf(&fullname, "%s/%s", dir->data, name);
>> + v9fs_string_sprintf(&fullname, DELIMITER_IN_PATH, dir->data, name);
>> if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
>> if (flags == AT_REMOVEDIR) {
>> /*
>> * If directory remove .virtfs_metadata contained in the
>> * directory
>> */
>> - buffer = g_strdup_printf("%s/%s/%s", ctx->fs_root,
>> + buffer = g_strdup_printf(DELIMITER_IN_PATH2, ctx->fs_root,
>> fullname.data, VIRTFS_META_DIR);
>> ret = remove(buffer);
>> g_free(buffer);
>> + error_printf("local_unlinkat: .virtfs_metadata %d %d\n",
>> + ret, errno);
>> if (ret < 0 && errno != ENOENT) {
>> /*
>> * We didn't had the .virtfs_metadata file. May be file
>> created
>> @@ -1121,6 +1370,8 @@ static int local_unlinkat(FsContext *ctx, V9fsPath
>> *dir,
>> */
>> buffer = local_mapped_attr_path(ctx, fullname.data);
>> ret = remove(buffer);
>> + error_printf("local_unlinkat: local_mapped_attr_path %d %d\n",
>> + ret, errno);
>> g_free(buffer);
>> if (ret < 0 && errno != ENOENT) {
>> /*
>> @@ -1133,6 +1384,19 @@ static int local_unlinkat(FsContext *ctx,
>> V9fsPath *dir,
>> /* Remove the name finally */
>> buffer = rpath(ctx, fullname.data);
>> ret = remove(buffer);
>> + error_printf("local_unlinkat: final |%s| %d %d\n", buffer, ret,
>> errno);
>> + /* extension for MingW: remove or Windows can't handle
>> directories... */
>> +#ifdef _WIN32
>> + /* mifritscher: Try to delete it as directory
>> + (AT_REMOVEDIR doesn't seem to be set in this case
>> + (testcase: rmdir from Linux)) */
>> + if (ret < 0) {
>> + ret = rmdir(buffer);
>> + error_printf("local_unlinkat: final rmdir |%s| %d %d\n",
>> + buffer, ret, errno);
>> +
>> + }
>> +#endif
>> g_free(buffer);
>>
>> err_out:
>> @@ -1140,6 +1404,7 @@ err_out:
>> return ret;
>> }
>>
>> +#ifndef _WIN32
>> static int local_ioc_getversion(FsContext *ctx, V9fsPath *path,
>> mode_t st_mode, uint64_t *st_gen)
>> {
>> @@ -1167,12 +1432,18 @@ static int local_ioc_getversion(FsContext *ctx,
>> V9fsPath *path,
>> return -1;
>> #endif
>> }
>> +#endif
>>
>> static int local_init(FsContext *ctx)
>> {
>> int err = 0;
>> +#ifdef FS_IOC_GETVERSION
>> struct statfs stbuf;
>> +#endif
>>
>> +#ifdef _WIN32
>> + ctx->xops = 0;
>> +#else
>> if (ctx->export_flags & V9FS_SM_PASSTHROUGH) {
>> ctx->xops = passthrough_xattr_ops;
>> } else if (ctx->export_flags & V9FS_SM_MAPPED) {
>> @@ -1186,6 +1457,7 @@ static int local_init(FsContext *ctx)
>> */
>> ctx->xops = passthrough_xattr_ops;
>> }
>> +#endif
>> ctx->export_flags |= V9FS_PATHNAME_FSCONTEXT;
>> #ifdef FS_IOC_GETVERSION
>> /*
>> diff --git a/hw/9pfs/9p-synth.c b/hw/9pfs/9p-synth.c
>> index f1475df..8355722 100644
>> --- a/hw/9pfs/9p-synth.c
>> +++ b/hw/9pfs/9p-synth.c
>> @@ -15,7 +15,9 @@
>> #include "qemu/osdep.h"
>> #include "hw/virtio/virtio.h"
>> #include "9p.h"
>> -#include "9p-xattr.h"
>> +#ifndef _WIN32
>> + #include "9p-xattr.h"
>> +#endif
>> #include "fsdev/qemu-fsdev.h"
>> #include "9p-synth.h"
>> #include "qemu/rcu.h"
>> @@ -152,8 +154,10 @@ static void v9fs_synth_fill_statbuf(V9fsSynthNode
>> *node, struct stat *stbuf)
>> stbuf->st_gid = 0;
>> stbuf->st_rdev = 0;
>> stbuf->st_size = 0;
>> +#ifndef _WIN32
>> stbuf->st_blksize = 0;
>> stbuf->st_blocks = 0;
>> +#endif
>> stbuf->st_atime = 0;
>> stbuf->st_mtime = 0;
>> stbuf->st_ctime = 0;
>> @@ -222,7 +226,11 @@ static void v9fs_synth_direntry(V9fsSynthNode
>> *node,
>> {
>> strcpy(entry->d_name, node->name);
>> entry->d_ino = node->attr->inode;
>> +#ifdef _WIN32
>> + #warning "Can cause problems!"
>> +#else
>> entry->d_off = off + 1;
>> +#endif
>> }
>>
>> static int v9fs_synth_get_dentry(V9fsSynthNode *dir, struct dirent
>> *entry,
>> diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c
>> index f5e3012..7980f33 100644
>> --- a/hw/9pfs/9p.c
>> +++ b/hw/9pfs/9p.c
>> @@ -20,7 +20,21 @@
>> #include "qemu/sockets.h"
>> #include "virtio-9p.h"
>> #include "fsdev/qemu-fsdev.h"
>> -#include "9p-xattr.h"
>> +#ifdef _WIN32
>> +/* taken from linux/kdev_t.h */
>> +# define MINORBITS 20
>> +# define MINORMASK ((1U << MINORBITS) - 1)
>> +
>> +# define major(dev) ((unsigned int) ((dev) >> MINORBITS))
>> +# define minor(dev) ((unsigned int) ((dev) & MINORMASK))
>> +# define makedev(ma, mi) (((ma) << MINORBITS) | (mi))
>> +
>> +/* taken from linux/include/linux/stat.h */
>> +# define UTIME_NOW ((1l << 30) - 1l)
>> +# define UTIME_OMIT ((1l << 30) - 2l)
>> +#else
>> +# include "9p-xattr.h"
>> +#endif
>> #include "coth.h"
>> #include "trace.h"
>> #include "migration/migration.h"
>> @@ -576,9 +590,11 @@ static void stat_to_qid(const struct stat *stbuf,
>> V9fsQID *qidp)
>> if (S_ISDIR(stbuf->st_mode)) {
>> qidp->type |= P9_QID_TYPE_DIR;
>> }
>> - if (S_ISLNK(stbuf->st_mode)) {
>> - qidp->type |= P9_QID_TYPE_SYMLINK;
>> - }
>> + #ifndef _WIN32
>> + if (S_ISLNK(stbuf->st_mode)) {
>> + qidp->type |= P9_QID_TYPE_SYMLINK;
>> + }
>> + #endif
>> }
>>
>> static int fid_to_qid(V9fsPDU *pdu, V9fsFidState *fidp, V9fsQID *qidp)
>> @@ -677,12 +693,15 @@ static mode_t v9mode_to_mode(uint32_t mode,
>> V9fsString *extension)
>> ret |= S_IFDIR;
>> }
>>
>> +#ifndef _WIN32
>> if (mode & P9_STAT_MODE_SYMLINK) {
>> ret |= S_IFLNK;
>> }
>> if (mode & P9_STAT_MODE_SOCKET) {
>> ret |= S_IFSOCK;
>> }
>> +#endif
>> +
>> if (mode & P9_STAT_MODE_NAMED_PIPE) {
>> ret |= S_IFIFO;
>> }
>> @@ -698,6 +717,7 @@ static mode_t v9mode_to_mode(uint32_t mode,
>> V9fsString *extension)
>> ret |= S_IFREG;
>> }
>>
>> +#ifndef _WIN32
>> if (mode & P9_STAT_MODE_SETUID) {
>> ret |= S_ISUID;
>> }
>> @@ -707,6 +727,7 @@ static mode_t v9mode_to_mode(uint32_t mode,
>> V9fsString *extension)
>> if (mode & P9_STAT_MODE_SETVTX) {
>> ret |= S_ISVTX;
>> }
>> +#endif
>>
>> return ret;
>> }
>> @@ -762,6 +783,7 @@ static uint32_t stat_to_v9mode(const struct stat
>> *stbuf)
>> mode |= P9_STAT_MODE_DIR;
>> }
>>
>> +#ifndef _WIN32
>> if (S_ISLNK(stbuf->st_mode)) {
>> mode |= P9_STAT_MODE_SYMLINK;
>> }
>> @@ -769,6 +791,7 @@ static uint32_t stat_to_v9mode(const struct stat
>> *stbuf)
>> if (S_ISSOCK(stbuf->st_mode)) {
>> mode |= P9_STAT_MODE_SOCKET;
>> }
>> +#endif
>>
>> if (S_ISFIFO(stbuf->st_mode)) {
>> mode |= P9_STAT_MODE_NAMED_PIPE;
>> @@ -778,6 +801,7 @@ static uint32_t stat_to_v9mode(const struct stat
>> *stbuf)
>> mode |= P9_STAT_MODE_DEVICE;
>> }
>>
>> +#ifndef _WIN32
>> if (stbuf->st_mode & S_ISUID) {
>> mode |= P9_STAT_MODE_SETUID;
>> }
>> @@ -789,6 +813,7 @@ static uint32_t stat_to_v9mode(const struct stat
>> *stbuf)
>> if (stbuf->st_mode & S_ISVTX) {
>> mode |= P9_STAT_MODE_SETVTX;
>> }
>> +#endif
>>
>> return mode;
>> }
>> @@ -881,14 +906,34 @@ static void stat_to_v9stat_dotl(V9fsState *s,
>> const struct stat *stbuf,
>> v9lstat->st_gid = stbuf->st_gid;
>> v9lstat->st_rdev = stbuf->st_rdev;
>> v9lstat->st_size = stbuf->st_size;
>> +#ifdef _WIN32
>> + /* Blksize is the optimal EA-block,
>> + while blocks always refers to 512 blocks
>> + */
>> + v9lstat->st_blksize = 4096;
>> + v9lstat->st_blocks = ((stbuf->st_size + 1) / 512) + 1;
>> +#else
>> v9lstat->st_blksize = stbuf->st_blksize;
>> v9lstat->st_blocks = stbuf->st_blocks;
>> +#endif
>> v9lstat->st_atime_sec = stbuf->st_atime;
>> +#ifdef _WIN32
>> + v9lstat->st_atime_nsec = 0;
>> +#else
>> v9lstat->st_atime_nsec = stbuf->st_atim.tv_nsec;
>> +#endif
>> v9lstat->st_mtime_sec = stbuf->st_mtime;
>> +#ifdef _WIN32
>> + v9lstat->st_mtime_nsec = 0;
>> +#else
>> v9lstat->st_mtime_nsec = stbuf->st_mtim.tv_nsec;
>> +#endif
>> v9lstat->st_ctime_sec = stbuf->st_ctime;
>> +#ifdef _WIN32
>> + v9lstat->st_ctime_nsec = 0;
>> +#else
>> v9lstat->st_ctime_nsec = stbuf->st_ctim.tv_nsec;
>> +#endif
>> /* Currently we only support BASIC fields in stat */
>> v9lstat->st_result_mask = P9_STATS_BASIC;
>>
>> @@ -1639,7 +1684,10 @@ static int v9fs_do_readdir_with_stat(V9fsPDU
>> *pdu,
>> v9fs_path_init(&path);
>> err = v9fs_co_readdir_r(pdu, fidp, dent, &result);
>> if (err || !result) {
>> + error_printf("v9fs_do_readdir_with_stat: exiting...\n");
>> break;
>> + } else {
>> + error_printf("v9fs_do_readdir_with_stat: continue\n");
>> }
>> err = v9fs_co_name_to_path(pdu, &fidp->path, dent->d_name,
>> &path);
>> if (err < 0) {
>> @@ -1666,7 +1714,12 @@ static int v9fs_do_readdir_with_stat(V9fsPDU
>> *pdu,
>> count += len;
>> v9fs_stat_free(&v9stat);
>> v9fs_path_free(&path);
>> +#ifdef _WIN32
>> + #warning "Probably right, but could make problems!"
>> + saved_dir_pos = v9fs_co_telldir(pdu, fidp);
>> +#else
>> saved_dir_pos = dent->d_off;
>> +#endif
>> }
>> out:
>> g_free(dent);
>> @@ -1806,6 +1859,9 @@ static int v9fs_do_readdir(V9fsPDU *pdu,
>> int32_t count = 0;
>> off_t saved_dir_pos;
>> struct dirent *dent, *result;
>> +#ifdef _WIN32
>> + uint8_t type = 0; /* DT_UNKNOWN */
>> +#endif
>>
>> /* save the directory position */
>> saved_dir_pos = v9fs_co_telldir(pdu, fidp);
>> @@ -1818,15 +1874,27 @@ static int v9fs_do_readdir(V9fsPDU *pdu,
>> while (1) {
>> err = v9fs_co_readdir_r(pdu, fidp, dent, &result);
>> if (err || !result) {
>> + error_printf("v9fs_do_readdir: exiting...\n");
>> break;
>> + } else {
>> + error_printf("v9fs_do_readdir: continue\n");
>> }
>> v9fs_string_init(&name);
>> + if (!dent->d_name) {
>> + error_printf("\ndent->d_name is NULL!\n");
>> + break;
>> + } else {
>> + error_printf("v9fs_do_readdir: entry is named %s, strlen
>> %u\n",
>> + dent->d_name, strlen(dent->d_name));
>> + }
>> v9fs_string_sprintf(&name, "%s", dent->d_name);
>> if ((count + v9fs_readdir_data_size(&name)) > max_count) {
>> /* Ran out of buffer. Set dir back to old position and
>> return */
>> v9fs_co_seekdir(pdu, fidp, saved_dir_pos);
>> v9fs_string_free(&name);
>> g_free(dent);
>> + error_printf("v9fs_do_readdir: RAN OUT OF BUFFER return
>> %d\n\n",
>> + count);
>> return count;
>> }
>> /*
>> @@ -1841,9 +1909,16 @@ static int v9fs_do_readdir(V9fsPDU *pdu,
>> qid.version = 0;
>>
>> /* 11 = 7 + 4 (7 = start offset, 4 = space for storing count)
>> */
>> +#ifdef _WIN32
>> + #warning "Probably right, but could make problems!"
>> + len = pdu_marshal(pdu, 11 + count, "Qqbs",
>> + &qid, v9fs_co_telldir(pdu, fidp),
>> + type, &name);
>> +#else
>> len = pdu_marshal(pdu, 11 + count, "Qqbs",
>> &qid, dent->d_off,
>> dent->d_type, &name);
>> +#endif
>> if (len < 0) {
>> v9fs_co_seekdir(pdu, fidp, saved_dir_pos);
>> v9fs_string_free(&name);
>> @@ -1852,12 +1927,18 @@ static int v9fs_do_readdir(V9fsPDU *pdu,
>> }
>> count += len;
>> v9fs_string_free(&name);
>> +#ifdef _WIN32
>> + #warning "Probably right, but could make problems!"
>> + saved_dir_pos = v9fs_co_telldir(pdu, fidp);
>> +#else
>> saved_dir_pos = dent->d_off;
>> +#endif
>> }
>> g_free(dent);
>> if (err < 0) {
>> return err;
>> }
>> + error_printf("v9fs_do_readdir: return %d\n\n", count);
>> return count;
>> }
>>
>> @@ -1878,6 +1959,8 @@ static void v9fs_readdir(void *opaque)
>> goto out_nofid;
>> }
>> trace_v9fs_readdir(pdu->tag, pdu->id, fid, initial_offset,
>> max_count);
>> + error_printf("v9fs_readdir initial: %llu max count: %u\n",
>> + initial_offset, max_count);
>>
>> fidp = get_fid(pdu, fid);
>> if (fidp == NULL) {
>> @@ -1904,10 +1987,13 @@ static void v9fs_readdir(void *opaque)
>> }
>> retval += count + offset;
>> trace_v9fs_readdir_return(pdu->tag, pdu->id, count, retval);
>> + error_printf("v9fs_readdir: count: %d retval: %d\n\n", count,
>> retval);
>> out:
>> put_fid(pdu, fidp);
>> out_nofid:
>> pdu_complete(pdu, retval);
>> +
>> + error_printf("v9fs_readdir: return\n");
>> }
>>
>> static int v9fs_xattr_write(V9fsState *s, V9fsPDU *pdu, V9fsFidState
>> *fidp,
>> @@ -2166,8 +2252,12 @@ static void v9fs_create(void *opaque)
>> }
>> v9fs_path_copy(&fidp->path, &path);
>> } else if (perm & P9_STAT_MODE_SOCKET) {
>> +#ifdef _WIN32
>> + err = -1;
>> +#else
>> err = v9fs_co_mknod(pdu, fidp, &name, fidp->uid, -1,
>> 0, S_IFSOCK | (perm & 0777), &stbuf);
>> +#endif
>> if (err < 0) {
>> goto out;
>> }
>> @@ -3338,7 +3428,7 @@ int v9fs_device_realize_common(V9fsState *s, Error
>> **errp)
>> * call back to do that. Since we are in the init path, we don't
>> * use co-routines here.
>> */
>> - if (s->ops->name_to_path(&s->ctx, NULL, "/", &path) < 0) {
>> + if (s->ops->name_to_path(&s->ctx, NULL, DELIMITER_STRING, &path) <
>> 0) {
>> error_setg(errp,
>> "error in converting name to path %s",
>> strerror(errno));
>> goto out;
>> @@ -3370,6 +3460,7 @@ void v9fs_device_unrealize_common(V9fsState *s,
>> Error **errp)
>>
>> static void __attribute__((__constructor__)) v9fs_set_fd_limit(void)
>> {
>> +#ifndef _WIN32
>> struct rlimit rlim;
>> if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) {
>> error_report("Failed to get the resource limit");
>> @@ -3377,4 +3468,5 @@ static void __attribute__((__constructor__))
>> v9fs_set_fd_limit(void)
>> }
>> open_fd_hw = rlim.rlim_cur - MIN(400, rlim.rlim_cur/3);
>> open_fd_rc = rlim.rlim_cur/2;
>> +#endif
>> }
>> diff --git a/hw/9pfs/9p.h b/hw/9pfs/9p.h
>> index 1a19418..7bc8863 100644
>> --- a/hw/9pfs/9p.h
>> +++ b/hw/9pfs/9p.h
>> @@ -3,7 +3,29 @@
>>
>> #include <dirent.h>
>> #include <utime.h>
>> -#include <sys/resource.h>
>> +#ifdef _WIN32
>> +/* Bad workaround, from http://octave.org/doxygen/3.4/fcntl_8h.html */
>> +# define O_NOCTTY 0
>> +# define O_NDELAY 0
>> +# define O_NONBLOCK O_NDELAY
>> +# define O_DSYNC 0
>> +# define O_DIRECT 0
>> +# define O_DIRECTORY 0
>> +# define O_NOFOLLOW 0
>> +# define O_NOATIME 0
>> +# define O_SYNC 0
>> +# define O_ASYNC 0
>> +
>> +# define FASYNC 0
>> +
>> +# define AT_REMOVEDIR 1
>> +
>> +# define NAME_MAX 260
>> +
>> +#else
>> +# include <sys/resource.h>
>> +#endif
>> +
>> #include <glib.h>
>> #include "standard-headers/linux/virtio_9p.h"
>> #include "hw/virtio/virtio.h"
>> @@ -12,6 +34,10 @@
>> #include "qemu/thread.h"
>> #include "qemu/coroutine.h"
>>
>> +#define DELIMITER_STRING "/"
>> +#define DELIMITER_IN_PATH "%s/%s"
>> +#define DELIMITER_IN_PATH2 "%s/%s/%s"
>> +
>
> Is this really needed (will there be different values for
> win32) ? If yes, I guess DELEMITER_STRING should be defined
> in a host arch specific header ? And anyway, this should be
> pushed to a separate patch.
I didn't like the spreading of this strings everywhere, so I defined these
constants. Yes, in the first step I thought I need them to be host OS
specific, but it turned out there is a better way.
>
>> enum {
>> P9_TLERROR = 6,
>> P9_RLERROR,
>> @@ -108,9 +134,49 @@ enum p9_proto_version {
>>
>> #define FID_REFERENCED 0x1
>> #define FID_NON_RECLAIMABLE 0x2
>> +
>> +/* combines the host's root dir and the path to a complete host path */
>> static inline char *rpath(FsContext *ctx, const char *path)
>> {
>> - return g_strdup_printf("%s/%s", ctx->fs_root, path);
>> + char *result;
>> + result = g_strdup_printf(DELIMITER_IN_PATH, ctx->fs_root, path);
>> +#ifdef _WIN32
>> + int input = 0;
>> + int output = 0;
>> + while (result[input]) {
>> + /* error_printf("<-%d %c\n", input, result[input]); */
>> + if (result[input] == '/') {
>> + result[output] = '\\';
>> + /* remove duplicate \... */
>
> Why do we need to remove duplicate \ ?
The other code relies that the host OS ignores dupplicate \ - they occured
in several places, e.g. when connecting the base (host) path and the path
given by the guest. Without remove them Windows bails out.
>
>> + if (output > 0 && result[output - 1] == '\\') {
>> + /* error_printf("remove duplicate \\\n"); */
>> + output--;
>> + } else {
>> + result[output] = '\\';
>> + }
>> + /* error_printf(" %c\n", result[output]); */
>> + } else {
>> + result[output] = result[input];
>> + }
>> + /* error_printf("->%d %c\n\n", output, result[output]); */
>> + input++;
>> + output++;
>> + }
>> + /* Kill last \ (but leave it if the char before is a : ...)
>
> Why kill last \ ?
Same reason as above ;-)
>
>> + So:
>> + C:\ -> C:\
>> + C:\blah\ -> C:\blah
>> + b\ -> b
>> + blah\ -> blah */
>> + if (output > 1 && result[output - 1] == '\\'
>> + && (output == 1 || result[output - 2] != ':')) {
>> + /* error_printf("Killed last \\\n"); */
>> + result[output - 1] = '\0';
>> + } else {
>> + result[output] = '\0';
>> + }
>> +#endif
>
> I understand we need to convert / to \, but I don't see why
> we should remove duplicates... and anyway, this should be
> moved to a fixup helper.
Where should I move the function to?
>
>> + return result;
>> }
>>
>> /*
>> diff --git a/hw/9pfs/Makefile.objs b/hw/9pfs/Makefile.objs
>> index da0ae0c..6f6ed19 100644
>> --- a/hw/9pfs/Makefile.objs
>> +++ b/hw/9pfs/Makefile.objs
>> @@ -1,9 +1,10 @@
>> common-obj-y = 9p.o
>> -common-obj-y += 9p-local.o 9p-xattr.o
>> -common-obj-y += 9p-xattr-user.o 9p-posix-acl.o
>> +common-obj-$(CONFIG_LINUX) += 9p-local.o 9p-xattr.o
>> +common-obj-$(CONFIG_LINUX) += 9p-xattr-user.o 9p-posix-acl.o
>> +common-obj-$(CONFIG_WIN32) += 9p-local.o
>> common-obj-y += coth.o cofs.o codir.o cofile.o
>> common-obj-y += coxattr.o 9p-synth.o
>> common-obj-$(CONFIG_OPEN_BY_HANDLE) += 9p-handle.o
>> -common-obj-y += 9p-proxy.o
>> +common-obj-$(CONFIG_POSIX) += 9p-proxy.o
>>
>> obj-y += virtio-9p-device.o
>> diff --git a/hw/9pfs/codir.c b/hw/9pfs/codir.c
>> index 91df7f7..399bd8a 100644
>> --- a/hw/9pfs/codir.c
>> +++ b/hw/9pfs/codir.c
>> @@ -17,6 +17,8 @@
>> #include "qemu/thread.h"
>> #include "qemu/coroutine.h"
>> #include "coth.h"
>> +/* mifritscher: after killing the debug printf, kill this as well! */
>> +#include "qemu/error-report.h"
>>
>> int v9fs_co_readdir_r(V9fsPDU *pdu, V9fsFidState *fidp, struct dirent
>> *dent,
>> struct dirent **result)
>> @@ -37,6 +39,12 @@ int v9fs_co_readdir_r(V9fsPDU *pdu, V9fsFidState
>> *fidp, struct dirent *dent,
>> err = 0;
>> }
>> });
>> +#ifdef _WIN32
>> + error_printf("v9fs_co_readdir_r: %s %d %p\n",
>> + (&fidp->fs)->dir->dd_name, err, *result);
>> +#else
>> + error_printf("v9fs_co_readdir_r: %d %p\n", err, *result);
>> +#endif
>> return err;
>> }
>>
>> @@ -55,6 +63,12 @@ off_t v9fs_co_telldir(V9fsPDU *pdu, V9fsFidState
>> *fidp)
>> err = -errno;
>> }
>> });
>> +#ifdef _WIN32
>> + error_printf("v9fs_co_telldir_r: %s %lld\n",
>> + (&fidp->fs)->dir->dd_name, err);
>> +#else
>> + error_printf("v9fs_co_telldir_r: %ld\n", err);
>> +#endif
>> return err;
>> }
>>
>> @@ -68,6 +82,11 @@ void v9fs_co_seekdir(V9fsPDU *pdu, V9fsFidState
>> *fidp, off_t offset)
>> {
>> s->ops->seekdir(&s->ctx, &fidp->fs, offset);
>> });
>> +#ifdef _WIN32
>> + error_printf("v9fs_co_seekdir: %s\n", (&fidp->fs)->dir->dd_name);
>> +#else
>> + error_printf("v9fs_co_seekdir\n");
>> +#endif
>> }
>>
>> void v9fs_co_rewinddir(V9fsPDU *pdu, V9fsFidState *fidp)
>> @@ -80,6 +99,11 @@ void v9fs_co_rewinddir(V9fsPDU *pdu, V9fsFidState
>> *fidp)
>> {
>> s->ops->rewinddir(&s->ctx, &fidp->fs);
>> });
>> +#ifdef _WIN32
>> + error_printf("v9fs_co_rewinddir: %s\n", (&fidp->fs)->dir->dd_name);
>> +#else
>> + error_printf("v9fs_co_rewinddir\n");
>> +#endif
>> }
>>
>> int v9fs_co_mkdir(V9fsPDU *pdu, V9fsFidState *fidp, V9fsString *name,
>> @@ -116,6 +140,7 @@ int v9fs_co_mkdir(V9fsPDU *pdu, V9fsFidState *fidp,
>> V9fsString *name,
>> }
>> });
>> v9fs_path_unlock(s);
>> + error_printf("v9fs_co_mkdir: %d\n", err);
>> return err;
>> }
>>
>> @@ -144,6 +169,11 @@ int v9fs_co_opendir(V9fsPDU *pdu, V9fsFidState
>> *fidp)
>> v9fs_reclaim_fd(pdu);
>> }
>> }
>> +#ifdef _WIN32
>> + error_printf("v9fs_co_opendir: %s %d\n", (&fidp->fs)->dir->dd_name,
>> err);
>> +#else
>> + error_printf("v9fs_co_opendir: %d\n", err);
>> +#endif
>> return err;
>> }
>>
>> @@ -165,5 +195,6 @@ int v9fs_co_closedir(V9fsPDU *pdu, V9fsFidOpenState
>> *fs)
>> if (!err) {
>> total_open_fd--;
>> }
>> + error_printf("v9fs_co_closedir: %d\n", err);
>> return err;
>> }
>> diff --git a/hw/9pfs/cofile.c b/hw/9pfs/cofile.c
>> index 293483e..a9c1a10 100644
>> --- a/hw/9pfs/cofile.c
>> +++ b/hw/9pfs/cofile.c
>> @@ -17,6 +17,8 @@
>> #include "qemu/thread.h"
>> #include "qemu/coroutine.h"
>> #include "coth.h"
>> +/* mifritscher: after killing the debug printf, kill this as well! */
>> +#include "qemu/error-report.h"
>>
>> int v9fs_co_st_gen(V9fsPDU *pdu, V9fsPath *path, mode_t st_mode,
>> V9fsStatDotl *v9stat)
>> @@ -39,6 +41,7 @@ int v9fs_co_st_gen(V9fsPDU *pdu, V9fsPath *path,
>> mode_t st_mode,
>> });
>> v9fs_path_unlock(s);
>> }
>> + error_printf("v9fs_co_st_gen: %d\n", err);
>> return err;
>> }
>>
>> @@ -59,6 +62,7 @@ int v9fs_co_lstat(V9fsPDU *pdu, V9fsPath *path, struct
>> stat *stbuf)
>> }
>> });
>> v9fs_path_unlock(s);
>> + error_printf("v9fs_co_lstat: %d\n", err);
>> return err;
>> }
>>
>> @@ -91,6 +95,7 @@ int v9fs_co_fstat(V9fsPDU *pdu, V9fsFidState *fidp,
>> struct stat *stbuf)
>> err = 0;
>> }
>> }
>> + error_printf("v9fs_co_fstat: %s %d\n", (&fidp->path)->data, err);
>> return err;
>> }
>>
>> @@ -119,6 +124,7 @@ int v9fs_co_open(V9fsPDU *pdu, V9fsFidState *fidp,
>> int flags)
>> v9fs_reclaim_fd(pdu);
>> }
>> }
>> + error_printf("v9fs_co_open: %s %d\n", (&fidp->path)->data, err);
>> return err;
>> }
>>
>> @@ -147,13 +153,17 @@ int v9fs_co_open2(V9fsPDU *pdu, V9fsFidState
>> *fidp, V9fsString *name, gid_t gid,
>> {
>> err = s->ops->open2(&s->ctx, &fidp->path,
>> name->data, flags, &cred, &fidp->fs);
>> + error_printf("v9fs_co_open2: open returned %d\n", err);
>> if (err < 0) {
>> err = -errno;
>> } else {
>> v9fs_path_init(&path);
>> err = v9fs_name_to_path(s, &fidp->path, name->data,
>> &path);
>> + error_printf("v9fs_co_open2: v9fs_name_to_path returned
>> %d\n",
>> + err);
>> if (!err) {
>> err = s->ops->lstat(&s->ctx, &path, stbuf);
>> + error_printf("v9fs_co_open2: lstat returned %d\n",
>> err);
>> if (err < 0) {
>> err = -errno;
>> s->ops->close(&s->ctx, &fidp->fs);
>> @@ -173,6 +183,7 @@ int v9fs_co_open2(V9fsPDU *pdu, V9fsFidState *fidp,
>> V9fsString *name, gid_t gid,
>> v9fs_reclaim_fd(pdu);
>> }
>> }
>> + error_printf("v9fs_co_open2: %s %d\n", (&fidp->path)->data, err);
>> return err;
>> }
>>
>> @@ -194,6 +205,7 @@ int v9fs_co_close(V9fsPDU *pdu, V9fsFidOpenState
>> *fs)
>> if (!err) {
>> total_open_fd--;
>> }
>> + error_printf("v9fs_co_close: %d\n", err);
>> return err;
>> }
>>
>> @@ -234,6 +246,7 @@ int v9fs_co_link(V9fsPDU *pdu, V9fsFidState *oldfid,
>> }
>> });
>> v9fs_path_unlock(s);
>> + error_printf("v9fs_co_link: %d\n", err);
>> return err;
>> }
>>
>> @@ -253,6 +266,7 @@ int v9fs_co_pwritev(V9fsPDU *pdu, V9fsFidState
>> *fidp,
>> err = -errno;
>> }
>> });
>> + error_printf("v9fs_co_pwritev: %s %d\n", (&fidp->path)->data, err);
>> return err;
>> }
>>
>> @@ -272,5 +286,6 @@ int v9fs_co_preadv(V9fsPDU *pdu, V9fsFidState *fidp,
>> err = -errno;
>> }
>> });
>> + error_printf("v9fs_co_preadv: %s %d\n", (&fidp->path)->data, err);
>> return err;
>> }
>> diff --git a/hw/9pfs/cofs.c b/hw/9pfs/cofs.c
>> index 18c81cb..a3a42bf 100644
>> --- a/hw/9pfs/cofs.c
>> +++ b/hw/9pfs/cofs.c
>> @@ -17,6 +17,8 @@
>> #include "qemu/thread.h"
>> #include "qemu/coroutine.h"
>> #include "coth.h"
>> +/* mifritscher: after killing the debug printf, kill this as well! */
>> +#include "qemu/error-report.h"
>>
>> static ssize_t __readlink(V9fsState *s, V9fsPath *path, V9fsString
>> *buf)
>> {
>> @@ -67,6 +69,7 @@ int v9fs_co_readlink(V9fsPDU *pdu, V9fsPath *path,
>> V9fsString *buf)
>> }
>> });
>> v9fs_path_unlock(s);
>> + error_printf("v9fs_co_readlink: %d\n", err);
>> return err;
>> }
>>
>> @@ -87,6 +90,7 @@ int v9fs_co_statfs(V9fsPDU *pdu, V9fsPath *path,
>> struct statfs *stbuf)
>> }
>> });
>> v9fs_path_unlock(s);
>> + error_printf("v9fs_co_statfs: %d\n", err);
>> return err;
>> }
>>
>> @@ -110,6 +114,7 @@ int v9fs_co_chmod(V9fsPDU *pdu, V9fsPath *path,
>> mode_t mode)
>> }
>> });
>> v9fs_path_unlock(s);
>> + error_printf("v9fs_co_chmod: %d\n", err);
>> return err;
>> }
>>
>> @@ -131,6 +136,7 @@ int v9fs_co_utimensat(V9fsPDU *pdu, V9fsPath *path,
>> }
>> });
>> v9fs_path_unlock(s);
>> + error_printf("v9fs_co_utimensat: %d\n", err);
>> return err;
>> }
>>
>> @@ -155,6 +161,7 @@ int v9fs_co_chown(V9fsPDU *pdu, V9fsPath *path,
>> uid_t uid, gid_t gid)
>> }
>> });
>> v9fs_path_unlock(s);
>> + error_printf("v9fs_co_chown: %d\n", err);
>> return err;
>> }
>>
>> @@ -175,6 +182,7 @@ int v9fs_co_truncate(V9fsPDU *pdu, V9fsPath *path,
>> off_t size)
>> }
>> });
>> v9fs_path_unlock(s);
>> + error_printf("v9fs_co_truncate: %d\n", err);
>> return err;
>> }
>>
>> @@ -213,6 +221,7 @@ int v9fs_co_mknod(V9fsPDU *pdu, V9fsFidState *fidp,
>> V9fsString *name, uid_t uid,
>> }
>> });
>> v9fs_path_unlock(s);
>> + error_printf("v9fs_co_mknod: %d\n", err);
>> return err;
>> }
>>
>> @@ -234,6 +243,7 @@ int v9fs_co_remove(V9fsPDU *pdu, V9fsPath *path)
>> }
>> });
>> v9fs_path_unlock(s);
>> + error_printf("v9fs_co_remove: %d\n", err);
>> return err;
>> }
>>
>> @@ -254,6 +264,7 @@ int v9fs_co_unlinkat(V9fsPDU *pdu, V9fsPath *path,
>> V9fsString *name, int flags)
>> }
>> });
>> v9fs_path_unlock(s);
>> + error_printf("v9fs_co_unlinkat: %d\n", err);
>> return err;
>> }
>>
>> @@ -273,6 +284,7 @@ int v9fs_co_rename(V9fsPDU *pdu, V9fsPath *oldpath,
>> V9fsPath *newpath)
>> err = -errno;
>> }
>> });
>> + error_printf("v9fs_co_rename: %d\n", err);
>> return err;
>> }
>>
>> @@ -293,6 +305,7 @@ int v9fs_co_renameat(V9fsPDU *pdu, V9fsPath
>> *olddirpath, V9fsString *oldname,
>> err = -errno;
>> }
>> });
>> + error_printf("v9fs_co_renameat: %d\n", err);
>> return err;
>> }
>>
>> @@ -331,6 +344,7 @@ int v9fs_co_symlink(V9fsPDU *pdu, V9fsFidState
>> *dfidp, V9fsString *name,
>> }
>> });
>> v9fs_path_unlock(s);
>> + error_printf("v9fs_co_symlink: %d\n", err);
>> return err;
>> }
>>
>> @@ -361,5 +375,6 @@ int v9fs_co_name_to_path(V9fsPDU *pdu, V9fsPath
>> *dirpath,
>> }
>> });
>> }
>> + error_printf("v9fs_co_name_to_path: %d\n", err);
>> return err;
>> }
>> diff --git a/hw/9pfs/coxattr.c b/hw/9pfs/coxattr.c
>> index 6ad96ea..49fbd5e 100644
>> --- a/hw/9pfs/coxattr.c
>> +++ b/hw/9pfs/coxattr.c
>> @@ -17,6 +17,8 @@
>> #include "qemu/thread.h"
>> #include "qemu/coroutine.h"
>> #include "coth.h"
>> +/* mifritscher: after killing the debug printf, kill this as well! */
>> +#include "qemu/error-report.h"
>>
>> int v9fs_co_llistxattr(V9fsPDU *pdu, V9fsPath *path, void *value,
>> size_t size)
>> {
>> @@ -35,6 +37,7 @@ int v9fs_co_llistxattr(V9fsPDU *pdu, V9fsPath *path,
>> void *value, size_t size)
>> }
>> });
>> v9fs_path_unlock(s);
>> + error_printf("v9fs_co_llistxattr: %d\n", err);
>> return err;
>> }
>>
>> @@ -59,6 +62,7 @@ int v9fs_co_lgetxattr(V9fsPDU *pdu, V9fsPath *path,
>> }
>> });
>> v9fs_path_unlock(s);
>> + error_printf("v9fs_co_lgetxattr: %d\n", err);
>> return err;
>> }
>>
>> @@ -83,6 +87,7 @@ int v9fs_co_lsetxattr(V9fsPDU *pdu, V9fsPath *path,
>> }
>> });
>> v9fs_path_unlock(s);
>> + error_printf("v9fs_co_lsetxattr: %d\n", err);
>> return err;
>> }
>>
>> @@ -104,5 +109,6 @@ int v9fs_co_lremovexattr(V9fsPDU *pdu, V9fsPath
>> *path,
>> }
>> });
>> v9fs_path_unlock(s);
>> + error_printf("v9fs_co_lremovexattr: %d\n", err);
>> return err;
>> }
>> diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c
>> index a38850e..59d0a50 100644
>> --- a/hw/9pfs/virtio-9p-device.c
>> +++ b/hw/9pfs/virtio-9p-device.c
>> @@ -17,7 +17,9 @@
>> #include "qemu/sockets.h"
>> #include "virtio-9p.h"
>> #include "fsdev/qemu-fsdev.h"
>> -#include "9p-xattr.h"
>> +#ifndef WIN32
>> + #include "9p-xattr.h"
>> +#endif
>> #include "coth.h"
>> #include "hw/virtio/virtio-access.h"
>> #include "qemu/iov.h"
>
>