diff mbox

[v2,WIP,RFC] Add initial 9pfs support for Windows hosts v2

Message ID 1460447520-12499-1-git-send-email-michael@fritscher.net (mailing list archive)
State New, archived
Headers show

Commit Message

Michael Fritscher April 12, 2016, 7:52 a.m. UTC
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 <michael@fritscher.net>
---
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(-)

Comments

Greg Kurz April 13, 2016, 12:30 p.m. UTC | #1
On Tue, 12 Apr 2016 09:52:00 +0200
Michael Fritscher <michael@fritscher.net> 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 <michael@fritscher.net>
> ---
> 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!
> 

Hi Michael !

Impressive work ! :)

Since this is a big patch, it will take probably some time for me to review.
I'll comment on easy stuff first, and probably send more emails when I get
time to go deeper.

Anyway, this is a new feature and it won't go upstream until 2.6 is out.

Cheers.

--
Greg
Greg Kurz April 14, 2016, 7:17 p.m. UTC | #2
Hi Michael,

I have some more comments that should end up in a preliminary patch.

Cheers.

--
Greg

On Tue, 12 Apr 2016 09:52:00 +0200
Michael Fritscher <michael@fritscher.net> 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 <michael@fritscher.net>
> ---
> 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>

This should be included by include/sysemu/os-posix.h, and you just need to add a 
forward declaration for struct statfs before struct FileOperations somewhere below.

> +#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;
> +};

All this block belongs to include/sysemu/os-win32.h.

> +#endif
> +
Greg Kurz May 9, 2016, 8:38 a.m. UTC | #3
More comments.

On Tue, 12 Apr 2016 09:52:00 +0200
Michael Fritscher <michael@fritscher.net> 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 <michael@fritscher.net>
> ---
> 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 ?

> +# 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 ?

> +# 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.

> +    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.

> +    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...

>  #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 ?

>      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 ?

>      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.

>  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 \ ?

> +            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 \ ?

> +    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.

> +    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"
Michael Fritscher May 9, 2016, 9:12 a.m. UTC | #4
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 <michael@fritscher.net> 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 <michael@fritscher.net>
>> ---
>> 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"
>
>
Greg Kurz May 10, 2016, 11:26 a.m. UTC | #5
On Mon, 9 May 2016 11:12:51 +0200
"Michael Fritscher" <michael@fritscher.net> wrote:

> Hello Greg,
> 

Hi Michael !

> 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?
> 

Dunno... I always redo a full round of coding/git when splitting
big patches.

> > More comments.
> >
> > On Tue, 12 Apr 2016 09:52:00 +0200
> > Michael Fritscher <michael@fritscher.net> 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 <michael@fritscher.net>
> >> ---
> >> 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.

That's the way it goes :)

> >  
> >> +# 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)
> 

Hmm... what problem ? Can't it be fixed ?

> >  
> >> +# 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
> >> +

Since these are standard names also used in FileOperations, I guess
it's better to have static inline functions returning 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?

Something like pthread_mutex_lock() if it exists in win32 ?

> @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?
> 

Maybe you can leave it in 9p-local.c for the moment.

> >  
> >>      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 ;-)
> 

Ok, understood.

> >  
> >> +    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?
> 

In a #ifdef _WIN32 block just above the definition of rpath()
would be a good start.

> >  
> >> +    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;SWUP
> >>  }
> >>
> >> @@ -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;
> >>  }SWUP
> >>
> >> @@ -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"  
> >
> >  
> 
>
Michael Fritscher Aug. 28, 2017, 7:35 a.m. UTC | #6
Good day,

only a short announcement: Sorry for the very long delay :-( But I'm
working on this again. The biggest issue seems to be the *at stuff. I'll
try to workaround this via getting the directories' path from the file
descriptor with the /proc (as it is already done in the 9pfs_utils) -
luckily,the mingw environment emulates the /proc. If this doesn't work
I've another idea (the file descriptors needs to be "registered" with the
path (and saved in a sparse vector or map with the fd as key and the path
as value). The "big" solution would be to write a 9p_local_windows.c from
scratch, but I would like to avoid it.

Additionally, I changed my approach: Instead of one big patch with
everything in it, I split it into 2 patch series with several patches:

  * The first one only fixes the build via adding #ifdefs, creating stubs
in os-win32.h etc. and introduces no regressions. Status: Ready in my
local repo: It compiles fine with enabled 9pfs and works. If 9pfs is
tried to use there is a clean error message that the fsdev couldn't be
initialized - as expected.
  * The second one actually get 9pfs working. This involves mostly
implementing the *at functions and a few tiny things (O_BINARY and so
on) Status: Not started yet (will be at the next weekend I hope), but is
a combination of parts of the the old patch + the implementation of the
*at functions.

My hope is that the first series could be merged independently from the
second. Meanings? If so I'll clean up the first patch series a bit
(History cleaning) and send it to the list.

Best regards,
Michael Fritscher
Greg Kurz Sept. 4, 2017, 8:35 a.m. UTC | #7
On Mon, 28 Aug 2017 09:35:45 +0200
"Michael Fritscher" <michael@fritscher.net> wrote:

> Good day,
> 

Hi!

> only a short announcement: Sorry for the very long delay :-( But I'm
> working on this again. The biggest issue seems to be the *at stuff. I'll
> try to workaround this via getting the directories' path from the file
> descriptor with the /proc (as it is already done in the 9pfs_utils) -
> luckily,the mingw environment emulates the /proc. If this doesn't work
> I've another idea (the file descriptors needs to be "registered" with the
> path (and saved in a sparse vector or map with the fd as key and the path
> as value). The "big" solution would be to write a 9p_local_windows.c from
> scratch, but I would like to avoid it.
> 
> Additionally, I changed my approach: Instead of one big patch with
> everything in it, I split it into 2 patch series with several patches:
> 

I'd prefer to have a single series with all the patches because...

>   * The first one only fixes the build via adding #ifdefs, creating stubs
> in os-win32.h etc. and introduces no regressions. Status: Ready in my
> local repo: It compiles fine with enabled 9pfs and works. If 9pfs is
> tried to use there is a clean error message that the fsdev couldn't be
> initialized - as expected.
>   * The second one actually get 9pfs working. This involves mostly
> implementing the *at functions and a few tiny things (O_BINARY and so
> on) Status: Not started yet (will be at the next weekend I hope), but is
> a combination of parts of the the old patch + the implementation of the
> *at functions.
> 
> My hope is that the first series could be merged independently from the
> second. Meanings? If so I'll clean up the first patch series a bit

... I don't want to merge a bunch of code before I'm 100% sure the 9pfs
support on win32 is viable.

Cheers,

--
Greg

> (History cleaning) and send it to the list.
> 
> Best regards,
> Michael Fritscher
>
diff mbox

Patch

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)
+# 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;
+}
+
+# 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); */
+    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);
+    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
 #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);
     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);
     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"
+
 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 \... */
+            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 : ...)
+    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
+    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"