All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 00/19] At present there is no Windows support for 9p file system.
@ 2022-11-11  4:22 Bin Meng
  2022-11-11  4:22 ` [PATCH v2 01/19] qemu/xattr.h: Exclude <sys/xattr.h> for Windows Bin Meng
                   ` (18 more replies)
  0 siblings, 19 replies; 36+ messages in thread
From: Bin Meng @ 2022-11-11  4:22 UTC (permalink / raw)
  To: qemu-devel
  Cc: Christian Schoenebeck, Daniel P. Berrangé,
	Greg Kurz, Keno Fischer, Laurent Vivier, Marc-André Lureau,
	Paolo Bonzini, Peter Maydell, Philippe Mathieu-Daudé,
	Richard Henderson, Thomas Huth

This series adds initial Windows support for 9p file system.

'local' file system backend driver is supported on Windows,
including open, read, write, close, rename, remove, etc.
All security models are supported. The mapped (mapped-xattr)
security model is implemented using NTFS Alternate Data Stream
(ADS) so the 9p export path shall be on an NTFS partition.

'synth' driver is adapted for Windows too so that we can now
run qtests on Windows for 9p related regression testing.

Example command line to test:

  "-fsdev local,path=c:\msys64,security_model=mapped,id=p9 -device virtio-9p-pci,fsdev=p9,mount_tag=p9fs"

Changes in v2:
- Change to introduce QemuFd_t in osdep.h
- Use the new QemuFd_t type
- Add S_IFLNK related macros to support symbolic link
- Support symbolic link when security model is "mapped-xattr" or "mapped-file"
- Update to support symbolic link when applicable
- Warn user if a specific 9pfs operation is not supported
- Use qemu_dirent_off() directly instead of coroutine
- new patch: "hw/9pfs: Add a helper qemu_stat_rdev()"
- new patch: "hw/9pfs: Add a helper qemu_stat_blksize()"
- Use precise platform check in ifdefs to avoid automatically
  opting-out other future platforms unintentionally
- new patch: "hw/9pfs: Update v9fs_set_fd_limit() for Windows"
- Use a more compact solution in the switch..case.. block
- Move getuid() to virtio-9p-client.h

Bin Meng (7):
  qemu/xattr.h: Exclude <sys/xattr.h> for Windows
  hw/9pfs: Drop unnecessary *xattr wrapper API declarations
  hw/9pfs: Replace the direct call to xxxat() APIs with a wrapper
  osdep.h: Introduce a QEMU file descriptor type
  hw/9pfs: Update 9pfs to use the new QemuFd_t type
  hw/9pfs: Add a helper qemu_stat_rdev()
  hw/9pfs: Add a helper qemu_stat_blksize()

Guohuai Shi (12):
  hw/9pfs: Add missing definitions for Windows
  hw/9pfs: Implement Windows specific utilities functions for 9pfs
  hw/9pfs: Update the local fs driver to support Windows
  hw/9pfs: Support getting current directory offset for Windows
  hw/9pfs: Disable unsupported flags and features for Windows
  hw/9pfs: Update v9fs_set_fd_limit() for Windows
  hw/9pfs: Add Linux error number definition
  hw/9pfs: Translate Windows errno to Linux value
  fsdev: Disable proxy fs driver on Windows
  hw/9pfs: Update synth fs driver for Windows
  tests/qtest: virtio-9p-test: Adapt the case for win32
  meson.build: Turn on virtfs for Windows

 meson.build                           |  10 +-
 fsdev/file-op-9p.h                    |  33 +
 hw/9pfs/9p-linux-errno.h              | 151 ++++
 hw/9pfs/9p-local.h                    |  14 +-
 hw/9pfs/9p-util.h                     | 170 +++--
 hw/9pfs/9p.h                          |  33 +
 include/qemu/osdep.h                  |  26 +
 include/qemu/xattr.h                  |   4 +-
 tests/qtest/libqos/virtio-9p-client.h |   7 +
 fsdev/qemu-fsdev.c                    |   2 +
 hw/9pfs/9p-local.c                    | 592 +++++++++++++---
 hw/9pfs/9p-synth.c                    |   5 +-
 hw/9pfs/9p-util-darwin.c              |  14 +-
 hw/9pfs/9p-util-linux.c               |  14 +-
 hw/9pfs/9p-util-win32.c               | 963 ++++++++++++++++++++++++++
 hw/9pfs/9p-xattr.c                    |  16 +-
 hw/9pfs/9p.c                          |  86 ++-
 hw/9pfs/codir.c                       |   2 +-
 fsdev/meson.build                     |   1 +
 hw/9pfs/meson.build                   |   8 +-
 20 files changed, 1939 insertions(+), 212 deletions(-)
 create mode 100644 hw/9pfs/9p-linux-errno.h
 create mode 100644 hw/9pfs/9p-util-win32.c

-- 
2.25.1



^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH v2 01/19] qemu/xattr.h: Exclude <sys/xattr.h> for Windows
  2022-11-11  4:22 [PATCH v2 00/19] At present there is no Windows support for 9p file system Bin Meng
@ 2022-11-11  4:22 ` Bin Meng
  2022-11-11  4:22 ` [PATCH v2 02/19] hw/9pfs: Drop unnecessary *xattr wrapper API declarations Bin Meng
                   ` (17 subsequent siblings)
  18 siblings, 0 replies; 36+ messages in thread
From: Bin Meng @ 2022-11-11  4:22 UTC (permalink / raw)
  To: qemu-devel
  Cc: Christian Schoenebeck, Greg Kurz, Keno Fischer,
	Philippe Mathieu-Daudé

Windows does not have <sys/xattr.h>.

Signed-off-by: Bin Meng <bin.meng@windriver.com>
---

(no changes since v1)

 include/qemu/xattr.h | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/include/qemu/xattr.h b/include/qemu/xattr.h
index f1d0f7be74..b08a934acc 100644
--- a/include/qemu/xattr.h
+++ b/include/qemu/xattr.h
@@ -25,7 +25,9 @@
 #  if !defined(ENOATTR)
 #    define ENOATTR ENODATA
 #  endif
-#  include <sys/xattr.h>
+#  ifndef CONFIG_WIN32
+#    include <sys/xattr.h>
+#  endif
 #endif
 
 #endif
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v2 02/19] hw/9pfs: Drop unnecessary *xattr wrapper API declarations
  2022-11-11  4:22 [PATCH v2 00/19] At present there is no Windows support for 9p file system Bin Meng
  2022-11-11  4:22 ` [PATCH v2 01/19] qemu/xattr.h: Exclude <sys/xattr.h> for Windows Bin Meng
@ 2022-11-11  4:22 ` Bin Meng
  2022-11-18  8:42   ` Greg Kurz
  2022-11-11  4:22 ` [PATCH v2 03/19] hw/9pfs: Replace the direct call to xxxat() APIs with a wrapper Bin Meng
                   ` (16 subsequent siblings)
  18 siblings, 1 reply; 36+ messages in thread
From: Bin Meng @ 2022-11-11  4:22 UTC (permalink / raw)
  To: qemu-devel; +Cc: Christian Schoenebeck, Greg Kurz

These are not used anywhere in the source tree. Drop them.

Signed-off-by: Bin Meng <bin.meng@windriver.com>
---

(no changes since v1)

 hw/9pfs/9p-util.h | 11 -----------
 1 file changed, 11 deletions(-)

diff --git a/hw/9pfs/9p-util.h b/hw/9pfs/9p-util.h
index c3526144c9..ccfc8b1cb3 100644
--- a/hw/9pfs/9p-util.h
+++ b/hw/9pfs/9p-util.h
@@ -90,19 +90,8 @@ static inline int errno_to_dotl(int err) {
 
 #ifdef CONFIG_DARWIN
 #define qemu_fgetxattr(...) fgetxattr(__VA_ARGS__, 0, 0)
-#define qemu_lgetxattr(...) getxattr(__VA_ARGS__, 0, XATTR_NOFOLLOW)
-#define qemu_llistxattr(...) listxattr(__VA_ARGS__, XATTR_NOFOLLOW)
-#define qemu_lremovexattr(...) removexattr(__VA_ARGS__, XATTR_NOFOLLOW)
-static inline int qemu_lsetxattr(const char *path, const char *name,
-                                 const void *value, size_t size, int flags) {
-    return setxattr(path, name, value, size, 0, flags | XATTR_NOFOLLOW);
-}
 #else
 #define qemu_fgetxattr fgetxattr
-#define qemu_lgetxattr lgetxattr
-#define qemu_llistxattr llistxattr
-#define qemu_lremovexattr lremovexattr
-#define qemu_lsetxattr lsetxattr
 #endif
 
 static inline void close_preserve_errno(int fd)
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v2 03/19] hw/9pfs: Replace the direct call to xxxat() APIs with a wrapper
  2022-11-11  4:22 [PATCH v2 00/19] At present there is no Windows support for 9p file system Bin Meng
  2022-11-11  4:22 ` [PATCH v2 01/19] qemu/xattr.h: Exclude <sys/xattr.h> for Windows Bin Meng
  2022-11-11  4:22 ` [PATCH v2 02/19] hw/9pfs: Drop unnecessary *xattr wrapper API declarations Bin Meng
@ 2022-11-11  4:22 ` Bin Meng
  2022-11-11  4:22 ` [PATCH v2 04/19] osdep.h: Introduce a QEMU file descriptor type Bin Meng
                   ` (15 subsequent siblings)
  18 siblings, 0 replies; 36+ messages in thread
From: Bin Meng @ 2022-11-11  4:22 UTC (permalink / raw)
  To: qemu-devel; +Cc: Christian Schoenebeck, Greg Kurz

xxxat() APIs are only available on POSIX platforms. For future
extension to Windows, let's replace the direct call to xxxat()
APIs with a wrapper.

Signed-off-by: Bin Meng <bin.meng@windriver.com>
---

(no changes since v1)

 hw/9pfs/9p-util.h  | 15 +++++++++++----
 hw/9pfs/9p-local.c | 32 ++++++++++++++++----------------
 2 files changed, 27 insertions(+), 20 deletions(-)

diff --git a/hw/9pfs/9p-util.h b/hw/9pfs/9p-util.h
index ccfc8b1cb3..c314cf381d 100644
--- a/hw/9pfs/9p-util.h
+++ b/hw/9pfs/9p-util.h
@@ -94,6 +94,13 @@ static inline int errno_to_dotl(int err) {
 #define qemu_fgetxattr fgetxattr
 #endif
 
+#define qemu_openat     openat
+#define qemu_fstatat    fstatat
+#define qemu_mkdirat    mkdirat
+#define qemu_renameat   renameat
+#define qemu_utimensat  utimensat
+#define qemu_unlinkat   unlinkat
+
 static inline void close_preserve_errno(int fd)
 {
     int serrno = errno;
@@ -103,8 +110,8 @@ static inline void close_preserve_errno(int fd)
 
 static inline int openat_dir(int dirfd, const char *name)
 {
-    return openat(dirfd, name,
-                  O_DIRECTORY | O_RDONLY | O_NOFOLLOW | O_PATH_9P_UTIL);
+    return qemu_openat(dirfd, name,
+                       O_DIRECTORY | O_RDONLY | O_NOFOLLOW | O_PATH_9P_UTIL);
 }
 
 static inline int openat_file(int dirfd, const char *name, int flags,
@@ -115,8 +122,8 @@ static inline int openat_file(int dirfd, const char *name, int flags,
 #ifndef CONFIG_DARWIN
 again:
 #endif
-    fd = openat(dirfd, name, flags | O_NOFOLLOW | O_NOCTTY | O_NONBLOCK,
-                mode);
+    fd = qemu_openat(dirfd, name, flags | O_NOFOLLOW | O_NOCTTY | O_NONBLOCK,
+                     mode);
     if (fd == -1) {
 #ifndef CONFIG_DARWIN
         if (errno == EPERM && (flags & O_NOATIME)) {
diff --git a/hw/9pfs/9p-local.c b/hw/9pfs/9p-local.c
index d42ce6d8b8..d2246a3d7e 100644
--- a/hw/9pfs/9p-local.c
+++ b/hw/9pfs/9p-local.c
@@ -103,14 +103,14 @@ static void renameat_preserve_errno(int odirfd, const char *opath, int ndirfd,
                                     const char *npath)
 {
     int serrno = errno;
-    renameat(odirfd, opath, ndirfd, npath);
+    qemu_renameat(odirfd, opath, ndirfd, npath);
     errno = serrno;
 }
 
 static void unlinkat_preserve_errno(int dirfd, const char *path, int flags)
 {
     int serrno = errno;
-    unlinkat(dirfd, path, flags);
+    qemu_unlinkat(dirfd, path, flags);
     errno = serrno;
 }
 
@@ -194,7 +194,7 @@ static int local_lstat(FsContext *fs_ctx, V9fsPath *fs_path, struct stat *stbuf)
         goto out;
     }
 
-    err = fstatat(dirfd, name, stbuf, AT_SYMLINK_NOFOLLOW);
+    err = qemu_fstatat(dirfd, name, stbuf, AT_SYMLINK_NOFOLLOW);
     if (err) {
         goto err_out;
     }
@@ -253,7 +253,7 @@ static int local_set_mapped_file_attrat(int dirfd, const char *name,
             }
         }
     } else {
-        ret = mkdirat(dirfd, VIRTFS_META_DIR, 0700);
+        ret = qemu_mkdirat(dirfd, VIRTFS_META_DIR, 0700);
         if (ret < 0 && errno != EEXIST) {
             return -1;
         }
@@ -349,7 +349,7 @@ static int fchmodat_nofollow(int dirfd, const char *name, mode_t mode)
      */
 
      /* First, we clear non-racing symlinks out of the way. */
-    if (fstatat(dirfd, name, &stbuf, AT_SYMLINK_NOFOLLOW)) {
+    if (qemu_fstatat(dirfd, name, &stbuf, AT_SYMLINK_NOFOLLOW)) {
         return -1;
     }
     if (S_ISLNK(stbuf.st_mode)) {
@@ -734,7 +734,7 @@ static int local_mkdir(FsContext *fs_ctx, V9fsPath *dir_path,
 
     if (fs_ctx->export_flags & V9FS_SM_MAPPED ||
         fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
-        err = mkdirat(dirfd, name, fs_ctx->dmode);
+        err = qemu_mkdirat(dirfd, name, fs_ctx->dmode);
         if (err == -1) {
             goto out;
         }
@@ -750,7 +750,7 @@ static int local_mkdir(FsContext *fs_ctx, V9fsPath *dir_path,
         }
     } else if (fs_ctx->export_flags & V9FS_SM_PASSTHROUGH ||
                fs_ctx->export_flags & V9FS_SM_NONE) {
-        err = mkdirat(dirfd, name, credp->fc_mode);
+        err = qemu_mkdirat(dirfd, name, credp->fc_mode);
         if (err == -1) {
             goto out;
         }
@@ -990,7 +990,7 @@ static int local_link(FsContext *ctx, V9fsPath *oldpath,
     if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
         int omap_dirfd, nmap_dirfd;
 
-        ret = mkdirat(ndirfd, VIRTFS_META_DIR, 0700);
+        ret = qemu_mkdirat(ndirfd, VIRTFS_META_DIR, 0700);
         if (ret < 0 && errno != EEXIST) {
             goto err_undo_link;
         }
@@ -1085,7 +1085,7 @@ static int local_utimensat(FsContext *s, V9fsPath *fs_path,
         goto out;
     }
 
-    ret = utimensat(dirfd, name, buf, AT_SYMLINK_NOFOLLOW);
+    ret = qemu_utimensat(dirfd, name, buf, AT_SYMLINK_NOFOLLOW);
     close_preserve_errno(dirfd);
 out:
     g_free(dirpath);
@@ -1116,7 +1116,7 @@ static int local_unlinkat_common(FsContext *ctx, int dirfd, const char *name,
             if (fd == -1) {
                 return -1;
             }
-            ret = unlinkat(fd, VIRTFS_META_DIR, AT_REMOVEDIR);
+            ret = qemu_unlinkat(fd, VIRTFS_META_DIR, AT_REMOVEDIR);
             close_preserve_errno(fd);
             if (ret < 0 && errno != ENOENT) {
                 return -1;
@@ -1124,7 +1124,7 @@ static int local_unlinkat_common(FsContext *ctx, int dirfd, const char *name,
         }
         map_dirfd = openat_dir(dirfd, VIRTFS_META_DIR);
         if (map_dirfd != -1) {
-            ret = unlinkat(map_dirfd, name, 0);
+            ret = qemu_unlinkat(map_dirfd, name, 0);
             close_preserve_errno(map_dirfd);
             if (ret < 0 && errno != ENOENT) {
                 return -1;
@@ -1134,7 +1134,7 @@ static int local_unlinkat_common(FsContext *ctx, int dirfd, const char *name,
         }
     }
 
-    return unlinkat(dirfd, name, flags);
+    return qemu_unlinkat(dirfd, name, flags);
 }
 
 static int local_remove(FsContext *ctx, const char *path)
@@ -1151,7 +1151,7 @@ static int local_remove(FsContext *ctx, const char *path)
         goto out;
     }
 
-    if (fstatat(dirfd, name, &stbuf, AT_SYMLINK_NOFOLLOW) < 0) {
+    if (qemu_fstatat(dirfd, name, &stbuf, AT_SYMLINK_NOFOLLOW) < 0) {
         goto err_out;
     }
 
@@ -1296,7 +1296,7 @@ static int local_renameat(FsContext *ctx, V9fsPath *olddir,
         return -1;
     }
 
-    ret = renameat(odirfd, old_name, ndirfd, new_name);
+    ret = qemu_renameat(odirfd, old_name, ndirfd, new_name);
     if (ret < 0) {
         goto out;
     }
@@ -1304,7 +1304,7 @@ static int local_renameat(FsContext *ctx, V9fsPath *olddir,
     if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
         int omap_dirfd, nmap_dirfd;
 
-        ret = mkdirat(ndirfd, VIRTFS_META_DIR, 0700);
+        ret = qemu_mkdirat(ndirfd, VIRTFS_META_DIR, 0700);
         if (ret < 0 && errno != EEXIST) {
             goto err_undo_rename;
         }
@@ -1321,7 +1321,7 @@ static int local_renameat(FsContext *ctx, V9fsPath *olddir,
         }
 
         /* rename the .virtfs_metadata files */
-        ret = renameat(omap_dirfd, old_name, nmap_dirfd, new_name);
+        ret = qemu_renameat(omap_dirfd, old_name, nmap_dirfd, new_name);
         close_preserve_errno(nmap_dirfd);
         close_preserve_errno(omap_dirfd);
         if (ret < 0 && errno != ENOENT) {
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v2 04/19] osdep.h: Introduce a QEMU file descriptor type
  2022-11-11  4:22 [PATCH v2 00/19] At present there is no Windows support for 9p file system Bin Meng
                   ` (2 preceding siblings ...)
  2022-11-11  4:22 ` [PATCH v2 03/19] hw/9pfs: Replace the direct call to xxxat() APIs with a wrapper Bin Meng
@ 2022-11-11  4:22 ` Bin Meng
  2022-11-11  9:07   ` Daniel P. Berrangé
  2022-11-11  4:22 ` [PATCH v2 05/19] hw/9pfs: Update 9pfs to use the new QemuFd_t type Bin Meng
                   ` (14 subsequent siblings)
  18 siblings, 1 reply; 36+ messages in thread
From: Bin Meng @ 2022-11-11  4:22 UTC (permalink / raw)
  To: qemu-devel
  Cc: Daniel P. Berrangé,
	Marc-André Lureau, Peter Maydell,
	Philippe Mathieu-Daudé,
	Richard Henderson

Introduce a new QemuFd_t type to represent a file descriptor for
different platforms. On POSIX platforms, this is a file descriptor
On Windows, this is a file handle.

Signed-off-by: Bin Meng <bin.meng@windriver.com>

---

Changes in v2:
- Change to introduce QemuFd_t in osdep.h

 include/qemu/osdep.h | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h
index b9c4307779..45fc8bb5d9 100644
--- a/include/qemu/osdep.h
+++ b/include/qemu/osdep.h
@@ -705,6 +705,32 @@ static inline int platform_does_not_support_system(const char *command)
 }
 #endif /* !HAVE_SYSTEM_FUNCTION */
 
+/*
+ * QEMU file descriptor type
+ *
+ * On POSIX platforms, this is a file descriptor (int).
+ * On Windows, this is a file handle (HANDLE).
+ */
+#ifndef _WIN32
+typedef int QemuFd_t;
+#define QEMU_FD_INVALID -1
+#else
+typedef HANDLE QemuFd_t;
+#define QEMU_FD_INVALID INVALID_HANDLE_VALUE
+#endif
+
+/**
+ * qemu_fd_invalid - determine if a given QEMU file descriptor is invalid
+ *
+ * @fd: the value of a QEMU file descriptor
+ *
+ * Returns true if a given QEMU file descriptor is invalid, otherwise false.
+ */
+static inline bool qemu_fd_invalid(QemuFd_t fd)
+{
+    return (fd == QEMU_FD_INVALID);
+}
+
 #ifdef __cplusplus
 }
 #endif
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v2 05/19] hw/9pfs: Update 9pfs to use the new QemuFd_t type
  2022-11-11  4:22 [PATCH v2 00/19] At present there is no Windows support for 9p file system Bin Meng
                   ` (3 preceding siblings ...)
  2022-11-11  4:22 ` [PATCH v2 04/19] osdep.h: Introduce a QEMU file descriptor type Bin Meng
@ 2022-11-11  4:22 ` Bin Meng
  2022-11-18  9:29   ` Greg Kurz
  2022-11-11  4:22 ` [PATCH v2 06/19] hw/9pfs: Add missing definitions for Windows Bin Meng
                   ` (13 subsequent siblings)
  18 siblings, 1 reply; 36+ messages in thread
From: Bin Meng @ 2022-11-11  4:22 UTC (permalink / raw)
  To: qemu-devel; +Cc: Christian Schoenebeck, Greg Kurz

With this new QemuFd_t type, it significantly reduces the number of
deviated code paths when adding Windows support.

Signed-off-by: Bin Meng <bin.meng@windriver.com>

---

Changes in v2:
- Use the new QemuFd_t type

 hw/9pfs/9p-local.h       |   6 +-
 hw/9pfs/9p-util.h        |  26 +++---
 hw/9pfs/9p-local.c       | 174 ++++++++++++++++++++-------------------
 hw/9pfs/9p-util-darwin.c |  14 ++--
 hw/9pfs/9p-util-linux.c  |  14 ++--
 hw/9pfs/9p-xattr.c       |  16 ++--
 6 files changed, 129 insertions(+), 121 deletions(-)

diff --git a/hw/9pfs/9p-local.h b/hw/9pfs/9p-local.h
index 32c72749d9..66a21316a0 100644
--- a/hw/9pfs/9p-local.h
+++ b/hw/9pfs/9p-local.h
@@ -13,8 +13,8 @@
 #ifndef QEMU_9P_LOCAL_H
 #define QEMU_9P_LOCAL_H
 
-int local_open_nofollow(FsContext *fs_ctx, const char *path, int flags,
-                        mode_t mode);
-int local_opendir_nofollow(FsContext *fs_ctx, const char *path);
+QemuFd_t local_open_nofollow(FsContext *fs_ctx, const char *path, int flags,
+                             mode_t mode);
+QemuFd_t local_opendir_nofollow(FsContext *fs_ctx, const char *path);
 
 #endif
diff --git a/hw/9pfs/9p-util.h b/hw/9pfs/9p-util.h
index c314cf381d..3d6bd1a51e 100644
--- a/hw/9pfs/9p-util.h
+++ b/hw/9pfs/9p-util.h
@@ -101,30 +101,31 @@ static inline int errno_to_dotl(int err) {
 #define qemu_utimensat  utimensat
 #define qemu_unlinkat   unlinkat
 
-static inline void close_preserve_errno(int fd)
+static inline void close_preserve_errno(QemuFd_t fd)
 {
     int serrno = errno;
     close(fd);
     errno = serrno;
 }
 
-static inline int openat_dir(int dirfd, const char *name)
+static inline QemuFd_t openat_dir(QemuFd_t dirfd, const char *name)
 {
     return qemu_openat(dirfd, name,
                        O_DIRECTORY | O_RDONLY | O_NOFOLLOW | O_PATH_9P_UTIL);
 }
 
-static inline int openat_file(int dirfd, const char *name, int flags,
-                              mode_t mode)
+static inline QemuFd_t openat_file(QemuFd_t dirfd, const char *name,
+                                   int flags, mode_t mode)
 {
-    int fd, serrno, ret;
+    int serrno, ret;
+    QemuFd_t fd;
 
 #ifndef CONFIG_DARWIN
 again:
 #endif
     fd = qemu_openat(dirfd, name, flags | O_NOFOLLOW | O_NOCTTY | O_NONBLOCK,
                      mode);
-    if (fd == -1) {
+    if (qemu_fd_invalid(fd)) {
 #ifndef CONFIG_DARWIN
         if (errno == EPERM && (flags & O_NOATIME)) {
             /*
@@ -155,13 +156,13 @@ again:
     return fd;
 }
 
-ssize_t fgetxattrat_nofollow(int dirfd, const char *path, const char *name,
-                             void *value, size_t size);
-int fsetxattrat_nofollow(int dirfd, const char *path, const char *name,
+ssize_t fgetxattrat_nofollow(QemuFd_t dirfd, const char *path,
+                             const char *name, void *value, size_t size);
+int fsetxattrat_nofollow(QemuFd_t dirfd, const char *path, const char *name,
                          void *value, size_t size, int flags);
-ssize_t flistxattrat_nofollow(int dirfd, const char *filename,
+ssize_t flistxattrat_nofollow(QemuFd_t dirfd, const char *filename,
                               char *list, size_t size);
-ssize_t fremovexattrat_nofollow(int dirfd, const char *filename,
+ssize_t fremovexattrat_nofollow(QemuFd_t dirfd, const char *filename,
                                 const char *name);
 
 /*
@@ -219,6 +220,7 @@ static inline struct dirent *qemu_dirent_dup(struct dirent *dent)
 #if defined CONFIG_DARWIN && defined CONFIG_PTHREAD_FCHDIR_NP
 int pthread_fchdir_np(int fd) __attribute__((weak_import));
 #endif
-int qemu_mknodat(int dirfd, const char *filename, mode_t mode, dev_t dev);
+int qemu_mknodat(QemuFd_t dirfd, const char *filename, mode_t mode,
+                 dev_t dev);
 
 #endif
diff --git a/hw/9pfs/9p-local.c b/hw/9pfs/9p-local.c
index d2246a3d7e..22377a3105 100644
--- a/hw/9pfs/9p-local.c
+++ b/hw/9pfs/9p-local.c
@@ -54,18 +54,18 @@
 #endif
 
 typedef struct {
-    int mountfd;
+    QemuFd_t mountfd;
 } LocalData;
 
-int local_open_nofollow(FsContext *fs_ctx, const char *path, int flags,
-                        mode_t mode)
+QemuFd_t local_open_nofollow(FsContext *fs_ctx, const char *path, int flags,
+                             mode_t mode)
 {
     LocalData *data = fs_ctx->private;
-    int fd = data->mountfd;
+    QemuFd_t fd = data->mountfd;
 
-    while (*path && fd != -1) {
+    while (*path && !qemu_fd_invalid(fd)) {
         const char *c;
-        int next_fd;
+        QemuFd_t next_fd;
         char *head;
 
         /* Only relative paths without consecutive slashes */
@@ -94,20 +94,21 @@ int local_open_nofollow(FsContext *fs_ctx, const char *path, int flags,
     return fd;
 }
 
-int local_opendir_nofollow(FsContext *fs_ctx, const char *path)
+QemuFd_t local_opendir_nofollow(FsContext *fs_ctx, const char *path)
 {
     return local_open_nofollow(fs_ctx, path, O_DIRECTORY | O_RDONLY, 0);
 }
 
-static void renameat_preserve_errno(int odirfd, const char *opath, int ndirfd,
-                                    const char *npath)
+static void renameat_preserve_errno(QemuFd_t odirfd, const char *opath,
+                                    QemuFd_t ndirfd, const char *npath)
 {
     int serrno = errno;
     qemu_renameat(odirfd, opath, ndirfd, npath);
     errno = serrno;
 }
 
-static void unlinkat_preserve_errno(int dirfd, const char *path, int flags)
+static void unlinkat_preserve_errno(QemuFd_t dirfd, const char *path,
+                                    int flags)
 {
     int serrno = errno;
     qemu_unlinkat(dirfd, path, flags);
@@ -117,9 +118,10 @@ static void unlinkat_preserve_errno(int dirfd, const char *path, int flags)
 #define VIRTFS_META_DIR ".virtfs_metadata"
 #define VIRTFS_META_ROOT_FILE VIRTFS_META_DIR "_root"
 
-static FILE *local_fopenat(int dirfd, const char *name, const char *mode)
+static FILE *local_fopenat(QemuFd_t dirfd, const char *name, const char *mode)
 {
-    int fd, o_mode = 0;
+    QemuFd_t fd;
+    int o_mode = 0;
     FILE *fp;
     int flags;
     /*
@@ -134,7 +136,7 @@ static FILE *local_fopenat(int dirfd, const char *name, const char *mode)
         return NULL;
     }
     fd = openat_file(dirfd, name, flags, o_mode);
-    if (fd == -1) {
+    if (qemu_fd_invalid(fd)) {
         return NULL;
     }
     fp = fdopen(fd, mode);
@@ -145,16 +147,16 @@ static FILE *local_fopenat(int dirfd, const char *name, const char *mode)
 }
 
 #define ATTR_MAX 100
-static void local_mapped_file_attr(int dirfd, const char *name,
+static void local_mapped_file_attr(QemuFd_t dirfd, const char *name,
                                    struct stat *stbuf)
 {
     FILE *fp;
     char buf[ATTR_MAX];
-    int map_dirfd;
+    QemuFd_t map_dirfd;
 
     if (strcmp(name, ".")) {
         map_dirfd = openat_dir(dirfd, VIRTFS_META_DIR);
-        if (map_dirfd == -1) {
+        if (qemu_fd_invalid(map_dirfd)) {
             return;
         }
 
@@ -187,10 +189,10 @@ static int local_lstat(FsContext *fs_ctx, V9fsPath *fs_path, struct stat *stbuf)
     int err = -1;
     char *dirpath = g_path_get_dirname(fs_path->data);
     char *name = g_path_get_basename(fs_path->data);
-    int dirfd;
+    QemuFd_t dirfd;
 
     dirfd = local_opendir_nofollow(fs_ctx, dirpath);
-    if (dirfd == -1) {
+    if (qemu_fd_invalid(dirfd)) {
         goto out;
     }
 
@@ -233,14 +235,14 @@ out:
     return err;
 }
 
-static int local_set_mapped_file_attrat(int dirfd, const char *name,
+static int local_set_mapped_file_attrat(QemuFd_t dirfd, const char *name,
                                         FsCred *credp)
 {
     FILE *fp;
     int ret;
     char buf[ATTR_MAX];
     int uid = -1, gid = -1, mode = -1, rdev = -1;
-    int map_dirfd = -1, map_fd;
+    QemuFd_t map_dirfd = QEMU_FD_INVALID, map_fd;
     bool is_root = !strcmp(name, ".");
 
     if (is_root) {
@@ -259,7 +261,7 @@ static int local_set_mapped_file_attrat(int dirfd, const char *name,
         }
 
         map_dirfd = openat_dir(dirfd, VIRTFS_META_DIR);
-        if (map_dirfd == -1) {
+        if (qemu_fd_invalid(map_dirfd)) {
             return -1;
         }
 
@@ -296,7 +298,7 @@ update_map_file:
         /* We can't go this far with map_dirfd not being a valid file descriptor
          * but some versions of gcc aren't smart enough to see it.
          */
-        if (map_dirfd != -1) {
+        if (!qemu_fd_invalid(map_dirfd)) {
             close_preserve_errno(map_dirfd);
         }
     }
@@ -305,7 +307,7 @@ update_map_file:
     }
 
     map_fd = fileno(fp);
-    assert(map_fd != -1);
+    assert(!qemu_fd_invalid(map_fd));
     ret = fchmod(map_fd, 0600);
     assert(ret == 0);
 
@@ -339,10 +341,11 @@ update_map_file:
     return 0;
 }
 
-static int fchmodat_nofollow(int dirfd, const char *name, mode_t mode)
+static int fchmodat_nofollow(QemuFd_t dirfd, const char *name, mode_t mode)
 {
     struct stat stbuf;
-    int fd, ret;
+    QemuFd_t fd;
+    int ret;
 
     /* FIXME: this should be handled with fchmodat(AT_SYMLINK_NOFOLLOW).
      * Unfortunately, the linux kernel doesn't implement it yet.
@@ -362,16 +365,16 @@ static int fchmodat_nofollow(int dirfd, const char *name, mode_t mode)
     /* Fallback for systems that don't support O_PATH: we depend on the file
      * being readable or writable.
      */
-    if (fd == -1) {
+    if (qemu_fd_invalid(fd)) {
         /* In case the file is writable-only and isn't a directory. */
         if (errno == EACCES) {
             fd = openat_file(dirfd, name, O_WRONLY, 0);
         }
-        if (fd == -1 && errno == EISDIR) {
+        if (qemu_fd_invalid(fd) && errno == EISDIR) {
             errno = EACCES;
         }
     }
-    if (fd == -1) {
+    if (qemu_fd_invalid(fd)) {
         return -1;
     }
     ret = fchmod(fd, mode);
@@ -380,7 +383,7 @@ static int fchmodat_nofollow(int dirfd, const char *name, mode_t mode)
      * link, O_PATH | O_NOFOLLOW causes openat(2) to return a file descriptor
      * referring to the symbolic link.
      */
-    if (fd == -1) {
+    if (qemu_fd_invalid(fd)) {
         return -1;
     }
 
@@ -401,7 +404,7 @@ static int fchmodat_nofollow(int dirfd, const char *name, mode_t mode)
     return ret;
 }
 
-static int local_set_xattrat(int dirfd, const char *path, FsCred *credp)
+static int local_set_xattrat(QemuFd_t dirfd, const char *path, FsCred *credp)
 {
     int err;
 
@@ -440,7 +443,7 @@ static int local_set_xattrat(int dirfd, const char *path, FsCred *credp)
     return 0;
 }
 
-static int local_set_cred_passthrough(FsContext *fs_ctx, int dirfd,
+static int local_set_cred_passthrough(FsContext *fs_ctx, QemuFd_t dirfd,
                                       const char *name, FsCred *credp)
 {
     if (fchownat(dirfd, name, credp->fc_uid, credp->fc_gid,
@@ -464,10 +467,10 @@ static ssize_t local_readlink(FsContext *fs_ctx, V9fsPath *fs_path,
 
     if ((fs_ctx->export_flags & V9FS_SM_MAPPED) ||
         (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE)) {
-        int fd;
+        QemuFd_t fd;
 
         fd = local_open_nofollow(fs_ctx, fs_path->data, O_RDONLY, 0);
-        if (fd == -1) {
+        if (qemu_fd_invalid(fd)) {
             return -1;
         }
         do {
@@ -478,10 +481,10 @@ static ssize_t local_readlink(FsContext *fs_ctx, V9fsPath *fs_path,
                (fs_ctx->export_flags & V9FS_SM_NONE)) {
         char *dirpath = g_path_get_dirname(fs_path->data);
         char *name = g_path_get_basename(fs_path->data);
-        int dirfd;
+        QemuFd_t dirfd;
 
         dirfd = local_opendir_nofollow(fs_ctx, dirpath);
-        if (dirfd == -1) {
+        if (qemu_fd_invalid(dirfd)) {
             goto out;
         }
 
@@ -507,10 +510,10 @@ static int local_closedir(FsContext *ctx, V9fsFidOpenState *fs)
 static int local_open(FsContext *ctx, V9fsPath *fs_path,
                       int flags, V9fsFidOpenState *fs)
 {
-    int fd;
+    QemuFd_t fd;
 
     fd = local_open_nofollow(ctx, fs_path->data, flags, 0);
-    if (fd == -1) {
+    if (qemu_fd_invalid(fd)) {
         return -1;
     }
     fs->fd = fd;
@@ -520,11 +523,11 @@ static int local_open(FsContext *ctx, V9fsPath *fs_path,
 static int local_opendir(FsContext *ctx,
                          V9fsPath *fs_path, V9fsFidOpenState *fs)
 {
-    int dirfd;
+    QemuFd_t dirfd;
     DIR *stream;
 
     dirfd = local_opendir_nofollow(ctx, fs_path->data);
-    if (dirfd == -1) {
+    if (qemu_fd_invalid(dirfd)) {
         return -1;
     }
 
@@ -640,10 +643,10 @@ static int local_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
     char *dirpath = g_path_get_dirname(fs_path->data);
     char *name = g_path_get_basename(fs_path->data);
     int ret = -1;
-    int dirfd;
+    QemuFd_t dirfd;
 
     dirfd = local_opendir_nofollow(fs_ctx, dirpath);
-    if (dirfd == -1) {
+    if (qemu_fd_invalid(dirfd)) {
         goto out;
     }
 
@@ -667,7 +670,7 @@ static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path,
                        const char *name, FsCred *credp)
 {
     int err = -1;
-    int dirfd;
+    QemuFd_t dirfd;
 
     if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE &&
         local_is_mapped_file_metadata(fs_ctx, name)) {
@@ -676,7 +679,7 @@ static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path,
     }
 
     dirfd = local_opendir_nofollow(fs_ctx, dir_path->data);
-    if (dirfd == -1) {
+    if (qemu_fd_invalid(dirfd)) {
         return -1;
     }
 
@@ -719,7 +722,7 @@ static int local_mkdir(FsContext *fs_ctx, V9fsPath *dir_path,
                        const char *name, FsCred *credp)
 {
     int err = -1;
-    int dirfd;
+    QemuFd_t dirfd;
 
     if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE &&
         local_is_mapped_file_metadata(fs_ctx, name)) {
@@ -728,7 +731,7 @@ static int local_mkdir(FsContext *fs_ctx, V9fsPath *dir_path,
     }
 
     dirfd = local_opendir_nofollow(fs_ctx, dir_path->data);
-    if (dirfd == -1) {
+    if (qemu_fd_invalid(dirfd)) {
         return -1;
     }
 
@@ -816,9 +819,9 @@ static int local_fstat(FsContext *fs_ctx, int fid_type,
 static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
                        int flags, FsCred *credp, V9fsFidOpenState *fs)
 {
-    int fd = -1;
+    QemuFd_t fd = QEMU_FD_INVALID;
     int err = -1;
-    int dirfd;
+    QemuFd_t dirfd;
 
     if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE &&
         local_is_mapped_file_metadata(fs_ctx, name)) {
@@ -832,7 +835,7 @@ static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
     flags |= O_NOFOLLOW;
 
     dirfd = local_opendir_nofollow(fs_ctx, dir_path->data);
-    if (dirfd == -1) {
+    if (qemu_fd_invalid(dirfd)) {
         return -1;
     }
 
@@ -840,7 +843,7 @@ static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
     if (fs_ctx->export_flags & V9FS_SM_MAPPED ||
         fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
         fd = openat_file(dirfd, name, flags, fs_ctx->fmode);
-        if (fd == -1) {
+        if (qemu_fd_invalid(fd)) {
             goto out;
         }
         credp->fc_mode = credp->fc_mode | S_IFREG;
@@ -856,7 +859,7 @@ 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)) {
         fd = openat_file(dirfd, name, flags, credp->fc_mode);
-        if (fd == -1) {
+        if (qemu_fd_invalid(fd)) {
             goto out;
         }
         err = local_set_cred_passthrough(fs_ctx, dirfd, name, credp);
@@ -882,7 +885,7 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath,
                          V9fsPath *dir_path, const char *name, FsCred *credp)
 {
     int err = -1;
-    int dirfd;
+    QemuFd_t dirfd;
 
     if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE &&
         local_is_mapped_file_metadata(fs_ctx, name)) {
@@ -891,19 +894,19 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath,
     }
 
     dirfd = local_opendir_nofollow(fs_ctx, dir_path->data);
-    if (dirfd == -1) {
+    if (qemu_fd_invalid(dirfd)) {
         return -1;
     }
 
     /* Determine the security model */
     if (fs_ctx->export_flags & V9FS_SM_MAPPED ||
         fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
-        int fd;
+        QemuFd_t fd;
         ssize_t oldpath_size, write_size;
 
         fd = openat_file(dirfd, name, O_CREAT | O_EXCL | O_RDWR,
                          fs_ctx->fmode);
-        if (fd == -1) {
+        if (qemu_fd_invalid(fd)) {
             goto out;
         }
         /* Write the oldpath (target) to the file. */
@@ -962,7 +965,7 @@ static int local_link(FsContext *ctx, V9fsPath *oldpath,
     char *odirpath = g_path_get_dirname(oldpath->data);
     char *oname = g_path_get_basename(oldpath->data);
     int ret = -1;
-    int odirfd, ndirfd;
+    QemuFd_t odirfd, ndirfd;
 
     if (ctx->export_flags & V9FS_SM_MAPPED_FILE &&
         local_is_mapped_file_metadata(ctx, name)) {
@@ -971,12 +974,12 @@ static int local_link(FsContext *ctx, V9fsPath *oldpath,
     }
 
     odirfd = local_opendir_nofollow(ctx, odirpath);
-    if (odirfd == -1) {
+    if (qemu_fd_invalid(odirfd)) {
         goto out;
     }
 
     ndirfd = local_opendir_nofollow(ctx, dirpath->data);
-    if (ndirfd == -1) {
+    if (qemu_fd_invalid(ndirfd)) {
         close_preserve_errno(odirfd);
         goto out;
     }
@@ -996,12 +999,12 @@ static int local_link(FsContext *ctx, V9fsPath *oldpath,
         }
 
         omap_dirfd = openat_dir(odirfd, VIRTFS_META_DIR);
-        if (omap_dirfd == -1) {
+        if (qemu_fd_invalid(omap_dirfd)) {
             goto err;
         }
 
         nmap_dirfd = openat_dir(ndirfd, VIRTFS_META_DIR);
-        if (nmap_dirfd == -1) {
+        if (qemu_fd_invalid(nmap_dirfd)) {
             close_preserve_errno(omap_dirfd);
             goto err;
         }
@@ -1032,10 +1035,11 @@ out:
 
 static int local_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size)
 {
-    int fd, ret;
+    QemuFd_t fd;
+    int ret;
 
     fd = local_open_nofollow(ctx, fs_path->data, O_WRONLY, 0);
-    if (fd == -1) {
+    if (qemu_fd_invalid(fd)) {
         return -1;
     }
     ret = ftruncate(fd, size);
@@ -1048,10 +1052,10 @@ static int local_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
     char *dirpath = g_path_get_dirname(fs_path->data);
     char *name = g_path_get_basename(fs_path->data);
     int ret = -1;
-    int dirfd;
+    QemuFd_t dirfd;
 
     dirfd = local_opendir_nofollow(fs_ctx, dirpath);
-    if (dirfd == -1) {
+    if (qemu_fd_invalid(dirfd)) {
         goto out;
     }
 
@@ -1078,10 +1082,11 @@ static int local_utimensat(FsContext *s, V9fsPath *fs_path,
 {
     char *dirpath = g_path_get_dirname(fs_path->data);
     char *name = g_path_get_basename(fs_path->data);
-    int dirfd, ret = -1;
+    QemuFd_t dirfd;
+    int ret = -1;
 
     dirfd = local_opendir_nofollow(s, dirpath);
-    if (dirfd == -1) {
+    if (qemu_fd_invalid(dirfd)) {
         goto out;
     }
 
@@ -1093,13 +1098,13 @@ out:
     return ret;
 }
 
-static int local_unlinkat_common(FsContext *ctx, int dirfd, const char *name,
-                                 int flags)
+static int local_unlinkat_common(FsContext *ctx, QemuFd_t dirfd,
+                                 const char *name, int flags)
 {
     int ret;
 
     if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
-        int map_dirfd;
+        QemuFd_t map_dirfd;
 
         /* We need to remove the metadata as well:
          * - the metadata directory if we're removing a directory
@@ -1110,10 +1115,10 @@ static int local_unlinkat_common(FsContext *ctx, int dirfd, const char *name,
          * mode. We just ignore the error.
          */
         if (flags == AT_REMOVEDIR) {
-            int fd;
+            QemuFd_t fd;
 
             fd = openat_dir(dirfd, name);
-            if (fd == -1) {
+            if (qemu_fd_invalid(fd)) {
                 return -1;
             }
             ret = qemu_unlinkat(fd, VIRTFS_META_DIR, AT_REMOVEDIR);
@@ -1123,7 +1128,7 @@ static int local_unlinkat_common(FsContext *ctx, int dirfd, const char *name,
             }
         }
         map_dirfd = openat_dir(dirfd, VIRTFS_META_DIR);
-        if (map_dirfd != -1) {
+        if (!qemu_fd_invalid(map_dirfd)) {
             ret = qemu_unlinkat(map_dirfd, name, 0);
             close_preserve_errno(map_dirfd);
             if (ret < 0 && errno != ENOENT) {
@@ -1143,11 +1148,11 @@ static int local_remove(FsContext *ctx, const char *path)
     char *dirpath = g_path_get_dirname(path);
     char *name = g_path_get_basename(path);
     int flags = 0;
-    int dirfd;
+    QemuFd_t dirfd;
     int err = -1;
 
     dirfd = local_opendir_nofollow(ctx, dirpath);
-    if (dirfd == -1) {
+    if (qemu_fd_invalid(dirfd)) {
         goto out;
     }
 
@@ -1188,10 +1193,11 @@ static int local_fsync(FsContext *ctx, int fid_type,
 
 static int local_statfs(FsContext *s, V9fsPath *fs_path, struct statfs *stbuf)
 {
-    int fd, ret;
+    QemuFd_t fd;
+    int ret;
 
     fd = local_open_nofollow(s, fs_path->data, O_RDONLY, 0);
-    if (fd == -1) {
+    if (qemu_fd_invalid(fd)) {
         return -1;
     }
     ret = fstatfs(fd, stbuf);
@@ -1276,7 +1282,7 @@ static int local_renameat(FsContext *ctx, V9fsPath *olddir,
                           const char *new_name)
 {
     int ret;
-    int odirfd, ndirfd;
+    QemuFd_t odirfd, ndirfd;
 
     if (ctx->export_flags & V9FS_SM_MAPPED_FILE &&
         (local_is_mapped_file_metadata(ctx, old_name) ||
@@ -1286,12 +1292,12 @@ static int local_renameat(FsContext *ctx, V9fsPath *olddir,
     }
 
     odirfd = local_opendir_nofollow(ctx, olddir->data);
-    if (odirfd == -1) {
+    if (qemu_fd_invalid(odirfd)) {
         return -1;
     }
 
     ndirfd = local_opendir_nofollow(ctx, newdir->data);
-    if (ndirfd == -1) {
+    if (qemu_fd_invalid(ndirfd)) {
         close_preserve_errno(odirfd);
         return -1;
     }
@@ -1302,7 +1308,7 @@ static int local_renameat(FsContext *ctx, V9fsPath *olddir,
     }
 
     if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
-        int omap_dirfd, nmap_dirfd;
+        QemuFd_t omap_dirfd, nmap_dirfd;
 
         ret = qemu_mkdirat(ndirfd, VIRTFS_META_DIR, 0700);
         if (ret < 0 && errno != EEXIST) {
@@ -1310,12 +1316,12 @@ static int local_renameat(FsContext *ctx, V9fsPath *olddir,
         }
 
         omap_dirfd = openat_dir(odirfd, VIRTFS_META_DIR);
-        if (omap_dirfd == -1) {
+        if (qemu_fd_invalid(omap_dirfd)) {
             goto err;
         }
 
         nmap_dirfd = openat_dir(ndirfd, VIRTFS_META_DIR);
-        if (nmap_dirfd == -1) {
+        if (qemu_fd_invalid(nmap_dirfd)) {
             close_preserve_errno(omap_dirfd);
             goto err;
         }
@@ -1373,7 +1379,7 @@ static int local_unlinkat(FsContext *ctx, V9fsPath *dir,
                           const char *name, int flags)
 {
     int ret;
-    int dirfd;
+    QemuFd_t dirfd;
 
     if (ctx->export_flags & V9FS_SM_MAPPED_FILE &&
         local_is_mapped_file_metadata(ctx, name)) {
@@ -1382,7 +1388,7 @@ static int local_unlinkat(FsContext *ctx, V9fsPath *dir,
     }
 
     dirfd = local_opendir_nofollow(ctx, dir->data);
-    if (dirfd == -1) {
+    if (qemu_fd_invalid(dirfd)) {
         return -1;
     }
 
@@ -1446,7 +1452,7 @@ static int local_init(FsContext *ctx, Error **errp)
     LocalData *data = g_malloc(sizeof(*data));
 
     data->mountfd = open(ctx->fs_root, O_DIRECTORY | O_RDONLY);
-    if (data->mountfd == -1) {
+    if (qemu_fd_invalid(data->mountfd)) {
         error_setg_errno(errp, errno, "failed to open '%s'", ctx->fs_root);
         goto err;
     }
diff --git a/hw/9pfs/9p-util-darwin.c b/hw/9pfs/9p-util-darwin.c
index 95146e7354..f85cfd26bb 100644
--- a/hw/9pfs/9p-util-darwin.c
+++ b/hw/9pfs/9p-util-darwin.c
@@ -11,8 +11,8 @@
 #include "qemu/error-report.h"
 #include "9p-util.h"
 
-ssize_t fgetxattrat_nofollow(int dirfd, const char *filename, const char *name,
-                             void *value, size_t size)
+ssize_t fgetxattrat_nofollow(QemuFd_t dirfd, const char *filename,
+                             const char *name, void *value, size_t size)
 {
     int ret;
     int fd = openat_file(dirfd, filename,
@@ -25,7 +25,7 @@ ssize_t fgetxattrat_nofollow(int dirfd, const char *filename, const char *name,
     return ret;
 }
 
-ssize_t flistxattrat_nofollow(int dirfd, const char *filename,
+ssize_t flistxattrat_nofollow(QemuFd_t dirfd, const char *filename,
                               char *list, size_t size)
 {
     int ret;
@@ -39,7 +39,7 @@ ssize_t flistxattrat_nofollow(int dirfd, const char *filename,
     return ret;
 }
 
-ssize_t fremovexattrat_nofollow(int dirfd, const char *filename,
+ssize_t fremovexattrat_nofollow(QemuFd_t dirfd, const char *filename,
                                 const char *name)
 {
     int ret;
@@ -52,8 +52,8 @@ ssize_t fremovexattrat_nofollow(int dirfd, const char *filename,
     return ret;
 }
 
-int fsetxattrat_nofollow(int dirfd, const char *filename, const char *name,
-                         void *value, size_t size, int flags)
+int fsetxattrat_nofollow(QemuFd_t dirfd, const char *filename,
+                         const char *name, void *value, size_t size, int flags)
 {
     int ret;
     int fd = openat_file(dirfd, filename, O_PATH_9P_UTIL | O_NOFOLLOW, 0);
@@ -110,7 +110,7 @@ out:
     return err;
 }
 
-int qemu_mknodat(int dirfd, const char *filename, mode_t mode, dev_t dev)
+int qemu_mknodat(QemuFd_t dirfd, const char *filename, mode_t mode, dev_t dev)
 {
     int preserved_errno, err;
 
diff --git a/hw/9pfs/9p-util-linux.c b/hw/9pfs/9p-util-linux.c
index db451b0784..8dd9da10b6 100644
--- a/hw/9pfs/9p-util-linux.c
+++ b/hw/9pfs/9p-util-linux.c
@@ -19,8 +19,8 @@
 #include "qemu/xattr.h"
 #include "9p-util.h"
 
-ssize_t fgetxattrat_nofollow(int dirfd, const char *filename, const char *name,
-                             void *value, size_t size)
+ssize_t fgetxattrat_nofollow(QemuFd_t dirfd, const char *filename,
+                             const char *name, void *value, size_t size)
 {
     char *proc_path = g_strdup_printf("/proc/self/fd/%d/%s", dirfd, filename);
     int ret;
@@ -30,7 +30,7 @@ ssize_t fgetxattrat_nofollow(int dirfd, const char *filename, const char *name,
     return ret;
 }
 
-ssize_t flistxattrat_nofollow(int dirfd, const char *filename,
+ssize_t flistxattrat_nofollow(QemuFd_t dirfd, const char *filename,
                               char *list, size_t size)
 {
     char *proc_path = g_strdup_printf("/proc/self/fd/%d/%s", dirfd, filename);
@@ -41,7 +41,7 @@ ssize_t flistxattrat_nofollow(int dirfd, const char *filename,
     return ret;
 }
 
-ssize_t fremovexattrat_nofollow(int dirfd, const char *filename,
+ssize_t fremovexattrat_nofollow(QemuFd_t dirfd, const char *filename,
                                 const char *name)
 {
     char *proc_path = g_strdup_printf("/proc/self/fd/%d/%s", dirfd, filename);
@@ -52,8 +52,8 @@ ssize_t fremovexattrat_nofollow(int dirfd, const char *filename,
     return ret;
 }
 
-int fsetxattrat_nofollow(int dirfd, const char *filename, const char *name,
-                         void *value, size_t size, int flags)
+int fsetxattrat_nofollow(QemuFd_t dirfd, const char *filename,
+                         const char *name, void *value, size_t size, int flags)
 {
     char *proc_path = g_strdup_printf("/proc/self/fd/%d/%s", dirfd, filename);
     int ret;
@@ -64,7 +64,7 @@ int fsetxattrat_nofollow(int dirfd, const char *filename, const char *name,
 
 }
 
-int qemu_mknodat(int dirfd, const char *filename, mode_t mode, dev_t dev)
+int qemu_mknodat(QemuFd_t dirfd, const char *filename, mode_t mode, dev_t dev)
 {
     return mknodat(dirfd, filename, mode, dev);
 }
diff --git a/hw/9pfs/9p-xattr.c b/hw/9pfs/9p-xattr.c
index 9ae69dd8db..062bf2d1f0 100644
--- a/hw/9pfs/9p-xattr.c
+++ b/hw/9pfs/9p-xattr.c
@@ -78,13 +78,13 @@ ssize_t v9fs_list_xattr(FsContext *ctx, const char *path,
     char *orig_value, *orig_value_start;
     ssize_t xattr_len, parsed_len = 0, attr_len;
     char *dirpath, *name;
-    int dirfd;
+    QemuFd_t dirfd;
 
     /* Get the actual len */
     dirpath = g_path_get_dirname(path);
     dirfd = local_opendir_nofollow(ctx, dirpath);
     g_free(dirpath);
-    if (dirfd == -1) {
+    if (qemu_fd_invalid(dirfd)) {
         return -1;
     }
 
@@ -168,11 +168,11 @@ ssize_t local_getxattr_nofollow(FsContext *ctx, const char *path,
 {
     char *dirpath = g_path_get_dirname(path);
     char *filename = g_path_get_basename(path);
-    int dirfd;
+    QemuFd_t dirfd;
     ssize_t ret = -1;
 
     dirfd = local_opendir_nofollow(ctx, dirpath);
-    if (dirfd == -1) {
+    if (qemu_fd_invalid(dirfd)) {
         goto out;
     }
 
@@ -196,11 +196,11 @@ ssize_t local_setxattr_nofollow(FsContext *ctx, const char *path,
 {
     char *dirpath = g_path_get_dirname(path);
     char *filename = g_path_get_basename(path);
-    int dirfd;
+    QemuFd_t dirfd;
     ssize_t ret = -1;
 
     dirfd = local_opendir_nofollow(ctx, dirpath);
-    if (dirfd == -1) {
+    if (qemu_fd_invalid(dirfd)) {
         goto out;
     }
 
@@ -223,11 +223,11 @@ ssize_t local_removexattr_nofollow(FsContext *ctx, const char *path,
 {
     char *dirpath = g_path_get_dirname(path);
     char *filename = g_path_get_basename(path);
-    int dirfd;
+    QemuFd_t dirfd;
     ssize_t ret = -1;
 
     dirfd = local_opendir_nofollow(ctx, dirpath);
-    if (dirfd == -1) {
+    if (qemu_fd_invalid(dirfd)) {
         goto out;
     }
 
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v2 06/19] hw/9pfs: Add missing definitions for Windows
  2022-11-11  4:22 [PATCH v2 00/19] At present there is no Windows support for 9p file system Bin Meng
                   ` (4 preceding siblings ...)
  2022-11-11  4:22 ` [PATCH v2 05/19] hw/9pfs: Update 9pfs to use the new QemuFd_t type Bin Meng
@ 2022-11-11  4:22 ` Bin Meng
  2022-11-14 16:40   ` Christian Schoenebeck
  2022-11-11  4:22 ` [PATCH v2 07/19] hw/9pfs: Implement Windows specific utilities functions for 9pfs Bin Meng
                   ` (12 subsequent siblings)
  18 siblings, 1 reply; 36+ messages in thread
From: Bin Meng @ 2022-11-11  4:22 UTC (permalink / raw)
  To: qemu-devel; +Cc: Guohuai Shi, Christian Schoenebeck, Greg Kurz

From: Guohuai Shi <guohuai.shi@windriver.com>

Some definitions currently used by the 9pfs codes are only available
on POSIX platforms. Let's add our own ones in preparation to adding
9pfs support for Windows.

Signed-off-by: Guohuai Shi <guohuai.shi@windriver.com>
Signed-off-by: Bin Meng <bin.meng@windriver.com>

---

Changes in v2:
- Add S_IFLNK related macros to support symbolic link

 fsdev/file-op-9p.h | 33 +++++++++++++++++++++++++++++++++
 hw/9pfs/9p.h       | 33 +++++++++++++++++++++++++++++++++
 2 files changed, 66 insertions(+)

diff --git a/fsdev/file-op-9p.h b/fsdev/file-op-9p.h
index 4997677460..7d9a736b66 100644
--- a/fsdev/file-op-9p.h
+++ b/fsdev/file-op-9p.h
@@ -27,6 +27,39 @@
 # include <sys/mount.h>
 #endif
 
+#ifdef CONFIG_WIN32
+
+/* POSIX structure not defined in Windows */
+
+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 /* CONFIG_WIN32 */
+
 #define SM_LOCAL_MODE_BITS    0600
 #define SM_LOCAL_DIR_MODE_BITS    0700
 
diff --git a/hw/9pfs/9p.h b/hw/9pfs/9p.h
index 2fce4140d1..957a7e4ccc 100644
--- a/hw/9pfs/9p.h
+++ b/hw/9pfs/9p.h
@@ -3,13 +3,46 @@
 
 #include <dirent.h>
 #include <utime.h>
+#ifndef CONFIG_WIN32
 #include <sys/resource.h>
+#endif
 #include "fsdev/file-op-9p.h"
 #include "fsdev/9p-iov-marshal.h"
 #include "qemu/thread.h"
 #include "qemu/coroutine.h"
 #include "qemu/qht.h"
 
+#ifdef CONFIG_WIN32
+
+#define NAME_MAX            MAX_PATH
+
+/* macros required for build, values do not matter */
+#define AT_SYMLINK_NOFOLLOW 0x100   /* Do not follow symbolic links */
+#define AT_REMOVEDIR        0x200   /* Remove directory instead of file */
+#define O_DIRECTORY         02000000
+
+#define makedev(major, minor)   \
+        ((dev_t)((((major) & 0xfff) << 8) | ((minor) & 0xff)))
+#define major(dev)  ((unsigned int)(((dev) >> 8) & 0xfff))
+#define minor(dev)  ((unsigned int)(((dev) & 0xff)))
+
+#ifndef S_IFLNK
+/*
+ * Currenlty Windows/MinGW does not provide the following flag macros,
+ * so define them here for 9p codes.
+ *
+ * Once Windows/MinGW provides them, remove the defines to prevent conflicts.
+ */
+#define S_IFLNK         0xA000
+#define S_ISUID         0x0800
+#define S_ISGID         0x0400
+#define S_ISVTX         0x0200
+
+#define S_ISLNK(mode)   ((mode & S_IFMT) == S_IFLNK)
+#endif /* S_IFLNK */
+
+#endif /* CONFIG_WIN32 */
+
 enum {
     P9_TLERROR = 6,
     P9_RLERROR,
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v2 07/19] hw/9pfs: Implement Windows specific utilities functions for 9pfs
  2022-11-11  4:22 [PATCH v2 00/19] At present there is no Windows support for 9p file system Bin Meng
                   ` (5 preceding siblings ...)
  2022-11-11  4:22 ` [PATCH v2 06/19] hw/9pfs: Add missing definitions for Windows Bin Meng
@ 2022-11-11  4:22 ` Bin Meng
  2022-11-17 15:55   ` Christian Schoenebeck
  2022-11-11  4:22 ` [PATCH v2 08/19] hw/9pfs: Update the local fs driver to support Windows Bin Meng
                   ` (11 subsequent siblings)
  18 siblings, 1 reply; 36+ messages in thread
From: Bin Meng @ 2022-11-11  4:22 UTC (permalink / raw)
  To: qemu-devel; +Cc: Guohuai Shi, Christian Schoenebeck, Greg Kurz

From: Guohuai Shi <guohuai.shi@windriver.com>

Windows POSIX API and MinGW library do not provide the NO_FOLLOW
flag, and do not allow opening a directory by POSIX open(). This
causes all xxx_at() functions cannot work directly. However, we
can provide Windows handle based functions to emulate xxx_at()
functions (e.g.: openat_win32, utimensat_win32, etc.).

NTFS ADS (Alternate Data Streams) is used to emulate 9pfs extended
attributes on Windows. Symbolic link is only supported when security
model is "mapped-xattr" or "mapped-file".

Signed-off-by: Guohuai Shi <guohuai.shi@windriver.com>
Signed-off-by: Bin Meng <bin.meng@windriver.com>

---

Changes in v2:
- Support symbolic link when security model is "mapped-xattr" or "mapped-file"

 hw/9pfs/9p-local.h      |   7 +
 hw/9pfs/9p-util.h       |  38 +-
 hw/9pfs/9p-local.c      |   4 -
 hw/9pfs/9p-util-win32.c | 934 ++++++++++++++++++++++++++++++++++++++++
 4 files changed, 978 insertions(+), 5 deletions(-)
 create mode 100644 hw/9pfs/9p-util-win32.c

diff --git a/hw/9pfs/9p-local.h b/hw/9pfs/9p-local.h
index 66a21316a0..eb4f39ddc2 100644
--- a/hw/9pfs/9p-local.h
+++ b/hw/9pfs/9p-local.h
@@ -13,6 +13,13 @@
 #ifndef QEMU_9P_LOCAL_H
 #define QEMU_9P_LOCAL_H
 
+typedef struct {
+    QemuFd_t mountfd;
+#ifdef CONFIG_WIN32
+    char *root_path;
+#endif
+} LocalData;
+
 QemuFd_t local_open_nofollow(FsContext *fs_ctx, const char *path, int flags,
                              mode_t mode);
 QemuFd_t local_opendir_nofollow(FsContext *fs_ctx, const char *path);
diff --git a/hw/9pfs/9p-util.h b/hw/9pfs/9p-util.h
index 3d6bd1a51e..5fb854bf61 100644
--- a/hw/9pfs/9p-util.h
+++ b/hw/9pfs/9p-util.h
@@ -88,26 +88,61 @@ static inline int errno_to_dotl(int err) {
     return err;
 }
 
-#ifdef CONFIG_DARWIN
+#if defined(CONFIG_DARWIN)
 #define qemu_fgetxattr(...) fgetxattr(__VA_ARGS__, 0, 0)
+#elif defined(CONFIG_WIN32)
+#define qemu_fgetxattr fgetxattr_win32
 #else
 #define qemu_fgetxattr fgetxattr
 #endif
 
+#ifdef CONFIG_WIN32
+#define qemu_openat     openat_win32
+#define qemu_fstatat    fstatat_win32
+#define qemu_mkdirat    mkdirat_win32
+#define qemu_renameat   renameat_win32
+#define qemu_utimensat  utimensat_win32
+#define qemu_unlinkat   unlinkat_win32
+#else
 #define qemu_openat     openat
 #define qemu_fstatat    fstatat
 #define qemu_mkdirat    mkdirat
 #define qemu_renameat   renameat
 #define qemu_utimensat  utimensat
 #define qemu_unlinkat   unlinkat
+#endif
+
+#ifdef CONFIG_WIN32
+char *get_full_path_win32(QemuFd_t fd, const char *name);
+ssize_t fgetxattr_win32(int fd, const char *name, void *value, size_t size);
+QemuFd_t openat_win32(QemuFd_t dirfd, const char *pathname, int flags,
+                      mode_t mode);
+int fstatat_win32(QemuFd_t dirfd, const char *pathname,
+                  struct stat *statbuf, int flags);
+int mkdirat_win32(QemuFd_t dirfd, const char *pathname, mode_t mode);
+int renameat_win32(QemuFd_t olddirfd, const char *oldpath,
+                   QemuFd_t newdirfd, const char *newpath);
+int utimensat_win32(QemuFd_t dirfd, const char *pathname,
+                    const struct timespec times[2], int flags);
+int unlinkat_win32(QemuFd_t dirfd, const char *pathname, int flags);
+int statfs_win32(const char *root_path, struct statfs *stbuf);
+QemuFd_t openat_dir(QemuFd_t dirfd, const char *name);
+QemuFd_t openat_file(QemuFd_t dirfd, const char *name, int flags,
+                     mode_t mode);
+#endif
 
 static inline void close_preserve_errno(QemuFd_t fd)
 {
     int serrno = errno;
+#ifndef CONFIG_WIN32
     close(fd);
+#else
+    CloseHandle(fd);
+#endif
     errno = serrno;
 }
 
+#ifndef CONFIG_WIN32
 static inline QemuFd_t openat_dir(QemuFd_t dirfd, const char *name)
 {
     return qemu_openat(dirfd, name,
@@ -155,6 +190,7 @@ again:
     errno = serrno;
     return fd;
 }
+#endif
 
 ssize_t fgetxattrat_nofollow(QemuFd_t dirfd, const char *path,
                              const char *name, void *value, size_t size);
diff --git a/hw/9pfs/9p-local.c b/hw/9pfs/9p-local.c
index 22377a3105..24e21141d5 100644
--- a/hw/9pfs/9p-local.c
+++ b/hw/9pfs/9p-local.c
@@ -53,10 +53,6 @@
 #define BTRFS_SUPER_MAGIC 0x9123683E
 #endif
 
-typedef struct {
-    QemuFd_t mountfd;
-} LocalData;
-
 QemuFd_t local_open_nofollow(FsContext *fs_ctx, const char *path, int flags,
                              mode_t mode)
 {
diff --git a/hw/9pfs/9p-util-win32.c b/hw/9pfs/9p-util-win32.c
new file mode 100644
index 0000000000..ed3d519937
--- /dev/null
+++ b/hw/9pfs/9p-util-win32.c
@@ -0,0 +1,934 @@
+/*
+ * 9p utilities (Windows Implementation)
+ *
+ * Copyright (c) 2022 Wind River Systems, Inc.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+/*
+ * This file contains Windows only functions for 9pfs.
+ *
+ * For 9pfs Windows host, the following features are different from Linux host:
+ *
+ * 1. Windows POSIX API does not provide the NO_FOLLOW flag, that means MinGW
+ *    cannot detect if a path is a symbolic link or not. Also Windows do not
+ *    provide POSIX compatible readlink(). Supporting symbolic link in 9pfs on
+ *    Windows may cause security issues, so symbolic link support is disabled
+ *    completely for security model "none" or "passthrough".
+ *
+ * 2. Windows file system does not support extended attributes directly. 9pfs
+ *    for Windows uses NTFS ADS (Alternate Data Streams) to emulate extended
+ *    attributes.
+ *
+ * 3. statfs() is not available on Windows. qemu_statfs() is used to emulate it.
+ *
+ * 4. On Windows trying to open a directory with the open() API will fail.
+ *    This is because Windows does not allow opening directory in normal usage.
+ *
+ *    As a result of this, all xxx_at() functions won't work directly on
+ *    Windows, e.g.: openat(), unlinkat(), etc.
+ *
+ *    As xxx_at() can prevent parent directory to be modified on Linux host,
+ *    to support this and prevent security issue, all xxx_at() APIs are replaced
+ *    by xxx_at_win32() and Windows handle is used to replace the directory fd.
+ *
+ *    Windows file system does not allow replacing a file or directory if it is
+ *    referenced by a handle. Keep the handle open will lock and protect the
+ *    parent directory and make the access to files atomically.
+ *
+ *    If we don't protect (lock) the parent directory, the parent directory may
+ *    be replaced by others (e.g.: a symbolic link) and cause security issues.
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "qemu/error-report.h"
+#include "9p.h"
+#include "9p-util.h"
+#include "9p-local.h"
+
+#include <windows.h>
+#include <dirent.h>
+
+#define V9FS_MAGIC  0x53465039  /* string "9PFS" */
+
+/*
+ * build_ads_name - construct Windows ADS name
+ *
+ * This function constructs Windows NTFS ADS (Alternate Data Streams) name
+ * to <namebuf>.
+ */
+static int build_ads_name(char *namebuf, size_t namebuf_len,
+                          const char *filename, const char *ads_name)
+{
+    size_t total_size;
+
+    total_size = strlen(filename) + strlen(ads_name) + 2;
+    if (total_size  > namebuf_len) {
+        return -1;
+    }
+
+    /*
+     * NTFS ADS (Alternate Data Streams) name format: filename:ads_name
+     * e.g.: D:\1.txt:my_ads_name
+     */
+
+    strcpy(namebuf, filename);
+    strcat(namebuf, ":");
+    strcat(namebuf, ads_name);
+
+    return 0;
+}
+
+/*
+ * copy_ads_name - copy ADS name from buffer returned by FindNextStreamW()
+ *
+ * This function removes string "$DATA" in ADS name string returned by
+ * FindNextStreamW(), and copies the real ADS name to <namebuf>.
+ */
+static ssize_t copy_ads_name(char *namebuf, size_t namebuf_len,
+                             char *full_ads_name)
+{
+    char *p1, *p2;
+
+    /*
+     * NTFS ADS (Alternate Data Streams) name from enumerate data format:
+     * :ads_name:$DATA, e.g.: :my_ads_name:$DATA
+     *
+     * ADS name from FindNextStreamW() always has ":$DATA" string at the end.
+     *
+     * This function copies ADS name to namebuf.
+     */
+
+    p1 = strchr(full_ads_name, ':');
+    if (p1 == NULL) {
+        return -1;
+    }
+
+    p2 = strchr(p1 + 1, ':');
+    if (p2 == NULL) {
+        return -1;
+    }
+
+    /* skip empty ads name */
+    if (p2 - p1 == 1) {
+        return 0;
+    }
+
+    if (p2 - p1 + 1 > namebuf_len) {
+        return -1;
+    }
+
+    memcpy(namebuf, p1 + 1, p2 - p1 - 1);
+    namebuf[p2 - p1 - 1] = '\0';
+
+    return p2 - p1;
+}
+
+/*
+ * get_full_path_win32 - get full file name base on a handle
+ *
+ * This function gets full file name based on a handle specified by <fd> to
+ * a file or directory.
+ *
+ * Caller function needs to free the file name string after use.
+ */
+char *get_full_path_win32(QemuFd_t fd, const char *name)
+{
+    g_autofree char *full_file_name = NULL;
+    DWORD total_size;
+    DWORD name_size;
+
+    full_file_name = g_malloc0(NAME_MAX);
+
+    /* get parent directory full file name */
+    name_size = GetFinalPathNameByHandle(fd, full_file_name,
+                                         NAME_MAX - 1, FILE_NAME_NORMALIZED);
+    if (name_size == 0 || name_size > NAME_MAX - 1) {
+        return NULL;
+    }
+
+    /* full path returned is the "\\?\" syntax, remove the lead string */
+    memmove(full_file_name, full_file_name + 4, NAME_MAX - 4);
+
+    if (name != NULL) {
+        total_size = strlen(full_file_name) + strlen(name) + 2;
+
+        if (total_size > NAME_MAX) {
+            return NULL;
+        }
+
+        /* build sub-directory file name */
+        strcat(full_file_name, "\\");
+        strcat(full_file_name, name);
+    }
+
+    return g_steal_pointer(&full_file_name);
+}
+
+/*
+ * fgetxattr_win32 - get extended attribute by fd
+ *
+ * This function gets extened attribute by <fd>. <fd> will be translated to
+ * Windows handle.
+ *
+ * This function emulates extended attribute by NTFS ADS.
+ */
+ssize_t fgetxattr_win32(int fd, const char *name, void *value, size_t size)
+{
+    g_autofree char *full_file_name = NULL;
+    char ads_file_name[NAME_MAX + 1] = {0};
+    DWORD dwBytesRead;
+    HANDLE hStream;
+    HANDLE hFile;
+
+    hFile = (HANDLE)_get_osfhandle(fd);
+
+    full_file_name = get_full_path_win32(hFile, NULL);
+    if (full_file_name == NULL) {
+        errno = EIO;
+        return -1;
+    }
+
+    if (build_ads_name(ads_file_name, NAME_MAX, full_file_name, name) < 0) {
+        errno = EIO;
+        return -1;
+    }
+
+    hStream = CreateFile(ads_file_name, GENERIC_READ, FILE_SHARE_READ, NULL,
+                         OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+    if (hStream == INVALID_HANDLE_VALUE &&
+        GetLastError() == ERROR_FILE_NOT_FOUND) {
+        errno = ENODATA;
+        return -1;
+    }
+
+    if (ReadFile(hStream, value, size, &dwBytesRead, NULL) == FALSE) {
+        errno = EIO;
+        CloseHandle(hStream);
+        return -1;
+    }
+
+    CloseHandle(hStream);
+
+    return dwBytesRead;
+}
+
+/*
+ * openat_win32 - emulate openat()
+ *
+ * This function emulates openat().
+ *
+ * Windows POSIX API does not support opening a directory by open(). Only
+ * handle of directory can be opened by CreateFile().
+ *
+ * So openat_win32() has to use a directory handle instead of a directory fd.
+ *
+ * For symbolic access:
+ * 1. Parent directory handle <dirfd> should not be a symbolic link because
+ *    it is opened by openat_dir() which can prevent from opening a link to
+ *    a dirctory.
+ * 2. Link flag in <mode> is not set because Windows does not have this flag.
+ *    Create a new symbolic link will be denied.
+ * 3. This function checks file symbolic link attribute after open.
+ *
+ * So symbolic link will not be accessed by 9p client.
+ */
+QemuFd_t openat_win32(QemuFd_t dirfd, const char *pathname, int flags,
+                      mode_t mode)
+{
+    g_autofree char *full_file_name1 = NULL;
+    g_autofree char *full_file_name2 = NULL;
+    HANDLE hFile = INVALID_HANDLE_VALUE;
+    int fd;
+
+    full_file_name1 = get_full_path_win32(dirfd, pathname);
+    if (full_file_name1 == NULL) {
+        return hFile;
+    }
+
+    fd = open(full_file_name1, flags, mode);
+    if (fd > 0) {
+        DWORD attribute;
+        hFile = (HANDLE)_get_osfhandle(fd);
+
+        full_file_name2 = get_full_path_win32(hFile, NULL);
+        attribute = GetFileAttributes(full_file_name2);
+
+        /* check if it is a symbolic link */
+        if ((attribute == INVALID_FILE_ATTRIBUTES)
+            || (attribute & FILE_ATTRIBUTE_REPARSE_POINT) != 0) {
+            errno = EACCES;
+            hFile = INVALID_HANDLE_VALUE;
+            close(fd);
+        }
+    }
+
+    return hFile;
+}
+
+/*
+ * fstatat_win32 - emulate fstatat()
+ *
+ * This function emulates fstatat().
+ *
+ * Windows POSIX API does not support opening a directory by open(). Only
+ * handle of directory can be opened by CreateFile().
+ *
+ * So fstatat_win32() has to use a directory handle instead of a directory fd.
+ *
+ * Access to a symbolic link will be denied to prevent security issues.
+ */
+int fstatat_win32(QemuFd_t dirfd, const char *pathname,
+                  struct stat *statbuf, int flags)
+{
+    g_autofree char *full_file_name = NULL;
+    HANDLE hFile = INVALID_HANDLE_VALUE;
+    BY_HANDLE_FILE_INFORMATION file_info;
+    DWORD attribute;
+    int err = 0;
+    int ret = -1;
+    ino_t st_ino;
+
+    full_file_name = get_full_path_win32(dirfd, pathname);
+    if (full_file_name == NULL) {
+        return ret;
+    }
+
+    /* open file to lock it */
+    hFile = CreateFile(full_file_name, GENERIC_READ,
+                       FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+                       NULL,
+                       OPEN_EXISTING,
+                       FILE_FLAG_BACKUP_SEMANTICS
+                       | FILE_FLAG_OPEN_REPARSE_POINT,
+                       NULL);
+
+    if (hFile == INVALID_HANDLE_VALUE) {
+        err = EACCES;
+        goto out;
+    }
+
+    attribute = GetFileAttributes(full_file_name);
+
+    /* check if it is a symbolic link */
+    if ((attribute == INVALID_FILE_ATTRIBUTES)
+        || (attribute & FILE_ATTRIBUTE_REPARSE_POINT) != 0) {
+        errno = EACCES;
+        goto out;
+    }
+
+    ret = stat(full_file_name, statbuf);
+
+    if (GetFileInformationByHandle(hFile, &file_info) == 0) {
+        errno = EACCES;
+        goto out;
+    }
+
+    /*
+     * Windows (NTFS) file ID is a 64-bit ID:
+     *   16-bit sequence ID + 48 bit segment number
+     *
+     * But currently, ino_t defined in Windows header file is only 16-bit,
+     * and it is not patched by MinGW. So we build a pseudo inode number
+     * by the low 32-bit segment number when ino_t is only 16-bit.
+     */
+    if (sizeof(st_ino) == sizeof(uint64_t)) {
+        st_ino = (ino_t)((uint64_t)file_info.nFileIndexLow
+                         | (((uint64_t)file_info.nFileIndexHigh) << 32));
+    } else if (sizeof(st_ino) == sizeof(uint16_t)) {
+        st_ino = (ino_t)(((uint16_t)file_info.nFileIndexLow)
+                         ^ ((uint16_t)(file_info.nFileIndexLow >> 16)));
+    } else {
+        st_ino = (ino_t)file_info.nFileIndexLow;
+    }
+
+    statbuf->st_ino = st_ino;
+
+out:
+    if (hFile != INVALID_HANDLE_VALUE) {
+        CloseHandle(hFile);
+    }
+
+    if (err != 0) {
+        errno = err;
+    }
+    return ret;
+}
+
+/*
+ * mkdirat_win32 - emulate mkdirat()
+ *
+ * This function emulates mkdirat().
+ *
+ * Windows POSIX API does not support opening a directory by open(). Only
+ * handle of directory can be opened by CreateFile().
+ *
+ * So mkdirat_win32() has to use a directory handle instead of a directory fd.
+ */
+int mkdirat_win32(QemuFd_t dirfd, const char *pathname, mode_t mode)
+{
+    g_autofree char *full_file_name = NULL;
+    int ret = -1;
+
+    full_file_name = get_full_path_win32(dirfd, pathname);
+    if (full_file_name == NULL) {
+        return ret;
+    }
+
+    ret = mkdir(full_file_name);
+
+    return ret;
+}
+
+/*
+ * renameat_win32 - emulate renameat()
+ *
+ * This function emulates renameat().
+ *
+ * Windows POSIX API does not support openning a directory by open(). Only
+ * handle of directory can be opened by CreateFile().
+ *
+ * So renameat_win32() has to use a directory handle instead of a directory fd.
+ *
+ * Access to a symbolic link will be denied to prevent security issues.
+ */
+int renameat_win32(HANDLE olddirfd, const char *oldpath,
+                   HANDLE newdirfd, const char *newpath)
+{
+    g_autofree char *full_old_name = NULL;
+    g_autofree char *full_new_name = NULL;
+    HANDLE hFile;
+    DWORD attribute;
+    int err = 0;
+    int ret = -1;
+
+    full_old_name = get_full_path_win32(olddirfd, oldpath);
+    full_new_name = get_full_path_win32(newdirfd, newpath);
+    if (full_old_name == NULL || full_new_name == NULL) {
+        return ret;
+    }
+
+    /* open file to lock it */
+    hFile = CreateFile(full_old_name, GENERIC_READ,
+                       FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+                       NULL,
+                       OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+
+    attribute = GetFileAttributes(full_old_name);
+
+    /* check if it is a symbolic link */
+    if ((attribute == INVALID_FILE_ATTRIBUTES)
+        || (attribute & FILE_ATTRIBUTE_REPARSE_POINT) != 0) {
+        err = EACCES;
+        goto out;
+    }
+
+    CloseHandle(hFile);
+
+    ret = rename(full_old_name, full_new_name);
+out:
+    if (err != 0) {
+        errno = err;
+    }
+    return ret;
+}
+
+/*
+ * utimensat_win32 - emulate utimensat()
+ *
+ * This function emulates utimensat().
+ *
+ * Windows POSIX API does not support opening a directory by open(). Only
+ * handle of directory can be opened by CreateFile().
+ *
+ * So utimensat_win32() has to use a directory handle instead of a directory fd.
+ *
+ * Access to a symbolic link will be denied to prevent security issues.
+ */
+int utimensat_win32(QemuFd_t dirfd, const char *pathname,
+                    const struct timespec times[2], int flags)
+{
+    g_autofree char *full_file_name = NULL;
+    HANDLE hFile = INVALID_HANDLE_VALUE;
+    DWORD attribute;
+    struct utimbuf tm;
+    int err = 0;
+    int ret = -1;
+
+    full_file_name = get_full_path_win32(dirfd, pathname);
+    if (full_file_name == NULL) {
+        return ret;
+    }
+
+    /* open file to lock it */
+    hFile = CreateFile(full_file_name, GENERIC_READ,
+                       FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+                       NULL,
+                       OPEN_EXISTING,
+                       FILE_FLAG_BACKUP_SEMANTICS
+                       | FILE_FLAG_OPEN_REPARSE_POINT,
+                       NULL);
+
+    if (hFile == INVALID_HANDLE_VALUE) {
+        err = EACCES;
+        goto out;
+    }
+
+    attribute = GetFileAttributes(full_file_name);
+
+    /* check if it is a symbolic link */
+    if ((attribute == INVALID_FILE_ATTRIBUTES)
+        || (attribute & FILE_ATTRIBUTE_REPARSE_POINT) != 0) {
+        errno = EACCES;
+        goto out;
+    }
+
+    tm.actime = times[0].tv_sec;
+    tm.modtime = times[1].tv_sec;
+
+    ret = utime(full_file_name, &tm);
+
+out:
+    if (hFile != INVALID_HANDLE_VALUE) {
+        CloseHandle(hFile);
+    }
+
+    if (err != 0) {
+        errno = err;
+    }
+    return ret;
+}
+
+/*
+ * unlinkat_win32 - emulate unlinkat()
+ *
+ * This function emulates unlinkat().
+ *
+ * Windows POSIX API does not support opening a directory by open(). Only
+ * handle of directory can be opened by CreateFile().
+ *
+ * So unlinkat_win32() has to use a directory handle instead of a directory fd.
+ *
+ * Access to a symbolic link will be denied to prevent security issues.
+ */
+
+int unlinkat_win32(QemuFd_t dirfd, const char *pathname, int flags)
+{
+    g_autofree char *full_file_name = NULL;
+    HANDLE hFile;
+    DWORD attribute;
+    int err = 0;
+    int ret = -1;
+
+    full_file_name = get_full_path_win32(dirfd, pathname);
+    if (full_file_name == NULL) {
+        return ret;
+    }
+
+    /* open file to prevent other one modify it */
+    hFile = CreateFile(full_file_name, GENERIC_READ,
+                       FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+                       NULL,
+                       OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+
+    attribute = GetFileAttributes(full_file_name);
+
+    /* check if it is a symbolic link */
+    if ((attribute == INVALID_FILE_ATTRIBUTES)
+        || (attribute & FILE_ATTRIBUTE_REPARSE_POINT) != 0) {
+        err = EACCES;
+        goto out;
+    }
+
+    if (flags == AT_REMOVEDIR) { /* remove directory */
+        if ((attribute & FILE_ATTRIBUTE_DIRECTORY) == 0) {
+            err = ENOTDIR;
+            goto out;
+        }
+        ret = rmdir(full_file_name);
+    } else { /* remove regular file */
+        if ((attribute & FILE_ATTRIBUTE_DIRECTORY) != 0) {
+            err = EISDIR;
+            goto out;
+        }
+        ret = remove(full_file_name);
+    }
+
+    /* after last handle closed, file will be removed */
+    CloseHandle(hFile);
+
+out:
+    if (err != 0) {
+        errno = err;
+    }
+    return ret;
+}
+
+/*
+ * statfs_win32 - statfs() on Windows
+ *
+ * This function emulates statfs() on Windows host.
+ */
+int statfs_win32(const char *path, struct statfs *stbuf)
+{
+    char RealPath[4] = { 0 };
+    unsigned long SectorsPerCluster;
+    unsigned long BytesPerSector;
+    unsigned long NumberOfFreeClusters;
+    unsigned long TotalNumberOfClusters;
+
+    /* only need first 3 bytes, e.g. "C:\ABC", only need "C:\" */
+    memcpy(RealPath, path, 3);
+
+    if (GetDiskFreeSpace(RealPath, &SectorsPerCluster, &BytesPerSector,
+                         &NumberOfFreeClusters, &TotalNumberOfClusters) == 0) {
+        errno = EIO;
+        return -1;
+    }
+
+    stbuf->f_type = V9FS_MAGIC;
+    stbuf->f_bsize =
+        (__fsword_t)SectorsPerCluster * (__fsword_t)BytesPerSector;
+    stbuf->f_blocks = (fsblkcnt_t)TotalNumberOfClusters;
+    stbuf->f_bfree = (fsblkcnt_t)NumberOfFreeClusters;
+    stbuf->f_bavail = (fsblkcnt_t)NumberOfFreeClusters;
+    stbuf->f_files = -1;
+    stbuf->f_ffree = -1;
+    stbuf->f_namelen = NAME_MAX;
+    stbuf->f_frsize = 0;
+    stbuf->f_flags = 0;
+
+    return 0;
+}
+
+/*
+ * openat_dir - emulate openat_dir()
+ *
+ * This function emulates openat_dir().
+ *
+ * Windows POSIX API does not support opening a directory by open(). Only
+ * handle of directory can be opened by CreateFile().
+ *
+ * So openat_dir() has to use a directory handle instead of a directory fd.
+ *
+ * Access to a symbolic link will be denied to prevent security issues.
+ */
+QemuFd_t openat_dir(QemuFd_t dirfd, const char *name)
+{
+    g_autofree char *full_file_name = NULL;
+    HANDLE hSubDir;
+    DWORD attribute;
+
+    full_file_name = get_full_path_win32(dirfd, name);
+    if (full_file_name == NULL) {
+        return INVALID_HANDLE_VALUE;
+    }
+
+    attribute = GetFileAttributes(full_file_name);
+    if (attribute == INVALID_FILE_ATTRIBUTES) {
+        return INVALID_HANDLE_VALUE;
+    }
+
+    /* check if it is a directory */
+    if ((attribute & FILE_ATTRIBUTE_DIRECTORY) == 0) {
+        return INVALID_HANDLE_VALUE;
+    }
+
+    /* do not allow opening a symbolic link */
+    if ((attribute & FILE_ATTRIBUTE_REPARSE_POINT) != 0) {
+        return INVALID_HANDLE_VALUE;
+    }
+
+    /* open it */
+    hSubDir = CreateFile(full_file_name, GENERIC_READ,
+                         FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+                         NULL,
+                         OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+    return hSubDir;
+}
+
+QemuFd_t openat_file(QemuFd_t dirfd, const char *name, int flags,
+                     mode_t mode)
+{
+    return openat_win32(dirfd, name, flags | _O_BINARY, mode);
+}
+
+/*
+ * fgetxattrat_nofollow - get extended attribute
+ *
+ * This function gets extended attribute from file <path> in the directory
+ * specified by <dirfd>. The extended atrribute name is specified by <name>
+ * and return value will be put in <value>.
+ *
+ * This function emulates extended attribute by NTFS ADS.
+ */
+ssize_t fgetxattrat_nofollow(QemuFd_t dirfd, const char *path,
+                             const char *name, void *value, size_t size)
+{
+    g_autofree char *full_file_name = NULL;
+    char ads_file_name[NAME_MAX + 1] = { 0 };
+    DWORD dwBytesRead;
+    HANDLE hStream;
+
+    full_file_name = get_full_path_win32(dirfd, path);
+    if (full_file_name == NULL) {
+        errno = EIO;
+        return -1;
+    }
+
+    if (build_ads_name(ads_file_name, NAME_MAX, full_file_name, name) < 0) {
+        errno = EIO;
+        return -1;
+    }
+
+    hStream = CreateFile(ads_file_name, GENERIC_READ, FILE_SHARE_READ, NULL,
+                         OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+    if (hStream == INVALID_HANDLE_VALUE &&
+        GetLastError() == ERROR_FILE_NOT_FOUND) {
+        errno = ENODATA;
+        return -1;
+    }
+
+    if (ReadFile(hStream, value, size, &dwBytesRead, NULL) == FALSE) {
+        errno = EIO;
+        CloseHandle(hStream);
+        return -1;
+    }
+
+    CloseHandle(hStream);
+
+    return dwBytesRead;
+}
+
+/*
+ * fsetxattrat_nofollow - set extended attribute
+ *
+ * This function set extended attribute to file <path> in the directory
+ * specified by <dirfd>.
+ *
+ * This function emulates extended attribute by NTFS ADS.
+ */
+
+int fsetxattrat_nofollow(QemuFd_t dirfd, const char *path, const char *name,
+                         void *value, size_t size, int flags)
+{
+    g_autofree char *full_file_name = NULL;
+    char ads_file_name[NAME_MAX + 1] = { 0 };
+    DWORD dwBytesWrite;
+    HANDLE hStream;
+
+    full_file_name = get_full_path_win32(dirfd, path);
+    if (full_file_name == NULL) {
+        errno = EIO;
+        return -1;
+    }
+
+    if (build_ads_name(ads_file_name, NAME_MAX, full_file_name, name) < 0) {
+        errno = EIO;
+        return -1;
+    }
+
+    hStream = CreateFile(ads_file_name, GENERIC_WRITE, FILE_SHARE_READ, NULL,
+                         CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+    if (hStream == INVALID_HANDLE_VALUE) {
+        errno = EIO;
+        return -1;
+    }
+
+    if (WriteFile(hStream, value, size, &dwBytesWrite, NULL) == FALSE) {
+        errno = EIO;
+        CloseHandle(hStream);
+        return -1;
+    }
+
+    CloseHandle(hStream);
+
+    return 0;
+}
+
+/*
+ * flistxattrat_nofollow - list extended attribute
+ *
+ * This function gets extended attribute lists from file <filename> in the
+ * directory specified by <dirfd>. Lists returned will be put in <list>.
+ *
+ * This function emulates extended attribute by NTFS ADS.
+ */
+ssize_t flistxattrat_nofollow(QemuFd_t dirfd, const char *filename,
+                              char *list, size_t size)
+{
+    g_autofree char *full_file_name = NULL;
+    WCHAR WideCharStr[NAME_MAX + 1] = { 0 };
+    char full_ads_name[NAME_MAX + 1];
+    WIN32_FIND_STREAM_DATA fsd;
+    BOOL bFindNext;
+    char *list_ptr = list;
+    size_t list_left_size = size;
+    HANDLE hFind;
+    int ret;
+
+    full_file_name = get_full_path_win32(dirfd, filename);
+    if (full_file_name == NULL) {
+        errno = EIO;
+        return -1;
+    }
+
+    /*
+     * ADS enumerate function only has WCHAR version, so we need to
+     * covert filename to utf-8 string.
+     */
+    ret = MultiByteToWideChar(CP_UTF8, 0, full_file_name,
+                              strlen(full_file_name), WideCharStr, NAME_MAX);
+    if (ret == 0) {
+        errno = EIO;
+        return -1;
+    }
+
+    hFind = FindFirstStreamW(WideCharStr, FindStreamInfoStandard, &fsd, 0);
+    if (hFind == INVALID_HANDLE_VALUE) {
+        errno = ENODATA;
+        return -1;
+    }
+
+    do {
+        memset(full_ads_name, 0, sizeof(full_ads_name));
+
+        /*
+         * ADS enumerate function only has WCHAR version, so we need to
+         * covert cStreamName to utf-8 string.
+         */
+        ret = WideCharToMultiByte(CP_UTF8, 0,
+                                  fsd.cStreamName, wcslen(fsd.cStreamName) + 1,
+                                  full_ads_name, sizeof(full_ads_name) - 1,
+                                  NULL, NULL);
+        if (ret == 0) {
+            if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
+                errno = ERANGE;
+            }
+            CloseHandle(hFind);
+            return -1;
+        }
+
+        ret = copy_ads_name(list_ptr, list_left_size, full_ads_name);
+        if (ret < 0) {
+            errno = ERANGE;
+            CloseHandle(hFind);
+            return -1;
+        }
+
+        list_ptr = list_ptr + ret;
+        list_left_size = list_left_size - ret;
+
+        bFindNext = FindNextStreamW(hFind, &fsd);
+    } while (bFindNext);
+
+    CloseHandle(hFind);
+
+    return size - list_left_size;
+}
+
+/*
+ * fremovexattrat_nofollow - remove extended attribute
+ *
+ * This function removes an extended attribute from file <filename> in the
+ * directory specified by <dirfd>.
+ *
+ * This function emulates extended attribute by NTFS ADS.
+ */
+ssize_t fremovexattrat_nofollow(QemuFd_t dirfd, const char *filename,
+                                const char *name)
+{
+    g_autofree char *full_file_name = NULL;
+    char ads_file_name[NAME_MAX + 1] = { 0 };
+
+    full_file_name = get_full_path_win32(dirfd, filename);
+    if (full_file_name == NULL) {
+        errno = EIO;
+        return -1;
+    }
+
+    if (build_ads_name(ads_file_name, NAME_MAX, filename, name) < 0) {
+        errno = EIO;
+        return -1;
+    }
+
+    if (DeleteFile(ads_file_name) != 0) {
+        if (GetLastError() == ERROR_FILE_NOT_FOUND) {
+            errno = ENODATA;
+            return -1;
+        }
+    }
+
+    return 0;
+}
+
+/*
+ * local_opendir_nofollow - open a Windows directory
+ *
+ * This function returns a Windows file handle of the directory specified by
+ * <dirpath> based on 9pfs mount point.
+ *
+ * Windows POSIX API does not support opening a directory by open(). Only
+ * handle of directory can be opened by CreateFile().
+ *
+ * This function checks the resolved path of <dirpath>. If the resolved
+ * path is not in the scope of root directory (e.g. by symbolic link), then
+ * this function will fail to prevent any security issues.
+ */
+HANDLE local_opendir_nofollow(FsContext *fs_ctx, const char *dirpath)
+{
+    g_autofree char *full_file_name = NULL;
+    LocalData *data = fs_ctx->private;
+    HANDLE hDir;
+
+    hDir = openat_dir(data->mountfd, dirpath);
+    if (hDir == INVALID_HANDLE_VALUE) {
+        return INVALID_HANDLE_VALUE;
+    }
+
+    full_file_name = get_full_path_win32(hDir, NULL);
+    if (full_file_name == NULL) {
+        CloseHandle(hDir);
+        return INVALID_HANDLE_VALUE;
+    }
+
+    /*
+     * Check if the resolved path is in the root directory scope:
+     * data->root_path and full_file_name are full path with symbolic
+     * link resolved, so fs_ctx->root_path must be in the head of
+     * full_file_name. If not, that means guest OS tries to open a file not
+     * in the scope of mount point. This operation should be denied.
+     */
+    if (memcmp(full_file_name, data->root_path,
+               strlen(data->root_path)) != 0) {
+        CloseHandle(hDir);
+        hDir = INVALID_HANDLE_VALUE;
+    }
+
+    return hDir;
+}
+
+/*
+ * qemu_mknodat - mknodat emulate function
+ *
+ * This function emulates mknodat on Windows. It only works when security
+ * model is mapped or mapped-xattr.
+ */
+int qemu_mknodat(QemuFd_t dirfd, const char *filename, mode_t mode, dev_t dev)
+{
+    if (S_ISREG(mode) || !(mode & S_IFMT)) {
+        HANDLE hFile = openat_file(dirfd, filename, O_CREAT, mode);
+        if (hFile == INVALID_HANDLE_VALUE) {
+            return -1;
+        }
+        close_preserve_errno(hFile);
+        return 0;
+    }
+
+    error_report_once("Unsupported operation for mknodat");
+    errno = ENOTSUP;
+    return -1;
+}
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v2 08/19] hw/9pfs: Update the local fs driver to support Windows
  2022-11-11  4:22 [PATCH v2 00/19] At present there is no Windows support for 9p file system Bin Meng
                   ` (6 preceding siblings ...)
  2022-11-11  4:22 ` [PATCH v2 07/19] hw/9pfs: Implement Windows specific utilities functions for 9pfs Bin Meng
@ 2022-11-11  4:22 ` Bin Meng
  2022-11-11  4:22 ` [PATCH v2 09/19] hw/9pfs: Support getting current directory offset for Windows Bin Meng
                   ` (10 subsequent siblings)
  18 siblings, 0 replies; 36+ messages in thread
From: Bin Meng @ 2022-11-11  4:22 UTC (permalink / raw)
  To: qemu-devel; +Cc: Guohuai Shi, Christian Schoenebeck, Greg Kurz

From: Guohuai Shi <guohuai.shi@windriver.com>

Update the 9p 'local' file system driver to support Windows,
including open, read, write, close, rename, remove, etc.

All security models are supported. The mapped (mapped-xattr)
security model is implemented using NTFS Alternate Data Stream
(ADS) so the 9p export path shall be on an NTFS partition.

Symbolic link and hard link are not supported when security
model is "passthrough" or "none", because Windows NTFS does
not fully support them with POSIX compatibility. Symbolic
link is enabled when security model is "mapped-file" or
"mapped-xattr".

inode remap is always enabled because Windows file system
does not provide a compatible inode number.

mknod() is not supported because Windows does not support it.
chown() and chmod() are not supported when 9pfs is configured
with security mode to 'none' or 'passthrough' because Windows
host does not support such type request.

Signed-off-by: Guohuai Shi <guohuai.shi@windriver.com>
Signed-off-by: Bin Meng <bin.meng@windriver.com>

---

Changes in v2:
- Update to support symbolic link when applicable
- Warn user if a specific 9pfs operation is not supported

 hw/9pfs/9p-local.h |   1 +
 hw/9pfs/9p-local.c | 388 +++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 378 insertions(+), 11 deletions(-)

diff --git a/hw/9pfs/9p-local.h b/hw/9pfs/9p-local.h
index eb4f39ddc2..311067d9af 100644
--- a/hw/9pfs/9p-local.h
+++ b/hw/9pfs/9p-local.h
@@ -17,6 +17,7 @@ typedef struct {
     QemuFd_t mountfd;
 #ifdef CONFIG_WIN32
     char *root_path;
+    DWORD block_size;
 #endif
 } LocalData;
 
diff --git a/hw/9pfs/9p-local.c b/hw/9pfs/9p-local.c
index 24e21141d5..20e3091cd7 100644
--- a/hw/9pfs/9p-local.c
+++ b/hw/9pfs/9p-local.c
@@ -1,5 +1,5 @@
 /*
- * 9p Posix callback
+ * 9p callback
  *
  * Copyright IBM, Corp. 2010
  *
@@ -21,11 +21,13 @@
 #include "9p-xattr.h"
 #include "9p-util.h"
 #include "fsdev/qemu-fsdev.h"   /* local_ops */
+#ifndef CONFIG_WIN32
 #include <arpa/inet.h>
 #include <pwd.h>
 #include <grp.h>
 #include <sys/socket.h>
 #include <sys/un.h>
+#endif
 #include "qemu/xattr.h"
 #include "qapi/error.h"
 #include "qemu/cutils.h"
@@ -38,7 +40,9 @@
 #include <linux/magic.h>
 #endif
 #endif
+#ifndef CONFIG_WIN32
 #include <sys/ioctl.h>
+#endif
 
 #ifndef XFS_SUPER_MAGIC
 #define XFS_SUPER_MAGIC  0x58465342
@@ -90,10 +94,12 @@ QemuFd_t local_open_nofollow(FsContext *fs_ctx, const char *path, int flags,
     return fd;
 }
 
+#ifndef CONFIG_WIN32
 QemuFd_t local_opendir_nofollow(FsContext *fs_ctx, const char *path)
 {
     return local_open_nofollow(fs_ctx, path, O_DIRECTORY | O_RDONLY, 0);
 }
+#endif
 
 static void renameat_preserve_errno(QemuFd_t odirfd, const char *opath,
                                     QemuFd_t ndirfd, const char *npath)
@@ -135,10 +141,20 @@ static FILE *local_fopenat(QemuFd_t dirfd, const char *name, const char *mode)
     if (qemu_fd_invalid(fd)) {
         return NULL;
     }
+#ifdef CONFIG_WIN32
+    int _flags = mode[0] == 'r' ? O_RDONLY : 0;
+    int _fd = _open_osfhandle((intptr_t)fd, _flags);
+    assert(_fd != -1);
+    fp = fdopen(_fd, mode);
+    if (!fp) {
+        close(_fd);
+    }
+#else
     fp = fdopen(fd, mode);
     if (!fp) {
         close(fd);
     }
+#endif
     return fp;
 }
 
@@ -238,7 +254,7 @@ static int local_set_mapped_file_attrat(QemuFd_t dirfd, const char *name,
     int ret;
     char buf[ATTR_MAX];
     int uid = -1, gid = -1, mode = -1, rdev = -1;
-    QemuFd_t map_dirfd = QEMU_FD_INVALID, map_fd;
+    QemuFd_t map_dirfd = QEMU_FD_INVALID;
     bool is_root = !strcmp(name, ".");
 
     if (is_root) {
@@ -302,10 +318,12 @@ update_map_file:
         return -1;
     }
 
-    map_fd = fileno(fp);
+#ifndef CONFIG_WIN32
+    QemuFd_t map_fd = fileno(fp);
     assert(!qemu_fd_invalid(map_fd));
     ret = fchmod(map_fd, 0600);
     assert(ret == 0);
+#endif
 
     if (credp->fc_uid != -1) {
         uid = credp->fc_uid;
@@ -337,6 +355,7 @@ update_map_file:
     return 0;
 }
 
+#ifndef CONFIG_WIN32
 static int fchmodat_nofollow(QemuFd_t dirfd, const char *name, mode_t mode)
 {
     struct stat stbuf;
@@ -399,6 +418,7 @@ static int fchmodat_nofollow(QemuFd_t dirfd, const char *name, mode_t mode)
     close_preserve_errno(fd);
     return ret;
 }
+#endif
 
 static int local_set_xattrat(QemuFd_t dirfd, const char *path, FsCred *credp)
 {
@@ -439,6 +459,7 @@ static int local_set_xattrat(QemuFd_t dirfd, const char *path, FsCred *credp)
     return 0;
 }
 
+#ifndef CONFIG_WIN32
 static int local_set_cred_passthrough(FsContext *fs_ctx, QemuFd_t dirfd,
                                       const char *name, FsCred *credp)
 {
@@ -455,6 +476,7 @@ static int local_set_cred_passthrough(FsContext *fs_ctx, QemuFd_t dirfd,
 
     return fchmodat_nofollow(dirfd, name, credp->fc_mode & 07777);
 }
+#endif
 
 static ssize_t local_readlink(FsContext *fs_ctx, V9fsPath *fs_path,
                               char *buf, size_t bufsz)
@@ -464,17 +486,33 @@ static ssize_t local_readlink(FsContext *fs_ctx, V9fsPath *fs_path,
     if ((fs_ctx->export_flags & V9FS_SM_MAPPED) ||
         (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE)) {
         QemuFd_t fd;
+        int _fd;
 
         fd = local_open_nofollow(fs_ctx, fs_path->data, O_RDONLY, 0);
         if (qemu_fd_invalid(fd)) {
             return -1;
         }
+#ifdef CONFIG_WIN32
+        _fd = _open_osfhandle((intptr_t)fd, 0);
+#else
+        _fd = fd;
+#endif
         do {
-            tsize = read(fd, (void *)buf, bufsz);
+            tsize = read(_fd, (void *)buf, bufsz);
         } while (tsize == -1 && errno == EINTR);
+#ifdef CONFIG_WIN32
+        close(_fd);
+#else
         close_preserve_errno(fd);
+#endif
     } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
                (fs_ctx->export_flags & V9FS_SM_NONE)) {
+#ifdef CONFIG_WIN32
+        errno = ENOTSUP;
+        error_report_once("readlink is not available on Windows host when"
+                          "security_model is \"none\" or \"passthrough\"");
+        tsize = -1;
+#else
         char *dirpath = g_path_get_dirname(fs_path->data);
         char *name = g_path_get_basename(fs_path->data);
         QemuFd_t dirfd;
@@ -489,6 +527,7 @@ static ssize_t local_readlink(FsContext *fs_ctx, V9fsPath *fs_path,
     out:
         g_free(name);
         g_free(dirpath);
+#endif
     }
     return tsize;
 }
@@ -512,7 +551,13 @@ static int local_open(FsContext *ctx, V9fsPath *fs_path,
     if (qemu_fd_invalid(fd)) {
         return -1;
     }
+#ifdef CONFIG_WIN32
+    int _fd = _open_osfhandle((intptr_t)fd, 0);
+    assert(_fd != -1);
+    fs->fd = _fd;
+#else
     fs->fd = fd;
+#endif
     return fs->fd;
 }
 
@@ -527,9 +572,24 @@ static int local_opendir(FsContext *ctx,
         return -1;
     }
 
+#ifdef CONFIG_WIN32
+    char *full_file_name = get_full_path_win32(dirfd, NULL);
+    if (full_file_name == NULL) {
+        CloseHandle(dirfd);
+        return -1;
+    }
+    stream = opendir(full_file_name);
+    g_free(full_file_name);
+#else
     stream = fdopendir(dirfd);
+#endif
+
     if (!stream) {
+#ifdef CONFIG_WIN32
+        CloseHandle(dirfd);
+#else
         close(dirfd);
+#endif
         return -1;
     }
     fs->dir.stream = stream;
@@ -572,13 +632,17 @@ again:
 #endif
 
     if (ctx->export_flags & V9FS_SM_MAPPED) {
+#ifndef CONFIG_WIN32
         entry->d_type = DT_UNKNOWN;
+#endif
     } else if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
         if (local_is_mapped_file_metadata(ctx, entry->d_name)) {
             /* skip the meta data */
             goto again;
         }
+#ifndef CONFIG_WIN32
         entry->d_type = DT_UNKNOWN;
+#endif
     }
 
     return entry;
@@ -586,7 +650,94 @@ again:
 
 static void local_seekdir(FsContext *ctx, V9fsFidOpenState *fs, off_t off)
 {
+#ifndef CONFIG_WIN32
+    seekdir(fs->dir.stream, off);
+#else
+    off_t count;
+    struct dirent *findentry;
+    struct dirent *entry;
+    size_t namelen[3] = { 0 };
+    off_t direntoff[3] = { -1, -1, -1 };
+    char *d_name[3];
+    int i;
+
+    /*
+     * MinGW's seekdir() requires directory is not modified. If guest OS is
+     * modifying the directory when calling seekdir(), e.g.: "rm -rf *",
+     * then MinGW's seekdir() will seek to a wrong offset.
+     *
+     * This function saves some old offset directory entry name,
+     * and looks up current entry again, and compares the offset.
+     *
+     * If the new offset is less than the old offset, that means someone is
+     * deleting files in the directory, thus we need to seek offset backward.
+     *
+     * If the new offset is larger than the old offset, that means someone is
+     * creating files in the directory, thus we need to seek offset forward.
+     */
+
+    direntoff[0] = telldir(fs->dir.stream);
+
+    /* do nothing if current offset is 0 or EOF */
+    if (direntoff[0] == 0 || direntoff[0] < 0) {
+        seekdir(fs->dir.stream, off);
+        return;
+    }
+
+    d_name[0] = g_malloc0(sizeof(entry->d_name) * 3);
+    d_name[1] = d_name[0] + sizeof(entry->d_name);
+    d_name[2] = d_name[1] + sizeof(entry->d_name);
+
+    /* save 3 nearest entries and offsets */
+    for (i = 0; i < 3; i++) {
+        entry = &fs->dir.stream->dd_dir;
+
+        memcpy(d_name[i], entry->d_name, entry->d_namlen);
+        namelen[i] = strlen(d_name[i]) + 1;
+
+        direntoff[i] = telldir(fs->dir.stream);
+
+        entry = readdir(fs->dir.stream);
+        if (entry == NULL) {
+            break;
+        }
+    }
+
+    /* look up saved entries again */
+    for (i = 0; i < 3 && direntoff[i] != -1; i++) {
+        rewinddir(fs->dir.stream);
+        count = 0;
+        while ((findentry = readdir(fs->dir.stream)) != NULL) {
+            count++;
+
+            if (memcmp(findentry->d_name, d_name[i], namelen[i]) == 0) {
+                if (count + i == direntoff[i]) {
+                    seekdir(fs->dir.stream, off);
+                    goto out;
+                } else if (count + i < direntoff[i]) {
+                    off = off - (direntoff[i] - count) - i;
+                    if (off <= 0) {
+                        off = 0;
+                    }
+                    seekdir(fs->dir.stream, off);
+                    goto out;
+                } else {
+                    off = off + (count - direntoff[i]) - i;
+                    seekdir(fs->dir.stream, off);
+                    goto out;
+                }
+            }
+        }
+    }
+
+    /* cannot get anything, seek backward */
+    off = off - 1;
     seekdir(fs->dir.stream, off);
+
+out:
+    g_free(d_name[0]);
+    return;
+#endif
 }
 
 static ssize_t local_preadv(FsContext *ctx, V9fsFidOpenState *fs,
@@ -652,7 +803,14 @@ static int local_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
         ret = local_set_mapped_file_attrat(dirfd, name, credp);
     } else if (fs_ctx->export_flags & V9FS_SM_PASSTHROUGH ||
                fs_ctx->export_flags & V9FS_SM_NONE) {
+#ifdef CONFIG_WIN32
+        errno = ENOTSUP;
+        error_report_once("chmod is not available on Windows host when"
+                          "security_model is \"none\" or \"passthrough\"");
+        ret = -1;
+#else
         ret = fchmodat_nofollow(dirfd, name, credp->fc_mode);
+#endif
     }
     close_preserve_errno(dirfd);
 
@@ -696,6 +854,12 @@ static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path,
         }
     } else if (fs_ctx->export_flags & V9FS_SM_PASSTHROUGH ||
                fs_ctx->export_flags & V9FS_SM_NONE) {
+#ifdef CONFIG_WIN32
+        errno = ENOTSUP;
+        error_report_once("mknod is not available on Windows host when"
+                          "security_model is \"none\" or \"passthrough\"");
+        goto out;
+#else
         err = qemu_mknodat(dirfd, name, credp->fc_mode, credp->fc_rdev);
         if (err == -1) {
             goto out;
@@ -704,6 +868,7 @@ static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path,
         if (err == -1) {
             goto err_end;
         }
+#endif
     }
     goto out;
 
@@ -753,10 +918,12 @@ static int local_mkdir(FsContext *fs_ctx, V9fsPath *dir_path,
         if (err == -1) {
             goto out;
         }
+#ifndef CONFIG_WIN32
         err = local_set_cred_passthrough(fs_ctx, dirfd, name, credp);
         if (err == -1) {
             goto err_end;
         }
+#endif
     }
     goto out;
 
@@ -773,7 +940,12 @@ static int local_fstat(FsContext *fs_ctx, int fid_type,
     int err, fd;
 
     if (fid_type == P9_FID_DIR) {
+#ifdef CONFIG_WIN32
+        errno = ENOTSUP;
+        return -1;  /* Windows do not allow opening a directory by open() */
+#else
         fd = dirfd(fs->dir.stream);
+#endif
     } else {
         fd = fs->fd;
     }
@@ -825,10 +997,10 @@ static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
         return -1;
     }
 
-    /*
-     * Mark all the open to not follow symlinks
-     */
+#ifndef CONFIG_WIN32
+    /* Mark all the open to not follow symlinks */
     flags |= O_NOFOLLOW;
+#endif
 
     dirfd = local_opendir_nofollow(fs_ctx, dir_path->data);
     if (qemu_fd_invalid(dirfd)) {
@@ -858,13 +1030,22 @@ static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
         if (qemu_fd_invalid(fd)) {
             goto out;
         }
+#ifndef CONFIG_WIN32
         err = local_set_cred_passthrough(fs_ctx, dirfd, name, credp);
         if (err == -1) {
             goto err_end;
         }
+#endif
     }
+#ifdef CONFIG_WIN32
+    int _fd = _open_osfhandle((intptr_t)fd, 0);
+    assert(_fd != -1);
+    err = _fd;
+    fs->fd = _fd;
+#else
     err = fd;
     fs->fd = fd;
+#endif
     goto out;
 
 err_end:
@@ -898,6 +1079,7 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath,
     if (fs_ctx->export_flags & V9FS_SM_MAPPED ||
         fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
         QemuFd_t fd;
+        int _fd;
         ssize_t oldpath_size, write_size;
 
         fd = openat_file(dirfd, name, O_CREAT | O_EXCL | O_RDWR,
@@ -905,12 +1087,21 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath,
         if (qemu_fd_invalid(fd)) {
             goto out;
         }
+#ifdef CONFIG_WIN32
+        _fd = _open_osfhandle((intptr_t)fd, 0);
+#else
+        _fd = fd;
+#endif
         /* Write the oldpath (target) to the file. */
         oldpath_size = strlen(oldpath);
         do {
-            write_size = write(fd, (void *)oldpath, oldpath_size);
+            write_size = write(_fd, (void *)oldpath, oldpath_size);
         } while (write_size == -1 && errno == EINTR);
+#ifdef CONFIG_WIN32
+        close(_fd);
+#else
         close_preserve_errno(fd);
+#endif
 
         if (write_size != oldpath_size) {
             goto err_end;
@@ -928,6 +1119,21 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath,
         }
     } else if (fs_ctx->export_flags & V9FS_SM_PASSTHROUGH ||
                fs_ctx->export_flags & V9FS_SM_NONE) {
+#ifdef CONFIG_WIN32
+        /*
+         * Windows symbolic link requires administrator privilage.
+         * And Windows does not provide any interface like readlink().
+         * All symbolic links on Windows are always absolute paths.
+         * It's not 100% compatible with POSIX symbolic link.
+         *
+         * With above reasons, symbolic link with "passthrough" or "none"
+         * mode is disabled on Windows host.
+         */
+        errno = ENOTSUP;
+        error_report_once("symlink is not available on Windows host when"
+                          "security_model is \"none\" or \"passthrough\"");
+        goto out;
+#else
         err = symlinkat(oldpath, dirfd, name);
         if (err) {
             goto out;
@@ -945,6 +1151,7 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath,
                 err = 0;
             }
         }
+#endif
     }
     goto out;
 
@@ -958,6 +1165,11 @@ out:
 static int local_link(FsContext *ctx, V9fsPath *oldpath,
                       V9fsPath *dirpath, const char *name)
 {
+#ifdef CONFIG_WIN32
+    errno = ENOTSUP;
+    error_report_once("link is not available on Windows host");
+    return -1;
+#else
     char *odirpath = g_path_get_dirname(oldpath->data);
     char *oname = g_path_get_basename(oldpath->data);
     int ret = -1;
@@ -1027,6 +1239,7 @@ out:
     g_free(oname);
     g_free(odirpath);
     return ret;
+#endif
 }
 
 static int local_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size)
@@ -1038,7 +1251,13 @@ static int local_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size)
     if (qemu_fd_invalid(fd)) {
         return -1;
     }
+#ifdef CONFIG_WIN32
+    int _fd = _open_osfhandle((intptr_t)fd, 0);
+    assert(_fd != -1);
+    ret = ftruncate(_fd, size);
+#else
     ret = ftruncate(fd, size);
+#endif
     close_preserve_errno(fd);
     return ret;
 }
@@ -1058,8 +1277,15 @@ static int local_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
     if ((credp->fc_uid == -1 && credp->fc_gid == -1) ||
         (fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
         (fs_ctx->export_flags & V9FS_SM_NONE)) {
+#ifdef CONFIG_WIN32
+        errno = ENOTSUP;
+        error_report_once("chown is not available on Windows host when"
+                          "security_model is \"none\" or \"passthrough\"");
+        ret = -1;
+#else
         ret = fchownat(dirfd, name, credp->fc_uid, credp->fc_gid,
                        AT_SYMLINK_NOFOLLOW);
+#endif
     } else if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
         ret = local_set_xattrat(dirfd, name, credp);
     } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
@@ -1172,6 +1398,12 @@ out:
 static int local_fsync(FsContext *ctx, int fid_type,
                        V9fsFidOpenState *fs, int datasync)
 {
+#ifdef CONFIG_WIN32
+    if (fid_type != P9_FID_DIR) {
+        return _commit(fs->fd);
+    }
+    return 0;
+#else
     int fd;
 
     if (fid_type == P9_FID_DIR) {
@@ -1185,12 +1417,14 @@ static int local_fsync(FsContext *ctx, int fid_type,
     } else {
         return fsync(fd);
     }
+#endif
 }
 
 static int local_statfs(FsContext *s, V9fsPath *fs_path, struct statfs *stbuf)
 {
-    QemuFd_t fd;
     int ret;
+#ifndef CONFIG_WIN32
+    QemuFd_t fd;
 
     fd = local_open_nofollow(s, fs_path->data, O_RDONLY, 0);
     if (qemu_fd_invalid(fd)) {
@@ -1198,39 +1432,65 @@ static int local_statfs(FsContext *s, V9fsPath *fs_path, struct statfs *stbuf)
     }
     ret = fstatfs(fd, stbuf);
     close_preserve_errno(fd);
+#else
+    LocalData *data = (LocalData *)s->private;
+
+    ret = statfs_win32(data->root_path, stbuf);
+    if (ret == 0) {
+        /* use context address as fsid */
+        memcpy(&stbuf->f_fsid, s, sizeof(intptr_t));
+    }
+#endif
+
     return ret;
 }
 
 static ssize_t local_lgetxattr(FsContext *ctx, V9fsPath *fs_path,
                                const char *name, void *value, size_t size)
 {
+#ifdef CONFIG_WIN32
+    return -1;
+#else
     char *path = fs_path->data;
 
     return v9fs_get_xattr(ctx, path, name, value, size);
+#endif
 }
 
 static ssize_t local_llistxattr(FsContext *ctx, V9fsPath *fs_path,
                                 void *value, size_t size)
 {
+#ifdef CONFIG_WIN32
+    return -1;
+#else
     char *path = fs_path->data;
 
     return v9fs_list_xattr(ctx, path, value, size);
+#endif
 }
 
 static int local_lsetxattr(FsContext *ctx, V9fsPath *fs_path, const char *name,
                            void *value, size_t size, int flags)
 {
+#ifdef CONFIG_WIN32
+    return -1;
+#else
     char *path = fs_path->data;
 
     return v9fs_set_xattr(ctx, path, name, value, size, flags);
+#endif
 }
 
 static int local_lremovexattr(FsContext *ctx, V9fsPath *fs_path,
                               const char *name)
 {
+#ifdef CONFIG_WIN32
+    return -1;
+#else
     char *path = fs_path->data;
 
     return v9fs_remove_xattr(ctx, path, name);
+#endif
 }
 
 static int local_name_to_path(FsContext *ctx, V9fsPath *dir_path,
@@ -1393,6 +1653,7 @@ static int local_unlinkat(FsContext *ctx, V9fsPath *dir,
     return ret;
 }
 
+#ifndef CONFIG_WIN32
 #ifdef FS_IOC_GETVERSION
 static int local_ioc_getversion(FsContext *ctx, V9fsPath *path,
                                 mode_t st_mode, uint64_t *st_gen)
@@ -1442,11 +1703,88 @@ static int local_ioc_getversion_init(FsContext *ctx, LocalData *data, Error **er
 #endif
     return 0;
 }
+#endif
 
-static int local_init(FsContext *ctx, Error **errp)
+#ifdef CONFIG_WIN32
+static int init_win32_root_directory(FsContext *ctx, LocalData *data,
+                                     Error **errp)
 {
-    LocalData *data = g_malloc(sizeof(*data));
+    HANDLE mountfd;
+    char *root_path;
+    DWORD SectorsPerCluster;
+    DWORD BytesPerSector;
+    DWORD NumberOfFreeClusters;
+    DWORD TotalNumberOfClusters;
+    char disk_root[4] = { 0 };
+
+    mountfd = CreateFile(ctx->fs_root, GENERIC_READ,
+                         FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+                         NULL,
+                         OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+    if (mountfd == INVALID_HANDLE_VALUE) {
+        error_setg_errno(errp, EINVAL, "cannot open %s", ctx->fs_root);
+        return -1;
+    }
+
+    if ((ctx->export_flags & V9FS_SM_MAPPED) != 0) {
+        wchar_t fs_name[MAX_PATH + 1] = {0};
+        wchar_t ntfs_name[5] = {'N', 'T', 'F', 'S'};
 
+        /* Get file system type name */
+        if (GetVolumeInformationByHandleW(mountfd, NULL, 0, NULL, NULL, NULL,
+                                          fs_name, MAX_PATH + 1) == 0) {
+            error_setg_errno(errp, EINVAL,
+                             "cannot get file system information");
+            CloseHandle(mountfd);
+            return -1;
+        }
+
+        /*
+         * security_model=mapped(-xattr) requires a fileystem on Windows that
+         * supports Alternate Data Stream (ADS). NTFS is one of them, and is
+         * probably most popular on Windows. It is fair enough to assume
+         * Windows users to use NTFS for the mapped security model.
+         */
+        if (wcscmp(fs_name, ntfs_name) != 0) {
+            CloseHandle(mountfd);
+            error_setg_errno(errp, EINVAL, "require NTFS file system");
+            return -1;
+        }
+    }
+
+    root_path = get_full_path_win32(mountfd, NULL);
+    if (root_path == NULL) {
+        CloseHandle(mountfd);
+        error_setg_errno(errp, EINVAL, "cannot get full root path");
+        return -1;
+    }
+
+    /* copy the first 3 characters for the root directory */
+    memcpy(disk_root, root_path, 3);
+
+    if (GetDiskFreeSpace(disk_root, &SectorsPerCluster, &BytesPerSector,
+                         &NumberOfFreeClusters, &TotalNumberOfClusters) == 0) {
+        CloseHandle(mountfd);
+        error_setg_errno(errp, EINVAL, "cannot get file system block size");
+        return -1;
+    }
+
+    /*
+     * hold the root handle will prevent other one to delete or replace the
+     * root directory during runtime.
+     */
+    data->mountfd = mountfd;
+    data->root_path = root_path;
+    data->block_size = SectorsPerCluster * BytesPerSector;
+
+    return 0;
+}
+#endif
+
+static int local_init(FsContext *ctx, Error **errp)
+{
+    LocalData *data = g_malloc0(sizeof(*data));
+#ifndef CONFIG_WIN32
     data->mountfd = open(ctx->fs_root, O_DIRECTORY | O_RDONLY);
     if (qemu_fd_invalid(data->mountfd)) {
         error_setg_errno(errp, errno, "failed to open '%s'", ctx->fs_root);
@@ -1457,7 +1795,17 @@ static int local_init(FsContext *ctx, Error **errp)
         close(data->mountfd);
         goto err;
     }
+#else
+    if (init_win32_root_directory(ctx, data, errp) != 0) {
+        goto err;
+    }
 
+    /*
+     * Always enable inode remap since Windows file system does not
+     * have inode number.
+     */
+    ctx->export_flags |= V9FS_REMAP_INODES;
+#endif
     if (ctx->export_flags & V9FS_SM_PASSTHROUGH) {
         ctx->xops = passthrough_xattr_ops;
     } else if (ctx->export_flags & V9FS_SM_MAPPED) {
@@ -1477,6 +1825,15 @@ static int local_init(FsContext *ctx, Error **errp)
     return 0;
 
 err:
+#ifdef CONFIG_WIN32
+    if (data->root_path != NULL) {
+        g_free(data->root_path);
+    }
+
+    if (data->mountfd != 0 && data->mountfd != INVALID_HANDLE_VALUE) {
+        CloseHandle(data->mountfd);
+    }
+#endif
     g_free(data);
     return -1;
 }
@@ -1488,8 +1845,17 @@ static void local_cleanup(FsContext *ctx)
     if (!data) {
         return;
     }
+#ifdef CONFIG_WIN32
+    if (data->root_path != NULL) {
+        g_free(data->root_path);
+    }
 
+    if (data->mountfd != 0 && data->mountfd != INVALID_HANDLE_VALUE) {
+        CloseHandle(data->mountfd);
+    }
+#else
     close(data->mountfd);
+#endif
     g_free(data);
 }
 
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v2 09/19] hw/9pfs: Support getting current directory offset for Windows
  2022-11-11  4:22 [PATCH v2 00/19] At present there is no Windows support for 9p file system Bin Meng
                   ` (7 preceding siblings ...)
  2022-11-11  4:22 ` [PATCH v2 08/19] hw/9pfs: Update the local fs driver to support Windows Bin Meng
@ 2022-11-11  4:22 ` Bin Meng
  2022-11-11  4:22 ` [PATCH v2 10/19] hw/9pfs: Add a helper qemu_stat_rdev() Bin Meng
                   ` (9 subsequent siblings)
  18 siblings, 0 replies; 36+ messages in thread
From: Bin Meng @ 2022-11-11  4:22 UTC (permalink / raw)
  To: qemu-devel; +Cc: Guohuai Shi, Christian Schoenebeck, Greg Kurz

From: Guohuai Shi <guohuai.shi@windriver.com>

On Windows 'struct dirent' does not have current directory offset.
Update qemu_dirent_off() to support Windows.

While we are here, add a build time check to error out if a new
host does not implement this helper.

Signed-off-by: Guohuai Shi <guohuai.shi@windriver.com>
Signed-off-by: Bin Meng <bin.meng@windriver.com>

---

Changes in v2:
- Use qemu_dirent_off() directly instead of coroutine

 hw/9pfs/9p-util.h       | 11 ++++++++---
 hw/9pfs/9p-util-win32.c |  7 +++++++
 hw/9pfs/9p.c            |  4 ++--
 hw/9pfs/codir.c         |  2 +-
 4 files changed, 18 insertions(+), 6 deletions(-)

diff --git a/hw/9pfs/9p-util.h b/hw/9pfs/9p-util.h
index 5fb854bf61..892465b392 100644
--- a/hw/9pfs/9p-util.h
+++ b/hw/9pfs/9p-util.h
@@ -129,6 +129,7 @@ int statfs_win32(const char *root_path, struct statfs *stbuf);
 QemuFd_t openat_dir(QemuFd_t dirfd, const char *name);
 QemuFd_t openat_file(QemuFd_t dirfd, const char *name, int flags,
                      mode_t mode);
+off_t qemu_dirent_off_win32(void *s, void *fs);
 #endif
 
 static inline void close_preserve_errno(QemuFd_t fd)
@@ -207,12 +208,16 @@ ssize_t fremovexattrat_nofollow(QemuFd_t dirfd, const char *filename,
  * so ensure it is manually injected earlier and call here when
  * needed.
  */
-static inline off_t qemu_dirent_off(struct dirent *dent)
+static inline off_t qemu_dirent_off(struct dirent *dent, void *s, void *fs)
 {
-#ifdef CONFIG_DARWIN
+#if defined(CONFIG_DARWIN)
     return dent->d_seekoff;
-#else
+#elif defined(CONFIG_LINUX)
     return dent->d_off;
+#elif defined(CONFIG_WIN32)
+    return qemu_dirent_off_win32(s, fs);
+#else
+#error Missing qemu_dirent_off() implementation for this host system
 #endif
 }
 
diff --git a/hw/9pfs/9p-util-win32.c b/hw/9pfs/9p-util-win32.c
index ed3d519937..a8b8b8c832 100644
--- a/hw/9pfs/9p-util-win32.c
+++ b/hw/9pfs/9p-util-win32.c
@@ -932,3 +932,10 @@ int qemu_mknodat(QemuFd_t dirfd, const char *filename, mode_t mode, dev_t dev)
     errno = ENOTSUP;
     return -1;
 }
+
+off_t qemu_dirent_off_win32(void *s, void *fs)
+{
+    V9fsState *v9fs = s;
+
+    return v9fs->ops->telldir(&v9fs->ctx, (V9fsFidOpenState *)fs);
+}
diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c
index 072cf67956..be247eeb30 100644
--- a/hw/9pfs/9p.c
+++ b/hw/9pfs/9p.c
@@ -2336,7 +2336,7 @@ static int coroutine_fn v9fs_do_readdir_with_stat(V9fsPDU *pdu,
         count += len;
         v9fs_stat_free(&v9stat);
         v9fs_path_free(&path);
-        saved_dir_pos = qemu_dirent_off(dent);
+        saved_dir_pos = qemu_dirent_off(dent, pdu->s, &fidp->fs);
     }
 
     v9fs_readdir_unlock(&fidp->fs.dir);
@@ -2537,7 +2537,7 @@ static int coroutine_fn v9fs_do_readdir(V9fsPDU *pdu, V9fsFidState *fidp,
             qid.version = 0;
         }
 
-        off = qemu_dirent_off(dent);
+        off = qemu_dirent_off(dent, pdu->s, &fidp->fs);
         v9fs_string_init(&name);
         v9fs_string_sprintf(&name, "%s", dent->d_name);
 
diff --git a/hw/9pfs/codir.c b/hw/9pfs/codir.c
index 93ba44fb75..d40515a607 100644
--- a/hw/9pfs/codir.c
+++ b/hw/9pfs/codir.c
@@ -168,7 +168,7 @@ static int do_readdir_many(V9fsPDU *pdu, V9fsFidState *fidp,
         }
 
         size += len;
-        saved_dir_pos = qemu_dirent_off(dent);
+        saved_dir_pos = qemu_dirent_off(dent, s, &fidp->fs);
     }
 
     /* restore (last) saved position */
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v2 10/19] hw/9pfs: Add a helper qemu_stat_rdev()
  2022-11-11  4:22 [PATCH v2 00/19] At present there is no Windows support for 9p file system Bin Meng
                   ` (8 preceding siblings ...)
  2022-11-11  4:22 ` [PATCH v2 09/19] hw/9pfs: Support getting current directory offset for Windows Bin Meng
@ 2022-11-11  4:22 ` Bin Meng
  2022-11-11  4:22 ` [PATCH v2 11/19] hw/9pfs: Add a helper qemu_stat_blksize() Bin Meng
                   ` (8 subsequent siblings)
  18 siblings, 0 replies; 36+ messages in thread
From: Bin Meng @ 2022-11-11  4:22 UTC (permalink / raw)
  To: qemu-devel; +Cc: Guohuai Shi, Christian Schoenebeck, Greg Kurz

As Windows host does not have stat->st_rdev field, we use the first
3 characters of the root path to build a device id.

Add a helper qemu_stat_rdev() to use it to avoid direct access to
stat->st_rdev.

Co-developed-by: Guohuai Shi <guohuai.shi@windriver.com>
Signed-off-by: Bin Meng <bin.meng@windriver.com>

---

Changes in v2:
- new patch: "hw/9pfs: Add a helper qemu_stat_rdev()"

 hw/9pfs/9p-util.h       | 20 +++++++++++++++++---
 hw/9pfs/9p-util-win32.c | 15 +++++++++++++++
 hw/9pfs/9p.c            |  7 +++++--
 3 files changed, 37 insertions(+), 5 deletions(-)

diff --git a/hw/9pfs/9p-util.h b/hw/9pfs/9p-util.h
index 892465b392..c424cb00ca 100644
--- a/hw/9pfs/9p-util.h
+++ b/hw/9pfs/9p-util.h
@@ -19,7 +19,7 @@
 #define O_PATH_9P_UTIL 0
 #endif
 
-#if !defined(CONFIG_LINUX)
+#ifdef CONFIG_DARWIN
 
 /*
  * Generates a Linux device number (a.k.a. dev_t) for given device major
@@ -51,10 +51,12 @@ static inline uint64_t makedev_dotl(uint32_t dev_major, uint32_t dev_minor)
  */
 static inline uint64_t host_dev_to_dotl_dev(dev_t dev)
 {
-#ifdef CONFIG_LINUX
+#if defined(CONFIG_LINUX) || defined(CONFIG_WIN32)
     return dev;
-#else
+#elif defined(CONFIG_DARWIN)
     return makedev_dotl(major(dev), minor(dev));
+#else
+#error Missing host_dev_to_dotl_dev() implementation for this host system
 #endif
 }
 
@@ -130,6 +132,7 @@ QemuFd_t openat_dir(QemuFd_t dirfd, const char *name);
 QemuFd_t openat_file(QemuFd_t dirfd, const char *name, int flags,
                      mode_t mode);
 off_t qemu_dirent_off_win32(void *s, void *fs);
+uint64_t qemu_stat_rdev_win32(void *fs_ctx);
 #endif
 
 static inline void close_preserve_errno(QemuFd_t fd)
@@ -251,6 +254,17 @@ static inline struct dirent *qemu_dirent_dup(struct dirent *dent)
     return g_memdup(dent, sz);
 }
 
+static inline uint64_t qemu_stat_rdev(const struct stat *stbuf, void *fs_ctx)
+{
+#if defined(CONFIG_LINUX) || defined(CONFIG_DARWIN)
+    return stbuf->st_rdev;
+#elif defined(CONFIG_WIN32)
+    return qemu_stat_rdev_win32(fs_ctx);
+#else
+#error Missing qemu_stat_rdev() implementation for this host system
+#endif
+}
+
 /*
  * As long as mknodat is not available on macOS, this workaround
  * using pthread_fchdir_np is needed. qemu_mknodat is defined in
diff --git a/hw/9pfs/9p-util-win32.c b/hw/9pfs/9p-util-win32.c
index a8b8b8c832..44c10370ae 100644
--- a/hw/9pfs/9p-util-win32.c
+++ b/hw/9pfs/9p-util-win32.c
@@ -939,3 +939,18 @@ off_t qemu_dirent_off_win32(void *s, void *fs)
 
     return v9fs->ops->telldir(&v9fs->ctx, (V9fsFidOpenState *)fs);
 }
+
+uint64_t qemu_stat_rdev_win32(void *fs_ctx)
+{
+    uint64_t rdev = 0;
+    LocalData *data = ((FsContext *)fs_ctx)->private;
+
+    /*
+     * As Windows host does not have stat->st_rdev field, we use the first
+     * 3 characters of the root path to build a device id.
+     *
+     * (Windows root path always starts from a driver letter like "C:\")
+     */
+    memcpy(&rdev, data->root_path, 3);
+    return rdev;
+}
diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c
index be247eeb30..7080503b97 100644
--- a/hw/9pfs/9p.c
+++ b/hw/9pfs/9p.c
@@ -1266,7 +1266,8 @@ static int coroutine_fn stat_to_v9stat(V9fsPDU *pdu, V9fsPath *path,
     } else if (v9stat->mode & P9_STAT_MODE_DEVICE) {
         v9fs_string_sprintf(&v9stat->extension, "%c %u %u",
                 S_ISCHR(stbuf->st_mode) ? 'c' : 'b',
-                major(stbuf->st_rdev), minor(stbuf->st_rdev));
+                major(qemu_stat_rdev(stbuf, &pdu->s->ctx)),
+                minor(qemu_stat_rdev(stbuf, &pdu->s->ctx)));
     } else if (S_ISDIR(stbuf->st_mode) || S_ISREG(stbuf->st_mode)) {
         v9fs_string_sprintf(&v9stat->extension, "%s %lu",
                 "HARDLINKCOUNT", (unsigned long)stbuf->st_nlink);
@@ -1340,13 +1341,15 @@ static int32_t stat_to_iounit(const V9fsPDU *pdu, const struct stat *stbuf)
 static int stat_to_v9stat_dotl(V9fsPDU *pdu, const struct stat *stbuf,
                                 V9fsStatDotl *v9lstat)
 {
+    dev_t rdev = qemu_stat_rdev(stbuf, &pdu->s->ctx);
+
     memset(v9lstat, 0, sizeof(*v9lstat));
 
     v9lstat->st_mode = stbuf->st_mode;
     v9lstat->st_nlink = stbuf->st_nlink;
     v9lstat->st_uid = stbuf->st_uid;
     v9lstat->st_gid = stbuf->st_gid;
-    v9lstat->st_rdev = host_dev_to_dotl_dev(stbuf->st_rdev);
+    v9lstat->st_rdev = host_dev_to_dotl_dev(rdev);
     v9lstat->st_size = stbuf->st_size;
     v9lstat->st_blksize = stat_to_iounit(pdu, stbuf);
     v9lstat->st_blocks = stbuf->st_blocks;
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v2 11/19] hw/9pfs: Add a helper qemu_stat_blksize()
  2022-11-11  4:22 [PATCH v2 00/19] At present there is no Windows support for 9p file system Bin Meng
                   ` (9 preceding siblings ...)
  2022-11-11  4:22 ` [PATCH v2 10/19] hw/9pfs: Add a helper qemu_stat_rdev() Bin Meng
@ 2022-11-11  4:22 ` Bin Meng
  2022-11-11  4:22 ` [PATCH v2 12/19] hw/9pfs: Disable unsupported flags and features for Windows Bin Meng
                   ` (7 subsequent siblings)
  18 siblings, 0 replies; 36+ messages in thread
From: Bin Meng @ 2022-11-11  4:22 UTC (permalink / raw)
  To: qemu-devel; +Cc: Guohuai Shi, Christian Schoenebeck, Greg Kurz

As Windows host does not have stat->st_blksize field, we use the one
we calculated in init_win32_root_directory().

Add a helper qemu_stat_blksize() and use it to avoid direct access to
stat->st_blksize.

Co-developed-by: Guohuai Shi <guohuai.shi@windriver.com>
Signed-off-by: Bin Meng <bin.meng@windriver.com>

---

Changes in v2:
- new patch: "hw/9pfs: Add a helper qemu_stat_blksize()"

 hw/9pfs/9p-util.h       | 12 ++++++++++++
 hw/9pfs/9p-util-win32.c |  7 +++++++
 hw/9pfs/9p.c            |  7 ++++++-
 3 files changed, 25 insertions(+), 1 deletion(-)

diff --git a/hw/9pfs/9p-util.h b/hw/9pfs/9p-util.h
index c424cb00ca..df84374b78 100644
--- a/hw/9pfs/9p-util.h
+++ b/hw/9pfs/9p-util.h
@@ -133,6 +133,7 @@ QemuFd_t openat_file(QemuFd_t dirfd, const char *name, int flags,
                      mode_t mode);
 off_t qemu_dirent_off_win32(void *s, void *fs);
 uint64_t qemu_stat_rdev_win32(void *fs_ctx);
+uint64_t qemu_stat_blksize_win32(void *fs_ctx);
 #endif
 
 static inline void close_preserve_errno(QemuFd_t fd)
@@ -265,6 +266,17 @@ static inline uint64_t qemu_stat_rdev(const struct stat *stbuf, void *fs_ctx)
 #endif
 }
 
+static inline uint64_t qemu_stat_blksize(const struct stat *stbuf, void *fs_ctx)
+{
+#if defined(CONFIG_LINUX) || defined(CONFIG_DARWIN)
+    return stbuf->st_blksize;
+#elif defined(CONFIG_WIN32)
+    return qemu_stat_blksize_win32(fs_ctx);
+#else
+#error Missing qemu_stat_blksize() implementation for this host system
+#endif
+}
+
 /*
  * As long as mknodat is not available on macOS, this workaround
  * using pthread_fchdir_np is needed. qemu_mknodat is defined in
diff --git a/hw/9pfs/9p-util-win32.c b/hw/9pfs/9p-util-win32.c
index 44c10370ae..064f878e5e 100644
--- a/hw/9pfs/9p-util-win32.c
+++ b/hw/9pfs/9p-util-win32.c
@@ -954,3 +954,10 @@ uint64_t qemu_stat_rdev_win32(void *fs_ctx)
     memcpy(&rdev, data->root_path, 3);
     return rdev;
 }
+
+uint64_t qemu_stat_blksize_win32(void *fs_ctx)
+{
+    LocalData *data = ((FsContext *)fs_ctx)->private;
+
+    return (uint64_t)data->block_size;
+}
diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c
index 7080503b97..169578cc1d 100644
--- a/hw/9pfs/9p.c
+++ b/hw/9pfs/9p.c
@@ -1335,7 +1335,7 @@ static int32_t blksize_to_iounit(const V9fsPDU *pdu, int32_t blksize)
 
 static int32_t stat_to_iounit(const V9fsPDU *pdu, const struct stat *stbuf)
 {
-    return blksize_to_iounit(pdu, stbuf->st_blksize);
+    return blksize_to_iounit(pdu, qemu_stat_blksize(stbuf, &pdu->s->ctx));
 }
 
 static int stat_to_v9stat_dotl(V9fsPDU *pdu, const struct stat *stbuf,
@@ -1352,7 +1352,12 @@ static int stat_to_v9stat_dotl(V9fsPDU *pdu, const struct stat *stbuf,
     v9lstat->st_rdev = host_dev_to_dotl_dev(rdev);
     v9lstat->st_size = stbuf->st_size;
     v9lstat->st_blksize = stat_to_iounit(pdu, stbuf);
+#if defined(CONFIG_LINUX) || defined(CONFIG_DARWIN)
     v9lstat->st_blocks = stbuf->st_blocks;
+#elif defined(CONFIG_WIN32)
+    v9lstat->st_blocks = ROUND_UP(v9lstat->st_size / v9lstat->st_blksize,
+                                  v9lstat->st_blksize);
+#endif
     v9lstat->st_atime_sec = stbuf->st_atime;
     v9lstat->st_mtime_sec = stbuf->st_mtime;
     v9lstat->st_ctime_sec = stbuf->st_ctime;
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v2 12/19] hw/9pfs: Disable unsupported flags and features for Windows
  2022-11-11  4:22 [PATCH v2 00/19] At present there is no Windows support for 9p file system Bin Meng
                   ` (10 preceding siblings ...)
  2022-11-11  4:22 ` [PATCH v2 11/19] hw/9pfs: Add a helper qemu_stat_blksize() Bin Meng
@ 2022-11-11  4:22 ` Bin Meng
  2022-11-11  4:22 ` [PATCH v2 13/19] hw/9pfs: Update v9fs_set_fd_limit() " Bin Meng
                   ` (6 subsequent siblings)
  18 siblings, 0 replies; 36+ messages in thread
From: Bin Meng @ 2022-11-11  4:22 UTC (permalink / raw)
  To: qemu-devel; +Cc: Guohuai Shi, Christian Schoenebeck, Greg Kurz

From: Guohuai Shi <guohuai.shi@windriver.com>

Some flags and features are not supported on Windows, like mknod,
readlink, file mode, etc. Update the codes for Windows.

Signed-off-by: Guohuai Shi <guohuai.shi@windriver.com>
Signed-off-by: Bin Meng <bin.meng@windriver.com>

---

Changes in v2:
- Use precise platform check in ifdefs to avoid automatically
  opting-out other future platforms unintentionally

 hw/9pfs/9p.c | 45 ++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 38 insertions(+), 7 deletions(-)

diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c
index 169578cc1d..0b5e1fa8d2 100644
--- a/hw/9pfs/9p.c
+++ b/hw/9pfs/9p.c
@@ -39,6 +39,11 @@
 #include "qemu/xxhash.h"
 #include <math.h>
 
+#ifdef CONFIG_WIN32
+#define UTIME_NOW   ((1l << 30) - 1l)
+#define UTIME_OMIT  ((1l << 30) - 2l)
+#endif
+
 int open_fd_hw;
 int total_open_fd;
 static int open_fd_rc;
@@ -132,13 +137,17 @@ static int dotl_to_open_flags(int flags)
     DotlOpenflagMap dotl_oflag_map[] = {
         { P9_DOTL_CREATE, O_CREAT },
         { P9_DOTL_EXCL, O_EXCL },
+#ifndef CONFIG_WIN32
         { P9_DOTL_NOCTTY , O_NOCTTY },
+#endif
         { P9_DOTL_TRUNC, O_TRUNC },
         { P9_DOTL_APPEND, O_APPEND },
+#ifndef CONFIG_WIN32
         { P9_DOTL_NONBLOCK, O_NONBLOCK } ,
         { P9_DOTL_DSYNC, O_DSYNC },
         { P9_DOTL_FASYNC, FASYNC },
-#ifndef CONFIG_DARWIN
+#endif
+#if !defined(CONFIG_DARWIN) && !defined(CONFIG_WIN32)
         { P9_DOTL_NOATIME, O_NOATIME },
         /*
          *  On Darwin, we could map to F_NOCACHE, which is
@@ -151,8 +160,10 @@ static int dotl_to_open_flags(int flags)
 #endif
         { P9_DOTL_LARGEFILE, O_LARGEFILE },
         { P9_DOTL_DIRECTORY, O_DIRECTORY },
+#ifndef CONFIG_WIN32
         { P9_DOTL_NOFOLLOW, O_NOFOLLOW },
         { P9_DOTL_SYNC, O_SYNC },
+#endif
     };
 
     for (i = 0; i < ARRAY_SIZE(dotl_oflag_map); i++) {
@@ -179,8 +190,11 @@ static int get_dotl_openflags(V9fsState *s, int oflags)
      * Filter the client open flags
      */
     flags = dotl_to_open_flags(oflags);
-    flags &= ~(O_NOCTTY | O_ASYNC | O_CREAT);
-#ifndef CONFIG_DARWIN
+    flags &= ~(O_CREAT);
+#ifndef CONFIG_WIN32
+    flags &= ~(O_NOCTTY | O_ASYNC);
+#endif
+#if !defined(CONFIG_DARWIN) && !defined(CONFIG_WIN32)
     /*
      * Ignore direct disk access hint until the server supports it.
      */
@@ -1117,12 +1131,14 @@ static mode_t v9mode_to_mode(uint32_t mode, V9fsString *extension)
     if (mode & P9_STAT_MODE_SYMLINK) {
         ret |= S_IFLNK;
     }
+#ifndef CONFIG_WIN32
     if (mode & P9_STAT_MODE_SOCKET) {
         ret |= S_IFSOCK;
     }
     if (mode & P9_STAT_MODE_NAMED_PIPE) {
         ret |= S_IFIFO;
     }
+#endif
     if (mode & P9_STAT_MODE_DEVICE) {
         if (extension->size && extension->data[0] == 'c') {
             ret |= S_IFCHR;
@@ -1203,6 +1219,7 @@ static uint32_t stat_to_v9mode(const struct stat *stbuf)
         mode |= P9_STAT_MODE_SYMLINK;
     }
 
+#ifndef CONFIG_WIN32
     if (S_ISSOCK(stbuf->st_mode)) {
         mode |= P9_STAT_MODE_SOCKET;
     }
@@ -1210,6 +1227,7 @@ static uint32_t stat_to_v9mode(const struct stat *stbuf)
     if (S_ISFIFO(stbuf->st_mode)) {
         mode |= P9_STAT_MODE_NAMED_PIPE;
     }
+#endif
 
     if (S_ISBLK(stbuf->st_mode) || S_ISCHR(stbuf->st_mode)) {
         mode |= P9_STAT_MODE_DEVICE;
@@ -1365,7 +1383,8 @@ static int stat_to_v9stat_dotl(V9fsPDU *pdu, const struct stat *stbuf,
     v9lstat->st_atime_nsec = stbuf->st_atimespec.tv_nsec;
     v9lstat->st_mtime_nsec = stbuf->st_mtimespec.tv_nsec;
     v9lstat->st_ctime_nsec = stbuf->st_ctimespec.tv_nsec;
-#else
+#endif
+#ifdef CONFIG_LINUX
     v9lstat->st_atime_nsec = stbuf->st_atim.tv_nsec;
     v9lstat->st_mtime_nsec = stbuf->st_mtim.tv_nsec;
     v9lstat->st_ctime_nsec = stbuf->st_ctim.tv_nsec;
@@ -2488,6 +2507,7 @@ static int coroutine_fn v9fs_do_readdir(V9fsPDU *pdu, V9fsFidState *fidp,
     struct dirent *dent;
     struct stat *st;
     struct V9fsDirEnt *entries = NULL;
+    unsigned char d_type = 0;
 
     /*
      * inode remapping requires the device id, which in turn might be
@@ -2549,10 +2569,13 @@ static int coroutine_fn v9fs_do_readdir(V9fsPDU *pdu, V9fsFidState *fidp,
         v9fs_string_init(&name);
         v9fs_string_sprintf(&name, "%s", dent->d_name);
 
+#ifndef CONFIG_WIN32
+        d_type = dent->d_type;
+#endif
         /* 11 = 7 + 4 (7 = start offset, 4 = space for storing count) */
         len = pdu_marshal(pdu, 11 + count, "Qqbs",
                           &qid, off,
-                          dent->d_type, &name);
+                          d_type, &name);
 
         v9fs_string_free(&name);
 
@@ -2908,8 +2931,12 @@ static void coroutine_fn v9fs_create(void *opaque)
         v9fs_path_copy(&fidp->path, &path);
         v9fs_path_unlock(s);
     } else if (perm & P9_STAT_MODE_SOCKET) {
+#ifndef CONFIG_WIN32
         err = v9fs_co_mknod(pdu, fidp, &name, fidp->uid, -1,
                             0, S_IFSOCK | (perm & 0777), &stbuf);
+#else
+        err = -ENOTSUP;
+#endif
         if (err < 0) {
             goto out;
         }
@@ -3979,7 +4006,7 @@ out_nofid:
 #if defined(CONFIG_LINUX)
 /* Currently, only Linux has XATTR_SIZE_MAX */
 #define P9_XATTR_SIZE_MAX XATTR_SIZE_MAX
-#elif defined(CONFIG_DARWIN)
+#elif defined(CONFIG_DARWIN) || defined(CONFIG_WIN32)
 /*
  * Darwin doesn't seem to define a maximum xattr size in its user
  * space header, so manually configure it across platforms as 64k.
@@ -3996,6 +4023,8 @@ out_nofid:
 
 static void coroutine_fn v9fs_xattrcreate(void *opaque)
 {
+    V9fsPDU *pdu = opaque;
+#ifndef CONFIG_WIN32
     int flags, rflags = 0;
     int32_t fid;
     uint64_t size;
@@ -4004,7 +4033,6 @@ static void coroutine_fn v9fs_xattrcreate(void *opaque)
     size_t offset = 7;
     V9fsFidState *file_fidp;
     V9fsFidState *xattr_fidp;
-    V9fsPDU *pdu = opaque;
 
     v9fs_string_init(&name);
     err = pdu_unmarshal(pdu, offset, "dsqd", &fid, &name, &size, &flags);
@@ -4057,6 +4085,9 @@ out_put_fid:
 out_nofid:
     pdu_complete(pdu, err);
     v9fs_string_free(&name);
+#else
+    pdu_complete(pdu, -1);
+#endif
 }
 
 static void coroutine_fn v9fs_readlink(void *opaque)
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v2 13/19] hw/9pfs: Update v9fs_set_fd_limit() for Windows
  2022-11-11  4:22 [PATCH v2 00/19] At present there is no Windows support for 9p file system Bin Meng
                   ` (11 preceding siblings ...)
  2022-11-11  4:22 ` [PATCH v2 12/19] hw/9pfs: Disable unsupported flags and features for Windows Bin Meng
@ 2022-11-11  4:22 ` Bin Meng
  2022-11-11  4:22 ` [PATCH v2 14/19] hw/9pfs: Add Linux error number definition Bin Meng
                   ` (5 subsequent siblings)
  18 siblings, 0 replies; 36+ messages in thread
From: Bin Meng @ 2022-11-11  4:22 UTC (permalink / raw)
  To: qemu-devel; +Cc: Guohuai Shi, Christian Schoenebeck, Greg Kurz

From: Guohuai Shi <guohuai.shi@windriver.com>

Use _getmaxstdio() to set the fd limit on Windows.

Signed-off-by: Guohuai Shi <guohuai.shi@windriver.com>
Signed-off-by: Bin Meng <bin.meng@windriver.com>

---

Changes in v2:
- new patch: "hw/9pfs: Update v9fs_set_fd_limit() for Windows"

 hw/9pfs/9p.c | 23 ++++++++++++++++++++---
 1 file changed, 20 insertions(+), 3 deletions(-)

diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c
index 0b5e1fa8d2..be1d2a4f04 100644
--- a/hw/9pfs/9p.c
+++ b/hw/9pfs/9p.c
@@ -4392,11 +4392,28 @@ void v9fs_reset(V9fsState *s)
 
 static void __attribute__((__constructor__)) v9fs_set_fd_limit(void)
 {
+    int rlim_cur;
+    int ret;
+
+#ifndef CONFIG_WIN32
     struct rlimit rlim;
-    if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) {
+    ret = getrlimit(RLIMIT_NOFILE, &rlim);
+    rlim_cur = rlim.rlim_cur;
+#else
+    /*
+     * On Windows host, _getmaxstdio() actually returns the number of max
+     * open files at the stdio level. It *may* be smaller than the number
+     * of open files by open() or CreateFile().
+     */
+    ret = _getmaxstdio();
+    rlim_cur = ret;
+#endif
+
+    if (ret < 0) {
         error_report("Failed to get the resource limit");
         exit(1);
     }
-    open_fd_hw = rlim.rlim_cur - MIN(400, rlim.rlim_cur / 3);
-    open_fd_rc = rlim.rlim_cur / 2;
+
+    open_fd_hw = rlim_cur - MIN(400, rlim_cur / 3);
+    open_fd_rc = rlim_cur / 2;
 }
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v2 14/19] hw/9pfs: Add Linux error number definition
  2022-11-11  4:22 [PATCH v2 00/19] At present there is no Windows support for 9p file system Bin Meng
                   ` (12 preceding siblings ...)
  2022-11-11  4:22 ` [PATCH v2 13/19] hw/9pfs: Update v9fs_set_fd_limit() " Bin Meng
@ 2022-11-11  4:22 ` Bin Meng
  2022-11-11  4:22 ` [PATCH v2 15/19] hw/9pfs: Translate Windows errno to Linux value Bin Meng
                   ` (4 subsequent siblings)
  18 siblings, 0 replies; 36+ messages in thread
From: Bin Meng @ 2022-11-11  4:22 UTC (permalink / raw)
  To: qemu-devel; +Cc: Guohuai Shi, Christian Schoenebeck, Greg Kurz

From: Guohuai Shi <guohuai.shi@windriver.com>

When using 9p2000.L protocol, the errno should use the Linux errno.
Currently magic numbers with comments are used. Replace these with
macros for future expansion.

Signed-off-by: Guohuai Shi <guohuai.shi@windriver.com>
Signed-off-by: Bin Meng <bin.meng@windriver.com>

---

Changes in v2:
- Use a more compact solution in the switch..case.. block

 hw/9pfs/9p-linux-errno.h | 151 +++++++++++++++++++++++++++++++++++++++
 hw/9pfs/9p-util.h        |  25 ++++---
 2 files changed, 163 insertions(+), 13 deletions(-)
 create mode 100644 hw/9pfs/9p-linux-errno.h

diff --git a/hw/9pfs/9p-linux-errno.h b/hw/9pfs/9p-linux-errno.h
new file mode 100644
index 0000000000..56c37fa293
--- /dev/null
+++ b/hw/9pfs/9p-linux-errno.h
@@ -0,0 +1,151 @@
+/*
+ * 9p Linux errno translation definition
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include <errno.h>
+
+#ifndef QEMU_9P_LINUX_ERRNO_H
+#define QEMU_9P_LINUX_ERRNO_H
+
+/*
+ * This file contains the Linux errno definitions to translate errnos set by
+ * the 9P server (running on non-Linux hosts) to a corresponding errno value.
+ *
+ * This list should be periodically reviewed and updated; particularly for
+ * errnos that might be set as a result of a file system operation.
+ */
+
+#define L_EPERM             1   /* Operation not permitted */
+#define L_ENOENT            2   /* No such file or directory */
+#define L_ESRCH             3   /* No such process */
+#define L_EINTR             4   /* Interrupted system call */
+#define L_EIO               5   /* I/O error */
+#define L_ENXIO             6   /* No such device or address */
+#define L_E2BIG             7   /* Argument list too long */
+#define L_ENOEXEC           8   /* Exec format error */
+#define L_EBADF             9   /* Bad file number */
+#define L_ECHILD            10  /* No child processes */
+#define L_EAGAIN            11  /* Try again */
+#define L_ENOMEM            12  /* Out of memory */
+#define L_EACCES            13  /* Permission denied */
+#define L_EFAULT            14  /* Bad address */
+#define L_ENOTBLK           15  /* Block device required */
+#define L_EBUSY             16  /* Device or resource busy */
+#define L_EEXIST            17  /* File exists */
+#define L_EXDEV             18  /* Cross-device link */
+#define L_ENODEV            19  /* No such device */
+#define L_ENOTDIR           20  /* Not a directory */
+#define L_EISDIR            21  /* Is a directory */
+#define L_EINVAL            22  /* Invalid argument */
+#define L_ENFILE            23  /* File table overflow */
+#define L_EMFILE            24  /* Too many open files */
+#define L_ENOTTY            25  /* Not a typewriter */
+#define L_ETXTBSY           26  /* Text file busy */
+#define L_EFBIG             27  /* File too large */
+#define L_ENOSPC            28  /* No space left on device */
+#define L_ESPIPE            29  /* Illegal seek */
+#define L_EROFS             30  /* Read-only file system */
+#define L_EMLINK            31  /* Too many links */
+#define L_EPIPE             32  /* Broken pipe */
+#define L_EDOM              33  /* Math argument out of domain of func */
+#define L_ERANGE            34  /* Math result not representable */
+#define L_EDEADLK           35  /* Resource deadlock would occur */
+#define L_ENAMETOOLONG      36  /* File name too long */
+#define L_ENOLCK            37  /* No record locks available */
+#define L_ENOSYS            38  /* Function not implemented */
+#define L_ENOTEMPTY         39  /* Directory not empty */
+#define L_ELOOP             40  /* Too many symbolic links encountered */
+#define L_ENOMSG            42  /* No message of desired type */
+#define L_EIDRM             43  /* Identifier removed */
+#define L_ECHRNG            44  /* Channel number out of range */
+#define L_EL2NSYNC          45  /* Level 2 not synchronized */
+#define L_EL3HLT            46  /* Level 3 halted */
+#define L_EL3RST            47  /* Level 3 reset */
+#define L_ELNRNG            48  /* Link number out of range */
+#define L_EUNATCH           49  /* Protocol driver not attached */
+#define L_ENOCSI            50  /* No CSI structure available */
+#define L_EL2HLT            51  /* Level 2 halted */
+#define L_EBADE             52  /* Invalid exchange */
+#define L_EBADR             53  /* Invalid request descriptor */
+#define L_EXFULL            54  /* Exchange full */
+#define L_ENOANO            55  /* No anode */
+#define L_EBADRQC           56  /* Invalid request code */
+#define L_EBADSLT           57  /* Invalid slot */
+#define L_EBFONT            58  /* Bad font file format */
+#define L_ENOSTR            59  /* Device not a stream */
+#define L_ENODATA           61  /* No data available */
+#define L_ETIME             62  /* Timer expired */
+#define L_ENOSR             63  /* Out of streams resources */
+#define L_ENONET            64  /* Machine is not on the network */
+#define L_ENOPKG            65  /* Package not installed */
+#define L_EREMOTE           66  /* Object is remote */
+#define L_ENOLINK           67  /* Link has been severed */
+#define L_EADV              68  /* Advertise error */
+#define L_ESRMNT            69  /* Srmount error */
+#define L_ECOMM             70  /* Communication error on send */
+#define L_EPROTO            71  /* Protocol error */
+#define L_EMULTIHOP         72  /* Multihop attempted */
+#define L_EDOTDOT           73  /* RFS specific error */
+#define L_EBADMSG           74  /* Not a data message */
+#define L_EOVERFLOW         75  /* Value too large for defined data type */
+#define L_ENOTUNIQ          76  /* Name not unique on network */
+#define L_EBADFD            77  /* File descriptor in bad state */
+#define L_EREMCHG           78  /* Remote address changed */
+#define L_ELIBACC           79  /* Can not access a needed shared library */
+#define L_ELIBBAD           80  /* Accessing a corrupted shared library */
+#define L_ELIBSCN           81  /* .lib section in a.out corrupted */
+#define L_ELIBMAX           82  /* Attempting to link in too many shared libs */
+#define L_ELIBEXEC          83  /* Cannot exec a shared library directly */
+#define L_EILSEQ            84  /* Illegal byte sequence */
+#define L_ERESTART          85  /* Interrupted system call should be restarted */
+#define L_ESTRPIPE          86  /* Streams pipe error */
+#define L_EUSERS            87  /* Too many users */
+#define L_ENOTSOCK          88  /* Socket operation on non-socket */
+#define L_EDESTADDRREQ      89  /* Destination address required */
+#define L_EMSGSIZE          90  /* Message too long */
+#define L_EPROTOTYPE        91  /* Protocol wrong type for socket */
+#define L_ENOPROTOOPT       92  /* Protocol not available */
+#define L_EPROTONOSUPPORT   93  /* Protocol not supported */
+#define L_ESOCKTNOSUPPORT   94  /* Socket type not supported */
+#define L_EOPNOTSUPP        95  /* Operation not supported on transport endpoint */
+#define L_EPFNOSUPPORT      96  /* Protocol family not supported */
+#define L_EAFNOSUPPORT      97  /* Address family not supported by protocol */
+#define L_EADDRINUSE        98  /* Address already in use */
+#define L_EADDRNOTAVAIL     99  /* Cannot assign requested address */
+#define L_ENETDOWN          100 /* Network is down */
+#define L_ENETUNREACH       101 /* Network is unreachable */
+#define L_ENETRESET         102 /* Network dropped connection because of reset */
+#define L_ECONNABORTED      103 /* Software caused connection abort */
+#define L_ECONNRESET        104 /* Connection reset by peer */
+#define L_ENOBUFS           105 /* No buffer space available */
+#define L_EISCONN           106 /* Transport endpoint is already connected */
+#define L_ENOTCONN          107 /* Transport endpoint is not connected */
+#define L_ESHUTDOWN         108 /* Cannot send after transport endpoint shutdown */
+#define L_ETOOMANYREFS      109 /* Too many references: cannot splice */
+#define L_ETIMEDOUT         110 /* Connection timed out */
+#define L_ECONNREFUSED      111 /* Connection refused */
+#define L_EHOSTDOWN         112 /* Host is down */
+#define L_EHOSTUNREACH      113 /* No route to host */
+#define L_EALREADY          114 /* Operation already in progress */
+#define L_EINPROGRESS       115 /* Operation now in progress */
+#define L_ESTALE            116 /* Stale NFS file handle */
+#define L_EUCLEAN           117 /* Structure needs cleaning */
+#define L_ENOTNAM           118 /* Not a XENIX named type file */
+#define L_ENAVAIL           119 /* No XENIX semaphores available */
+#define L_EISNAM            120 /* Is a named type file */
+#define L_EREMOTEIO         121 /* Remote I/O error */
+#define L_EDQUOT            122 /* Quota exceeded */
+#define L_ENOMEDIUM         123 /* No medium found */
+#define L_EMEDIUMTYPE       124 /* Wrong medium type */
+#define L_ECANCELED         125 /* Operation Canceled */
+#define L_ENOKEY            126 /* Required key not available */
+#define L_EKEYEXPIRED       127 /* Key has expired */
+#define L_EKEYREVOKED       128 /* Key has been revoked */
+#define L_EKEYREJECTED      129 /* Key was rejected by service */
+#define L_EOWNERDEAD        130 /* Owner died */
+#define L_ENOTRECOVERABLE   131 /* State not recoverable */
+
+#endif /* QEMU_9P_LINUX_ERRNO_H */
diff --git a/hw/9pfs/9p-util.h b/hw/9pfs/9p-util.h
index df84374b78..c76a53f2a8 100644
--- a/hw/9pfs/9p-util.h
+++ b/hw/9pfs/9p-util.h
@@ -60,8 +60,11 @@ static inline uint64_t host_dev_to_dotl_dev(dev_t dev)
 #endif
 }
 
+#include "9p-linux-errno.h"
+
 /* Translates errno from host -> Linux if needed */
-static inline int errno_to_dotl(int err) {
+static inline int errno_to_dotl(int err)
+{
 #if defined(CONFIG_LINUX)
     /* nothing to translate (Linux -> Linux) */
 #elif defined(CONFIG_DARWIN)
@@ -71,18 +74,14 @@ static inline int errno_to_dotl(int err) {
      * FIXME: Only most important errnos translated here yet, this should be
      * extended to as many errnos being translated as possible in future.
      */
-    if (err == ENAMETOOLONG) {
-        err = 36; /* ==ENAMETOOLONG on Linux */
-    } else if (err == ENOTEMPTY) {
-        err = 39; /* ==ENOTEMPTY on Linux */
-    } else if (err == ELOOP) {
-        err = 40; /* ==ELOOP on Linux */
-    } else if (err == ENOATTR) {
-        err = 61; /* ==ENODATA on Linux */
-    } else if (err == ENOTSUP) {
-        err = 95; /* ==EOPNOTSUPP on Linux */
-    } else if (err == EOPNOTSUPP) {
-        err = 95; /* ==EOPNOTSUPP on Linux */
+    switch (err) {
+    case ENAMETOOLONG:  return L_ENAMETOOLONG;
+    case ENOTEMPTY:     return L_ENOTEMPTY;
+    case ELOOP:         return L_ELOOP;
+    case ENOATTR:       return L_ENODATA;
+    case ENOTSUP        return L_EOPNOTSUPP;
+    case EOPNOTSUPP:    return L_EOPNOTSUPP;
+    default:            g_assert_not_reached();
     }
 #else
 #error Missing errno translation to Linux for this host system
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v2 15/19] hw/9pfs: Translate Windows errno to Linux value
  2022-11-11  4:22 [PATCH v2 00/19] At present there is no Windows support for 9p file system Bin Meng
                   ` (13 preceding siblings ...)
  2022-11-11  4:22 ` [PATCH v2 14/19] hw/9pfs: Add Linux error number definition Bin Meng
@ 2022-11-11  4:22 ` Bin Meng
  2022-11-11  4:22 ` [PATCH v2 16/19] fsdev: Disable proxy fs driver on Windows Bin Meng
                   ` (3 subsequent siblings)
  18 siblings, 0 replies; 36+ messages in thread
From: Bin Meng @ 2022-11-11  4:22 UTC (permalink / raw)
  To: qemu-devel; +Cc: Guohuai Shi, Christian Schoenebeck, Greg Kurz

From: Guohuai Shi <guohuai.shi@windriver.com>

Some of Windows error numbers have different value from Linux ones.
For example, ENOTEMPTY is defined to 39 in Linux, but is defined to
41 in Windows. So deleting a directory from a Linux guest on top
of QEMU from a Windows host complains:

  # rmdir tmp
  rmdir: 'tmp': Unknown error 41

This commit provides error number translation from Windows to Linux.
It can make Linux guest OS happy with the error number when running
on top of QEMU from a Windows host.

Signed-off-by: Guohuai Shi <guohuai.shi@windriver.com>
Signed-off-by: Bin Meng <bin.meng@windriver.com>
---

(no changes since v1)

 hw/9pfs/9p-util.h | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/hw/9pfs/9p-util.h b/hw/9pfs/9p-util.h
index c76a53f2a8..598e2980e1 100644
--- a/hw/9pfs/9p-util.h
+++ b/hw/9pfs/9p-util.h
@@ -67,9 +67,9 @@ static inline int errno_to_dotl(int err)
 {
 #if defined(CONFIG_LINUX)
     /* nothing to translate (Linux -> Linux) */
-#elif defined(CONFIG_DARWIN)
+#elif defined(CONFIG_DARWIN) || defined(CONFIG_WIN32)
     /*
-     * translation mandatory for macOS hosts
+     * translation mandatory for different hosts
      *
      * FIXME: Only most important errnos translated here yet, this should be
      * extended to as many errnos being translated as possible in future.
@@ -78,9 +78,17 @@ static inline int errno_to_dotl(int err)
     case ENAMETOOLONG:  return L_ENAMETOOLONG;
     case ENOTEMPTY:     return L_ENOTEMPTY;
     case ELOOP:         return L_ELOOP;
+#ifdef CONFIG_DARWIN
     case ENOATTR:       return L_ENODATA;
     case ENOTSUP        return L_EOPNOTSUPP;
     case EOPNOTSUPP:    return L_EOPNOTSUPP;
+#endif
+#ifdef CONFIG_WIN32
+    case EDEADLK:       return L_EDEADLK;
+    case ENOLCK:        return L_ENOLCK;
+    case ENOSYS:        return L_ENOSYS;
+    case EILSEQ:        return L_EILSEQ;
+#endif
     default:            g_assert_not_reached();
     }
 #else
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v2 16/19] fsdev: Disable proxy fs driver on Windows
  2022-11-11  4:22 [PATCH v2 00/19] At present there is no Windows support for 9p file system Bin Meng
                   ` (14 preceding siblings ...)
  2022-11-11  4:22 ` [PATCH v2 15/19] hw/9pfs: Translate Windows errno to Linux value Bin Meng
@ 2022-11-11  4:22 ` Bin Meng
  2022-11-11  4:22 ` [PATCH v2 17/19] hw/9pfs: Update synth fs driver for Windows Bin Meng
                   ` (2 subsequent siblings)
  18 siblings, 0 replies; 36+ messages in thread
From: Bin Meng @ 2022-11-11  4:22 UTC (permalink / raw)
  To: qemu-devel; +Cc: Guohuai Shi, Christian Schoenebeck, Greg Kurz

From: Guohuai Shi <guohuai.shi@windriver.com>

We don't plan to support 'proxy' file system driver for 9pfs on
Windows. Disable it for Windows build.

Signed-off-by: Guohuai Shi <guohuai.shi@windriver.com>
Signed-off-by: Bin Meng <bin.meng@windriver.com>
---

(no changes since v1)

 fsdev/qemu-fsdev.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/fsdev/qemu-fsdev.c b/fsdev/qemu-fsdev.c
index 3da64e9f72..58e0710fbb 100644
--- a/fsdev/qemu-fsdev.c
+++ b/fsdev/qemu-fsdev.c
@@ -89,6 +89,7 @@ static FsDriverTable FsDrivers[] = {
             NULL
         },
     },
+#ifndef CONFIG_WIN32
     {
         .name = "proxy",
         .ops = &proxy_ops,
@@ -100,6 +101,7 @@ static FsDriverTable FsDrivers[] = {
             NULL
         },
     },
+#endif
 };
 
 static int validate_opt(void *opaque, const char *name, const char *value,
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v2 17/19] hw/9pfs: Update synth fs driver for Windows
  2022-11-11  4:22 [PATCH v2 00/19] At present there is no Windows support for 9p file system Bin Meng
                   ` (15 preceding siblings ...)
  2022-11-11  4:22 ` [PATCH v2 16/19] fsdev: Disable proxy fs driver on Windows Bin Meng
@ 2022-11-11  4:22 ` Bin Meng
  2022-11-11 10:30   ` Philippe Mathieu-Daudé
  2022-11-11  4:22 ` [PATCH v2 18/19] tests/qtest: virtio-9p-test: Adapt the case for win32 Bin Meng
  2022-11-11  4:22 ` [PATCH v2 19/19] meson.build: Turn on virtfs for Windows Bin Meng
  18 siblings, 1 reply; 36+ messages in thread
From: Bin Meng @ 2022-11-11  4:22 UTC (permalink / raw)
  To: qemu-devel; +Cc: Guohuai Shi, Christian Schoenebeck, Greg Kurz

From: Guohuai Shi <guohuai.shi@windriver.com>

Adapt synth fs driver for Windows in preparation to running qtest
9p testing on Windows.

Signed-off-by: Guohuai Shi <guohuai.shi@windriver.com>
Signed-off-by: Bin Meng <bin.meng@windriver.com>
---

(no changes since v1)

 hw/9pfs/9p-synth.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/hw/9pfs/9p-synth.c b/hw/9pfs/9p-synth.c
index 1c5813e4dd..6d33eb1cf3 100644
--- a/hw/9pfs/9p-synth.c
+++ b/hw/9pfs/9p-synth.c
@@ -152,8 +152,10 @@ static void synth_fill_statbuf(V9fsSynthNode *node, struct stat *stbuf)
     stbuf->st_gid = 0;
     stbuf->st_rdev = 0;
     stbuf->st_size = 0;
+#ifndef CONFIG_WIN32
     stbuf->st_blksize = 0;
     stbuf->st_blocks = 0;
+#endif
     stbuf->st_atime = 0;
     stbuf->st_mtime = 0;
     stbuf->st_ctime = 0;
@@ -236,7 +238,8 @@ static void synth_direntry(V9fsSynthNode *node,
     entry->d_ino = node->attr->inode;
 #ifdef CONFIG_DARWIN
     entry->d_seekoff = off + 1;
-#else
+#endif
+#ifdef CONFIG_LINUX
     entry->d_off = off + 1;
 #endif
 }
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v2 18/19] tests/qtest: virtio-9p-test: Adapt the case for win32
  2022-11-11  4:22 [PATCH v2 00/19] At present there is no Windows support for 9p file system Bin Meng
                   ` (16 preceding siblings ...)
  2022-11-11  4:22 ` [PATCH v2 17/19] hw/9pfs: Update synth fs driver for Windows Bin Meng
@ 2022-11-11  4:22 ` Bin Meng
  2022-11-11  7:48   ` Thomas Huth
  2022-11-11  4:22 ` [PATCH v2 19/19] meson.build: Turn on virtfs for Windows Bin Meng
  18 siblings, 1 reply; 36+ messages in thread
From: Bin Meng @ 2022-11-11  4:22 UTC (permalink / raw)
  To: qemu-devel
  Cc: Guohuai Shi, Xuzhou Cheng, Laurent Vivier, Paolo Bonzini, Thomas Huth

From: Guohuai Shi <guohuai.shi@windriver.com>

Windows does not provide the getuid() API. Let's create a local
one and return a fixed value 0 as the uid for testing.

Co-developed-by: Xuzhou Cheng <xuzhou.cheng@windriver.com>
Signed-off-by: Guohuai Shi <guohuai.shi@windriver.com>
Signed-off-by: Bin Meng <bin.meng@windriver.com>

---

Changes in v2:
- Move getuid() to virtio-9p-client.h

 tests/qtest/libqos/virtio-9p-client.h | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/tests/qtest/libqos/virtio-9p-client.h b/tests/qtest/libqos/virtio-9p-client.h
index 78228eb97d..a5c0107580 100644
--- a/tests/qtest/libqos/virtio-9p-client.h
+++ b/tests/qtest/libqos/virtio-9p-client.h
@@ -491,4 +491,11 @@ void v9fs_rlink(P9Req *req);
 TunlinkatRes v9fs_tunlinkat(TunlinkatOpt);
 void v9fs_runlinkat(P9Req *req);
 
+#ifdef CONFIG_WIN32
+static inline uint32_t getuid(void)
+{
+    return 0;
+}
+#endif
+
 #endif
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v2 19/19] meson.build: Turn on virtfs for Windows
  2022-11-11  4:22 [PATCH v2 00/19] At present there is no Windows support for 9p file system Bin Meng
                   ` (17 preceding siblings ...)
  2022-11-11  4:22 ` [PATCH v2 18/19] tests/qtest: virtio-9p-test: Adapt the case for win32 Bin Meng
@ 2022-11-11  4:22 ` Bin Meng
  18 siblings, 0 replies; 36+ messages in thread
From: Bin Meng @ 2022-11-11  4:22 UTC (permalink / raw)
  To: qemu-devel
  Cc: Guohuai Shi, Christian Schoenebeck, Daniel P. Berrangé,
	Greg Kurz, Marc-André Lureau, Paolo Bonzini,
	Philippe Mathieu-Daudé,
	Thomas Huth

From: Guohuai Shi <guohuai.shi@windriver.com>

Enable virtfs configuration option for Windows host.

Signed-off-by: Guohuai Shi <guohuai.shi@windriver.com>
Signed-off-by: Bin Meng <bin.meng@windriver.com>

---

(no changes since v1)

 meson.build         | 10 +++++-----
 fsdev/meson.build   |  1 +
 hw/9pfs/meson.build |  8 +++++---
 3 files changed, 11 insertions(+), 8 deletions(-)

diff --git a/meson.build b/meson.build
index cf3e517e56..4b386556c0 100644
--- a/meson.build
+++ b/meson.build
@@ -1739,16 +1739,16 @@ dbus_display = get_option('dbus_display') \
   .allowed()
 
 have_virtfs = get_option('virtfs') \
-    .require(targetos == 'linux' or targetos == 'darwin',
-             error_message: 'virtio-9p (virtfs) requires Linux or macOS') \
-    .require(targetos == 'linux' or cc.has_function('pthread_fchdir_np'),
+    .require(targetos == 'linux' or targetos == 'darwin' or targetos == 'windows',
+             error_message: 'virtio-9p (virtfs) requires Linux or macOS or Windows') \
+    .require(targetos == 'linux' or targetos == 'windows' or cc.has_function('pthread_fchdir_np'),
              error_message: 'virtio-9p (virtfs) on macOS requires the presence of pthread_fchdir_np') \
-    .require(targetos == 'darwin' or (libattr.found() and libcap_ng.found()),
+    .require(targetos == 'darwin' or targetos == 'windows' or (libattr.found() and libcap_ng.found()),
              error_message: 'virtio-9p (virtfs) on Linux requires libcap-ng-devel and libattr-devel') \
     .disable_auto_if(not have_tools and not have_system) \
     .allowed()
 
-have_virtfs_proxy_helper = targetos != 'darwin' and have_virtfs and have_tools
+have_virtfs_proxy_helper = targetos != 'darwin' and targetos != 'windows' and have_virtfs and have_tools
 
 if get_option('block_drv_ro_whitelist') == ''
   config_host_data.set('CONFIG_BDRV_RO_WHITELIST', '')
diff --git a/fsdev/meson.build b/fsdev/meson.build
index b632b66348..2aad081aef 100644
--- a/fsdev/meson.build
+++ b/fsdev/meson.build
@@ -8,6 +8,7 @@ fsdev_ss.add(when: ['CONFIG_FSDEV_9P'], if_true: files(
 ), if_false: files('qemu-fsdev-dummy.c'))
 softmmu_ss.add_all(when: 'CONFIG_LINUX', if_true: fsdev_ss)
 softmmu_ss.add_all(when: 'CONFIG_DARWIN', if_true: fsdev_ss)
+softmmu_ss.add_all(when: 'CONFIG_WIN32', if_true: fsdev_ss)
 
 if have_virtfs_proxy_helper
   executable('virtfs-proxy-helper',
diff --git a/hw/9pfs/meson.build b/hw/9pfs/meson.build
index 12443b6ad5..aaa50e71f7 100644
--- a/hw/9pfs/meson.build
+++ b/hw/9pfs/meson.build
@@ -2,7 +2,6 @@ fs_ss = ss.source_set()
 fs_ss.add(files(
   '9p-local.c',
   '9p-posix-acl.c',
-  '9p-proxy.c',
   '9p-synth.c',
   '9p-xattr-user.c',
   '9p-xattr.c',
@@ -13,8 +12,11 @@ fs_ss.add(files(
   'coth.c',
   'coxattr.c',
 ))
-fs_ss.add(when: 'CONFIG_LINUX', if_true: files('9p-util-linux.c'))
-fs_ss.add(when: 'CONFIG_DARWIN', if_true: files('9p-util-darwin.c'))
+fs_ss.add(when: 'CONFIG_LINUX', if_true: files('9p-proxy.c',
+                                               '9p-util-linux.c'))
+fs_ss.add(when: 'CONFIG_DARWIN', if_true: files('9p-proxy.c',
+                                                '9p-util-darwin.c'))
+fs_ss.add(when: 'CONFIG_WIN32', if_true: files('9p-util-win32.c'))
 fs_ss.add(when: 'CONFIG_XEN', if_true: files('xen-9p-backend.c'))
 softmmu_ss.add_all(when: 'CONFIG_FSDEV_9P', if_true: fs_ss)
 
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* Re: [PATCH v2 18/19] tests/qtest: virtio-9p-test: Adapt the case for win32
  2022-11-11  4:22 ` [PATCH v2 18/19] tests/qtest: virtio-9p-test: Adapt the case for win32 Bin Meng
@ 2022-11-11  7:48   ` Thomas Huth
  0 siblings, 0 replies; 36+ messages in thread
From: Thomas Huth @ 2022-11-11  7:48 UTC (permalink / raw)
  To: Bin Meng, qemu-devel
  Cc: Guohuai Shi, Xuzhou Cheng, Laurent Vivier, Paolo Bonzini

On 11/11/2022 05.22, Bin Meng wrote:
> From: Guohuai Shi <guohuai.shi@windriver.com>
> 
> Windows does not provide the getuid() API. Let's create a local
> one and return a fixed value 0 as the uid for testing.
> 
> Co-developed-by: Xuzhou Cheng <xuzhou.cheng@windriver.com>
> Signed-off-by: Guohuai Shi <guohuai.shi@windriver.com>
> Signed-off-by: Bin Meng <bin.meng@windriver.com>
> 
> ---
> 
> Changes in v2:
> - Move getuid() to virtio-9p-client.h
> 
>   tests/qtest/libqos/virtio-9p-client.h | 7 +++++++
>   1 file changed, 7 insertions(+)
> 
> diff --git a/tests/qtest/libqos/virtio-9p-client.h b/tests/qtest/libqos/virtio-9p-client.h
> index 78228eb97d..a5c0107580 100644
> --- a/tests/qtest/libqos/virtio-9p-client.h
> +++ b/tests/qtest/libqos/virtio-9p-client.h
> @@ -491,4 +491,11 @@ void v9fs_rlink(P9Req *req);
>   TunlinkatRes v9fs_tunlinkat(TunlinkatOpt);
>   void v9fs_runlinkat(P9Req *req);
>   
> +#ifdef CONFIG_WIN32
> +static inline uint32_t getuid(void)
> +{
> +    return 0;
> +}
> +#endif
> +
>   #endif

Reviewed-by: Thomas Huth <thuth@redhat.com>



^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v2 04/19] osdep.h: Introduce a QEMU file descriptor type
  2022-11-11  4:22 ` [PATCH v2 04/19] osdep.h: Introduce a QEMU file descriptor type Bin Meng
@ 2022-11-11  9:07   ` Daniel P. Berrangé
  2022-11-11  9:23     ` Bin Meng
  0 siblings, 1 reply; 36+ messages in thread
From: Daniel P. Berrangé @ 2022-11-11  9:07 UTC (permalink / raw)
  To: Bin Meng
  Cc: qemu-devel, Marc-André Lureau, Peter Maydell,
	Philippe Mathieu-Daudé,
	Richard Henderson

On Fri, Nov 11, 2022 at 12:22:10PM +0800, Bin Meng wrote:
> Introduce a new QemuFd_t type to represent a file descriptor for
> different platforms. On POSIX platforms, this is a file descriptor
> On Windows, this is a file handle.

Can we not use  _open_osfhandle() to obtain a C runtime
file descriptor from the Windows HANDLE.  We do this in
QEMU's socket code, so we don't have to work wit different
types and APIs on Windows, and I think that's much nicer
in general.

> 
> Changes in v2:
> - Change to introduce QemuFd_t in osdep.h
> 
>  include/qemu/osdep.h | 26 ++++++++++++++++++++++++++
>  1 file changed, 26 insertions(+)
> 
> diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h
> index b9c4307779..45fc8bb5d9 100644
> --- a/include/qemu/osdep.h
> +++ b/include/qemu/osdep.h
> @@ -705,6 +705,32 @@ static inline int platform_does_not_support_system(const char *command)
>  }
>  #endif /* !HAVE_SYSTEM_FUNCTION */
>  
> +/*
> + * QEMU file descriptor type
> + *
> + * On POSIX platforms, this is a file descriptor (int).
> + * On Windows, this is a file handle (HANDLE).
> + */
> +#ifndef _WIN32
> +typedef int QemuFd_t;
> +#define QEMU_FD_INVALID -1
> +#else
> +typedef HANDLE QemuFd_t;
> +#define QEMU_FD_INVALID INVALID_HANDLE_VALUE
> +#endif
> +
> +/**
> + * qemu_fd_invalid - determine if a given QEMU file descriptor is invalid
> + *
> + * @fd: the value of a QEMU file descriptor
> + *
> + * Returns true if a given QEMU file descriptor is invalid, otherwise false.
> + */
> +static inline bool qemu_fd_invalid(QemuFd_t fd)
> +{
> +    return (fd == QEMU_FD_INVALID);
> +}
> +
>  #ifdef __cplusplus
>  }
>  #endif
> -- 
> 2.25.1
> 

With regards,
Daniel
-- 
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|



^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v2 04/19] osdep.h: Introduce a QEMU file descriptor type
  2022-11-11  9:07   ` Daniel P. Berrangé
@ 2022-11-11  9:23     ` Bin Meng
  2022-11-11  9:29       ` Daniel P. Berrangé
  0 siblings, 1 reply; 36+ messages in thread
From: Bin Meng @ 2022-11-11  9:23 UTC (permalink / raw)
  To: Daniel P. Berrangé
  Cc: Bin Meng, qemu-devel, Marc-André Lureau, Peter Maydell,
	Philippe Mathieu-Daudé,
	Richard Henderson

Hi Daniel,

On Fri, Nov 11, 2022 at 5:08 PM Daniel P. Berrangé <berrange@redhat.com> wrote:
>
> On Fri, Nov 11, 2022 at 12:22:10PM +0800, Bin Meng wrote:
> > Introduce a new QemuFd_t type to represent a file descriptor for
> > different platforms. On POSIX platforms, this is a file descriptor
> > On Windows, this is a file handle.
>
> Can we not use  _open_osfhandle() to obtain a C runtime
> file descriptor from the Windows HANDLE.  We do this in
> QEMU's socket code, so we don't have to work wit different
> types and APIs on Windows, and I think that's much nicer
> in general.
>

I am sorry I don't understand your suggestion. I checked
qemu-sockets.c and did not see how sockets connect to this change.

This change is required to make 9pfs Windows support much easier.

Regards,
Bin


^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v2 04/19] osdep.h: Introduce a QEMU file descriptor type
  2022-11-11  9:23     ` Bin Meng
@ 2022-11-11  9:29       ` Daniel P. Berrangé
  0 siblings, 0 replies; 36+ messages in thread
From: Daniel P. Berrangé @ 2022-11-11  9:29 UTC (permalink / raw)
  To: Bin Meng
  Cc: Bin Meng, qemu-devel, Marc-André Lureau, Peter Maydell,
	Philippe Mathieu-Daudé,
	Richard Henderson

On Fri, Nov 11, 2022 at 05:23:58PM +0800, Bin Meng wrote:
> Hi Daniel,
> 
> On Fri, Nov 11, 2022 at 5:08 PM Daniel P. Berrangé <berrange@redhat.com> wrote:
> >
> > On Fri, Nov 11, 2022 at 12:22:10PM +0800, Bin Meng wrote:
> > > Introduce a new QemuFd_t type to represent a file descriptor for
> > > different platforms. On POSIX platforms, this is a file descriptor
> > > On Windows, this is a file handle.
> >
> > Can we not use  _open_osfhandle() to obtain a C runtime
> > file descriptor from the Windows HANDLE.  We do this in
> > QEMU's socket code, so we don't have to work wit different
> > types and APIs on Windows, and I think that's much nicer
> > in general.
> >
> 
> I am sorry I don't understand your suggestion. I checked
> qemu-sockets.c and did not see how sockets connect to this change.
> 
> This change is required to make 9pfs Windows support much easier.

I'm just using it as an example to show that we can continue to
use a plain 'int fd' everywhere, and not invent a QemuFd_t type
abstraction

With regards,
Daniel
-- 
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|



^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v2 17/19] hw/9pfs: Update synth fs driver for Windows
  2022-11-11  4:22 ` [PATCH v2 17/19] hw/9pfs: Update synth fs driver for Windows Bin Meng
@ 2022-11-11 10:30   ` Philippe Mathieu-Daudé
  0 siblings, 0 replies; 36+ messages in thread
From: Philippe Mathieu-Daudé @ 2022-11-11 10:30 UTC (permalink / raw)
  To: Bin Meng, qemu-devel; +Cc: Guohuai Shi, Christian Schoenebeck, Greg Kurz

On 11/11/22 05:22, Bin Meng wrote:
> From: Guohuai Shi <guohuai.shi@windriver.com>
> 
> Adapt synth fs driver for Windows in preparation to running qtest
> 9p testing on Windows.
> 
> Signed-off-by: Guohuai Shi <guohuai.shi@windriver.com>
> Signed-off-by: Bin Meng <bin.meng@windriver.com>
> ---
> 
> (no changes since v1)
> 
>   hw/9pfs/9p-synth.c | 5 ++++-
>   1 file changed, 4 insertions(+), 1 deletion(-)

Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>



^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v2 06/19] hw/9pfs: Add missing definitions for Windows
  2022-11-11  4:22 ` [PATCH v2 06/19] hw/9pfs: Add missing definitions for Windows Bin Meng
@ 2022-11-14 16:40   ` Christian Schoenebeck
  2022-11-16  9:01     ` Shi, Guohuai
  0 siblings, 1 reply; 36+ messages in thread
From: Christian Schoenebeck @ 2022-11-14 16:40 UTC (permalink / raw)
  To: qemu-devel; +Cc: Guohuai Shi, Greg Kurz, Bin Meng

On Friday, November 11, 2022 5:22:12 AM CET Bin Meng wrote:
> From: Guohuai Shi <guohuai.shi@windriver.com>
> 
> Some definitions currently used by the 9pfs codes are only available
> on POSIX platforms. Let's add our own ones in preparation to adding
> 9pfs support for Windows.
> 
> Signed-off-by: Guohuai Shi <guohuai.shi@windriver.com>
> Signed-off-by: Bin Meng <bin.meng@windriver.com>
> 
> ---
> 
> Changes in v2:
> - Add S_IFLNK related macros to support symbolic link
> 
>  fsdev/file-op-9p.h | 33 +++++++++++++++++++++++++++++++++
>  hw/9pfs/9p.h       | 33 +++++++++++++++++++++++++++++++++
>  2 files changed, 66 insertions(+)
> 
> diff --git a/fsdev/file-op-9p.h b/fsdev/file-op-9p.h
> index 4997677460..7d9a736b66 100644
> --- a/fsdev/file-op-9p.h
> +++ b/fsdev/file-op-9p.h
> @@ -27,6 +27,39 @@
>  # include <sys/mount.h>
>  #endif
>  
> +#ifdef CONFIG_WIN32
> +
> +/* POSIX structure not defined in Windows */
> +
> +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;
> +};
> +

Does it make sense to define all of these, even though not being used?

> +#endif /* CONFIG_WIN32 */
> +
>  #define SM_LOCAL_MODE_BITS    0600
>  #define SM_LOCAL_DIR_MODE_BITS    0700
>  
> diff --git a/hw/9pfs/9p.h b/hw/9pfs/9p.h
> index 2fce4140d1..957a7e4ccc 100644
> --- a/hw/9pfs/9p.h
> +++ b/hw/9pfs/9p.h
> @@ -3,13 +3,46 @@
>  
>  #include <dirent.h>
>  #include <utime.h>
> +#ifndef CONFIG_WIN32
>  #include <sys/resource.h>
> +#endif
>  #include "fsdev/file-op-9p.h"
>  #include "fsdev/9p-iov-marshal.h"
>  #include "qemu/thread.h"
>  #include "qemu/coroutine.h"
>  #include "qemu/qht.h"
>  
> +#ifdef CONFIG_WIN32
> +
> +#define NAME_MAX            MAX_PATH

That's not quite the same. MAX_PATH on Windows corresponds to PATH_MAX on
POSIX, which is the max. length of an entire path (i.e. drive, multiple
directory names, filename, backslashes). AFAICS MAX_PATH is 260 on Windows.

The max. length of a single filename component OTOH is 255 on Windows by
default. I don't know if there is a macro for the latter, if not, maybe
just hard coding it here for now?

> +
> +/* macros required for build, values do not matter */
> +#define AT_SYMLINK_NOFOLLOW 0x100   /* Do not follow symbolic links */
> +#define AT_REMOVEDIR        0x200   /* Remove directory instead of file */
> +#define O_DIRECTORY         02000000
> +
> +#define makedev(major, minor)   \
> +        ((dev_t)((((major) & 0xfff) << 8) | ((minor) & 0xff)))
> +#define major(dev)  ((unsigned int)(((dev) >> 8) & 0xfff))
> +#define minor(dev)  ((unsigned int)(((dev) & 0xff)))
> +
> +#ifndef S_IFLNK
> +/*
> + * Currenlty Windows/MinGW does not provide the following flag macros,
> + * so define them here for 9p codes.
> + *
> + * Once Windows/MinGW provides them, remove the defines to prevent conflicts.
> + */
> +#define S_IFLNK         0xA000
> +#define S_ISUID         0x0800
> +#define S_ISGID         0x0400
> +#define S_ISVTX         0x0200
> +
> +#define S_ISLNK(mode)   ((mode & S_IFMT) == S_IFLNK)
> +#endif /* S_IFLNK */
> +
> +#endif /* CONFIG_WIN32 */
> +
>  enum {
>      P9_TLERROR = 6,
>      P9_RLERROR,
> 




^ permalink raw reply	[flat|nested] 36+ messages in thread

* RE: [PATCH v2 06/19] hw/9pfs: Add missing definitions for Windows
  2022-11-14 16:40   ` Christian Schoenebeck
@ 2022-11-16  9:01     ` Shi, Guohuai
  2022-11-16 12:52       ` Christian Schoenebeck
  0 siblings, 1 reply; 36+ messages in thread
From: Shi, Guohuai @ 2022-11-16  9:01 UTC (permalink / raw)
  To: Christian Schoenebeck, qemu-devel; +Cc: Greg Kurz, Meng, Bin



> -----Original Message-----
> From: Christian Schoenebeck <qemu_oss@crudebyte.com>
> Sent: Tuesday, November 15, 2022 00:41
> To: qemu-devel@nongnu.org
> Cc: Shi, Guohuai <Guohuai.Shi@windriver.com>; Greg Kurz <groug@kaod.org>;
> Meng, Bin <Bin.Meng@windriver.com>
> Subject: Re: [PATCH v2 06/19] hw/9pfs: Add missing definitions for Windows
> 
> CAUTION: This email comes from a non Wind River email account!
> Do not click links or open attachments unless you recognize the sender and
> know the content is safe.
> 
> On Friday, November 11, 2022 5:22:12 AM CET Bin Meng wrote:
> > From: Guohuai Shi <guohuai.shi@windriver.com>
> >
> > Some definitions currently used by the 9pfs codes are only available
> > on POSIX platforms. Let's add our own ones in preparation to adding
> > 9pfs support for Windows.
> >
> > Signed-off-by: Guohuai Shi <guohuai.shi@windriver.com>
> > Signed-off-by: Bin Meng <bin.meng@windriver.com>
> >
> > ---
> >
> > Changes in v2:
> > - Add S_IFLNK related macros to support symbolic link
> >
> >  fsdev/file-op-9p.h | 33 +++++++++++++++++++++++++++++++++
> >  hw/9pfs/9p.h       | 33 +++++++++++++++++++++++++++++++++
> >  2 files changed, 66 insertions(+)
> >
> > diff --git a/fsdev/file-op-9p.h b/fsdev/file-op-9p.h index
> > 4997677460..7d9a736b66 100644
> > --- a/fsdev/file-op-9p.h
> > +++ b/fsdev/file-op-9p.h
> > @@ -27,6 +27,39 @@
> >  # include <sys/mount.h>
> >  #endif
> >
> > +#ifdef CONFIG_WIN32
> > +
> > +/* POSIX structure not defined in Windows */
> > +
> > +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;
> > +};
> > +
> 
> Does it make sense to define all of these, even though not being used?

Windows does not have this definition, so use Linux definition can make less impact to 9pfs code.
If not, need to add many macro "#ifdef CONFIG_WIN32" in other places to disable the unsupported code.

> 
> > +#endif /* CONFIG_WIN32 */
> > +
> >  #define SM_LOCAL_MODE_BITS    0600
> >  #define SM_LOCAL_DIR_MODE_BITS    0700
> >
> > diff --git a/hw/9pfs/9p.h b/hw/9pfs/9p.h index 2fce4140d1..957a7e4ccc
> > 100644
> > --- a/hw/9pfs/9p.h
> > +++ b/hw/9pfs/9p.h
> > @@ -3,13 +3,46 @@
> >
> >  #include <dirent.h>
> >  #include <utime.h>
> > +#ifndef CONFIG_WIN32
> >  #include <sys/resource.h>
> > +#endif
> >  #include "fsdev/file-op-9p.h"
> >  #include "fsdev/9p-iov-marshal.h"
> >  #include "qemu/thread.h"
> >  #include "qemu/coroutine.h"
> >  #include "qemu/qht.h"
> >
> > +#ifdef CONFIG_WIN32
> > +
> > +#define NAME_MAX            MAX_PATH
> 
> That's not quite the same. MAX_PATH on Windows corresponds to PATH_MAX on
> POSIX, which is the max. length of an entire path (i.e. drive, multiple
> directory names, filename, backslashes). AFAICS MAX_PATH is 260 on Windows.
> 
> The max. length of a single filename component OTOH is 255 on Windows by
> default. I don't know if there is a macro for the latter, if not, maybe just
> hard coding it here for now?
> 

My mistake, it should be 255.

> > +
> > +/* macros required for build, values do not matter */
> > +#define AT_SYMLINK_NOFOLLOW 0x100   /* Do not follow symbolic links */
> > +#define AT_REMOVEDIR        0x200   /* Remove directory instead of file */
> > +#define O_DIRECTORY         02000000
> > +
> > +#define makedev(major, minor)   \
> > +        ((dev_t)((((major) & 0xfff) << 8) | ((minor) & 0xff)))
> > +#define major(dev)  ((unsigned int)(((dev) >> 8) & 0xfff)) #define
> > +minor(dev)  ((unsigned int)(((dev) & 0xff)))
> > +
> > +#ifndef S_IFLNK
> > +/*
> > + * Currenlty Windows/MinGW does not provide the following flag
> > +macros,
> > + * so define them here for 9p codes.
> > + *
> > + * Once Windows/MinGW provides them, remove the defines to prevent
> conflicts.
> > + */
> > +#define S_IFLNK         0xA000
> > +#define S_ISUID         0x0800
> > +#define S_ISGID         0x0400
> > +#define S_ISVTX         0x0200
> > +
> > +#define S_ISLNK(mode)   ((mode & S_IFMT) == S_IFLNK)
> > +#endif /* S_IFLNK */
> > +
> > +#endif /* CONFIG_WIN32 */
> > +
> >  enum {
> >      P9_TLERROR = 6,
> >      P9_RLERROR,
> >
> 



^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v2 06/19] hw/9pfs: Add missing definitions for Windows
  2022-11-16  9:01     ` Shi, Guohuai
@ 2022-11-16 12:52       ` Christian Schoenebeck
  0 siblings, 0 replies; 36+ messages in thread
From: Christian Schoenebeck @ 2022-11-16 12:52 UTC (permalink / raw)
  To: qemu-devel; +Cc: Greg Kurz, Meng, Bin, Shi, Guohuai

On Wednesday, November 16, 2022 10:01:39 AM CET Shi, Guohuai wrote:
[...]
> > > diff --git a/fsdev/file-op-9p.h b/fsdev/file-op-9p.h index
> > > 4997677460..7d9a736b66 100644
> > > --- a/fsdev/file-op-9p.h
> > > +++ b/fsdev/file-op-9p.h
> > > @@ -27,6 +27,39 @@
> > >  # include <sys/mount.h>
> > >  #endif
> > >
> > > +#ifdef CONFIG_WIN32
> > > +
> > > +/* POSIX structure not defined in Windows */
> > > +
> > > +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;
> > > +};
> > > +
> > 
> > Does it make sense to define all of these, even though not being used?
> 
> Windows does not have this definition, so use Linux definition can make less impact to 9pfs code.
> If not, need to add many macro "#ifdef CONFIG_WIN32" in other places to disable the unsupported code.

My bad, I thought most of these were not referenced in code at all, but I just
realized they are indeed. Only exception is probably `f_flags`, but I haven't
checked yet whether you are using that for something new in your patches.

The previous patches LGTM BTW. I still have to look at all following patches
though. So better wait some more days before posting a v3.

Best regards,
Christian Schoenebeck




^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v2 07/19] hw/9pfs: Implement Windows specific utilities functions for 9pfs
  2022-11-11  4:22 ` [PATCH v2 07/19] hw/9pfs: Implement Windows specific utilities functions for 9pfs Bin Meng
@ 2022-11-17 15:55   ` Christian Schoenebeck
  2022-11-17 16:38     ` Shi, Guohuai
  0 siblings, 1 reply; 36+ messages in thread
From: Christian Schoenebeck @ 2022-11-17 15:55 UTC (permalink / raw)
  To: qemu-devel; +Cc: Guohuai Shi, Greg Kurz, Bin Meng

On Friday, November 11, 2022 5:22:13 AM CET Bin Meng wrote:
> From: Guohuai Shi <guohuai.shi@windriver.com>
> 
> Windows POSIX API and MinGW library do not provide the NO_FOLLOW
> flag, and do not allow opening a directory by POSIX open(). This
> causes all xxx_at() functions cannot work directly. However, we
> can provide Windows handle based functions to emulate xxx_at()
> functions (e.g.: openat_win32, utimensat_win32, etc.).
> 
> NTFS ADS (Alternate Data Streams) is used to emulate 9pfs extended
> attributes on Windows. Symbolic link is only supported when security
> model is "mapped-xattr" or "mapped-file".
> 
> Signed-off-by: Guohuai Shi <guohuai.shi@windriver.com>
> Signed-off-by: Bin Meng <bin.meng@windriver.com>
> 
> ---
> 
> Changes in v2:
> - Support symbolic link when security model is "mapped-xattr" or "mapped-file"
> 
>  hw/9pfs/9p-local.h      |   7 +
>  hw/9pfs/9p-util.h       |  38 +-
>  hw/9pfs/9p-local.c      |   4 -
>  hw/9pfs/9p-util-win32.c | 934 ++++++++++++++++++++++++++++++++++++++++
>  4 files changed, 978 insertions(+), 5 deletions(-)
>  create mode 100644 hw/9pfs/9p-util-win32.c
> 
> diff --git a/hw/9pfs/9p-local.h b/hw/9pfs/9p-local.h
> index 66a21316a0..eb4f39ddc2 100644
> --- a/hw/9pfs/9p-local.h
> +++ b/hw/9pfs/9p-local.h
> @@ -13,6 +13,13 @@
>  #ifndef QEMU_9P_LOCAL_H
>  #define QEMU_9P_LOCAL_H
>  
> +typedef struct {
> +    QemuFd_t mountfd;
> +#ifdef CONFIG_WIN32
> +    char *root_path;
> +#endif
> +} LocalData;
> +
>  QemuFd_t local_open_nofollow(FsContext *fs_ctx, const char *path, int flags,
>                               mode_t mode);
>  QemuFd_t local_opendir_nofollow(FsContext *fs_ctx, const char *path);
> diff --git a/hw/9pfs/9p-util.h b/hw/9pfs/9p-util.h
> index 3d6bd1a51e..5fb854bf61 100644
> --- a/hw/9pfs/9p-util.h
> +++ b/hw/9pfs/9p-util.h
> @@ -88,26 +88,61 @@ static inline int errno_to_dotl(int err) {
>      return err;
>  }
>  
> -#ifdef CONFIG_DARWIN
> +#if defined(CONFIG_DARWIN)
>  #define qemu_fgetxattr(...) fgetxattr(__VA_ARGS__, 0, 0)
> +#elif defined(CONFIG_WIN32)
> +#define qemu_fgetxattr fgetxattr_win32
>  #else
>  #define qemu_fgetxattr fgetxattr
>  #endif
>  
> +#ifdef CONFIG_WIN32
> +#define qemu_openat     openat_win32
> +#define qemu_fstatat    fstatat_win32
> +#define qemu_mkdirat    mkdirat_win32
> +#define qemu_renameat   renameat_win32
> +#define qemu_utimensat  utimensat_win32
> +#define qemu_unlinkat   unlinkat_win32
> +#else
>  #define qemu_openat     openat
>  #define qemu_fstatat    fstatat
>  #define qemu_mkdirat    mkdirat
>  #define qemu_renameat   renameat
>  #define qemu_utimensat  utimensat
>  #define qemu_unlinkat   unlinkat
> +#endif
> +
> +#ifdef CONFIG_WIN32
> +char *get_full_path_win32(QemuFd_t fd, const char *name);
> +ssize_t fgetxattr_win32(int fd, const char *name, void *value, size_t size);
> +QemuFd_t openat_win32(QemuFd_t dirfd, const char *pathname, int flags,
> +                      mode_t mode);
> +int fstatat_win32(QemuFd_t dirfd, const char *pathname,
> +                  struct stat *statbuf, int flags);
> +int mkdirat_win32(QemuFd_t dirfd, const char *pathname, mode_t mode);
> +int renameat_win32(QemuFd_t olddirfd, const char *oldpath,
> +                   QemuFd_t newdirfd, const char *newpath);
> +int utimensat_win32(QemuFd_t dirfd, const char *pathname,
> +                    const struct timespec times[2], int flags);
> +int unlinkat_win32(QemuFd_t dirfd, const char *pathname, int flags);
> +int statfs_win32(const char *root_path, struct statfs *stbuf);
> +QemuFd_t openat_dir(QemuFd_t dirfd, const char *name);
> +QemuFd_t openat_file(QemuFd_t dirfd, const char *name, int flags,
> +                     mode_t mode);
> +#endif

That's quite a bunch of *_win32() prototypes. Maybe moving them into their own
9p-util-win32.h file?

>  static inline void close_preserve_errno(QemuFd_t fd)
>  {
>      int serrno = errno;
> +#ifndef CONFIG_WIN32
>      close(fd);
> +#else
> +    CloseHandle(fd);
> +#endif
>      errno = serrno;
>  }
>  
> +#ifndef CONFIG_WIN32
>  static inline QemuFd_t openat_dir(QemuFd_t dirfd, const char *name)
>  {
>      return qemu_openat(dirfd, name,
> @@ -155,6 +190,7 @@ again:
>      errno = serrno;
>      return fd;
>  }
> +#endif
>  
>  ssize_t fgetxattrat_nofollow(QemuFd_t dirfd, const char *path,
>                               const char *name, void *value, size_t size);
> diff --git a/hw/9pfs/9p-local.c b/hw/9pfs/9p-local.c
> index 22377a3105..24e21141d5 100644
> --- a/hw/9pfs/9p-local.c
> +++ b/hw/9pfs/9p-local.c
> @@ -53,10 +53,6 @@
>  #define BTRFS_SUPER_MAGIC 0x9123683E
>  #endif
>  
> -typedef struct {
> -    QemuFd_t mountfd;
> -} LocalData;
> -
>  QemuFd_t local_open_nofollow(FsContext *fs_ctx, const char *path, int flags,
>                               mode_t mode)
>  {
> diff --git a/hw/9pfs/9p-util-win32.c b/hw/9pfs/9p-util-win32.c
> new file mode 100644
> index 0000000000..ed3d519937
> --- /dev/null
> +++ b/hw/9pfs/9p-util-win32.c
> @@ -0,0 +1,934 @@
> +/*
> + * 9p utilities (Windows Implementation)
> + *
> + * Copyright (c) 2022 Wind River Systems, Inc.
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2 or later.
> + * See the COPYING file in the top-level directory.
> + */
> +
> +/*
> + * This file contains Windows only functions for 9pfs.
> + *
> + * For 9pfs Windows host, the following features are different from Linux host:
> + *
> + * 1. Windows POSIX API does not provide the NO_FOLLOW flag, that means MinGW
> + *    cannot detect if a path is a symbolic link or not. Also Windows do not
> + *    provide POSIX compatible readlink(). Supporting symbolic link in 9pfs on
> + *    Windows may cause security issues, so symbolic link support is disabled
> + *    completely for security model "none" or "passthrough".

So your standpoint is, guest cannot create links, therefore no need for
NO_FOLLOW and friends, safe. However a common use case for 9p is to export a
directory tree that was previously deployed by other means that might indeed
place links that might attempt to escape the sandbox. Don't you think that such
scenarios should be handled in some way?

> + *
> + * 2. Windows file system does not support extended attributes directly. 9pfs
> + *    for Windows uses NTFS ADS (Alternate Data Streams) to emulate extended
> + *    attributes.
> + *
> + * 3. statfs() is not available on Windows. qemu_statfs() is used to emulate it.
> + *
> + * 4. On Windows trying to open a directory with the open() API will fail.
> + *    This is because Windows does not allow opening directory in normal usage.
> + *
> + *    As a result of this, all xxx_at() functions won't work directly on
> + *    Windows, e.g.: openat(), unlinkat(), etc.
> + *
> + *    As xxx_at() can prevent parent directory to be modified on Linux host,
> + *    to support this and prevent security issue, all xxx_at() APIs are replaced
> + *    by xxx_at_win32() and Windows handle is used to replace the directory fd.

As you already have a Windows HANDLE, you could call NtCreateFile() to
implement openat(), no? NtCreateFile() takes an optional
`HANDLE RootDirectory` attribute with its ObjectAttributes function argument.

> + *
> + *    Windows file system does not allow replacing a file or directory if it is
> + *    referenced by a handle. Keep the handle open will lock and protect the
> + *    parent directory and make the access to files atomically.
> + *
> + *    If we don't protect (lock) the parent directory, the parent directory may
> + *    be replaced by others (e.g.: a symbolic link) and cause security issues.
> + */
> +
> +#include "qemu/osdep.h"
> +#include "qapi/error.h"
> +#include "qemu/error-report.h"
> +#include "9p.h"
> +#include "9p-util.h"
> +#include "9p-local.h"
> +
> +#include <windows.h>
> +#include <dirent.h>
> +
> +#define V9FS_MAGIC  0x53465039  /* string "9PFS" */
> +
> +/*
> + * build_ads_name - construct Windows ADS name
> + *
> + * This function constructs Windows NTFS ADS (Alternate Data Streams) name
> + * to <namebuf>.
> + */
> +static int build_ads_name(char *namebuf, size_t namebuf_len,
> +                          const char *filename, const char *ads_name)
> +{
> +    size_t total_size;
> +
> +    total_size = strlen(filename) + strlen(ads_name) + 2;
> +    if (total_size  > namebuf_len) {
> +        return -1;
> +    }
> +
> +    /*
> +     * NTFS ADS (Alternate Data Streams) name format: filename:ads_name
> +     * e.g.: D:\1.txt:my_ads_name
> +     */
> +
> +    strcpy(namebuf, filename);
> +    strcat(namebuf, ":");
> +    strcat(namebuf, ads_name);
> +
> +    return 0;
> +}
> +
> +/*
> + * copy_ads_name - copy ADS name from buffer returned by FindNextStreamW()
> + *
> + * This function removes string "$DATA" in ADS name string returned by
> + * FindNextStreamW(), and copies the real ADS name to <namebuf>.
> + */
> +static ssize_t copy_ads_name(char *namebuf, size_t namebuf_len,
> +                             char *full_ads_name)
> +{
> +    char *p1, *p2;
> +
> +    /*
> +     * NTFS ADS (Alternate Data Streams) name from enumerate data format:
> +     * :ads_name:$DATA, e.g.: :my_ads_name:$DATA
> +     *
> +     * ADS name from FindNextStreamW() always has ":$DATA" string at the end.
> +     *
> +     * This function copies ADS name to namebuf.
> +     */
> +
> +    p1 = strchr(full_ads_name, ':');
> +    if (p1 == NULL) {
> +        return -1;
> +    }
> +
> +    p2 = strchr(p1 + 1, ':');
> +    if (p2 == NULL) {
> +        return -1;
> +    }
> +
> +    /* skip empty ads name */
> +    if (p2 - p1 == 1) {
> +        return 0;
> +    }
> +
> +    if (p2 - p1 + 1 > namebuf_len) {
> +        return -1;
> +    }
> +
> +    memcpy(namebuf, p1 + 1, p2 - p1 - 1);
> +    namebuf[p2 - p1 - 1] = '\0';
> +
> +    return p2 - p1;
> +}
> +
> +/*
> + * get_full_path_win32 - get full file name base on a handle
> + *
> + * This function gets full file name based on a handle specified by <fd> to
> + * a file or directory.
> + *
> + * Caller function needs to free the file name string after use.
> + */
> +char *get_full_path_win32(QemuFd_t fd, const char *name)
> +{
> +    g_autofree char *full_file_name = NULL;
> +    DWORD total_size;
> +    DWORD name_size;
> +
> +    full_file_name = g_malloc0(NAME_MAX);
> +
> +    /* get parent directory full file name */
> +    name_size = GetFinalPathNameByHandle(fd, full_file_name,
> +                                         NAME_MAX - 1, FILE_NAME_NORMALIZED);
> +    if (name_size == 0 || name_size > NAME_MAX - 1) {
> +        return NULL;
> +    }
> +
> +    /* full path returned is the "\\?\" syntax, remove the lead string */
> +    memmove(full_file_name, full_file_name + 4, NAME_MAX - 4);
> +
> +    if (name != NULL) {
> +        total_size = strlen(full_file_name) + strlen(name) + 2;
> +
> +        if (total_size > NAME_MAX) {
> +            return NULL;
> +        }
> +
> +        /* build sub-directory file name */
> +        strcat(full_file_name, "\\");
> +        strcat(full_file_name, name);
> +    }
> +
> +    return g_steal_pointer(&full_file_name);
> +}
> +
> +/*
> + * fgetxattr_win32 - get extended attribute by fd
> + *
> + * This function gets extened attribute by <fd>. <fd> will be translated to
> + * Windows handle.
> + *
> + * This function emulates extended attribute by NTFS ADS.
> + */
> +ssize_t fgetxattr_win32(int fd, const char *name, void *value, size_t size)
> +{
> +    g_autofree char *full_file_name = NULL;
> +    char ads_file_name[NAME_MAX + 1] = {0};
> +    DWORD dwBytesRead;
> +    HANDLE hStream;
> +    HANDLE hFile;
> +
> +    hFile = (HANDLE)_get_osfhandle(fd);
> +
> +    full_file_name = get_full_path_win32(hFile, NULL);
> +    if (full_file_name == NULL) {
> +        errno = EIO;
> +        return -1;
> +    }
> +
> +    if (build_ads_name(ads_file_name, NAME_MAX, full_file_name, name) < 0) {
> +        errno = EIO;
> +        return -1;
> +    }
> +
> +    hStream = CreateFile(ads_file_name, GENERIC_READ, FILE_SHARE_READ, NULL,
> +                         OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
> +    if (hStream == INVALID_HANDLE_VALUE &&
> +        GetLastError() == ERROR_FILE_NOT_FOUND) {
> +        errno = ENODATA;
> +        return -1;
> +    }
> +
> +    if (ReadFile(hStream, value, size, &dwBytesRead, NULL) == FALSE) {
> +        errno = EIO;
> +        CloseHandle(hStream);
> +        return -1;
> +    }
> +
> +    CloseHandle(hStream);
> +
> +    return dwBytesRead;
> +}
> +
> +/*
> + * openat_win32 - emulate openat()
> + *
> + * This function emulates openat().
> + *
> + * Windows POSIX API does not support opening a directory by open(). Only
> + * handle of directory can be opened by CreateFile().
> + *
> + * So openat_win32() has to use a directory handle instead of a directory fd.
> + *
> + * For symbolic access:
> + * 1. Parent directory handle <dirfd> should not be a symbolic link because
> + *    it is opened by openat_dir() which can prevent from opening a link to
> + *    a dirctory.
> + * 2. Link flag in <mode> is not set because Windows does not have this flag.
> + *    Create a new symbolic link will be denied.
> + * 3. This function checks file symbolic link attribute after open.
> + *
> + * So symbolic link will not be accessed by 9p client.
> + */
> +QemuFd_t openat_win32(QemuFd_t dirfd, const char *pathname, int flags,
> +                      mode_t mode)
> +{
> +    g_autofree char *full_file_name1 = NULL;
> +    g_autofree char *full_file_name2 = NULL;
> +    HANDLE hFile = INVALID_HANDLE_VALUE;
> +    int fd;
> +
> +    full_file_name1 = get_full_path_win32(dirfd, pathname);
> +    if (full_file_name1 == NULL) {
> +        return hFile;
> +    }
> +
> +    fd = open(full_file_name1, flags, mode);
> +    if (fd > 0) {
> +        DWORD attribute;
> +        hFile = (HANDLE)_get_osfhandle(fd);
> +
> +        full_file_name2 = get_full_path_win32(hFile, NULL);
> +        attribute = GetFileAttributes(full_file_name2);
> +
> +        /* check if it is a symbolic link */
> +        if ((attribute == INVALID_FILE_ATTRIBUTES)
> +            || (attribute & FILE_ATTRIBUTE_REPARSE_POINT) != 0) {
> +            errno = EACCES;
> +            hFile = INVALID_HANDLE_VALUE;
> +            close(fd);
> +        }
> +    }
> +
> +    return hFile;
> +}
> +
> +/*
> + * fstatat_win32 - emulate fstatat()
> + *
> + * This function emulates fstatat().
> + *
> + * Windows POSIX API does not support opening a directory by open(). Only
> + * handle of directory can be opened by CreateFile().
> + *
> + * So fstatat_win32() has to use a directory handle instead of a directory fd.
> + *
> + * Access to a symbolic link will be denied to prevent security issues.
> + */
> +int fstatat_win32(QemuFd_t dirfd, const char *pathname,
> +                  struct stat *statbuf, int flags)
> +{
> +    g_autofree char *full_file_name = NULL;
> +    HANDLE hFile = INVALID_HANDLE_VALUE;
> +    BY_HANDLE_FILE_INFORMATION file_info;
> +    DWORD attribute;
> +    int err = 0;
> +    int ret = -1;
> +    ino_t st_ino;
> +
> +    full_file_name = get_full_path_win32(dirfd, pathname);
> +    if (full_file_name == NULL) {
> +        return ret;
> +    }
> +
> +    /* open file to lock it */
> +    hFile = CreateFile(full_file_name, GENERIC_READ,
> +                       FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
> +                       NULL,
> +                       OPEN_EXISTING,
> +                       FILE_FLAG_BACKUP_SEMANTICS
> +                       | FILE_FLAG_OPEN_REPARSE_POINT,
> +                       NULL);
> +
> +    if (hFile == INVALID_HANDLE_VALUE) {
> +        err = EACCES;
> +        goto out;
> +    }
> +
> +    attribute = GetFileAttributes(full_file_name);
> +
> +    /* check if it is a symbolic link */
> +    if ((attribute == INVALID_FILE_ATTRIBUTES)
> +        || (attribute & FILE_ATTRIBUTE_REPARSE_POINT) != 0) {
> +        errno = EACCES;
> +        goto out;
> +    }
> +
> +    ret = stat(full_file_name, statbuf);
> +
> +    if (GetFileInformationByHandle(hFile, &file_info) == 0) {
> +        errno = EACCES;
> +        goto out;
> +    }
> +
> +    /*
> +     * Windows (NTFS) file ID is a 64-bit ID:
> +     *   16-bit sequence ID + 48 bit segment number
> +     *
> +     * But currently, ino_t defined in Windows header file is only 16-bit,
> +     * and it is not patched by MinGW. So we build a pseudo inode number
> +     * by the low 32-bit segment number when ino_t is only 16-bit.
> +     */
> +    if (sizeof(st_ino) == sizeof(uint64_t)) {
> +        st_ino = (ino_t)((uint64_t)file_info.nFileIndexLow
> +                         | (((uint64_t)file_info.nFileIndexHigh) << 32));
> +    } else if (sizeof(st_ino) == sizeof(uint16_t)) {
> +        st_ino = (ino_t)(((uint16_t)file_info.nFileIndexLow)
> +                         ^ ((uint16_t)(file_info.nFileIndexLow >> 16)));
> +    } else {
> +        st_ino = (ino_t)file_info.nFileIndexLow;
> +    }
> +
> +    statbuf->st_ino = st_ino;
> +
> +out:
> +    if (hFile != INVALID_HANDLE_VALUE) {
> +        CloseHandle(hFile);
> +    }
> +
> +    if (err != 0) {
> +        errno = err;
> +    }
> +    return ret;
> +}
> +
> +/*
> + * mkdirat_win32 - emulate mkdirat()
> + *
> + * This function emulates mkdirat().
> + *
> + * Windows POSIX API does not support opening a directory by open(). Only
> + * handle of directory can be opened by CreateFile().
> + *
> + * So mkdirat_win32() has to use a directory handle instead of a directory fd.
> + */
> +int mkdirat_win32(QemuFd_t dirfd, const char *pathname, mode_t mode)
> +{
> +    g_autofree char *full_file_name = NULL;
> +    int ret = -1;
> +
> +    full_file_name = get_full_path_win32(dirfd, pathname);
> +    if (full_file_name == NULL) {
> +        return ret;
> +    }
> +
> +    ret = mkdir(full_file_name);
> +
> +    return ret;
> +}
> +
> +/*
> + * renameat_win32 - emulate renameat()
> + *
> + * This function emulates renameat().
> + *
> + * Windows POSIX API does not support openning a directory by open(). Only
> + * handle of directory can be opened by CreateFile().
> + *
> + * So renameat_win32() has to use a directory handle instead of a directory fd.
> + *
> + * Access to a symbolic link will be denied to prevent security issues.
> + */
> +int renameat_win32(HANDLE olddirfd, const char *oldpath,
> +                   HANDLE newdirfd, const char *newpath)
> +{
> +    g_autofree char *full_old_name = NULL;
> +    g_autofree char *full_new_name = NULL;
> +    HANDLE hFile;
> +    DWORD attribute;
> +    int err = 0;
> +    int ret = -1;
> +
> +    full_old_name = get_full_path_win32(olddirfd, oldpath);
> +    full_new_name = get_full_path_win32(newdirfd, newpath);
> +    if (full_old_name == NULL || full_new_name == NULL) {
> +        return ret;
> +    }
> +
> +    /* open file to lock it */
> +    hFile = CreateFile(full_old_name, GENERIC_READ,
> +                       FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
> +                       NULL,
> +                       OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
> +
> +    attribute = GetFileAttributes(full_old_name);
> +
> +    /* check if it is a symbolic link */
> +    if ((attribute == INVALID_FILE_ATTRIBUTES)
> +        || (attribute & FILE_ATTRIBUTE_REPARSE_POINT) != 0) {
> +        err = EACCES;
> +        goto out;
> +    }
> +
> +    CloseHandle(hFile);
> +
> +    ret = rename(full_old_name, full_new_name);
> +out:
> +    if (err != 0) {
> +        errno = err;
> +    }
> +    return ret;
> +}
> +
> +/*
> + * utimensat_win32 - emulate utimensat()
> + *
> + * This function emulates utimensat().
> + *
> + * Windows POSIX API does not support opening a directory by open(). Only
> + * handle of directory can be opened by CreateFile().
> + *
> + * So utimensat_win32() has to use a directory handle instead of a directory fd.
> + *
> + * Access to a symbolic link will be denied to prevent security issues.
> + */
> +int utimensat_win32(QemuFd_t dirfd, const char *pathname,
> +                    const struct timespec times[2], int flags)
> +{
> +    g_autofree char *full_file_name = NULL;
> +    HANDLE hFile = INVALID_HANDLE_VALUE;
> +    DWORD attribute;
> +    struct utimbuf tm;
> +    int err = 0;
> +    int ret = -1;
> +
> +    full_file_name = get_full_path_win32(dirfd, pathname);
> +    if (full_file_name == NULL) {
> +        return ret;
> +    }
> +
> +    /* open file to lock it */
> +    hFile = CreateFile(full_file_name, GENERIC_READ,
> +                       FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
> +                       NULL,
> +                       OPEN_EXISTING,
> +                       FILE_FLAG_BACKUP_SEMANTICS
> +                       | FILE_FLAG_OPEN_REPARSE_POINT,
> +                       NULL);
> +
> +    if (hFile == INVALID_HANDLE_VALUE) {
> +        err = EACCES;
> +        goto out;
> +    }
> +
> +    attribute = GetFileAttributes(full_file_name);
> +
> +    /* check if it is a symbolic link */
> +    if ((attribute == INVALID_FILE_ATTRIBUTES)
> +        || (attribute & FILE_ATTRIBUTE_REPARSE_POINT) != 0) {
> +        errno = EACCES;
> +        goto out;
> +    }
> +
> +    tm.actime = times[0].tv_sec;
> +    tm.modtime = times[1].tv_sec;
> +
> +    ret = utime(full_file_name, &tm);
> +
> +out:
> +    if (hFile != INVALID_HANDLE_VALUE) {
> +        CloseHandle(hFile);
> +    }
> +
> +    if (err != 0) {
> +        errno = err;
> +    }
> +    return ret;
> +}
> +
> +/*
> + * unlinkat_win32 - emulate unlinkat()
> + *
> + * This function emulates unlinkat().
> + *
> + * Windows POSIX API does not support opening a directory by open(). Only
> + * handle of directory can be opened by CreateFile().
> + *
> + * So unlinkat_win32() has to use a directory handle instead of a directory fd.
> + *
> + * Access to a symbolic link will be denied to prevent security issues.
> + */
> +
> +int unlinkat_win32(QemuFd_t dirfd, const char *pathname, int flags)
> +{
> +    g_autofree char *full_file_name = NULL;
> +    HANDLE hFile;
> +    DWORD attribute;
> +    int err = 0;
> +    int ret = -1;
> +
> +    full_file_name = get_full_path_win32(dirfd, pathname);
> +    if (full_file_name == NULL) {
> +        return ret;
> +    }
> +
> +    /* open file to prevent other one modify it */
> +    hFile = CreateFile(full_file_name, GENERIC_READ,
> +                       FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
> +                       NULL,
> +                       OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
> +
> +    attribute = GetFileAttributes(full_file_name);
> +
> +    /* check if it is a symbolic link */
> +    if ((attribute == INVALID_FILE_ATTRIBUTES)
> +        || (attribute & FILE_ATTRIBUTE_REPARSE_POINT) != 0) {
> +        err = EACCES;
> +        goto out;
> +    }
> +
> +    if (flags == AT_REMOVEDIR) { /* remove directory */
> +        if ((attribute & FILE_ATTRIBUTE_DIRECTORY) == 0) {
> +            err = ENOTDIR;
> +            goto out;
> +        }
> +        ret = rmdir(full_file_name);
> +    } else { /* remove regular file */
> +        if ((attribute & FILE_ATTRIBUTE_DIRECTORY) != 0) {
> +            err = EISDIR;
> +            goto out;
> +        }
> +        ret = remove(full_file_name);
> +    }
> +
> +    /* after last handle closed, file will be removed */
> +    CloseHandle(hFile);
> +
> +out:
> +    if (err != 0) {
> +        errno = err;
> +    }
> +    return ret;
> +}
> +
> +/*
> + * statfs_win32 - statfs() on Windows
> + *
> + * This function emulates statfs() on Windows host.
> + */
> +int statfs_win32(const char *path, struct statfs *stbuf)
> +{
> +    char RealPath[4] = { 0 };
> +    unsigned long SectorsPerCluster;
> +    unsigned long BytesPerSector;
> +    unsigned long NumberOfFreeClusters;
> +    unsigned long TotalNumberOfClusters;
> +
> +    /* only need first 3 bytes, e.g. "C:\ABC", only need "C:\" */
> +    memcpy(RealPath, path, 3);
> +
> +    if (GetDiskFreeSpace(RealPath, &SectorsPerCluster, &BytesPerSector,
> +                         &NumberOfFreeClusters, &TotalNumberOfClusters) == 0) {
> +        errno = EIO;
> +        return -1;
> +    }
> +
> +    stbuf->f_type = V9FS_MAGIC;
> +    stbuf->f_bsize =
> +        (__fsword_t)SectorsPerCluster * (__fsword_t)BytesPerSector;
> +    stbuf->f_blocks = (fsblkcnt_t)TotalNumberOfClusters;
> +    stbuf->f_bfree = (fsblkcnt_t)NumberOfFreeClusters;
> +    stbuf->f_bavail = (fsblkcnt_t)NumberOfFreeClusters;
> +    stbuf->f_files = -1;
> +    stbuf->f_ffree = -1;
> +    stbuf->f_namelen = NAME_MAX;
> +    stbuf->f_frsize = 0;
> +    stbuf->f_flags = 0;
> +
> +    return 0;
> +}
> +
> +/*
> + * openat_dir - emulate openat_dir()
> + *
> + * This function emulates openat_dir().
> + *
> + * Windows POSIX API does not support opening a directory by open(). Only
> + * handle of directory can be opened by CreateFile().
> + *
> + * So openat_dir() has to use a directory handle instead of a directory fd.
> + *
> + * Access to a symbolic link will be denied to prevent security issues.
> + */
> +QemuFd_t openat_dir(QemuFd_t dirfd, const char *name)
> +{
> +    g_autofree char *full_file_name = NULL;
> +    HANDLE hSubDir;
> +    DWORD attribute;
> +
> +    full_file_name = get_full_path_win32(dirfd, name);
> +    if (full_file_name == NULL) {
> +        return INVALID_HANDLE_VALUE;
> +    }
> +
> +    attribute = GetFileAttributes(full_file_name);
> +    if (attribute == INVALID_FILE_ATTRIBUTES) {
> +        return INVALID_HANDLE_VALUE;
> +    }
> +
> +    /* check if it is a directory */
> +    if ((attribute & FILE_ATTRIBUTE_DIRECTORY) == 0) {
> +        return INVALID_HANDLE_VALUE;
> +    }
> +
> +    /* do not allow opening a symbolic link */
> +    if ((attribute & FILE_ATTRIBUTE_REPARSE_POINT) != 0) {
> +        return INVALID_HANDLE_VALUE;
> +    }
> +
> +    /* open it */
> +    hSubDir = CreateFile(full_file_name, GENERIC_READ,
> +                         FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
> +                         NULL,
> +                         OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
> +    return hSubDir;
> +}
> +
> +QemuFd_t openat_file(QemuFd_t dirfd, const char *name, int flags,
> +                     mode_t mode)
> +{
> +    return openat_win32(dirfd, name, flags | _O_BINARY, mode);
> +}
> +
> +/*
> + * fgetxattrat_nofollow - get extended attribute
> + *
> + * This function gets extended attribute from file <path> in the directory
> + * specified by <dirfd>. The extended atrribute name is specified by <name>
> + * and return value will be put in <value>.
> + *
> + * This function emulates extended attribute by NTFS ADS.
> + */
> +ssize_t fgetxattrat_nofollow(QemuFd_t dirfd, const char *path,
> +                             const char *name, void *value, size_t size)
> +{
> +    g_autofree char *full_file_name = NULL;
> +    char ads_file_name[NAME_MAX + 1] = { 0 };
> +    DWORD dwBytesRead;
> +    HANDLE hStream;
> +
> +    full_file_name = get_full_path_win32(dirfd, path);
> +    if (full_file_name == NULL) {
> +        errno = EIO;
> +        return -1;
> +    }
> +
> +    if (build_ads_name(ads_file_name, NAME_MAX, full_file_name, name) < 0) {
> +        errno = EIO;
> +        return -1;
> +    }
> +
> +    hStream = CreateFile(ads_file_name, GENERIC_READ, FILE_SHARE_READ, NULL,
> +                         OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
> +    if (hStream == INVALID_HANDLE_VALUE &&
> +        GetLastError() == ERROR_FILE_NOT_FOUND) {
> +        errno = ENODATA;
> +        return -1;
> +    }
> +
> +    if (ReadFile(hStream, value, size, &dwBytesRead, NULL) == FALSE) {
> +        errno = EIO;
> +        CloseHandle(hStream);
> +        return -1;
> +    }
> +
> +    CloseHandle(hStream);
> +
> +    return dwBytesRead;
> +}
> +
> +/*
> + * fsetxattrat_nofollow - set extended attribute
> + *
> + * This function set extended attribute to file <path> in the directory
> + * specified by <dirfd>.
> + *
> + * This function emulates extended attribute by NTFS ADS.
> + */
> +
> +int fsetxattrat_nofollow(QemuFd_t dirfd, const char *path, const char *name,
> +                         void *value, size_t size, int flags)
> +{
> +    g_autofree char *full_file_name = NULL;
> +    char ads_file_name[NAME_MAX + 1] = { 0 };
> +    DWORD dwBytesWrite;
> +    HANDLE hStream;
> +
> +    full_file_name = get_full_path_win32(dirfd, path);
> +    if (full_file_name == NULL) {
> +        errno = EIO;
> +        return -1;
> +    }
> +
> +    if (build_ads_name(ads_file_name, NAME_MAX, full_file_name, name) < 0) {
> +        errno = EIO;
> +        return -1;
> +    }
> +
> +    hStream = CreateFile(ads_file_name, GENERIC_WRITE, FILE_SHARE_READ, NULL,
> +                         CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
> +    if (hStream == INVALID_HANDLE_VALUE) {
> +        errno = EIO;
> +        return -1;
> +    }
> +
> +    if (WriteFile(hStream, value, size, &dwBytesWrite, NULL) == FALSE) {
> +        errno = EIO;
> +        CloseHandle(hStream);
> +        return -1;
> +    }
> +
> +    CloseHandle(hStream);
> +
> +    return 0;
> +}
> +
> +/*
> + * flistxattrat_nofollow - list extended attribute
> + *
> + * This function gets extended attribute lists from file <filename> in the
> + * directory specified by <dirfd>. Lists returned will be put in <list>.
> + *
> + * This function emulates extended attribute by NTFS ADS.
> + */
> +ssize_t flistxattrat_nofollow(QemuFd_t dirfd, const char *filename,
> +                              char *list, size_t size)
> +{
> +    g_autofree char *full_file_name = NULL;
> +    WCHAR WideCharStr[NAME_MAX + 1] = { 0 };
> +    char full_ads_name[NAME_MAX + 1];
> +    WIN32_FIND_STREAM_DATA fsd;
> +    BOOL bFindNext;
> +    char *list_ptr = list;
> +    size_t list_left_size = size;
> +    HANDLE hFind;
> +    int ret;
> +
> +    full_file_name = get_full_path_win32(dirfd, filename);
> +    if (full_file_name == NULL) {
> +        errno = EIO;
> +        return -1;
> +    }
> +
> +    /*
> +     * ADS enumerate function only has WCHAR version, so we need to
> +     * covert filename to utf-8 string.
> +     */
> +    ret = MultiByteToWideChar(CP_UTF8, 0, full_file_name,
> +                              strlen(full_file_name), WideCharStr, NAME_MAX);
> +    if (ret == 0) {
> +        errno = EIO;
> +        return -1;
> +    }
> +
> +    hFind = FindFirstStreamW(WideCharStr, FindStreamInfoStandard, &fsd, 0);
> +    if (hFind == INVALID_HANDLE_VALUE) {
> +        errno = ENODATA;
> +        return -1;
> +    }
> +
> +    do {
> +        memset(full_ads_name, 0, sizeof(full_ads_name));
> +
> +        /*
> +         * ADS enumerate function only has WCHAR version, so we need to
> +         * covert cStreamName to utf-8 string.
> +         */
> +        ret = WideCharToMultiByte(CP_UTF8, 0,
> +                                  fsd.cStreamName, wcslen(fsd.cStreamName) + 1,
> +                                  full_ads_name, sizeof(full_ads_name) - 1,
> +                                  NULL, NULL);
> +        if (ret == 0) {
> +            if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
> +                errno = ERANGE;
> +            }
> +            CloseHandle(hFind);
> +            return -1;
> +        }
> +
> +        ret = copy_ads_name(list_ptr, list_left_size, full_ads_name);
> +        if (ret < 0) {
> +            errno = ERANGE;
> +            CloseHandle(hFind);
> +            return -1;
> +        }
> +
> +        list_ptr = list_ptr + ret;
> +        list_left_size = list_left_size - ret;
> +
> +        bFindNext = FindNextStreamW(hFind, &fsd);
> +    } while (bFindNext);
> +
> +    CloseHandle(hFind);
> +
> +    return size - list_left_size;
> +}
> +
> +/*
> + * fremovexattrat_nofollow - remove extended attribute
> + *
> + * This function removes an extended attribute from file <filename> in the
> + * directory specified by <dirfd>.
> + *
> + * This function emulates extended attribute by NTFS ADS.
> + */
> +ssize_t fremovexattrat_nofollow(QemuFd_t dirfd, const char *filename,
> +                                const char *name)
> +{
> +    g_autofree char *full_file_name = NULL;
> +    char ads_file_name[NAME_MAX + 1] = { 0 };
> +
> +    full_file_name = get_full_path_win32(dirfd, filename);
> +    if (full_file_name == NULL) {
> +        errno = EIO;
> +        return -1;
> +    }
> +
> +    if (build_ads_name(ads_file_name, NAME_MAX, filename, name) < 0) {
> +        errno = EIO;
> +        return -1;
> +    }
> +
> +    if (DeleteFile(ads_file_name) != 0) {
> +        if (GetLastError() == ERROR_FILE_NOT_FOUND) {
> +            errno = ENODATA;
> +            return -1;
> +        }
> +    }
> +
> +    return 0;
> +}
> +
> +/*
> + * local_opendir_nofollow - open a Windows directory
> + *
> + * This function returns a Windows file handle of the directory specified by
> + * <dirpath> based on 9pfs mount point.
> + *
> + * Windows POSIX API does not support opening a directory by open(). Only
> + * handle of directory can be opened by CreateFile().
> + *
> + * This function checks the resolved path of <dirpath>. If the resolved
> + * path is not in the scope of root directory (e.g. by symbolic link), then
> + * this function will fail to prevent any security issues.
> + */
> +HANDLE local_opendir_nofollow(FsContext *fs_ctx, const char *dirpath)
> +{
> +    g_autofree char *full_file_name = NULL;
> +    LocalData *data = fs_ctx->private;
> +    HANDLE hDir;
> +
> +    hDir = openat_dir(data->mountfd, dirpath);
> +    if (hDir == INVALID_HANDLE_VALUE) {
> +        return INVALID_HANDLE_VALUE;
> +    }
> +
> +    full_file_name = get_full_path_win32(hDir, NULL);
> +    if (full_file_name == NULL) {
> +        CloseHandle(hDir);
> +        return INVALID_HANDLE_VALUE;
> +    }
> +
> +    /*
> +     * Check if the resolved path is in the root directory scope:
> +     * data->root_path and full_file_name are full path with symbolic
> +     * link resolved, so fs_ctx->root_path must be in the head of
> +     * full_file_name. If not, that means guest OS tries to open a file not
> +     * in the scope of mount point. This operation should be denied.
> +     */
> +    if (memcmp(full_file_name, data->root_path,
> +               strlen(data->root_path)) != 0) {
> +        CloseHandle(hDir);
> +        hDir = INVALID_HANDLE_VALUE;
> +    }
> +
> +    return hDir;
> +}
> +
> +/*
> + * qemu_mknodat - mknodat emulate function
> + *
> + * This function emulates mknodat on Windows. It only works when security
> + * model is mapped or mapped-xattr.
> + */
> +int qemu_mknodat(QemuFd_t dirfd, const char *filename, mode_t mode, dev_t dev)
> +{
> +    if (S_ISREG(mode) || !(mode & S_IFMT)) {
> +        HANDLE hFile = openat_file(dirfd, filename, O_CREAT, mode);
> +        if (hFile == INVALID_HANDLE_VALUE) {
> +            return -1;
> +        }
> +        close_preserve_errno(hFile);
> +        return 0;
> +    }
> +
> +    error_report_once("Unsupported operation for mknodat");
> +    errno = ENOTSUP;
> +    return -1;
> +}
> 




^ permalink raw reply	[flat|nested] 36+ messages in thread

* RE: [PATCH v2 07/19] hw/9pfs: Implement Windows specific utilities functions for 9pfs
  2022-11-17 15:55   ` Christian Schoenebeck
@ 2022-11-17 16:38     ` Shi, Guohuai
  0 siblings, 0 replies; 36+ messages in thread
From: Shi, Guohuai @ 2022-11-17 16:38 UTC (permalink / raw)
  To: Christian Schoenebeck, qemu-devel; +Cc: Greg Kurz, Meng, Bin



> -----Original Message-----
> From: Christian Schoenebeck <qemu_oss@crudebyte.com>
> Sent: Thursday, November 17, 2022 23:55
> To: qemu-devel@nongnu.org
> Cc: Shi, Guohuai <Guohuai.Shi@windriver.com>; Greg Kurz <groug@kaod.org>;
> Meng, Bin <Bin.Meng@windriver.com>
> Subject: Re: [PATCH v2 07/19] hw/9pfs: Implement Windows specific utilities
> functions for 9pfs
> 
> CAUTION: This email comes from a non Wind River email account!
> Do not click links or open attachments unless you recognize the sender and
> know the content is safe.
> 
> On Friday, November 11, 2022 5:22:13 AM CET Bin Meng wrote:
> > From: Guohuai Shi <guohuai.shi@windriver.com>
> >
> > Windows POSIX API and MinGW library do not provide the NO_FOLLOW flag,
> > and do not allow opening a directory by POSIX open(). This causes all
> > xxx_at() functions cannot work directly. However, we can provide
> > Windows handle based functions to emulate xxx_at() functions (e.g.:
> > openat_win32, utimensat_win32, etc.).
> >
> > NTFS ADS (Alternate Data Streams) is used to emulate 9pfs extended
> > attributes on Windows. Symbolic link is only supported when security
> > model is "mapped-xattr" or "mapped-file".
> >
> > Signed-off-by: Guohuai Shi <guohuai.shi@windriver.com>
> > Signed-off-by: Bin Meng <bin.meng@windriver.com>
> >
> > ---
> >
> > Changes in v2:
> > - Support symbolic link when security model is "mapped-xattr" or "mapped-
> file"
> >
> >  hw/9pfs/9p-local.h      |   7 +
> >  hw/9pfs/9p-util.h       |  38 +-
> >  hw/9pfs/9p-local.c      |   4 -
> >  hw/9pfs/9p-util-win32.c | 934
> > ++++++++++++++++++++++++++++++++++++++++
> >  4 files changed, 978 insertions(+), 5 deletions(-)  create mode
> > 100644 hw/9pfs/9p-util-win32.c
> >
> > diff --git a/hw/9pfs/9p-local.h b/hw/9pfs/9p-local.h index
> > 66a21316a0..eb4f39ddc2 100644
> > --- a/hw/9pfs/9p-local.h
> > +++ b/hw/9pfs/9p-local.h
> > @@ -13,6 +13,13 @@
> >  #ifndef QEMU_9P_LOCAL_H
> >  #define QEMU_9P_LOCAL_H
> >
> > +typedef struct {
> > +    QemuFd_t mountfd;
> > +#ifdef CONFIG_WIN32
> > +    char *root_path;
> > +#endif
> > +} LocalData;
> > +
> >  QemuFd_t local_open_nofollow(FsContext *fs_ctx, const char *path, int
> flags,
> >                               mode_t mode);  QemuFd_t
> > local_opendir_nofollow(FsContext *fs_ctx, const char *path); diff
> > --git a/hw/9pfs/9p-util.h b/hw/9pfs/9p-util.h index
> > 3d6bd1a51e..5fb854bf61 100644
> > --- a/hw/9pfs/9p-util.h
> > +++ b/hw/9pfs/9p-util.h
> > @@ -88,26 +88,61 @@ static inline int errno_to_dotl(int err) {
> >      return err;
> >  }
> >
> > -#ifdef CONFIG_DARWIN
> > +#if defined(CONFIG_DARWIN)
> >  #define qemu_fgetxattr(...) fgetxattr(__VA_ARGS__, 0, 0)
> > +#elif defined(CONFIG_WIN32)
> > +#define qemu_fgetxattr fgetxattr_win32
> >  #else
> >  #define qemu_fgetxattr fgetxattr
> >  #endif
> >
> > +#ifdef CONFIG_WIN32
> > +#define qemu_openat     openat_win32
> > +#define qemu_fstatat    fstatat_win32
> > +#define qemu_mkdirat    mkdirat_win32
> > +#define qemu_renameat   renameat_win32
> > +#define qemu_utimensat  utimensat_win32
> > +#define qemu_unlinkat   unlinkat_win32
> > +#else
> >  #define qemu_openat     openat
> >  #define qemu_fstatat    fstatat
> >  #define qemu_mkdirat    mkdirat
> >  #define qemu_renameat   renameat
> >  #define qemu_utimensat  utimensat
> >  #define qemu_unlinkat   unlinkat
> > +#endif
> > +
> > +#ifdef CONFIG_WIN32
> > +char *get_full_path_win32(QemuFd_t fd, const char *name); ssize_t
> > +fgetxattr_win32(int fd, const char *name, void *value, size_t size);
> > +QemuFd_t openat_win32(QemuFd_t dirfd, const char *pathname, int flags,
> > +                      mode_t mode);
> > +int fstatat_win32(QemuFd_t dirfd, const char *pathname,
> > +                  struct stat *statbuf, int flags); int
> > +mkdirat_win32(QemuFd_t dirfd, const char *pathname, mode_t mode); int
> > +renameat_win32(QemuFd_t olddirfd, const char *oldpath,
> > +                   QemuFd_t newdirfd, const char *newpath); int
> > +utimensat_win32(QemuFd_t dirfd, const char *pathname,
> > +                    const struct timespec times[2], int flags); int
> > +unlinkat_win32(QemuFd_t dirfd, const char *pathname, int flags); int
> > +statfs_win32(const char *root_path, struct statfs *stbuf); QemuFd_t
> > +openat_dir(QemuFd_t dirfd, const char *name); QemuFd_t
> > +openat_file(QemuFd_t dirfd, const char *name, int flags,
> > +                     mode_t mode);
> > +#endif
> 
> That's quite a bunch of *_win32() prototypes. Maybe moving them into their
> own 9p-util-win32.h file?
> 
> >  static inline void close_preserve_errno(QemuFd_t fd)  {
> >      int serrno = errno;
> > +#ifndef CONFIG_WIN32
> >      close(fd);
> > +#else
> > +    CloseHandle(fd);
> > +#endif
> >      errno = serrno;
> >  }
> >
> > +#ifndef CONFIG_WIN32
> >  static inline QemuFd_t openat_dir(QemuFd_t dirfd, const char *name)
> > {
> >      return qemu_openat(dirfd, name,
> > @@ -155,6 +190,7 @@ again:
> >      errno = serrno;
> >      return fd;
> >  }
> > +#endif
> >
> >  ssize_t fgetxattrat_nofollow(QemuFd_t dirfd, const char *path,
> >                               const char *name, void *value, size_t
> > size); diff --git a/hw/9pfs/9p-local.c b/hw/9pfs/9p-local.c index
> > 22377a3105..24e21141d5 100644
> > --- a/hw/9pfs/9p-local.c
> > +++ b/hw/9pfs/9p-local.c
> > @@ -53,10 +53,6 @@
> >  #define BTRFS_SUPER_MAGIC 0x9123683E
> >  #endif
> >
> > -typedef struct {
> > -    QemuFd_t mountfd;
> > -} LocalData;
> > -
> >  QemuFd_t local_open_nofollow(FsContext *fs_ctx, const char *path, int
> flags,
> >                               mode_t mode)  { diff --git
> > a/hw/9pfs/9p-util-win32.c b/hw/9pfs/9p-util-win32.c new file mode
> > 100644 index 0000000000..ed3d519937
> > --- /dev/null
> > +++ b/hw/9pfs/9p-util-win32.c
> > @@ -0,0 +1,934 @@
> > +/*
> > + * 9p utilities (Windows Implementation)
> > + *
> > + * Copyright (c) 2022 Wind River Systems, Inc.
> > + *
> > + * This work is licensed under the terms of the GNU GPL, version 2 or
> later.
> > + * See the COPYING file in the top-level directory.
> > + */
> > +
> > +/*
> > + * This file contains Windows only functions for 9pfs.
> > + *
> > + * For 9pfs Windows host, the following features are different from Linux
> host:
> > + *
> > + * 1. Windows POSIX API does not provide the NO_FOLLOW flag, that means
> MinGW
> > + *    cannot detect if a path is a symbolic link or not. Also Windows do
> not
> > + *    provide POSIX compatible readlink(). Supporting symbolic link in
> 9pfs on
> > + *    Windows may cause security issues, so symbolic link support is
> disabled
> > + *    completely for security model "none" or "passthrough".
> 
> So your standpoint is, guest cannot create links, therefore no need for
> NO_FOLLOW and friends, safe. However a common use case for 9p is to export a
> directory tree that was previously deployed by other means that might indeed
> place links that might attempt to escape the sandbox. Don't you think that
> such scenarios should be handled in some way?

Previously deployed links are checked by flag FILE_ATTRIBUTE_REPARSE_POINT.
If a file is a link, it will have flag FILE_ATTRIBUTE_REPARSE_POINT returned by GetFileAttributes().
This flag is checked in openat_win32(), fstatat_win32(), renameat_win32(), utimensat_win32(), unlinkat_win32(), openat_dir().
So all scenarios are handled correctly.

> 
> > + *
> > + * 2. Windows file system does not support extended attributes directly.
> 9pfs
> > + *    for Windows uses NTFS ADS (Alternate Data Streams) to emulate
> extended
> > + *    attributes.
> > + *
> > + * 3. statfs() is not available on Windows. qemu_statfs() is used to
> emulate it.
> > + *
> > + * 4. On Windows trying to open a directory with the open() API will fail.
> > + *    This is because Windows does not allow opening directory in normal
> usage.
> > + *
> > + *    As a result of this, all xxx_at() functions won't work directly on
> > + *    Windows, e.g.: openat(), unlinkat(), etc.
> > + *
> > + *    As xxx_at() can prevent parent directory to be modified on Linux
> host,
> > + *    to support this and prevent security issue, all xxx_at() APIs are
> replaced
> > + *    by xxx_at_win32() and Windows handle is used to replace the
> directory fd.
> 
> As you already have a Windows HANDLE, you could call NtCreateFile() to
> implement openat(), no? NtCreateFile() takes an optional `HANDLE
> RootDirectory` attribute with its ObjectAttributes function argument.
> 

In the next version, no need provide "HANDLE" version functions. All functions are kept as old prototype: use fd, and convert fd to handle by _get_osfhandle().

Thanks
Guohuai 
> > + *
> > + *    Windows file system does not allow replacing a file or directory if
> it is
> > + *    referenced by a handle. Keep the handle open will lock and protect
> the
> > + *    parent directory and make the access to files atomically.
> > + *
> > + *    If we don't protect (lock) the parent directory, the parent
> directory may
> > + *    be replaced by others (e.g.: a symbolic link) and cause security
> issues.
> > + */
> > +
> > +#include "qemu/osdep.h"
> > +#include "qapi/error.h"
> > +#include "qemu/error-report.h"
> > +#include "9p.h"
> > +#include "9p-util.h"
> > +#include "9p-local.h"
> > +
> > +#include <windows.h>
> > +#include <dirent.h>
> > +
> > +#define V9FS_MAGIC  0x53465039  /* string "9PFS" */
> > +
> > +/*
> > + * build_ads_name - construct Windows ADS name
> > + *
> > + * This function constructs Windows NTFS ADS (Alternate Data Streams)
> > +name
> > + * to <namebuf>.
> > + */
> > +static int build_ads_name(char *namebuf, size_t namebuf_len,
> > +                          const char *filename, const char *ads_name)
> > +{
> > +    size_t total_size;
> > +
> > +    total_size = strlen(filename) + strlen(ads_name) + 2;
> > +    if (total_size  > namebuf_len) {
> > +        return -1;
> > +    }
> > +
> > +    /*
> > +     * NTFS ADS (Alternate Data Streams) name format: filename:ads_name
> > +     * e.g.: D:\1.txt:my_ads_name
> > +     */
> > +
> > +    strcpy(namebuf, filename);
> > +    strcat(namebuf, ":");
> > +    strcat(namebuf, ads_name);
> > +
> > +    return 0;
> > +}
> > +
> > +/*
> > + * copy_ads_name - copy ADS name from buffer returned by
> > +FindNextStreamW()
> > + *
> > + * This function removes string "$DATA" in ADS name string returned
> > +by
> > + * FindNextStreamW(), and copies the real ADS name to <namebuf>.
> > + */
> > +static ssize_t copy_ads_name(char *namebuf, size_t namebuf_len,
> > +                             char *full_ads_name) {
> > +    char *p1, *p2;
> > +
> > +    /*
> > +     * NTFS ADS (Alternate Data Streams) name from enumerate data format:
> > +     * :ads_name:$DATA, e.g.: :my_ads_name:$DATA
> > +     *
> > +     * ADS name from FindNextStreamW() always has ":$DATA" string at the
> end.
> > +     *
> > +     * This function copies ADS name to namebuf.
> > +     */
> > +
> > +    p1 = strchr(full_ads_name, ':');
> > +    if (p1 == NULL) {
> > +        return -1;
> > +    }
> > +
> > +    p2 = strchr(p1 + 1, ':');
> > +    if (p2 == NULL) {
> > +        return -1;
> > +    }
> > +
> > +    /* skip empty ads name */
> > +    if (p2 - p1 == 1) {
> > +        return 0;
> > +    }
> > +
> > +    if (p2 - p1 + 1 > namebuf_len) {
> > +        return -1;
> > +    }
> > +
> > +    memcpy(namebuf, p1 + 1, p2 - p1 - 1);
> > +    namebuf[p2 - p1 - 1] = '\0';
> > +
> > +    return p2 - p1;
> > +}
> > +
> > +/*
> > + * get_full_path_win32 - get full file name base on a handle
> > + *
> > + * This function gets full file name based on a handle specified by
> > +<fd> to
> > + * a file or directory.
> > + *
> > + * Caller function needs to free the file name string after use.
> > + */
> > +char *get_full_path_win32(QemuFd_t fd, const char *name) {
> > +    g_autofree char *full_file_name = NULL;
> > +    DWORD total_size;
> > +    DWORD name_size;
> > +
> > +    full_file_name = g_malloc0(NAME_MAX);
> > +
> > +    /* get parent directory full file name */
> > +    name_size = GetFinalPathNameByHandle(fd, full_file_name,
> > +                                         NAME_MAX - 1,
> FILE_NAME_NORMALIZED);
> > +    if (name_size == 0 || name_size > NAME_MAX - 1) {
> > +        return NULL;
> > +    }
> > +
> > +    /* full path returned is the "\\?\" syntax, remove the lead string */
> > +    memmove(full_file_name, full_file_name + 4, NAME_MAX - 4);
> > +
> > +    if (name != NULL) {
> > +        total_size = strlen(full_file_name) + strlen(name) + 2;
> > +
> > +        if (total_size > NAME_MAX) {
> > +            return NULL;
> > +        }
> > +
> > +        /* build sub-directory file name */
> > +        strcat(full_file_name, "\\");
> > +        strcat(full_file_name, name);
> > +    }
> > +
> > +    return g_steal_pointer(&full_file_name); }
> > +
> > +/*
> > + * fgetxattr_win32 - get extended attribute by fd
> > + *
> > + * This function gets extened attribute by <fd>. <fd> will be
> > +translated to
> > + * Windows handle.
> > + *
> > + * This function emulates extended attribute by NTFS ADS.
> > + */
> > +ssize_t fgetxattr_win32(int fd, const char *name, void *value, size_t
> > +size) {
> > +    g_autofree char *full_file_name = NULL;
> > +    char ads_file_name[NAME_MAX + 1] = {0};
> > +    DWORD dwBytesRead;
> > +    HANDLE hStream;
> > +    HANDLE hFile;
> > +
> > +    hFile = (HANDLE)_get_osfhandle(fd);
> > +
> > +    full_file_name = get_full_path_win32(hFile, NULL);
> > +    if (full_file_name == NULL) {
> > +        errno = EIO;
> > +        return -1;
> > +    }
> > +
> > +    if (build_ads_name(ads_file_name, NAME_MAX, full_file_name, name) < 0)
> {
> > +        errno = EIO;
> > +        return -1;
> > +    }
> > +
> > +    hStream = CreateFile(ads_file_name, GENERIC_READ, FILE_SHARE_READ,
> NULL,
> > +                         OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
> > +    if (hStream == INVALID_HANDLE_VALUE &&
> > +        GetLastError() == ERROR_FILE_NOT_FOUND) {
> > +        errno = ENODATA;
> > +        return -1;
> > +    }
> > +
> > +    if (ReadFile(hStream, value, size, &dwBytesRead, NULL) == FALSE) {
> > +        errno = EIO;
> > +        CloseHandle(hStream);
> > +        return -1;
> > +    }
> > +
> > +    CloseHandle(hStream);
> > +
> > +    return dwBytesRead;
> > +}
> > +
> > +/*
> > + * openat_win32 - emulate openat()
> > + *
> > + * This function emulates openat().
> > + *
> > + * Windows POSIX API does not support opening a directory by open().
> > +Only
> > + * handle of directory can be opened by CreateFile().
> > + *
> > + * So openat_win32() has to use a directory handle instead of a directory
> fd.
> > + *
> > + * For symbolic access:
> > + * 1. Parent directory handle <dirfd> should not be a symbolic link
> because
> > + *    it is opened by openat_dir() which can prevent from opening a link
> to
> > + *    a dirctory.
> > + * 2. Link flag in <mode> is not set because Windows does not have this
> flag.
> > + *    Create a new symbolic link will be denied.
> > + * 3. This function checks file symbolic link attribute after open.
> > + *
> > + * So symbolic link will not be accessed by 9p client.
> > + */
> > +QemuFd_t openat_win32(QemuFd_t dirfd, const char *pathname, int flags,
> > +                      mode_t mode)
> > +{
> > +    g_autofree char *full_file_name1 = NULL;
> > +    g_autofree char *full_file_name2 = NULL;
> > +    HANDLE hFile = INVALID_HANDLE_VALUE;
> > +    int fd;
> > +
> > +    full_file_name1 = get_full_path_win32(dirfd, pathname);
> > +    if (full_file_name1 == NULL) {
> > +        return hFile;
> > +    }
> > +
> > +    fd = open(full_file_name1, flags, mode);
> > +    if (fd > 0) {
> > +        DWORD attribute;
> > +        hFile = (HANDLE)_get_osfhandle(fd);
> > +
> > +        full_file_name2 = get_full_path_win32(hFile, NULL);
> > +        attribute = GetFileAttributes(full_file_name2);
> > +
> > +        /* check if it is a symbolic link */
> > +        if ((attribute == INVALID_FILE_ATTRIBUTES)
> > +            || (attribute & FILE_ATTRIBUTE_REPARSE_POINT) != 0) {
> > +            errno = EACCES;
> > +            hFile = INVALID_HANDLE_VALUE;
> > +            close(fd);
> > +        }
> > +    }
> > +
> > +    return hFile;
> > +}
> > +
> > +/*
> > + * fstatat_win32 - emulate fstatat()
> > + *
> > + * This function emulates fstatat().
> > + *
> > + * Windows POSIX API does not support opening a directory by open().
> > +Only
> > + * handle of directory can be opened by CreateFile().
> > + *
> > + * So fstatat_win32() has to use a directory handle instead of a directory
> fd.
> > + *
> > + * Access to a symbolic link will be denied to prevent security issues.
> > + */
> > +int fstatat_win32(QemuFd_t dirfd, const char *pathname,
> > +                  struct stat *statbuf, int flags) {
> > +    g_autofree char *full_file_name = NULL;
> > +    HANDLE hFile = INVALID_HANDLE_VALUE;
> > +    BY_HANDLE_FILE_INFORMATION file_info;
> > +    DWORD attribute;
> > +    int err = 0;
> > +    int ret = -1;
> > +    ino_t st_ino;
> > +
> > +    full_file_name = get_full_path_win32(dirfd, pathname);
> > +    if (full_file_name == NULL) {
> > +        return ret;
> > +    }
> > +
> > +    /* open file to lock it */
> > +    hFile = CreateFile(full_file_name, GENERIC_READ,
> > +                       FILE_SHARE_READ | FILE_SHARE_WRITE |
> FILE_SHARE_DELETE,
> > +                       NULL,
> > +                       OPEN_EXISTING,
> > +                       FILE_FLAG_BACKUP_SEMANTICS
> > +                       | FILE_FLAG_OPEN_REPARSE_POINT,
> > +                       NULL);
> > +
> > +    if (hFile == INVALID_HANDLE_VALUE) {
> > +        err = EACCES;
> > +        goto out;
> > +    }
> > +
> > +    attribute = GetFileAttributes(full_file_name);
> > +
> > +    /* check if it is a symbolic link */
> > +    if ((attribute == INVALID_FILE_ATTRIBUTES)
> > +        || (attribute & FILE_ATTRIBUTE_REPARSE_POINT) != 0) {
> > +        errno = EACCES;
> > +        goto out;
> > +    }
> > +
> > +    ret = stat(full_file_name, statbuf);
> > +
> > +    if (GetFileInformationByHandle(hFile, &file_info) == 0) {
> > +        errno = EACCES;
> > +        goto out;
> > +    }
> > +
> > +    /*
> > +     * Windows (NTFS) file ID is a 64-bit ID:
> > +     *   16-bit sequence ID + 48 bit segment number
> > +     *
> > +     * But currently, ino_t defined in Windows header file is only 16-bit,
> > +     * and it is not patched by MinGW. So we build a pseudo inode number
> > +     * by the low 32-bit segment number when ino_t is only 16-bit.
> > +     */
> > +    if (sizeof(st_ino) == sizeof(uint64_t)) {
> > +        st_ino = (ino_t)((uint64_t)file_info.nFileIndexLow
> > +                         | (((uint64_t)file_info.nFileIndexHigh) << 32));
> > +    } else if (sizeof(st_ino) == sizeof(uint16_t)) {
> > +        st_ino = (ino_t)(((uint16_t)file_info.nFileIndexLow)
> > +                         ^ ((uint16_t)(file_info.nFileIndexLow >> 16)));
> > +    } else {
> > +        st_ino = (ino_t)file_info.nFileIndexLow;
> > +    }
> > +
> > +    statbuf->st_ino = st_ino;
> > +
> > +out:
> > +    if (hFile != INVALID_HANDLE_VALUE) {
> > +        CloseHandle(hFile);
> > +    }
> > +
> > +    if (err != 0) {
> > +        errno = err;
> > +    }
> > +    return ret;
> > +}
> > +
> > +/*
> > + * mkdirat_win32 - emulate mkdirat()
> > + *
> > + * This function emulates mkdirat().
> > + *
> > + * Windows POSIX API does not support opening a directory by open().
> > +Only
> > + * handle of directory can be opened by CreateFile().
> > + *
> > + * So mkdirat_win32() has to use a directory handle instead of a directory
> fd.
> > + */
> > +int mkdirat_win32(QemuFd_t dirfd, const char *pathname, mode_t mode)
> > +{
> > +    g_autofree char *full_file_name = NULL;
> > +    int ret = -1;
> > +
> > +    full_file_name = get_full_path_win32(dirfd, pathname);
> > +    if (full_file_name == NULL) {
> > +        return ret;
> > +    }
> > +
> > +    ret = mkdir(full_file_name);
> > +
> > +    return ret;
> > +}
> > +
> > +/*
> > + * renameat_win32 - emulate renameat()
> > + *
> > + * This function emulates renameat().
> > + *
> > + * Windows POSIX API does not support openning a directory by open().
> > +Only
> > + * handle of directory can be opened by CreateFile().
> > + *
> > + * So renameat_win32() has to use a directory handle instead of a
> directory fd.
> > + *
> > + * Access to a symbolic link will be denied to prevent security issues.
> > + */
> > +int renameat_win32(HANDLE olddirfd, const char *oldpath,
> > +                   HANDLE newdirfd, const char *newpath) {
> > +    g_autofree char *full_old_name = NULL;
> > +    g_autofree char *full_new_name = NULL;
> > +    HANDLE hFile;
> > +    DWORD attribute;
> > +    int err = 0;
> > +    int ret = -1;
> > +
> > +    full_old_name = get_full_path_win32(olddirfd, oldpath);
> > +    full_new_name = get_full_path_win32(newdirfd, newpath);
> > +    if (full_old_name == NULL || full_new_name == NULL) {
> > +        return ret;
> > +    }
> > +
> > +    /* open file to lock it */
> > +    hFile = CreateFile(full_old_name, GENERIC_READ,
> > +                       FILE_SHARE_READ | FILE_SHARE_WRITE |
> FILE_SHARE_DELETE,
> > +                       NULL,
> > +                       OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS,
> > + NULL);
> > +
> > +    attribute = GetFileAttributes(full_old_name);
> > +
> > +    /* check if it is a symbolic link */
> > +    if ((attribute == INVALID_FILE_ATTRIBUTES)
> > +        || (attribute & FILE_ATTRIBUTE_REPARSE_POINT) != 0) {
> > +        err = EACCES;
> > +        goto out;
> > +    }
> > +
> > +    CloseHandle(hFile);
> > +
> > +    ret = rename(full_old_name, full_new_name);
> > +out:
> > +    if (err != 0) {
> > +        errno = err;
> > +    }
> > +    return ret;
> > +}
> > +
> > +/*
> > + * utimensat_win32 - emulate utimensat()
> > + *
> > + * This function emulates utimensat().
> > + *
> > + * Windows POSIX API does not support opening a directory by open().
> > +Only
> > + * handle of directory can be opened by CreateFile().
> > + *
> > + * So utimensat_win32() has to use a directory handle instead of a
> directory fd.
> > + *
> > + * Access to a symbolic link will be denied to prevent security issues.
> > + */
> > +int utimensat_win32(QemuFd_t dirfd, const char *pathname,
> > +                    const struct timespec times[2], int flags) {
> > +    g_autofree char *full_file_name = NULL;
> > +    HANDLE hFile = INVALID_HANDLE_VALUE;
> > +    DWORD attribute;
> > +    struct utimbuf tm;
> > +    int err = 0;
> > +    int ret = -1;
> > +
> > +    full_file_name = get_full_path_win32(dirfd, pathname);
> > +    if (full_file_name == NULL) {
> > +        return ret;
> > +    }
> > +
> > +    /* open file to lock it */
> > +    hFile = CreateFile(full_file_name, GENERIC_READ,
> > +                       FILE_SHARE_READ | FILE_SHARE_WRITE |
> FILE_SHARE_DELETE,
> > +                       NULL,
> > +                       OPEN_EXISTING,
> > +                       FILE_FLAG_BACKUP_SEMANTICS
> > +                       | FILE_FLAG_OPEN_REPARSE_POINT,
> > +                       NULL);
> > +
> > +    if (hFile == INVALID_HANDLE_VALUE) {
> > +        err = EACCES;
> > +        goto out;
> > +    }
> > +
> > +    attribute = GetFileAttributes(full_file_name);
> > +
> > +    /* check if it is a symbolic link */
> > +    if ((attribute == INVALID_FILE_ATTRIBUTES)
> > +        || (attribute & FILE_ATTRIBUTE_REPARSE_POINT) != 0) {
> > +        errno = EACCES;
> > +        goto out;
> > +    }
> > +
> > +    tm.actime = times[0].tv_sec;
> > +    tm.modtime = times[1].tv_sec;
> > +
> > +    ret = utime(full_file_name, &tm);
> > +
> > +out:
> > +    if (hFile != INVALID_HANDLE_VALUE) {
> > +        CloseHandle(hFile);
> > +    }
> > +
> > +    if (err != 0) {
> > +        errno = err;
> > +    }
> > +    return ret;
> > +}
> > +
> > +/*
> > + * unlinkat_win32 - emulate unlinkat()
> > + *
> > + * This function emulates unlinkat().
> > + *
> > + * Windows POSIX API does not support opening a directory by open().
> > +Only
> > + * handle of directory can be opened by CreateFile().
> > + *
> > + * So unlinkat_win32() has to use a directory handle instead of a
> directory fd.
> > + *
> > + * Access to a symbolic link will be denied to prevent security issues.
> > + */
> > +
> > +int unlinkat_win32(QemuFd_t dirfd, const char *pathname, int flags) {
> > +    g_autofree char *full_file_name = NULL;
> > +    HANDLE hFile;
> > +    DWORD attribute;
> > +    int err = 0;
> > +    int ret = -1;
> > +
> > +    full_file_name = get_full_path_win32(dirfd, pathname);
> > +    if (full_file_name == NULL) {
> > +        return ret;
> > +    }
> > +
> > +    /* open file to prevent other one modify it */
> > +    hFile = CreateFile(full_file_name, GENERIC_READ,
> > +                       FILE_SHARE_READ | FILE_SHARE_WRITE |
> FILE_SHARE_DELETE,
> > +                       NULL,
> > +                       OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS,
> > + NULL);
> > +
> > +    attribute = GetFileAttributes(full_file_name);
> > +
> > +    /* check if it is a symbolic link */
> > +    if ((attribute == INVALID_FILE_ATTRIBUTES)
> > +        || (attribute & FILE_ATTRIBUTE_REPARSE_POINT) != 0) {
> > +        err = EACCES;
> > +        goto out;
> > +    }
> > +
> > +    if (flags == AT_REMOVEDIR) { /* remove directory */
> > +        if ((attribute & FILE_ATTRIBUTE_DIRECTORY) == 0) {
> > +            err = ENOTDIR;
> > +            goto out;
> > +        }
> > +        ret = rmdir(full_file_name);
> > +    } else { /* remove regular file */
> > +        if ((attribute & FILE_ATTRIBUTE_DIRECTORY) != 0) {
> > +            err = EISDIR;
> > +            goto out;
> > +        }
> > +        ret = remove(full_file_name);
> > +    }
> > +
> > +    /* after last handle closed, file will be removed */
> > +    CloseHandle(hFile);
> > +
> > +out:
> > +    if (err != 0) {
> > +        errno = err;
> > +    }
> > +    return ret;
> > +}
> > +
> > +/*
> > + * statfs_win32 - statfs() on Windows
> > + *
> > + * This function emulates statfs() on Windows host.
> > + */
> > +int statfs_win32(const char *path, struct statfs *stbuf) {
> > +    char RealPath[4] = { 0 };
> > +    unsigned long SectorsPerCluster;
> > +    unsigned long BytesPerSector;
> > +    unsigned long NumberOfFreeClusters;
> > +    unsigned long TotalNumberOfClusters;
> > +
> > +    /* only need first 3 bytes, e.g. "C:\ABC", only need "C:\" */
> > +    memcpy(RealPath, path, 3);
> > +
> > +    if (GetDiskFreeSpace(RealPath, &SectorsPerCluster, &BytesPerSector,
> > +                         &NumberOfFreeClusters, &TotalNumberOfClusters) ==
> 0) {
> > +        errno = EIO;
> > +        return -1;
> > +    }
> > +
> > +    stbuf->f_type = V9FS_MAGIC;
> > +    stbuf->f_bsize =
> > +        (__fsword_t)SectorsPerCluster * (__fsword_t)BytesPerSector;
> > +    stbuf->f_blocks = (fsblkcnt_t)TotalNumberOfClusters;
> > +    stbuf->f_bfree = (fsblkcnt_t)NumberOfFreeClusters;
> > +    stbuf->f_bavail = (fsblkcnt_t)NumberOfFreeClusters;
> > +    stbuf->f_files = -1;
> > +    stbuf->f_ffree = -1;
> > +    stbuf->f_namelen = NAME_MAX;
> > +    stbuf->f_frsize = 0;
> > +    stbuf->f_flags = 0;
> > +
> > +    return 0;
> > +}
> > +
> > +/*
> > + * openat_dir - emulate openat_dir()
> > + *
> > + * This function emulates openat_dir().
> > + *
> > + * Windows POSIX API does not support opening a directory by open().
> > +Only
> > + * handle of directory can be opened by CreateFile().
> > + *
> > + * So openat_dir() has to use a directory handle instead of a directory fd.
> > + *
> > + * Access to a symbolic link will be denied to prevent security issues.
> > + */
> > +QemuFd_t openat_dir(QemuFd_t dirfd, const char *name) {
> > +    g_autofree char *full_file_name = NULL;
> > +    HANDLE hSubDir;
> > +    DWORD attribute;
> > +
> > +    full_file_name = get_full_path_win32(dirfd, name);
> > +    if (full_file_name == NULL) {
> > +        return INVALID_HANDLE_VALUE;
> > +    }
> > +
> > +    attribute = GetFileAttributes(full_file_name);
> > +    if (attribute == INVALID_FILE_ATTRIBUTES) {
> > +        return INVALID_HANDLE_VALUE;
> > +    }
> > +
> > +    /* check if it is a directory */
> > +    if ((attribute & FILE_ATTRIBUTE_DIRECTORY) == 0) {
> > +        return INVALID_HANDLE_VALUE;
> > +    }
> > +
> > +    /* do not allow opening a symbolic link */
> > +    if ((attribute & FILE_ATTRIBUTE_REPARSE_POINT) != 0) {
> > +        return INVALID_HANDLE_VALUE;
> > +    }
> > +
> > +    /* open it */
> > +    hSubDir = CreateFile(full_file_name, GENERIC_READ,
> > +                         FILE_SHARE_READ | FILE_SHARE_WRITE |
> FILE_SHARE_DELETE,
> > +                         NULL,
> > +                         OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
> > +    return hSubDir;
> > +}
> > +
> > +QemuFd_t openat_file(QemuFd_t dirfd, const char *name, int flags,
> > +                     mode_t mode)
> > +{
> > +    return openat_win32(dirfd, name, flags | _O_BINARY, mode); }
> > +
> > +/*
> > + * fgetxattrat_nofollow - get extended attribute
> > + *
> > + * This function gets extended attribute from file <path> in the
> > +directory
> > + * specified by <dirfd>. The extended atrribute name is specified by
> > +<name>
> > + * and return value will be put in <value>.
> > + *
> > + * This function emulates extended attribute by NTFS ADS.
> > + */
> > +ssize_t fgetxattrat_nofollow(QemuFd_t dirfd, const char *path,
> > +                             const char *name, void *value, size_t
> > +size) {
> > +    g_autofree char *full_file_name = NULL;
> > +    char ads_file_name[NAME_MAX + 1] = { 0 };
> > +    DWORD dwBytesRead;
> > +    HANDLE hStream;
> > +
> > +    full_file_name = get_full_path_win32(dirfd, path);
> > +    if (full_file_name == NULL) {
> > +        errno = EIO;
> > +        return -1;
> > +    }
> > +
> > +    if (build_ads_name(ads_file_name, NAME_MAX, full_file_name, name) < 0)
> {
> > +        errno = EIO;
> > +        return -1;
> > +    }
> > +
> > +    hStream = CreateFile(ads_file_name, GENERIC_READ, FILE_SHARE_READ,
> NULL,
> > +                         OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
> > +    if (hStream == INVALID_HANDLE_VALUE &&
> > +        GetLastError() == ERROR_FILE_NOT_FOUND) {
> > +        errno = ENODATA;
> > +        return -1;
> > +    }
> > +
> > +    if (ReadFile(hStream, value, size, &dwBytesRead, NULL) == FALSE) {
> > +        errno = EIO;
> > +        CloseHandle(hStream);
> > +        return -1;
> > +    }
> > +
> > +    CloseHandle(hStream);
> > +
> > +    return dwBytesRead;
> > +}
> > +
> > +/*
> > + * fsetxattrat_nofollow - set extended attribute
> > + *
> > + * This function set extended attribute to file <path> in the
> > +directory
> > + * specified by <dirfd>.
> > + *
> > + * This function emulates extended attribute by NTFS ADS.
> > + */
> > +
> > +int fsetxattrat_nofollow(QemuFd_t dirfd, const char *path, const char
> *name,
> > +                         void *value, size_t size, int flags) {
> > +    g_autofree char *full_file_name = NULL;
> > +    char ads_file_name[NAME_MAX + 1] = { 0 };
> > +    DWORD dwBytesWrite;
> > +    HANDLE hStream;
> > +
> > +    full_file_name = get_full_path_win32(dirfd, path);
> > +    if (full_file_name == NULL) {
> > +        errno = EIO;
> > +        return -1;
> > +    }
> > +
> > +    if (build_ads_name(ads_file_name, NAME_MAX, full_file_name, name) < 0)
> {
> > +        errno = EIO;
> > +        return -1;
> > +    }
> > +
> > +    hStream = CreateFile(ads_file_name, GENERIC_WRITE, FILE_SHARE_READ,
> NULL,
> > +                         CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
> > +    if (hStream == INVALID_HANDLE_VALUE) {
> > +        errno = EIO;
> > +        return -1;
> > +    }
> > +
> > +    if (WriteFile(hStream, value, size, &dwBytesWrite, NULL) == FALSE) {
> > +        errno = EIO;
> > +        CloseHandle(hStream);
> > +        return -1;
> > +    }
> > +
> > +    CloseHandle(hStream);
> > +
> > +    return 0;
> > +}
> > +
> > +/*
> > + * flistxattrat_nofollow - list extended attribute
> > + *
> > + * This function gets extended attribute lists from file <filename>
> > +in the
> > + * directory specified by <dirfd>. Lists returned will be put in <list>.
> > + *
> > + * This function emulates extended attribute by NTFS ADS.
> > + */
> > +ssize_t flistxattrat_nofollow(QemuFd_t dirfd, const char *filename,
> > +                              char *list, size_t size) {
> > +    g_autofree char *full_file_name = NULL;
> > +    WCHAR WideCharStr[NAME_MAX + 1] = { 0 };
> > +    char full_ads_name[NAME_MAX + 1];
> > +    WIN32_FIND_STREAM_DATA fsd;
> > +    BOOL bFindNext;
> > +    char *list_ptr = list;
> > +    size_t list_left_size = size;
> > +    HANDLE hFind;
> > +    int ret;
> > +
> > +    full_file_name = get_full_path_win32(dirfd, filename);
> > +    if (full_file_name == NULL) {
> > +        errno = EIO;
> > +        return -1;
> > +    }
> > +
> > +    /*
> > +     * ADS enumerate function only has WCHAR version, so we need to
> > +     * covert filename to utf-8 string.
> > +     */
> > +    ret = MultiByteToWideChar(CP_UTF8, 0, full_file_name,
> > +                              strlen(full_file_name), WideCharStr,
> NAME_MAX);
> > +    if (ret == 0) {
> > +        errno = EIO;
> > +        return -1;
> > +    }
> > +
> > +    hFind = FindFirstStreamW(WideCharStr, FindStreamInfoStandard, &fsd, 0);
> > +    if (hFind == INVALID_HANDLE_VALUE) {
> > +        errno = ENODATA;
> > +        return -1;
> > +    }
> > +
> > +    do {
> > +        memset(full_ads_name, 0, sizeof(full_ads_name));
> > +
> > +        /*
> > +         * ADS enumerate function only has WCHAR version, so we need to
> > +         * covert cStreamName to utf-8 string.
> > +         */
> > +        ret = WideCharToMultiByte(CP_UTF8, 0,
> > +                                  fsd.cStreamName, wcslen(fsd.cStreamName)
> + 1,
> > +                                  full_ads_name, sizeof(full_ads_name) - 1,
> > +                                  NULL, NULL);
> > +        if (ret == 0) {
> > +            if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
> > +                errno = ERANGE;
> > +            }
> > +            CloseHandle(hFind);
> > +            return -1;
> > +        }
> > +
> > +        ret = copy_ads_name(list_ptr, list_left_size, full_ads_name);
> > +        if (ret < 0) {
> > +            errno = ERANGE;
> > +            CloseHandle(hFind);
> > +            return -1;
> > +        }
> > +
> > +        list_ptr = list_ptr + ret;
> > +        list_left_size = list_left_size - ret;
> > +
> > +        bFindNext = FindNextStreamW(hFind, &fsd);
> > +    } while (bFindNext);
> > +
> > +    CloseHandle(hFind);
> > +
> > +    return size - list_left_size;
> > +}
> > +
> > +/*
> > + * fremovexattrat_nofollow - remove extended attribute
> > + *
> > + * This function removes an extended attribute from file <filename>
> > +in the
> > + * directory specified by <dirfd>.
> > + *
> > + * This function emulates extended attribute by NTFS ADS.
> > + */
> > +ssize_t fremovexattrat_nofollow(QemuFd_t dirfd, const char *filename,
> > +                                const char *name) {
> > +    g_autofree char *full_file_name = NULL;
> > +    char ads_file_name[NAME_MAX + 1] = { 0 };
> > +
> > +    full_file_name = get_full_path_win32(dirfd, filename);
> > +    if (full_file_name == NULL) {
> > +        errno = EIO;
> > +        return -1;
> > +    }
> > +
> > +    if (build_ads_name(ads_file_name, NAME_MAX, filename, name) < 0) {
> > +        errno = EIO;
> > +        return -1;
> > +    }
> > +
> > +    if (DeleteFile(ads_file_name) != 0) {
> > +        if (GetLastError() == ERROR_FILE_NOT_FOUND) {
> > +            errno = ENODATA;
> > +            return -1;
> > +        }
> > +    }
> > +
> > +    return 0;
> > +}
> > +
> > +/*
> > + * local_opendir_nofollow - open a Windows directory
> > + *
> > + * This function returns a Windows file handle of the directory
> > +specified by
> > + * <dirpath> based on 9pfs mount point.
> > + *
> > + * Windows POSIX API does not support opening a directory by open().
> > +Only
> > + * handle of directory can be opened by CreateFile().
> > + *
> > + * This function checks the resolved path of <dirpath>. If the
> > +resolved
> > + * path is not in the scope of root directory (e.g. by symbolic
> > +link), then
> > + * this function will fail to prevent any security issues.
> > + */
> > +HANDLE local_opendir_nofollow(FsContext *fs_ctx, const char *dirpath)
> > +{
> > +    g_autofree char *full_file_name = NULL;
> > +    LocalData *data = fs_ctx->private;
> > +    HANDLE hDir;
> > +
> > +    hDir = openat_dir(data->mountfd, dirpath);
> > +    if (hDir == INVALID_HANDLE_VALUE) {
> > +        return INVALID_HANDLE_VALUE;
> > +    }
> > +
> > +    full_file_name = get_full_path_win32(hDir, NULL);
> > +    if (full_file_name == NULL) {
> > +        CloseHandle(hDir);
> > +        return INVALID_HANDLE_VALUE;
> > +    }
> > +
> > +    /*
> > +     * Check if the resolved path is in the root directory scope:
> > +     * data->root_path and full_file_name are full path with symbolic
> > +     * link resolved, so fs_ctx->root_path must be in the head of
> > +     * full_file_name. If not, that means guest OS tries to open a file
> not
> > +     * in the scope of mount point. This operation should be denied.
> > +     */
> > +    if (memcmp(full_file_name, data->root_path,
> > +               strlen(data->root_path)) != 0) {
> > +        CloseHandle(hDir);
> > +        hDir = INVALID_HANDLE_VALUE;
> > +    }
> > +
> > +    return hDir;
> > +}
> > +
> > +/*
> > + * qemu_mknodat - mknodat emulate function
> > + *
> > + * This function emulates mknodat on Windows. It only works when
> > +security
> > + * model is mapped or mapped-xattr.
> > + */
> > +int qemu_mknodat(QemuFd_t dirfd, const char *filename, mode_t mode,
> > +dev_t dev) {
> > +    if (S_ISREG(mode) || !(mode & S_IFMT)) {
> > +        HANDLE hFile = openat_file(dirfd, filename, O_CREAT, mode);
> > +        if (hFile == INVALID_HANDLE_VALUE) {
> > +            return -1;
> > +        }
> > +        close_preserve_errno(hFile);
> > +        return 0;
> > +    }
> > +
> > +    error_report_once("Unsupported operation for mknodat");
> > +    errno = ENOTSUP;
> > +    return -1;
> > +}
> >
> 



^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v2 02/19] hw/9pfs: Drop unnecessary *xattr wrapper API declarations
  2022-11-11  4:22 ` [PATCH v2 02/19] hw/9pfs: Drop unnecessary *xattr wrapper API declarations Bin Meng
@ 2022-11-18  8:42   ` Greg Kurz
  2022-11-18 13:10     ` Christian Schoenebeck
  0 siblings, 1 reply; 36+ messages in thread
From: Greg Kurz @ 2022-11-18  8:42 UTC (permalink / raw)
  To: Bin Meng; +Cc: qemu-devel, Christian Schoenebeck, qemu-trivial

On Fri, 11 Nov 2022 12:22:08 +0800
Bin Meng <bin.meng@windriver.com> wrote:

> These are not used anywhere in the source tree. Drop them.
> 
> Signed-off-by: Bin Meng <bin.meng@windriver.com>
> ---
> 

This one could even go through the trivial tree right
away IMHO.

Reviewed-by: Greg Kurz <groug@kaod.org>

> (no changes since v1)
> 
>  hw/9pfs/9p-util.h | 11 -----------
>  1 file changed, 11 deletions(-)
> 
> diff --git a/hw/9pfs/9p-util.h b/hw/9pfs/9p-util.h
> index c3526144c9..ccfc8b1cb3 100644
> --- a/hw/9pfs/9p-util.h
> +++ b/hw/9pfs/9p-util.h
> @@ -90,19 +90,8 @@ static inline int errno_to_dotl(int err) {
>  
>  #ifdef CONFIG_DARWIN
>  #define qemu_fgetxattr(...) fgetxattr(__VA_ARGS__, 0, 0)
> -#define qemu_lgetxattr(...) getxattr(__VA_ARGS__, 0, XATTR_NOFOLLOW)
> -#define qemu_llistxattr(...) listxattr(__VA_ARGS__, XATTR_NOFOLLOW)
> -#define qemu_lremovexattr(...) removexattr(__VA_ARGS__, XATTR_NOFOLLOW)
> -static inline int qemu_lsetxattr(const char *path, const char *name,
> -                                 const void *value, size_t size, int flags) {
> -    return setxattr(path, name, value, size, 0, flags | XATTR_NOFOLLOW);
> -}
>  #else
>  #define qemu_fgetxattr fgetxattr
> -#define qemu_lgetxattr lgetxattr
> -#define qemu_llistxattr llistxattr
> -#define qemu_lremovexattr lremovexattr
> -#define qemu_lsetxattr lsetxattr
>  #endif
>  
>  static inline void close_preserve_errno(int fd)



^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v2 05/19] hw/9pfs: Update 9pfs to use the new QemuFd_t type
  2022-11-11  4:22 ` [PATCH v2 05/19] hw/9pfs: Update 9pfs to use the new QemuFd_t type Bin Meng
@ 2022-11-18  9:29   ` Greg Kurz
  2022-11-18 13:38     ` Christian Schoenebeck
  0 siblings, 1 reply; 36+ messages in thread
From: Greg Kurz @ 2022-11-18  9:29 UTC (permalink / raw)
  To: Bin Meng; +Cc: qemu-devel, Christian Schoenebeck

On Fri, 11 Nov 2022 12:22:11 +0800
Bin Meng <bin.meng@windriver.com> wrote:

> With this new QemuFd_t type, it significantly reduces the number of

I cannot find the definition of this type, nor the definition of
qemu_fd_invalid(). Missing patch ?

Anyway, IIUC this type is an int for linux and a HANDLE for windows,
right ?

According to win32 documentation at [1] :

HANDLE	
A handle to an object.

This type is declared in WinNT.h as follows:

typedef PVOID HANDLE;

and

PVOID	
A pointer to any type.

This type is declared in WinNT.h as follows:

typedef void *PVOID;

HANDLE is void *.

From docs/devel/style.rst:

Naming
======

Variables are lower_case_with_underscores; easy to type and read.  Structured
type names are in CamelCase; harder to type but standing out.  Enum type
names and function type names should also be in CamelCase.  Scalar type
names are lower_case_with_underscores_ending_with_a_t, like the POSIX
uint64_t and family.  Note that this last convention contradicts POSIX
and is therefore likely to be changed.

Both int and void * are scalar types, so I'd rather name it qemu_fd_t,
not using CamelCase at all so that it cannot be confused with a struct.

[1] https://learn.microsoft.com/en-us/windows/win32/winprog/windows-data-types

> deviated code paths when adding Windows support.
> 
> Signed-off-by: Bin Meng <bin.meng@windriver.com>
> 
> ---
> 
> Changes in v2:
> - Use the new QemuFd_t type
> 
>  hw/9pfs/9p-local.h       |   6 +-
>  hw/9pfs/9p-util.h        |  26 +++---
>  hw/9pfs/9p-local.c       | 174 ++++++++++++++++++++-------------------
>  hw/9pfs/9p-util-darwin.c |  14 ++--
>  hw/9pfs/9p-util-linux.c  |  14 ++--
>  hw/9pfs/9p-xattr.c       |  16 ++--
>  6 files changed, 129 insertions(+), 121 deletions(-)
> 
> diff --git a/hw/9pfs/9p-local.h b/hw/9pfs/9p-local.h
> index 32c72749d9..66a21316a0 100644
> --- a/hw/9pfs/9p-local.h
> +++ b/hw/9pfs/9p-local.h
> @@ -13,8 +13,8 @@
>  #ifndef QEMU_9P_LOCAL_H
>  #define QEMU_9P_LOCAL_H
>  
> -int local_open_nofollow(FsContext *fs_ctx, const char *path, int flags,
> -                        mode_t mode);
> -int local_opendir_nofollow(FsContext *fs_ctx, const char *path);
> +QemuFd_t local_open_nofollow(FsContext *fs_ctx, const char *path, int flags,
> +                             mode_t mode);
> +QemuFd_t local_opendir_nofollow(FsContext *fs_ctx, const char *path);
>  
>  #endif
> diff --git a/hw/9pfs/9p-util.h b/hw/9pfs/9p-util.h
> index c314cf381d..3d6bd1a51e 100644
> --- a/hw/9pfs/9p-util.h
> +++ b/hw/9pfs/9p-util.h
> @@ -101,30 +101,31 @@ static inline int errno_to_dotl(int err) {
>  #define qemu_utimensat  utimensat
>  #define qemu_unlinkat   unlinkat
>  
> -static inline void close_preserve_errno(int fd)
> +static inline void close_preserve_errno(QemuFd_t fd)
>  {
>      int serrno = errno;
>      close(fd);
>      errno = serrno;
>  }
>  
> -static inline int openat_dir(int dirfd, const char *name)
> +static inline QemuFd_t openat_dir(QemuFd_t dirfd, const char *name)
>  {
>      return qemu_openat(dirfd, name,
>                         O_DIRECTORY | O_RDONLY | O_NOFOLLOW | O_PATH_9P_UTIL);
>  }
>  
> -static inline int openat_file(int dirfd, const char *name, int flags,
> -                              mode_t mode)
> +static inline QemuFd_t openat_file(QemuFd_t dirfd, const char *name,
> +                                   int flags, mode_t mode)
>  {
> -    int fd, serrno, ret;
> +    int serrno, ret;
> +    QemuFd_t fd;
>  
>  #ifndef CONFIG_DARWIN
>  again:
>  #endif
>      fd = qemu_openat(dirfd, name, flags | O_NOFOLLOW | O_NOCTTY | O_NONBLOCK,
>                       mode);
> -    if (fd == -1) {
> +    if (qemu_fd_invalid(fd)) {
>  #ifndef CONFIG_DARWIN
>          if (errno == EPERM && (flags & O_NOATIME)) {
>              /*
> @@ -155,13 +156,13 @@ again:
>      return fd;
>  }
>  
> -ssize_t fgetxattrat_nofollow(int dirfd, const char *path, const char *name,
> -                             void *value, size_t size);
> -int fsetxattrat_nofollow(int dirfd, const char *path, const char *name,
> +ssize_t fgetxattrat_nofollow(QemuFd_t dirfd, const char *path,
> +                             const char *name, void *value, size_t size);
> +int fsetxattrat_nofollow(QemuFd_t dirfd, const char *path, const char *name,
>                           void *value, size_t size, int flags);
> -ssize_t flistxattrat_nofollow(int dirfd, const char *filename,
> +ssize_t flistxattrat_nofollow(QemuFd_t dirfd, const char *filename,
>                                char *list, size_t size);
> -ssize_t fremovexattrat_nofollow(int dirfd, const char *filename,
> +ssize_t fremovexattrat_nofollow(QemuFd_t dirfd, const char *filename,
>                                  const char *name);
>  
>  /*
> @@ -219,6 +220,7 @@ static inline struct dirent *qemu_dirent_dup(struct dirent *dent)
>  #if defined CONFIG_DARWIN && defined CONFIG_PTHREAD_FCHDIR_NP
>  int pthread_fchdir_np(int fd) __attribute__((weak_import));
>  #endif
> -int qemu_mknodat(int dirfd, const char *filename, mode_t mode, dev_t dev);
> +int qemu_mknodat(QemuFd_t dirfd, const char *filename, mode_t mode,
> +                 dev_t dev);
>  
>  #endif
> diff --git a/hw/9pfs/9p-local.c b/hw/9pfs/9p-local.c
> index d2246a3d7e..22377a3105 100644
> --- a/hw/9pfs/9p-local.c
> +++ b/hw/9pfs/9p-local.c
> @@ -54,18 +54,18 @@
>  #endif
>  
>  typedef struct {
> -    int mountfd;
> +    QemuFd_t mountfd;
>  } LocalData;
>  
> -int local_open_nofollow(FsContext *fs_ctx, const char *path, int flags,
> -                        mode_t mode)
> +QemuFd_t local_open_nofollow(FsContext *fs_ctx, const char *path, int flags,
> +                             mode_t mode)
>  {
>      LocalData *data = fs_ctx->private;
> -    int fd = data->mountfd;
> +    QemuFd_t fd = data->mountfd;
>  
> -    while (*path && fd != -1) {
> +    while (*path && !qemu_fd_invalid(fd)) {
>          const char *c;
> -        int next_fd;
> +        QemuFd_t next_fd;
>          char *head;
>  
>          /* Only relative paths without consecutive slashes */
> @@ -94,20 +94,21 @@ int local_open_nofollow(FsContext *fs_ctx, const char *path, int flags,
>      return fd;
>  }
>  
> -int local_opendir_nofollow(FsContext *fs_ctx, const char *path)
> +QemuFd_t local_opendir_nofollow(FsContext *fs_ctx, const char *path)
>  {
>      return local_open_nofollow(fs_ctx, path, O_DIRECTORY | O_RDONLY, 0);
>  }
>  
> -static void renameat_preserve_errno(int odirfd, const char *opath, int ndirfd,
> -                                    const char *npath)
> +static void renameat_preserve_errno(QemuFd_t odirfd, const char *opath,
> +                                    QemuFd_t ndirfd, const char *npath)
>  {
>      int serrno = errno;
>      qemu_renameat(odirfd, opath, ndirfd, npath);
>      errno = serrno;
>  }
>  
> -static void unlinkat_preserve_errno(int dirfd, const char *path, int flags)
> +static void unlinkat_preserve_errno(QemuFd_t dirfd, const char *path,
> +                                    int flags)
>  {
>      int serrno = errno;
>      qemu_unlinkat(dirfd, path, flags);
> @@ -117,9 +118,10 @@ static void unlinkat_preserve_errno(int dirfd, const char *path, int flags)
>  #define VIRTFS_META_DIR ".virtfs_metadata"
>  #define VIRTFS_META_ROOT_FILE VIRTFS_META_DIR "_root"
>  
> -static FILE *local_fopenat(int dirfd, const char *name, const char *mode)
> +static FILE *local_fopenat(QemuFd_t dirfd, const char *name, const char *mode)
>  {
> -    int fd, o_mode = 0;
> +    QemuFd_t fd;
> +    int o_mode = 0;
>      FILE *fp;
>      int flags;
>      /*
> @@ -134,7 +136,7 @@ static FILE *local_fopenat(int dirfd, const char *name, const char *mode)
>          return NULL;
>      }
>      fd = openat_file(dirfd, name, flags, o_mode);
> -    if (fd == -1) {
> +    if (qemu_fd_invalid(fd)) {
>          return NULL;
>      }
>      fp = fdopen(fd, mode);
> @@ -145,16 +147,16 @@ static FILE *local_fopenat(int dirfd, const char *name, const char *mode)
>  }
>  
>  #define ATTR_MAX 100
> -static void local_mapped_file_attr(int dirfd, const char *name,
> +static void local_mapped_file_attr(QemuFd_t dirfd, const char *name,
>                                     struct stat *stbuf)
>  {
>      FILE *fp;
>      char buf[ATTR_MAX];
> -    int map_dirfd;
> +    QemuFd_t map_dirfd;
>  
>      if (strcmp(name, ".")) {
>          map_dirfd = openat_dir(dirfd, VIRTFS_META_DIR);
> -        if (map_dirfd == -1) {
> +        if (qemu_fd_invalid(map_dirfd)) {
>              return;
>          }
>  
> @@ -187,10 +189,10 @@ static int local_lstat(FsContext *fs_ctx, V9fsPath *fs_path, struct stat *stbuf)
>      int err = -1;
>      char *dirpath = g_path_get_dirname(fs_path->data);
>      char *name = g_path_get_basename(fs_path->data);
> -    int dirfd;
> +    QemuFd_t dirfd;
>  
>      dirfd = local_opendir_nofollow(fs_ctx, dirpath);
> -    if (dirfd == -1) {
> +    if (qemu_fd_invalid(dirfd)) {
>          goto out;
>      }
>  
> @@ -233,14 +235,14 @@ out:
>      return err;
>  }
>  
> -static int local_set_mapped_file_attrat(int dirfd, const char *name,
> +static int local_set_mapped_file_attrat(QemuFd_t dirfd, const char *name,
>                                          FsCred *credp)
>  {
>      FILE *fp;
>      int ret;
>      char buf[ATTR_MAX];
>      int uid = -1, gid = -1, mode = -1, rdev = -1;
> -    int map_dirfd = -1, map_fd;
> +    QemuFd_t map_dirfd = QEMU_FD_INVALID, map_fd;
>      bool is_root = !strcmp(name, ".");
>  
>      if (is_root) {
> @@ -259,7 +261,7 @@ static int local_set_mapped_file_attrat(int dirfd, const char *name,
>          }
>  
>          map_dirfd = openat_dir(dirfd, VIRTFS_META_DIR);
> -        if (map_dirfd == -1) {
> +        if (qemu_fd_invalid(map_dirfd)) {
>              return -1;
>          }
>  
> @@ -296,7 +298,7 @@ update_map_file:
>          /* We can't go this far with map_dirfd not being a valid file descriptor
>           * but some versions of gcc aren't smart enough to see it.
>           */
> -        if (map_dirfd != -1) {
> +        if (!qemu_fd_invalid(map_dirfd)) {
>              close_preserve_errno(map_dirfd);
>          }
>      }
> @@ -305,7 +307,7 @@ update_map_file:
>      }
>  
>      map_fd = fileno(fp);
> -    assert(map_fd != -1);
> +    assert(!qemu_fd_invalid(map_fd));
>      ret = fchmod(map_fd, 0600);
>      assert(ret == 0);
>  
> @@ -339,10 +341,11 @@ update_map_file:
>      return 0;
>  }
>  
> -static int fchmodat_nofollow(int dirfd, const char *name, mode_t mode)
> +static int fchmodat_nofollow(QemuFd_t dirfd, const char *name, mode_t mode)
>  {
>      struct stat stbuf;
> -    int fd, ret;
> +    QemuFd_t fd;
> +    int ret;
>  
>      /* FIXME: this should be handled with fchmodat(AT_SYMLINK_NOFOLLOW).
>       * Unfortunately, the linux kernel doesn't implement it yet.
> @@ -362,16 +365,16 @@ static int fchmodat_nofollow(int dirfd, const char *name, mode_t mode)
>      /* Fallback for systems that don't support O_PATH: we depend on the file
>       * being readable or writable.
>       */
> -    if (fd == -1) {
> +    if (qemu_fd_invalid(fd)) {
>          /* In case the file is writable-only and isn't a directory. */
>          if (errno == EACCES) {
>              fd = openat_file(dirfd, name, O_WRONLY, 0);
>          }
> -        if (fd == -1 && errno == EISDIR) {
> +        if (qemu_fd_invalid(fd) && errno == EISDIR) {
>              errno = EACCES;
>          }
>      }
> -    if (fd == -1) {
> +    if (qemu_fd_invalid(fd)) {
>          return -1;
>      }
>      ret = fchmod(fd, mode);
> @@ -380,7 +383,7 @@ static int fchmodat_nofollow(int dirfd, const char *name, mode_t mode)
>       * link, O_PATH | O_NOFOLLOW causes openat(2) to return a file descriptor
>       * referring to the symbolic link.
>       */
> -    if (fd == -1) {
> +    if (qemu_fd_invalid(fd)) {
>          return -1;
>      }
>  
> @@ -401,7 +404,7 @@ static int fchmodat_nofollow(int dirfd, const char *name, mode_t mode)
>      return ret;
>  }
>  
> -static int local_set_xattrat(int dirfd, const char *path, FsCred *credp)
> +static int local_set_xattrat(QemuFd_t dirfd, const char *path, FsCred *credp)
>  {
>      int err;
>  
> @@ -440,7 +443,7 @@ static int local_set_xattrat(int dirfd, const char *path, FsCred *credp)
>      return 0;
>  }
>  
> -static int local_set_cred_passthrough(FsContext *fs_ctx, int dirfd,
> +static int local_set_cred_passthrough(FsContext *fs_ctx, QemuFd_t dirfd,
>                                        const char *name, FsCred *credp)
>  {
>      if (fchownat(dirfd, name, credp->fc_uid, credp->fc_gid,
> @@ -464,10 +467,10 @@ static ssize_t local_readlink(FsContext *fs_ctx, V9fsPath *fs_path,
>  
>      if ((fs_ctx->export_flags & V9FS_SM_MAPPED) ||
>          (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE)) {
> -        int fd;
> +        QemuFd_t fd;
>  
>          fd = local_open_nofollow(fs_ctx, fs_path->data, O_RDONLY, 0);
> -        if (fd == -1) {
> +        if (qemu_fd_invalid(fd)) {
>              return -1;
>          }
>          do {
> @@ -478,10 +481,10 @@ static ssize_t local_readlink(FsContext *fs_ctx, V9fsPath *fs_path,
>                 (fs_ctx->export_flags & V9FS_SM_NONE)) {
>          char *dirpath = g_path_get_dirname(fs_path->data);
>          char *name = g_path_get_basename(fs_path->data);
> -        int dirfd;
> +        QemuFd_t dirfd;
>  
>          dirfd = local_opendir_nofollow(fs_ctx, dirpath);
> -        if (dirfd == -1) {
> +        if (qemu_fd_invalid(dirfd)) {
>              goto out;
>          }
>  
> @@ -507,10 +510,10 @@ static int local_closedir(FsContext *ctx, V9fsFidOpenState *fs)
>  static int local_open(FsContext *ctx, V9fsPath *fs_path,
>                        int flags, V9fsFidOpenState *fs)
>  {
> -    int fd;
> +    QemuFd_t fd;
>  
>      fd = local_open_nofollow(ctx, fs_path->data, flags, 0);
> -    if (fd == -1) {
> +    if (qemu_fd_invalid(fd)) {
>          return -1;
>      }
>      fs->fd = fd;
> @@ -520,11 +523,11 @@ static int local_open(FsContext *ctx, V9fsPath *fs_path,
>  static int local_opendir(FsContext *ctx,
>                           V9fsPath *fs_path, V9fsFidOpenState *fs)
>  {
> -    int dirfd;
> +    QemuFd_t dirfd;
>      DIR *stream;
>  
>      dirfd = local_opendir_nofollow(ctx, fs_path->data);
> -    if (dirfd == -1) {
> +    if (qemu_fd_invalid(dirfd)) {
>          return -1;
>      }
>  
> @@ -640,10 +643,10 @@ static int local_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
>      char *dirpath = g_path_get_dirname(fs_path->data);
>      char *name = g_path_get_basename(fs_path->data);
>      int ret = -1;
> -    int dirfd;
> +    QemuFd_t dirfd;
>  
>      dirfd = local_opendir_nofollow(fs_ctx, dirpath);
> -    if (dirfd == -1) {
> +    if (qemu_fd_invalid(dirfd)) {
>          goto out;
>      }
>  
> @@ -667,7 +670,7 @@ static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path,
>                         const char *name, FsCred *credp)
>  {
>      int err = -1;
> -    int dirfd;
> +    QemuFd_t dirfd;
>  
>      if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE &&
>          local_is_mapped_file_metadata(fs_ctx, name)) {
> @@ -676,7 +679,7 @@ static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path,
>      }
>  
>      dirfd = local_opendir_nofollow(fs_ctx, dir_path->data);
> -    if (dirfd == -1) {
> +    if (qemu_fd_invalid(dirfd)) {
>          return -1;
>      }
>  
> @@ -719,7 +722,7 @@ static int local_mkdir(FsContext *fs_ctx, V9fsPath *dir_path,
>                         const char *name, FsCred *credp)
>  {
>      int err = -1;
> -    int dirfd;
> +    QemuFd_t dirfd;
>  
>      if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE &&
>          local_is_mapped_file_metadata(fs_ctx, name)) {
> @@ -728,7 +731,7 @@ static int local_mkdir(FsContext *fs_ctx, V9fsPath *dir_path,
>      }
>  
>      dirfd = local_opendir_nofollow(fs_ctx, dir_path->data);
> -    if (dirfd == -1) {
> +    if (qemu_fd_invalid(dirfd)) {
>          return -1;
>      }
>  
> @@ -816,9 +819,9 @@ static int local_fstat(FsContext *fs_ctx, int fid_type,
>  static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
>                         int flags, FsCred *credp, V9fsFidOpenState *fs)
>  {
> -    int fd = -1;
> +    QemuFd_t fd = QEMU_FD_INVALID;
>      int err = -1;
> -    int dirfd;
> +    QemuFd_t dirfd;
>  
>      if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE &&
>          local_is_mapped_file_metadata(fs_ctx, name)) {
> @@ -832,7 +835,7 @@ static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
>      flags |= O_NOFOLLOW;
>  
>      dirfd = local_opendir_nofollow(fs_ctx, dir_path->data);
> -    if (dirfd == -1) {
> +    if (qemu_fd_invalid(dirfd)) {
>          return -1;
>      }
>  
> @@ -840,7 +843,7 @@ static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
>      if (fs_ctx->export_flags & V9FS_SM_MAPPED ||
>          fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
>          fd = openat_file(dirfd, name, flags, fs_ctx->fmode);
> -        if (fd == -1) {
> +        if (qemu_fd_invalid(fd)) {
>              goto out;
>          }
>          credp->fc_mode = credp->fc_mode | S_IFREG;
> @@ -856,7 +859,7 @@ 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)) {
>          fd = openat_file(dirfd, name, flags, credp->fc_mode);
> -        if (fd == -1) {
> +        if (qemu_fd_invalid(fd)) {
>              goto out;
>          }
>          err = local_set_cred_passthrough(fs_ctx, dirfd, name, credp);
> @@ -882,7 +885,7 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath,
>                           V9fsPath *dir_path, const char *name, FsCred *credp)
>  {
>      int err = -1;
> -    int dirfd;
> +    QemuFd_t dirfd;
>  
>      if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE &&
>          local_is_mapped_file_metadata(fs_ctx, name)) {
> @@ -891,19 +894,19 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath,
>      }
>  
>      dirfd = local_opendir_nofollow(fs_ctx, dir_path->data);
> -    if (dirfd == -1) {
> +    if (qemu_fd_invalid(dirfd)) {
>          return -1;
>      }
>  
>      /* Determine the security model */
>      if (fs_ctx->export_flags & V9FS_SM_MAPPED ||
>          fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
> -        int fd;
> +        QemuFd_t fd;
>          ssize_t oldpath_size, write_size;
>  
>          fd = openat_file(dirfd, name, O_CREAT | O_EXCL | O_RDWR,
>                           fs_ctx->fmode);
> -        if (fd == -1) {
> +        if (qemu_fd_invalid(fd)) {
>              goto out;
>          }
>          /* Write the oldpath (target) to the file. */
> @@ -962,7 +965,7 @@ static int local_link(FsContext *ctx, V9fsPath *oldpath,
>      char *odirpath = g_path_get_dirname(oldpath->data);
>      char *oname = g_path_get_basename(oldpath->data);
>      int ret = -1;
> -    int odirfd, ndirfd;
> +    QemuFd_t odirfd, ndirfd;
>  
>      if (ctx->export_flags & V9FS_SM_MAPPED_FILE &&
>          local_is_mapped_file_metadata(ctx, name)) {
> @@ -971,12 +974,12 @@ static int local_link(FsContext *ctx, V9fsPath *oldpath,
>      }
>  
>      odirfd = local_opendir_nofollow(ctx, odirpath);
> -    if (odirfd == -1) {
> +    if (qemu_fd_invalid(odirfd)) {
>          goto out;
>      }
>  
>      ndirfd = local_opendir_nofollow(ctx, dirpath->data);
> -    if (ndirfd == -1) {
> +    if (qemu_fd_invalid(ndirfd)) {
>          close_preserve_errno(odirfd);
>          goto out;
>      }
> @@ -996,12 +999,12 @@ static int local_link(FsContext *ctx, V9fsPath *oldpath,
>          }
>  
>          omap_dirfd = openat_dir(odirfd, VIRTFS_META_DIR);
> -        if (omap_dirfd == -1) {
> +        if (qemu_fd_invalid(omap_dirfd)) {
>              goto err;
>          }
>  
>          nmap_dirfd = openat_dir(ndirfd, VIRTFS_META_DIR);
> -        if (nmap_dirfd == -1) {
> +        if (qemu_fd_invalid(nmap_dirfd)) {
>              close_preserve_errno(omap_dirfd);
>              goto err;
>          }
> @@ -1032,10 +1035,11 @@ out:
>  
>  static int local_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size)
>  {
> -    int fd, ret;
> +    QemuFd_t fd;
> +    int ret;
>  
>      fd = local_open_nofollow(ctx, fs_path->data, O_WRONLY, 0);
> -    if (fd == -1) {
> +    if (qemu_fd_invalid(fd)) {
>          return -1;
>      }
>      ret = ftruncate(fd, size);
> @@ -1048,10 +1052,10 @@ static int local_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
>      char *dirpath = g_path_get_dirname(fs_path->data);
>      char *name = g_path_get_basename(fs_path->data);
>      int ret = -1;
> -    int dirfd;
> +    QemuFd_t dirfd;
>  
>      dirfd = local_opendir_nofollow(fs_ctx, dirpath);
> -    if (dirfd == -1) {
> +    if (qemu_fd_invalid(dirfd)) {
>          goto out;
>      }
>  
> @@ -1078,10 +1082,11 @@ static int local_utimensat(FsContext *s, V9fsPath *fs_path,
>  {
>      char *dirpath = g_path_get_dirname(fs_path->data);
>      char *name = g_path_get_basename(fs_path->data);
> -    int dirfd, ret = -1;
> +    QemuFd_t dirfd;
> +    int ret = -1;
>  
>      dirfd = local_opendir_nofollow(s, dirpath);
> -    if (dirfd == -1) {
> +    if (qemu_fd_invalid(dirfd)) {
>          goto out;
>      }
>  
> @@ -1093,13 +1098,13 @@ out:
>      return ret;
>  }
>  
> -static int local_unlinkat_common(FsContext *ctx, int dirfd, const char *name,
> -                                 int flags)
> +static int local_unlinkat_common(FsContext *ctx, QemuFd_t dirfd,
> +                                 const char *name, int flags)
>  {
>      int ret;
>  
>      if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
> -        int map_dirfd;
> +        QemuFd_t map_dirfd;
>  
>          /* We need to remove the metadata as well:
>           * - the metadata directory if we're removing a directory
> @@ -1110,10 +1115,10 @@ static int local_unlinkat_common(FsContext *ctx, int dirfd, const char *name,
>           * mode. We just ignore the error.
>           */
>          if (flags == AT_REMOVEDIR) {
> -            int fd;
> +            QemuFd_t fd;
>  
>              fd = openat_dir(dirfd, name);
> -            if (fd == -1) {
> +            if (qemu_fd_invalid(fd)) {
>                  return -1;
>              }
>              ret = qemu_unlinkat(fd, VIRTFS_META_DIR, AT_REMOVEDIR);
> @@ -1123,7 +1128,7 @@ static int local_unlinkat_common(FsContext *ctx, int dirfd, const char *name,
>              }
>          }
>          map_dirfd = openat_dir(dirfd, VIRTFS_META_DIR);
> -        if (map_dirfd != -1) {
> +        if (!qemu_fd_invalid(map_dirfd)) {
>              ret = qemu_unlinkat(map_dirfd, name, 0);
>              close_preserve_errno(map_dirfd);
>              if (ret < 0 && errno != ENOENT) {
> @@ -1143,11 +1148,11 @@ static int local_remove(FsContext *ctx, const char *path)
>      char *dirpath = g_path_get_dirname(path);
>      char *name = g_path_get_basename(path);
>      int flags = 0;
> -    int dirfd;
> +    QemuFd_t dirfd;
>      int err = -1;
>  
>      dirfd = local_opendir_nofollow(ctx, dirpath);
> -    if (dirfd == -1) {
> +    if (qemu_fd_invalid(dirfd)) {
>          goto out;
>      }
>  
> @@ -1188,10 +1193,11 @@ static int local_fsync(FsContext *ctx, int fid_type,
>  
>  static int local_statfs(FsContext *s, V9fsPath *fs_path, struct statfs *stbuf)
>  {
> -    int fd, ret;
> +    QemuFd_t fd;
> +    int ret;
>  
>      fd = local_open_nofollow(s, fs_path->data, O_RDONLY, 0);
> -    if (fd == -1) {
> +    if (qemu_fd_invalid(fd)) {
>          return -1;
>      }
>      ret = fstatfs(fd, stbuf);
> @@ -1276,7 +1282,7 @@ static int local_renameat(FsContext *ctx, V9fsPath *olddir,
>                            const char *new_name)
>  {
>      int ret;
> -    int odirfd, ndirfd;
> +    QemuFd_t odirfd, ndirfd;
>  
>      if (ctx->export_flags & V9FS_SM_MAPPED_FILE &&
>          (local_is_mapped_file_metadata(ctx, old_name) ||
> @@ -1286,12 +1292,12 @@ static int local_renameat(FsContext *ctx, V9fsPath *olddir,
>      }
>  
>      odirfd = local_opendir_nofollow(ctx, olddir->data);
> -    if (odirfd == -1) {
> +    if (qemu_fd_invalid(odirfd)) {
>          return -1;
>      }
>  
>      ndirfd = local_opendir_nofollow(ctx, newdir->data);
> -    if (ndirfd == -1) {
> +    if (qemu_fd_invalid(ndirfd)) {
>          close_preserve_errno(odirfd);
>          return -1;
>      }
> @@ -1302,7 +1308,7 @@ static int local_renameat(FsContext *ctx, V9fsPath *olddir,
>      }
>  
>      if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
> -        int omap_dirfd, nmap_dirfd;
> +        QemuFd_t omap_dirfd, nmap_dirfd;
>  
>          ret = qemu_mkdirat(ndirfd, VIRTFS_META_DIR, 0700);
>          if (ret < 0 && errno != EEXIST) {
> @@ -1310,12 +1316,12 @@ static int local_renameat(FsContext *ctx, V9fsPath *olddir,
>          }
>  
>          omap_dirfd = openat_dir(odirfd, VIRTFS_META_DIR);
> -        if (omap_dirfd == -1) {
> +        if (qemu_fd_invalid(omap_dirfd)) {
>              goto err;
>          }
>  
>          nmap_dirfd = openat_dir(ndirfd, VIRTFS_META_DIR);
> -        if (nmap_dirfd == -1) {
> +        if (qemu_fd_invalid(nmap_dirfd)) {
>              close_preserve_errno(omap_dirfd);
>              goto err;
>          }
> @@ -1373,7 +1379,7 @@ static int local_unlinkat(FsContext *ctx, V9fsPath *dir,
>                            const char *name, int flags)
>  {
>      int ret;
> -    int dirfd;
> +    QemuFd_t dirfd;
>  
>      if (ctx->export_flags & V9FS_SM_MAPPED_FILE &&
>          local_is_mapped_file_metadata(ctx, name)) {
> @@ -1382,7 +1388,7 @@ static int local_unlinkat(FsContext *ctx, V9fsPath *dir,
>      }
>  
>      dirfd = local_opendir_nofollow(ctx, dir->data);
> -    if (dirfd == -1) {
> +    if (qemu_fd_invalid(dirfd)) {
>          return -1;
>      }
>  
> @@ -1446,7 +1452,7 @@ static int local_init(FsContext *ctx, Error **errp)
>      LocalData *data = g_malloc(sizeof(*data));
>  
>      data->mountfd = open(ctx->fs_root, O_DIRECTORY | O_RDONLY);
> -    if (data->mountfd == -1) {
> +    if (qemu_fd_invalid(data->mountfd)) {
>          error_setg_errno(errp, errno, "failed to open '%s'", ctx->fs_root);
>          goto err;
>      }
> diff --git a/hw/9pfs/9p-util-darwin.c b/hw/9pfs/9p-util-darwin.c
> index 95146e7354..f85cfd26bb 100644
> --- a/hw/9pfs/9p-util-darwin.c
> +++ b/hw/9pfs/9p-util-darwin.c
> @@ -11,8 +11,8 @@
>  #include "qemu/error-report.h"
>  #include "9p-util.h"
>  
> -ssize_t fgetxattrat_nofollow(int dirfd, const char *filename, const char *name,
> -                             void *value, size_t size)
> +ssize_t fgetxattrat_nofollow(QemuFd_t dirfd, const char *filename,
> +                             const char *name, void *value, size_t size)
>  {
>      int ret;
>      int fd = openat_file(dirfd, filename,
> @@ -25,7 +25,7 @@ ssize_t fgetxattrat_nofollow(int dirfd, const char *filename, const char *name,
>      return ret;
>  }
>  
> -ssize_t flistxattrat_nofollow(int dirfd, const char *filename,
> +ssize_t flistxattrat_nofollow(QemuFd_t dirfd, const char *filename,
>                                char *list, size_t size)
>  {
>      int ret;
> @@ -39,7 +39,7 @@ ssize_t flistxattrat_nofollow(int dirfd, const char *filename,
>      return ret;
>  }
>  
> -ssize_t fremovexattrat_nofollow(int dirfd, const char *filename,
> +ssize_t fremovexattrat_nofollow(QemuFd_t dirfd, const char *filename,
>                                  const char *name)
>  {
>      int ret;
> @@ -52,8 +52,8 @@ ssize_t fremovexattrat_nofollow(int dirfd, const char *filename,
>      return ret;
>  }
>  
> -int fsetxattrat_nofollow(int dirfd, const char *filename, const char *name,
> -                         void *value, size_t size, int flags)
> +int fsetxattrat_nofollow(QemuFd_t dirfd, const char *filename,
> +                         const char *name, void *value, size_t size, int flags)
>  {
>      int ret;
>      int fd = openat_file(dirfd, filename, O_PATH_9P_UTIL | O_NOFOLLOW, 0);
> @@ -110,7 +110,7 @@ out:
>      return err;
>  }
>  
> -int qemu_mknodat(int dirfd, const char *filename, mode_t mode, dev_t dev)
> +int qemu_mknodat(QemuFd_t dirfd, const char *filename, mode_t mode, dev_t dev)
>  {
>      int preserved_errno, err;
>  
> diff --git a/hw/9pfs/9p-util-linux.c b/hw/9pfs/9p-util-linux.c
> index db451b0784..8dd9da10b6 100644
> --- a/hw/9pfs/9p-util-linux.c
> +++ b/hw/9pfs/9p-util-linux.c
> @@ -19,8 +19,8 @@
>  #include "qemu/xattr.h"
>  #include "9p-util.h"
>  
> -ssize_t fgetxattrat_nofollow(int dirfd, const char *filename, const char *name,
> -                             void *value, size_t size)
> +ssize_t fgetxattrat_nofollow(QemuFd_t dirfd, const char *filename,
> +                             const char *name, void *value, size_t size)
>  {
>      char *proc_path = g_strdup_printf("/proc/self/fd/%d/%s", dirfd, filename);
>      int ret;
> @@ -30,7 +30,7 @@ ssize_t fgetxattrat_nofollow(int dirfd, const char *filename, const char *name,
>      return ret;
>  }
>  
> -ssize_t flistxattrat_nofollow(int dirfd, const char *filename,
> +ssize_t flistxattrat_nofollow(QemuFd_t dirfd, const char *filename,
>                                char *list, size_t size)
>  {
>      char *proc_path = g_strdup_printf("/proc/self/fd/%d/%s", dirfd, filename);
> @@ -41,7 +41,7 @@ ssize_t flistxattrat_nofollow(int dirfd, const char *filename,
>      return ret;
>  }
>  
> -ssize_t fremovexattrat_nofollow(int dirfd, const char *filename,
> +ssize_t fremovexattrat_nofollow(QemuFd_t dirfd, const char *filename,
>                                  const char *name)
>  {
>      char *proc_path = g_strdup_printf("/proc/self/fd/%d/%s", dirfd, filename);
> @@ -52,8 +52,8 @@ ssize_t fremovexattrat_nofollow(int dirfd, const char *filename,
>      return ret;
>  }
>  
> -int fsetxattrat_nofollow(int dirfd, const char *filename, const char *name,
> -                         void *value, size_t size, int flags)
> +int fsetxattrat_nofollow(QemuFd_t dirfd, const char *filename,
> +                         const char *name, void *value, size_t size, int flags)
>  {
>      char *proc_path = g_strdup_printf("/proc/self/fd/%d/%s", dirfd, filename);
>      int ret;
> @@ -64,7 +64,7 @@ int fsetxattrat_nofollow(int dirfd, const char *filename, const char *name,
>  
>  }
>  
> -int qemu_mknodat(int dirfd, const char *filename, mode_t mode, dev_t dev)
> +int qemu_mknodat(QemuFd_t dirfd, const char *filename, mode_t mode, dev_t dev)
>  {
>      return mknodat(dirfd, filename, mode, dev);
>  }
> diff --git a/hw/9pfs/9p-xattr.c b/hw/9pfs/9p-xattr.c
> index 9ae69dd8db..062bf2d1f0 100644
> --- a/hw/9pfs/9p-xattr.c
> +++ b/hw/9pfs/9p-xattr.c
> @@ -78,13 +78,13 @@ ssize_t v9fs_list_xattr(FsContext *ctx, const char *path,
>      char *orig_value, *orig_value_start;
>      ssize_t xattr_len, parsed_len = 0, attr_len;
>      char *dirpath, *name;
> -    int dirfd;
> +    QemuFd_t dirfd;
>  
>      /* Get the actual len */
>      dirpath = g_path_get_dirname(path);
>      dirfd = local_opendir_nofollow(ctx, dirpath);
>      g_free(dirpath);
> -    if (dirfd == -1) {
> +    if (qemu_fd_invalid(dirfd)) {
>          return -1;
>      }
>  
> @@ -168,11 +168,11 @@ ssize_t local_getxattr_nofollow(FsContext *ctx, const char *path,
>  {
>      char *dirpath = g_path_get_dirname(path);
>      char *filename = g_path_get_basename(path);
> -    int dirfd;
> +    QemuFd_t dirfd;
>      ssize_t ret = -1;
>  
>      dirfd = local_opendir_nofollow(ctx, dirpath);
> -    if (dirfd == -1) {
> +    if (qemu_fd_invalid(dirfd)) {
>          goto out;
>      }
>  
> @@ -196,11 +196,11 @@ ssize_t local_setxattr_nofollow(FsContext *ctx, const char *path,
>  {
>      char *dirpath = g_path_get_dirname(path);
>      char *filename = g_path_get_basename(path);
> -    int dirfd;
> +    QemuFd_t dirfd;
>      ssize_t ret = -1;
>  
>      dirfd = local_opendir_nofollow(ctx, dirpath);
> -    if (dirfd == -1) {
> +    if (qemu_fd_invalid(dirfd)) {
>          goto out;
>      }
>  
> @@ -223,11 +223,11 @@ ssize_t local_removexattr_nofollow(FsContext *ctx, const char *path,
>  {
>      char *dirpath = g_path_get_dirname(path);
>      char *filename = g_path_get_basename(path);
> -    int dirfd;
> +    QemuFd_t dirfd;
>      ssize_t ret = -1;
>  
>      dirfd = local_opendir_nofollow(ctx, dirpath);
> -    if (dirfd == -1) {
> +    if (qemu_fd_invalid(dirfd)) {
>          goto out;
>      }
>  



^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v2 02/19] hw/9pfs: Drop unnecessary *xattr wrapper API declarations
  2022-11-18  8:42   ` Greg Kurz
@ 2022-11-18 13:10     ` Christian Schoenebeck
  0 siblings, 0 replies; 36+ messages in thread
From: Christian Schoenebeck @ 2022-11-18 13:10 UTC (permalink / raw)
  To: Bin Meng, qemu-devel, qemu-trivial; +Cc: Greg Kurz

On Friday, November 18, 2022 9:42:26 AM CET Greg Kurz wrote:
> On Fri, 11 Nov 2022 12:22:08 +0800
> Bin Meng <bin.meng@windriver.com> wrote:
> 
> > These are not used anywhere in the source tree. Drop them.
> > 
> > Signed-off-by: Bin Meng <bin.meng@windriver.com>
> > ---
> > 
> 
> This one could even go through the trivial tree right
> away IMHO.

+1

> Reviewed-by: Greg Kurz <groug@kaod.org>
> 
> > (no changes since v1)
> > 
> >  hw/9pfs/9p-util.h | 11 -----------
> >  1 file changed, 11 deletions(-)
> > 
> > diff --git a/hw/9pfs/9p-util.h b/hw/9pfs/9p-util.h
> > index c3526144c9..ccfc8b1cb3 100644
> > --- a/hw/9pfs/9p-util.h
> > +++ b/hw/9pfs/9p-util.h
> > @@ -90,19 +90,8 @@ static inline int errno_to_dotl(int err) {
> >  
> >  #ifdef CONFIG_DARWIN
> >  #define qemu_fgetxattr(...) fgetxattr(__VA_ARGS__, 0, 0)
> > -#define qemu_lgetxattr(...) getxattr(__VA_ARGS__, 0, XATTR_NOFOLLOW)
> > -#define qemu_llistxattr(...) listxattr(__VA_ARGS__, XATTR_NOFOLLOW)
> > -#define qemu_lremovexattr(...) removexattr(__VA_ARGS__, XATTR_NOFOLLOW)
> > -static inline int qemu_lsetxattr(const char *path, const char *name,
> > -                                 const void *value, size_t size, int 
flags) {
> > -    return setxattr(path, name, value, size, 0, flags | XATTR_NOFOLLOW);
> > -}
> >  #else
> >  #define qemu_fgetxattr fgetxattr
> > -#define qemu_lgetxattr lgetxattr
> > -#define qemu_llistxattr llistxattr
> > -#define qemu_lremovexattr lremovexattr
> > -#define qemu_lsetxattr lsetxattr
> >  #endif
> >  
> >  static inline void close_preserve_errno(int fd)
> 
> 
> 




^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v2 05/19] hw/9pfs: Update 9pfs to use the new QemuFd_t type
  2022-11-18  9:29   ` Greg Kurz
@ 2022-11-18 13:38     ` Christian Schoenebeck
  2022-11-19 10:19       ` Greg Kurz
  0 siblings, 1 reply; 36+ messages in thread
From: Christian Schoenebeck @ 2022-11-18 13:38 UTC (permalink / raw)
  To: Bin Meng, qemu-devel, Greg Kurz

On Friday, November 18, 2022 10:29:51 AM CET Greg Kurz wrote:
> On Fri, 11 Nov 2022 12:22:11 +0800
> Bin Meng <bin.meng@windriver.com> wrote:
> 
> > With this new QemuFd_t type, it significantly reduces the number of
> 
> I cannot find the definition of this type, nor the definition of
> qemu_fd_invalid(). Missing patch ?

It's in patch 4. Looks like we were not CCed on that patch. :(

https://lore.kernel.org/qemu-devel/20221111042225.1115931-5-bin.meng@windriver.com/

> Anyway, IIUC this type is an int for linux and a HANDLE for windows,
> right ?
> 
> According to win32 documentation at [1] :
> 
> HANDLE	
> A handle to an object.
> 
> This type is declared in WinNT.h as follows:
> 
> typedef PVOID HANDLE;
> 
> and
> 
> PVOID	
> A pointer to any type.
> 
> This type is declared in WinNT.h as follows:
> 
> typedef void *PVOID;
> 
> HANDLE is void *.
> 
> From docs/devel/style.rst:
> 
> Naming
> ======
> 
> Variables are lower_case_with_underscores; easy to type and read.  Structured
> type names are in CamelCase; harder to type but standing out.  Enum type
> names and function type names should also be in CamelCase.  Scalar type
> names are lower_case_with_underscores_ending_with_a_t, like the POSIX
> uint64_t and family.  Note that this last convention contradicts POSIX
> and is therefore likely to be changed.
> 
> Both int and void * are scalar types, so I'd rather name it qemu_fd_t,
> not using CamelCase at all so that it cannot be confused with a struct.
> 
> [1] https://learn.microsoft.com/en-us/windows/win32/winprog/windows-data-types

Not that I had a strong opinion about this issue (as in general with coding
style topics). It was one of my suggested type names. To make this type long-
term proof I suggested to handle it as if it was a truly opaque type in QEMU:

https://lore.kernel.org/qemu-devel/4620086.XpUeK0iDWE@silver/

That is to explicitly not try to do things like:

    if (fd == -1)

at least not hard wired in user code. According to QEMU code style you should
probably then drop the trailing "_t" though.

> > deviated code paths when adding Windows support.
> > 
> > Signed-off-by: Bin Meng <bin.meng@windriver.com>
> > 
> > ---
> > 
> > Changes in v2:
> > - Use the new QemuFd_t type
> > 
> >  hw/9pfs/9p-local.h       |   6 +-
> >  hw/9pfs/9p-util.h        |  26 +++---
> >  hw/9pfs/9p-local.c       | 174 ++++++++++++++++++++-------------------
> >  hw/9pfs/9p-util-darwin.c |  14 ++--
> >  hw/9pfs/9p-util-linux.c  |  14 ++--
> >  hw/9pfs/9p-xattr.c       |  16 ++--
> >  6 files changed, 129 insertions(+), 121 deletions(-)
> > 
> > diff --git a/hw/9pfs/9p-local.h b/hw/9pfs/9p-local.h
> > index 32c72749d9..66a21316a0 100644
> > --- a/hw/9pfs/9p-local.h
> > +++ b/hw/9pfs/9p-local.h
> > @@ -13,8 +13,8 @@
> >  #ifndef QEMU_9P_LOCAL_H
> >  #define QEMU_9P_LOCAL_H
> >  
> > -int local_open_nofollow(FsContext *fs_ctx, const char *path, int flags,
> > -                        mode_t mode);
> > -int local_opendir_nofollow(FsContext *fs_ctx, const char *path);
> > +QemuFd_t local_open_nofollow(FsContext *fs_ctx, const char *path, int flags,
> > +                             mode_t mode);
> > +QemuFd_t local_opendir_nofollow(FsContext *fs_ctx, const char *path);
> >  
> >  #endif
> > diff --git a/hw/9pfs/9p-util.h b/hw/9pfs/9p-util.h
> > index c314cf381d..3d6bd1a51e 100644
> > --- a/hw/9pfs/9p-util.h
> > +++ b/hw/9pfs/9p-util.h
> > @@ -101,30 +101,31 @@ static inline int errno_to_dotl(int err) {
> >  #define qemu_utimensat  utimensat
> >  #define qemu_unlinkat   unlinkat
> >  
> > -static inline void close_preserve_errno(int fd)
> > +static inline void close_preserve_errno(QemuFd_t fd)
> >  {
> >      int serrno = errno;
> >      close(fd);
> >      errno = serrno;
> >  }
> >  
> > -static inline int openat_dir(int dirfd, const char *name)
> > +static inline QemuFd_t openat_dir(QemuFd_t dirfd, const char *name)
> >  {
> >      return qemu_openat(dirfd, name,
> >                         O_DIRECTORY | O_RDONLY | O_NOFOLLOW | O_PATH_9P_UTIL);
> >  }
> >  
> > -static inline int openat_file(int dirfd, const char *name, int flags,
> > -                              mode_t mode)
> > +static inline QemuFd_t openat_file(QemuFd_t dirfd, const char *name,
> > +                                   int flags, mode_t mode)
> >  {
> > -    int fd, serrno, ret;
> > +    int serrno, ret;
> > +    QemuFd_t fd;
> >  
> >  #ifndef CONFIG_DARWIN
> >  again:
> >  #endif
> >      fd = qemu_openat(dirfd, name, flags | O_NOFOLLOW | O_NOCTTY | O_NONBLOCK,
> >                       mode);
> > -    if (fd == -1) {
> > +    if (qemu_fd_invalid(fd)) {
> >  #ifndef CONFIG_DARWIN
> >          if (errno == EPERM && (flags & O_NOATIME)) {
> >              /*
> > @@ -155,13 +156,13 @@ again:
> >      return fd;
> >  }
> >  
> > -ssize_t fgetxattrat_nofollow(int dirfd, const char *path, const char *name,
> > -                             void *value, size_t size);
> > -int fsetxattrat_nofollow(int dirfd, const char *path, const char *name,
> > +ssize_t fgetxattrat_nofollow(QemuFd_t dirfd, const char *path,
> > +                             const char *name, void *value, size_t size);
> > +int fsetxattrat_nofollow(QemuFd_t dirfd, const char *path, const char *name,
> >                           void *value, size_t size, int flags);
> > -ssize_t flistxattrat_nofollow(int dirfd, const char *filename,
> > +ssize_t flistxattrat_nofollow(QemuFd_t dirfd, const char *filename,
> >                                char *list, size_t size);
> > -ssize_t fremovexattrat_nofollow(int dirfd, const char *filename,
> > +ssize_t fremovexattrat_nofollow(QemuFd_t dirfd, const char *filename,
> >                                  const char *name);
> >  
> >  /*
> > @@ -219,6 +220,7 @@ static inline struct dirent *qemu_dirent_dup(struct dirent *dent)
> >  #if defined CONFIG_DARWIN && defined CONFIG_PTHREAD_FCHDIR_NP
> >  int pthread_fchdir_np(int fd) __attribute__((weak_import));
> >  #endif
> > -int qemu_mknodat(int dirfd, const char *filename, mode_t mode, dev_t dev);
> > +int qemu_mknodat(QemuFd_t dirfd, const char *filename, mode_t mode,
> > +                 dev_t dev);
> >  
> >  #endif
> > diff --git a/hw/9pfs/9p-local.c b/hw/9pfs/9p-local.c
> > index d2246a3d7e..22377a3105 100644
> > --- a/hw/9pfs/9p-local.c
> > +++ b/hw/9pfs/9p-local.c
> > @@ -54,18 +54,18 @@
> >  #endif
> >  
> >  typedef struct {
> > -    int mountfd;
> > +    QemuFd_t mountfd;
> >  } LocalData;
> >  
> > -int local_open_nofollow(FsContext *fs_ctx, const char *path, int flags,
> > -                        mode_t mode)
> > +QemuFd_t local_open_nofollow(FsContext *fs_ctx, const char *path, int flags,
> > +                             mode_t mode)
> >  {
> >      LocalData *data = fs_ctx->private;
> > -    int fd = data->mountfd;
> > +    QemuFd_t fd = data->mountfd;
> >  
> > -    while (*path && fd != -1) {
> > +    while (*path && !qemu_fd_invalid(fd)) {
> >          const char *c;
> > -        int next_fd;
> > +        QemuFd_t next_fd;
> >          char *head;
> >  
> >          /* Only relative paths without consecutive slashes */
> > @@ -94,20 +94,21 @@ int local_open_nofollow(FsContext *fs_ctx, const char *path, int flags,
> >      return fd;
> >  }
> >  
> > -int local_opendir_nofollow(FsContext *fs_ctx, const char *path)
> > +QemuFd_t local_opendir_nofollow(FsContext *fs_ctx, const char *path)
> >  {
> >      return local_open_nofollow(fs_ctx, path, O_DIRECTORY | O_RDONLY, 0);
> >  }
> >  
> > -static void renameat_preserve_errno(int odirfd, const char *opath, int ndirfd,
> > -                                    const char *npath)
> > +static void renameat_preserve_errno(QemuFd_t odirfd, const char *opath,
> > +                                    QemuFd_t ndirfd, const char *npath)
> >  {
> >      int serrno = errno;
> >      qemu_renameat(odirfd, opath, ndirfd, npath);
> >      errno = serrno;
> >  }
> >  
> > -static void unlinkat_preserve_errno(int dirfd, const char *path, int flags)
> > +static void unlinkat_preserve_errno(QemuFd_t dirfd, const char *path,
> > +                                    int flags)
> >  {
> >      int serrno = errno;
> >      qemu_unlinkat(dirfd, path, flags);
> > @@ -117,9 +118,10 @@ static void unlinkat_preserve_errno(int dirfd, const char *path, int flags)
> >  #define VIRTFS_META_DIR ".virtfs_metadata"
> >  #define VIRTFS_META_ROOT_FILE VIRTFS_META_DIR "_root"
> >  
> > -static FILE *local_fopenat(int dirfd, const char *name, const char *mode)
> > +static FILE *local_fopenat(QemuFd_t dirfd, const char *name, const char *mode)
> >  {
> > -    int fd, o_mode = 0;
> > +    QemuFd_t fd;
> > +    int o_mode = 0;
> >      FILE *fp;
> >      int flags;
> >      /*
> > @@ -134,7 +136,7 @@ static FILE *local_fopenat(int dirfd, const char *name, const char *mode)
> >          return NULL;
> >      }
> >      fd = openat_file(dirfd, name, flags, o_mode);
> > -    if (fd == -1) {
> > +    if (qemu_fd_invalid(fd)) {
> >          return NULL;
> >      }
> >      fp = fdopen(fd, mode);
> > @@ -145,16 +147,16 @@ static FILE *local_fopenat(int dirfd, const char *name, const char *mode)
> >  }
> >  
> >  #define ATTR_MAX 100
> > -static void local_mapped_file_attr(int dirfd, const char *name,
> > +static void local_mapped_file_attr(QemuFd_t dirfd, const char *name,
> >                                     struct stat *stbuf)
> >  {
> >      FILE *fp;
> >      char buf[ATTR_MAX];
> > -    int map_dirfd;
> > +    QemuFd_t map_dirfd;
> >  
> >      if (strcmp(name, ".")) {
> >          map_dirfd = openat_dir(dirfd, VIRTFS_META_DIR);
> > -        if (map_dirfd == -1) {
> > +        if (qemu_fd_invalid(map_dirfd)) {
> >              return;
> >          }
> >  
> > @@ -187,10 +189,10 @@ static int local_lstat(FsContext *fs_ctx, V9fsPath *fs_path, struct stat *stbuf)
> >      int err = -1;
> >      char *dirpath = g_path_get_dirname(fs_path->data);
> >      char *name = g_path_get_basename(fs_path->data);
> > -    int dirfd;
> > +    QemuFd_t dirfd;
> >  
> >      dirfd = local_opendir_nofollow(fs_ctx, dirpath);
> > -    if (dirfd == -1) {
> > +    if (qemu_fd_invalid(dirfd)) {
> >          goto out;
> >      }
> >  
> > @@ -233,14 +235,14 @@ out:
> >      return err;
> >  }
> >  
> > -static int local_set_mapped_file_attrat(int dirfd, const char *name,
> > +static int local_set_mapped_file_attrat(QemuFd_t dirfd, const char *name,
> >                                          FsCred *credp)
> >  {
> >      FILE *fp;
> >      int ret;
> >      char buf[ATTR_MAX];
> >      int uid = -1, gid = -1, mode = -1, rdev = -1;
> > -    int map_dirfd = -1, map_fd;
> > +    QemuFd_t map_dirfd = QEMU_FD_INVALID, map_fd;
> >      bool is_root = !strcmp(name, ".");
> >  
> >      if (is_root) {
> > @@ -259,7 +261,7 @@ static int local_set_mapped_file_attrat(int dirfd, const char *name,
> >          }
> >  
> >          map_dirfd = openat_dir(dirfd, VIRTFS_META_DIR);
> > -        if (map_dirfd == -1) {
> > +        if (qemu_fd_invalid(map_dirfd)) {
> >              return -1;
> >          }
> >  
> > @@ -296,7 +298,7 @@ update_map_file:
> >          /* We can't go this far with map_dirfd not being a valid file descriptor
> >           * but some versions of gcc aren't smart enough to see it.
> >           */
> > -        if (map_dirfd != -1) {
> > +        if (!qemu_fd_invalid(map_dirfd)) {
> >              close_preserve_errno(map_dirfd);
> >          }
> >      }
> > @@ -305,7 +307,7 @@ update_map_file:
> >      }
> >  
> >      map_fd = fileno(fp);
> > -    assert(map_fd != -1);
> > +    assert(!qemu_fd_invalid(map_fd));
> >      ret = fchmod(map_fd, 0600);
> >      assert(ret == 0);
> >  
> > @@ -339,10 +341,11 @@ update_map_file:
> >      return 0;
> >  }
> >  
> > -static int fchmodat_nofollow(int dirfd, const char *name, mode_t mode)
> > +static int fchmodat_nofollow(QemuFd_t dirfd, const char *name, mode_t mode)
> >  {
> >      struct stat stbuf;
> > -    int fd, ret;
> > +    QemuFd_t fd;
> > +    int ret;
> >  
> >      /* FIXME: this should be handled with fchmodat(AT_SYMLINK_NOFOLLOW).
> >       * Unfortunately, the linux kernel doesn't implement it yet.
> > @@ -362,16 +365,16 @@ static int fchmodat_nofollow(int dirfd, const char *name, mode_t mode)
> >      /* Fallback for systems that don't support O_PATH: we depend on the file
> >       * being readable or writable.
> >       */
> > -    if (fd == -1) {
> > +    if (qemu_fd_invalid(fd)) {
> >          /* In case the file is writable-only and isn't a directory. */
> >          if (errno == EACCES) {
> >              fd = openat_file(dirfd, name, O_WRONLY, 0);
> >          }
> > -        if (fd == -1 && errno == EISDIR) {
> > +        if (qemu_fd_invalid(fd) && errno == EISDIR) {
> >              errno = EACCES;
> >          }
> >      }
> > -    if (fd == -1) {
> > +    if (qemu_fd_invalid(fd)) {
> >          return -1;
> >      }
> >      ret = fchmod(fd, mode);
> > @@ -380,7 +383,7 @@ static int fchmodat_nofollow(int dirfd, const char *name, mode_t mode)
> >       * link, O_PATH | O_NOFOLLOW causes openat(2) to return a file descriptor
> >       * referring to the symbolic link.
> >       */
> > -    if (fd == -1) {
> > +    if (qemu_fd_invalid(fd)) {
> >          return -1;
> >      }
> >  
> > @@ -401,7 +404,7 @@ static int fchmodat_nofollow(int dirfd, const char *name, mode_t mode)
> >      return ret;
> >  }
> >  
> > -static int local_set_xattrat(int dirfd, const char *path, FsCred *credp)
> > +static int local_set_xattrat(QemuFd_t dirfd, const char *path, FsCred *credp)
> >  {
> >      int err;
> >  
> > @@ -440,7 +443,7 @@ static int local_set_xattrat(int dirfd, const char *path, FsCred *credp)
> >      return 0;
> >  }
> >  
> > -static int local_set_cred_passthrough(FsContext *fs_ctx, int dirfd,
> > +static int local_set_cred_passthrough(FsContext *fs_ctx, QemuFd_t dirfd,
> >                                        const char *name, FsCred *credp)
> >  {
> >      if (fchownat(dirfd, name, credp->fc_uid, credp->fc_gid,
> > @@ -464,10 +467,10 @@ static ssize_t local_readlink(FsContext *fs_ctx, V9fsPath *fs_path,
> >  
> >      if ((fs_ctx->export_flags & V9FS_SM_MAPPED) ||
> >          (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE)) {
> > -        int fd;
> > +        QemuFd_t fd;
> >  
> >          fd = local_open_nofollow(fs_ctx, fs_path->data, O_RDONLY, 0);
> > -        if (fd == -1) {
> > +        if (qemu_fd_invalid(fd)) {
> >              return -1;
> >          }
> >          do {
> > @@ -478,10 +481,10 @@ static ssize_t local_readlink(FsContext *fs_ctx, V9fsPath *fs_path,
> >                 (fs_ctx->export_flags & V9FS_SM_NONE)) {
> >          char *dirpath = g_path_get_dirname(fs_path->data);
> >          char *name = g_path_get_basename(fs_path->data);
> > -        int dirfd;
> > +        QemuFd_t dirfd;
> >  
> >          dirfd = local_opendir_nofollow(fs_ctx, dirpath);
> > -        if (dirfd == -1) {
> > +        if (qemu_fd_invalid(dirfd)) {
> >              goto out;
> >          }
> >  
> > @@ -507,10 +510,10 @@ static int local_closedir(FsContext *ctx, V9fsFidOpenState *fs)
> >  static int local_open(FsContext *ctx, V9fsPath *fs_path,
> >                        int flags, V9fsFidOpenState *fs)
> >  {
> > -    int fd;
> > +    QemuFd_t fd;
> >  
> >      fd = local_open_nofollow(ctx, fs_path->data, flags, 0);
> > -    if (fd == -1) {
> > +    if (qemu_fd_invalid(fd)) {
> >          return -1;
> >      }
> >      fs->fd = fd;
> > @@ -520,11 +523,11 @@ static int local_open(FsContext *ctx, V9fsPath *fs_path,
> >  static int local_opendir(FsContext *ctx,
> >                           V9fsPath *fs_path, V9fsFidOpenState *fs)
> >  {
> > -    int dirfd;
> > +    QemuFd_t dirfd;
> >      DIR *stream;
> >  
> >      dirfd = local_opendir_nofollow(ctx, fs_path->data);
> > -    if (dirfd == -1) {
> > +    if (qemu_fd_invalid(dirfd)) {
> >          return -1;
> >      }
> >  
> > @@ -640,10 +643,10 @@ static int local_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
> >      char *dirpath = g_path_get_dirname(fs_path->data);
> >      char *name = g_path_get_basename(fs_path->data);
> >      int ret = -1;
> > -    int dirfd;
> > +    QemuFd_t dirfd;
> >  
> >      dirfd = local_opendir_nofollow(fs_ctx, dirpath);
> > -    if (dirfd == -1) {
> > +    if (qemu_fd_invalid(dirfd)) {
> >          goto out;
> >      }
> >  
> > @@ -667,7 +670,7 @@ static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path,
> >                         const char *name, FsCred *credp)
> >  {
> >      int err = -1;
> > -    int dirfd;
> > +    QemuFd_t dirfd;
> >  
> >      if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE &&
> >          local_is_mapped_file_metadata(fs_ctx, name)) {
> > @@ -676,7 +679,7 @@ static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path,
> >      }
> >  
> >      dirfd = local_opendir_nofollow(fs_ctx, dir_path->data);
> > -    if (dirfd == -1) {
> > +    if (qemu_fd_invalid(dirfd)) {
> >          return -1;
> >      }
> >  
> > @@ -719,7 +722,7 @@ static int local_mkdir(FsContext *fs_ctx, V9fsPath *dir_path,
> >                         const char *name, FsCred *credp)
> >  {
> >      int err = -1;
> > -    int dirfd;
> > +    QemuFd_t dirfd;
> >  
> >      if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE &&
> >          local_is_mapped_file_metadata(fs_ctx, name)) {
> > @@ -728,7 +731,7 @@ static int local_mkdir(FsContext *fs_ctx, V9fsPath *dir_path,
> >      }
> >  
> >      dirfd = local_opendir_nofollow(fs_ctx, dir_path->data);
> > -    if (dirfd == -1) {
> > +    if (qemu_fd_invalid(dirfd)) {
> >          return -1;
> >      }
> >  
> > @@ -816,9 +819,9 @@ static int local_fstat(FsContext *fs_ctx, int fid_type,
> >  static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
> >                         int flags, FsCred *credp, V9fsFidOpenState *fs)
> >  {
> > -    int fd = -1;
> > +    QemuFd_t fd = QEMU_FD_INVALID;
> >      int err = -1;
> > -    int dirfd;
> > +    QemuFd_t dirfd;
> >  
> >      if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE &&
> >          local_is_mapped_file_metadata(fs_ctx, name)) {
> > @@ -832,7 +835,7 @@ static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
> >      flags |= O_NOFOLLOW;
> >  
> >      dirfd = local_opendir_nofollow(fs_ctx, dir_path->data);
> > -    if (dirfd == -1) {
> > +    if (qemu_fd_invalid(dirfd)) {
> >          return -1;
> >      }
> >  
> > @@ -840,7 +843,7 @@ static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
> >      if (fs_ctx->export_flags & V9FS_SM_MAPPED ||
> >          fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
> >          fd = openat_file(dirfd, name, flags, fs_ctx->fmode);
> > -        if (fd == -1) {
> > +        if (qemu_fd_invalid(fd)) {
> >              goto out;
> >          }
> >          credp->fc_mode = credp->fc_mode | S_IFREG;
> > @@ -856,7 +859,7 @@ 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)) {
> >          fd = openat_file(dirfd, name, flags, credp->fc_mode);
> > -        if (fd == -1) {
> > +        if (qemu_fd_invalid(fd)) {
> >              goto out;
> >          }
> >          err = local_set_cred_passthrough(fs_ctx, dirfd, name, credp);
> > @@ -882,7 +885,7 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath,
> >                           V9fsPath *dir_path, const char *name, FsCred *credp)
> >  {
> >      int err = -1;
> > -    int dirfd;
> > +    QemuFd_t dirfd;
> >  
> >      if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE &&
> >          local_is_mapped_file_metadata(fs_ctx, name)) {
> > @@ -891,19 +894,19 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath,
> >      }
> >  
> >      dirfd = local_opendir_nofollow(fs_ctx, dir_path->data);
> > -    if (dirfd == -1) {
> > +    if (qemu_fd_invalid(dirfd)) {
> >          return -1;
> >      }
> >  
> >      /* Determine the security model */
> >      if (fs_ctx->export_flags & V9FS_SM_MAPPED ||
> >          fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
> > -        int fd;
> > +        QemuFd_t fd;
> >          ssize_t oldpath_size, write_size;
> >  
> >          fd = openat_file(dirfd, name, O_CREAT | O_EXCL | O_RDWR,
> >                           fs_ctx->fmode);
> > -        if (fd == -1) {
> > +        if (qemu_fd_invalid(fd)) {
> >              goto out;
> >          }
> >          /* Write the oldpath (target) to the file. */
> > @@ -962,7 +965,7 @@ static int local_link(FsContext *ctx, V9fsPath *oldpath,
> >      char *odirpath = g_path_get_dirname(oldpath->data);
> >      char *oname = g_path_get_basename(oldpath->data);
> >      int ret = -1;
> > -    int odirfd, ndirfd;
> > +    QemuFd_t odirfd, ndirfd;
> >  
> >      if (ctx->export_flags & V9FS_SM_MAPPED_FILE &&
> >          local_is_mapped_file_metadata(ctx, name)) {
> > @@ -971,12 +974,12 @@ static int local_link(FsContext *ctx, V9fsPath *oldpath,
> >      }
> >  
> >      odirfd = local_opendir_nofollow(ctx, odirpath);
> > -    if (odirfd == -1) {
> > +    if (qemu_fd_invalid(odirfd)) {
> >          goto out;
> >      }
> >  
> >      ndirfd = local_opendir_nofollow(ctx, dirpath->data);
> > -    if (ndirfd == -1) {
> > +    if (qemu_fd_invalid(ndirfd)) {
> >          close_preserve_errno(odirfd);
> >          goto out;
> >      }
> > @@ -996,12 +999,12 @@ static int local_link(FsContext *ctx, V9fsPath *oldpath,
> >          }
> >  
> >          omap_dirfd = openat_dir(odirfd, VIRTFS_META_DIR);
> > -        if (omap_dirfd == -1) {
> > +        if (qemu_fd_invalid(omap_dirfd)) {
> >              goto err;
> >          }
> >  
> >          nmap_dirfd = openat_dir(ndirfd, VIRTFS_META_DIR);
> > -        if (nmap_dirfd == -1) {
> > +        if (qemu_fd_invalid(nmap_dirfd)) {
> >              close_preserve_errno(omap_dirfd);
> >              goto err;
> >          }
> > @@ -1032,10 +1035,11 @@ out:
> >  
> >  static int local_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size)
> >  {
> > -    int fd, ret;
> > +    QemuFd_t fd;
> > +    int ret;
> >  
> >      fd = local_open_nofollow(ctx, fs_path->data, O_WRONLY, 0);
> > -    if (fd == -1) {
> > +    if (qemu_fd_invalid(fd)) {
> >          return -1;
> >      }
> >      ret = ftruncate(fd, size);
> > @@ -1048,10 +1052,10 @@ static int local_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
> >      char *dirpath = g_path_get_dirname(fs_path->data);
> >      char *name = g_path_get_basename(fs_path->data);
> >      int ret = -1;
> > -    int dirfd;
> > +    QemuFd_t dirfd;
> >  
> >      dirfd = local_opendir_nofollow(fs_ctx, dirpath);
> > -    if (dirfd == -1) {
> > +    if (qemu_fd_invalid(dirfd)) {
> >          goto out;
> >      }
> >  
> > @@ -1078,10 +1082,11 @@ static int local_utimensat(FsContext *s, V9fsPath *fs_path,
> >  {
> >      char *dirpath = g_path_get_dirname(fs_path->data);
> >      char *name = g_path_get_basename(fs_path->data);
> > -    int dirfd, ret = -1;
> > +    QemuFd_t dirfd;
> > +    int ret = -1;
> >  
> >      dirfd = local_opendir_nofollow(s, dirpath);
> > -    if (dirfd == -1) {
> > +    if (qemu_fd_invalid(dirfd)) {
> >          goto out;
> >      }
> >  
> > @@ -1093,13 +1098,13 @@ out:
> >      return ret;
> >  }
> >  
> > -static int local_unlinkat_common(FsContext *ctx, int dirfd, const char *name,
> > -                                 int flags)
> > +static int local_unlinkat_common(FsContext *ctx, QemuFd_t dirfd,
> > +                                 const char *name, int flags)
> >  {
> >      int ret;
> >  
> >      if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
> > -        int map_dirfd;
> > +        QemuFd_t map_dirfd;
> >  
> >          /* We need to remove the metadata as well:
> >           * - the metadata directory if we're removing a directory
> > @@ -1110,10 +1115,10 @@ static int local_unlinkat_common(FsContext *ctx, int dirfd, const char *name,
> >           * mode. We just ignore the error.
> >           */
> >          if (flags == AT_REMOVEDIR) {
> > -            int fd;
> > +            QemuFd_t fd;
> >  
> >              fd = openat_dir(dirfd, name);
> > -            if (fd == -1) {
> > +            if (qemu_fd_invalid(fd)) {
> >                  return -1;
> >              }
> >              ret = qemu_unlinkat(fd, VIRTFS_META_DIR, AT_REMOVEDIR);
> > @@ -1123,7 +1128,7 @@ static int local_unlinkat_common(FsContext *ctx, int dirfd, const char *name,
> >              }
> >          }
> >          map_dirfd = openat_dir(dirfd, VIRTFS_META_DIR);
> > -        if (map_dirfd != -1) {
> > +        if (!qemu_fd_invalid(map_dirfd)) {
> >              ret = qemu_unlinkat(map_dirfd, name, 0);
> >              close_preserve_errno(map_dirfd);
> >              if (ret < 0 && errno != ENOENT) {
> > @@ -1143,11 +1148,11 @@ static int local_remove(FsContext *ctx, const char *path)
> >      char *dirpath = g_path_get_dirname(path);
> >      char *name = g_path_get_basename(path);
> >      int flags = 0;
> > -    int dirfd;
> > +    QemuFd_t dirfd;
> >      int err = -1;
> >  
> >      dirfd = local_opendir_nofollow(ctx, dirpath);
> > -    if (dirfd == -1) {
> > +    if (qemu_fd_invalid(dirfd)) {
> >          goto out;
> >      }
> >  
> > @@ -1188,10 +1193,11 @@ static int local_fsync(FsContext *ctx, int fid_type,
> >  
> >  static int local_statfs(FsContext *s, V9fsPath *fs_path, struct statfs *stbuf)
> >  {
> > -    int fd, ret;
> > +    QemuFd_t fd;
> > +    int ret;
> >  
> >      fd = local_open_nofollow(s, fs_path->data, O_RDONLY, 0);
> > -    if (fd == -1) {
> > +    if (qemu_fd_invalid(fd)) {
> >          return -1;
> >      }
> >      ret = fstatfs(fd, stbuf);
> > @@ -1276,7 +1282,7 @@ static int local_renameat(FsContext *ctx, V9fsPath *olddir,
> >                            const char *new_name)
> >  {
> >      int ret;
> > -    int odirfd, ndirfd;
> > +    QemuFd_t odirfd, ndirfd;
> >  
> >      if (ctx->export_flags & V9FS_SM_MAPPED_FILE &&
> >          (local_is_mapped_file_metadata(ctx, old_name) ||
> > @@ -1286,12 +1292,12 @@ static int local_renameat(FsContext *ctx, V9fsPath *olddir,
> >      }
> >  
> >      odirfd = local_opendir_nofollow(ctx, olddir->data);
> > -    if (odirfd == -1) {
> > +    if (qemu_fd_invalid(odirfd)) {
> >          return -1;
> >      }
> >  
> >      ndirfd = local_opendir_nofollow(ctx, newdir->data);
> > -    if (ndirfd == -1) {
> > +    if (qemu_fd_invalid(ndirfd)) {
> >          close_preserve_errno(odirfd);
> >          return -1;
> >      }
> > @@ -1302,7 +1308,7 @@ static int local_renameat(FsContext *ctx, V9fsPath *olddir,
> >      }
> >  
> >      if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
> > -        int omap_dirfd, nmap_dirfd;
> > +        QemuFd_t omap_dirfd, nmap_dirfd;
> >  
> >          ret = qemu_mkdirat(ndirfd, VIRTFS_META_DIR, 0700);
> >          if (ret < 0 && errno != EEXIST) {
> > @@ -1310,12 +1316,12 @@ static int local_renameat(FsContext *ctx, V9fsPath *olddir,
> >          }
> >  
> >          omap_dirfd = openat_dir(odirfd, VIRTFS_META_DIR);
> > -        if (omap_dirfd == -1) {
> > +        if (qemu_fd_invalid(omap_dirfd)) {
> >              goto err;
> >          }
> >  
> >          nmap_dirfd = openat_dir(ndirfd, VIRTFS_META_DIR);
> > -        if (nmap_dirfd == -1) {
> > +        if (qemu_fd_invalid(nmap_dirfd)) {
> >              close_preserve_errno(omap_dirfd);
> >              goto err;
> >          }
> > @@ -1373,7 +1379,7 @@ static int local_unlinkat(FsContext *ctx, V9fsPath *dir,
> >                            const char *name, int flags)
> >  {
> >      int ret;
> > -    int dirfd;
> > +    QemuFd_t dirfd;
> >  
> >      if (ctx->export_flags & V9FS_SM_MAPPED_FILE &&
> >          local_is_mapped_file_metadata(ctx, name)) {
> > @@ -1382,7 +1388,7 @@ static int local_unlinkat(FsContext *ctx, V9fsPath *dir,
> >      }
> >  
> >      dirfd = local_opendir_nofollow(ctx, dir->data);
> > -    if (dirfd == -1) {
> > +    if (qemu_fd_invalid(dirfd)) {
> >          return -1;
> >      }
> >  
> > @@ -1446,7 +1452,7 @@ static int local_init(FsContext *ctx, Error **errp)
> >      LocalData *data = g_malloc(sizeof(*data));
> >  
> >      data->mountfd = open(ctx->fs_root, O_DIRECTORY | O_RDONLY);
> > -    if (data->mountfd == -1) {
> > +    if (qemu_fd_invalid(data->mountfd)) {
> >          error_setg_errno(errp, errno, "failed to open '%s'", ctx->fs_root);
> >          goto err;
> >      }
> > diff --git a/hw/9pfs/9p-util-darwin.c b/hw/9pfs/9p-util-darwin.c
> > index 95146e7354..f85cfd26bb 100644
> > --- a/hw/9pfs/9p-util-darwin.c
> > +++ b/hw/9pfs/9p-util-darwin.c
> > @@ -11,8 +11,8 @@
> >  #include "qemu/error-report.h"
> >  #include "9p-util.h"
> >  
> > -ssize_t fgetxattrat_nofollow(int dirfd, const char *filename, const char *name,
> > -                             void *value, size_t size)
> > +ssize_t fgetxattrat_nofollow(QemuFd_t dirfd, const char *filename,
> > +                             const char *name, void *value, size_t size)
> >  {
> >      int ret;
> >      int fd = openat_file(dirfd, filename,
> > @@ -25,7 +25,7 @@ ssize_t fgetxattrat_nofollow(int dirfd, const char *filename, const char *name,
> >      return ret;
> >  }
> >  
> > -ssize_t flistxattrat_nofollow(int dirfd, const char *filename,
> > +ssize_t flistxattrat_nofollow(QemuFd_t dirfd, const char *filename,
> >                                char *list, size_t size)
> >  {
> >      int ret;
> > @@ -39,7 +39,7 @@ ssize_t flistxattrat_nofollow(int dirfd, const char *filename,
> >      return ret;
> >  }
> >  
> > -ssize_t fremovexattrat_nofollow(int dirfd, const char *filename,
> > +ssize_t fremovexattrat_nofollow(QemuFd_t dirfd, const char *filename,
> >                                  const char *name)
> >  {
> >      int ret;
> > @@ -52,8 +52,8 @@ ssize_t fremovexattrat_nofollow(int dirfd, const char *filename,
> >      return ret;
> >  }
> >  
> > -int fsetxattrat_nofollow(int dirfd, const char *filename, const char *name,
> > -                         void *value, size_t size, int flags)
> > +int fsetxattrat_nofollow(QemuFd_t dirfd, const char *filename,
> > +                         const char *name, void *value, size_t size, int flags)
> >  {
> >      int ret;
> >      int fd = openat_file(dirfd, filename, O_PATH_9P_UTIL | O_NOFOLLOW, 0);
> > @@ -110,7 +110,7 @@ out:
> >      return err;
> >  }
> >  
> > -int qemu_mknodat(int dirfd, const char *filename, mode_t mode, dev_t dev)
> > +int qemu_mknodat(QemuFd_t dirfd, const char *filename, mode_t mode, dev_t dev)
> >  {
> >      int preserved_errno, err;
> >  
> > diff --git a/hw/9pfs/9p-util-linux.c b/hw/9pfs/9p-util-linux.c
> > index db451b0784..8dd9da10b6 100644
> > --- a/hw/9pfs/9p-util-linux.c
> > +++ b/hw/9pfs/9p-util-linux.c
> > @@ -19,8 +19,8 @@
> >  #include "qemu/xattr.h"
> >  #include "9p-util.h"
> >  
> > -ssize_t fgetxattrat_nofollow(int dirfd, const char *filename, const char *name,
> > -                             void *value, size_t size)
> > +ssize_t fgetxattrat_nofollow(QemuFd_t dirfd, const char *filename,
> > +                             const char *name, void *value, size_t size)
> >  {
> >      char *proc_path = g_strdup_printf("/proc/self/fd/%d/%s", dirfd, filename);
> >      int ret;
> > @@ -30,7 +30,7 @@ ssize_t fgetxattrat_nofollow(int dirfd, const char *filename, const char *name,
> >      return ret;
> >  }
> >  
> > -ssize_t flistxattrat_nofollow(int dirfd, const char *filename,
> > +ssize_t flistxattrat_nofollow(QemuFd_t dirfd, const char *filename,
> >                                char *list, size_t size)
> >  {
> >      char *proc_path = g_strdup_printf("/proc/self/fd/%d/%s", dirfd, filename);
> > @@ -41,7 +41,7 @@ ssize_t flistxattrat_nofollow(int dirfd, const char *filename,
> >      return ret;
> >  }
> >  
> > -ssize_t fremovexattrat_nofollow(int dirfd, const char *filename,
> > +ssize_t fremovexattrat_nofollow(QemuFd_t dirfd, const char *filename,
> >                                  const char *name)
> >  {
> >      char *proc_path = g_strdup_printf("/proc/self/fd/%d/%s", dirfd, filename);
> > @@ -52,8 +52,8 @@ ssize_t fremovexattrat_nofollow(int dirfd, const char *filename,
> >      return ret;
> >  }
> >  
> > -int fsetxattrat_nofollow(int dirfd, const char *filename, const char *name,
> > -                         void *value, size_t size, int flags)
> > +int fsetxattrat_nofollow(QemuFd_t dirfd, const char *filename,
> > +                         const char *name, void *value, size_t size, int flags)
> >  {
> >      char *proc_path = g_strdup_printf("/proc/self/fd/%d/%s", dirfd, filename);
> >      int ret;
> > @@ -64,7 +64,7 @@ int fsetxattrat_nofollow(int dirfd, const char *filename, const char *name,
> >  
> >  }
> >  
> > -int qemu_mknodat(int dirfd, const char *filename, mode_t mode, dev_t dev)
> > +int qemu_mknodat(QemuFd_t dirfd, const char *filename, mode_t mode, dev_t dev)
> >  {
> >      return mknodat(dirfd, filename, mode, dev);
> >  }
> > diff --git a/hw/9pfs/9p-xattr.c b/hw/9pfs/9p-xattr.c
> > index 9ae69dd8db..062bf2d1f0 100644
> > --- a/hw/9pfs/9p-xattr.c
> > +++ b/hw/9pfs/9p-xattr.c
> > @@ -78,13 +78,13 @@ ssize_t v9fs_list_xattr(FsContext *ctx, const char *path,
> >      char *orig_value, *orig_value_start;
> >      ssize_t xattr_len, parsed_len = 0, attr_len;
> >      char *dirpath, *name;
> > -    int dirfd;
> > +    QemuFd_t dirfd;
> >  
> >      /* Get the actual len */
> >      dirpath = g_path_get_dirname(path);
> >      dirfd = local_opendir_nofollow(ctx, dirpath);
> >      g_free(dirpath);
> > -    if (dirfd == -1) {
> > +    if (qemu_fd_invalid(dirfd)) {
> >          return -1;
> >      }
> >  
> > @@ -168,11 +168,11 @@ ssize_t local_getxattr_nofollow(FsContext *ctx, const char *path,
> >  {
> >      char *dirpath = g_path_get_dirname(path);
> >      char *filename = g_path_get_basename(path);
> > -    int dirfd;
> > +    QemuFd_t dirfd;
> >      ssize_t ret = -1;
> >  
> >      dirfd = local_opendir_nofollow(ctx, dirpath);
> > -    if (dirfd == -1) {
> > +    if (qemu_fd_invalid(dirfd)) {
> >          goto out;
> >      }
> >  
> > @@ -196,11 +196,11 @@ ssize_t local_setxattr_nofollow(FsContext *ctx, const char *path,
> >  {
> >      char *dirpath = g_path_get_dirname(path);
> >      char *filename = g_path_get_basename(path);
> > -    int dirfd;
> > +    QemuFd_t dirfd;
> >      ssize_t ret = -1;
> >  
> >      dirfd = local_opendir_nofollow(ctx, dirpath);
> > -    if (dirfd == -1) {
> > +    if (qemu_fd_invalid(dirfd)) {
> >          goto out;
> >      }
> >  
> > @@ -223,11 +223,11 @@ ssize_t local_removexattr_nofollow(FsContext *ctx, const char *path,
> >  {
> >      char *dirpath = g_path_get_dirname(path);
> >      char *filename = g_path_get_basename(path);
> > -    int dirfd;
> > +    QemuFd_t dirfd;
> >      ssize_t ret = -1;
> >  
> >      dirfd = local_opendir_nofollow(ctx, dirpath);
> > -    if (dirfd == -1) {
> > +    if (qemu_fd_invalid(dirfd)) {
> >          goto out;
> >      }
> >  
> 
> 
> 




^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v2 05/19] hw/9pfs: Update 9pfs to use the new QemuFd_t type
  2022-11-18 13:38     ` Christian Schoenebeck
@ 2022-11-19 10:19       ` Greg Kurz
  2022-11-19 15:22         ` Bin Meng
  0 siblings, 1 reply; 36+ messages in thread
From: Greg Kurz @ 2022-11-19 10:19 UTC (permalink / raw)
  To: Christian Schoenebeck; +Cc: Bin Meng, qemu-devel

On Fri, 18 Nov 2022 14:38:00 +0100
Christian Schoenebeck <qemu_oss@crudebyte.com> wrote:

> On Friday, November 18, 2022 10:29:51 AM CET Greg Kurz wrote:
> > On Fri, 11 Nov 2022 12:22:11 +0800
> > Bin Meng <bin.meng@windriver.com> wrote:
> > 
> > > With this new QemuFd_t type, it significantly reduces the number of
> > 
> > I cannot find the definition of this type, nor the definition of
> > qemu_fd_invalid(). Missing patch ?
> 
> It's in patch 4. Looks like we were not CCed on that patch. :(
> 

Oh I didn't check the numbering. I guess we were not CCed automatically...

> https://lore.kernel.org/qemu-devel/20221111042225.1115931-5-bin.meng@windriver.com/
> 

... because this only touches include/qemu/osdep.h .

Bin,

Please ensure that the maintainers are in the Cc list for all
patches in such a series, e.g. with explicit --cc arguments to
git-send-email.

> > Anyway, IIUC this type is an int for linux and a HANDLE for windows,
> > right ?
> > 
> > According to win32 documentation at [1] :
> > 
> > HANDLE	
> > A handle to an object.
> > 
> > This type is declared in WinNT.h as follows:
> > 
> > typedef PVOID HANDLE;
> > 
> > and
> > 
> > PVOID	
> > A pointer to any type.
> > 
> > This type is declared in WinNT.h as follows:
> > 
> > typedef void *PVOID;
> > 
> > HANDLE is void *.
> > 
> > From docs/devel/style.rst:
> > 
> > Naming
> > ======
> > 
> > Variables are lower_case_with_underscores; easy to type and read.  Structured
> > type names are in CamelCase; harder to type but standing out.  Enum type
> > names and function type names should also be in CamelCase.  Scalar type
> > names are lower_case_with_underscores_ending_with_a_t, like the POSIX
> > uint64_t and family.  Note that this last convention contradicts POSIX
> > and is therefore likely to be changed.
> > 
> > Both int and void * are scalar types, so I'd rather name it qemu_fd_t,
> > not using CamelCase at all so that it cannot be confused with a struct.
> > 
> > [1] https://learn.microsoft.com/en-us/windows/win32/winprog/windows-data-types
> 
> Not that I had a strong opinion about this issue (as in general with coding
> style topics). It was one of my suggested type names. To make this type long-
> term proof I suggested to handle it as if it was a truly opaque type in QEMU:
> 

A true opaque type in C is implemented with a structured type and pointers
to this type.

> https://lore.kernel.org/qemu-devel/4620086.XpUeK0iDWE@silver/
> 
> That is to explicitly not try to do things like:
> 
>     if (fd == -1)
> 
> at least not hard wired in user code. According to QEMU code style you should
> probably then drop the trailing "_t" though.
> 

Yes, either one is fine I guess. Most important part is to provide
a documented API to manipulate that type since, no matter the name,
it is still a scalar type that can be manipulated as such.

> > > deviated code paths when adding Windows support.
> > > 
> > > Signed-off-by: Bin Meng <bin.meng@windriver.com>
> > > 
> > > ---
> > > 
> > > Changes in v2:
> > > - Use the new QemuFd_t type
> > > 
> > >  hw/9pfs/9p-local.h       |   6 +-
> > >  hw/9pfs/9p-util.h        |  26 +++---
> > >  hw/9pfs/9p-local.c       | 174 ++++++++++++++++++++-------------------
> > >  hw/9pfs/9p-util-darwin.c |  14 ++--
> > >  hw/9pfs/9p-util-linux.c  |  14 ++--
> > >  hw/9pfs/9p-xattr.c       |  16 ++--
> > >  6 files changed, 129 insertions(+), 121 deletions(-)
> > > 
> > > diff --git a/hw/9pfs/9p-local.h b/hw/9pfs/9p-local.h
> > > index 32c72749d9..66a21316a0 100644
> > > --- a/hw/9pfs/9p-local.h
> > > +++ b/hw/9pfs/9p-local.h
> > > @@ -13,8 +13,8 @@
> > >  #ifndef QEMU_9P_LOCAL_H
> > >  #define QEMU_9P_LOCAL_H
> > >  
> > > -int local_open_nofollow(FsContext *fs_ctx, const char *path, int flags,
> > > -                        mode_t mode);
> > > -int local_opendir_nofollow(FsContext *fs_ctx, const char *path);
> > > +QemuFd_t local_open_nofollow(FsContext *fs_ctx, const char *path, int flags,
> > > +                             mode_t mode);
> > > +QemuFd_t local_opendir_nofollow(FsContext *fs_ctx, const char *path);
> > >  
> > >  #endif
> > > diff --git a/hw/9pfs/9p-util.h b/hw/9pfs/9p-util.h
> > > index c314cf381d..3d6bd1a51e 100644
> > > --- a/hw/9pfs/9p-util.h
> > > +++ b/hw/9pfs/9p-util.h
> > > @@ -101,30 +101,31 @@ static inline int errno_to_dotl(int err) {
> > >  #define qemu_utimensat  utimensat
> > >  #define qemu_unlinkat   unlinkat
> > >  
> > > -static inline void close_preserve_errno(int fd)
> > > +static inline void close_preserve_errno(QemuFd_t fd)
> > >  {
> > >      int serrno = errno;
> > >      close(fd);
> > >      errno = serrno;
> > >  }
> > >  
> > > -static inline int openat_dir(int dirfd, const char *name)
> > > +static inline QemuFd_t openat_dir(QemuFd_t dirfd, const char *name)
> > >  {
> > >      return qemu_openat(dirfd, name,
> > >                         O_DIRECTORY | O_RDONLY | O_NOFOLLOW | O_PATH_9P_UTIL);
> > >  }
> > >  
> > > -static inline int openat_file(int dirfd, const char *name, int flags,
> > > -                              mode_t mode)
> > > +static inline QemuFd_t openat_file(QemuFd_t dirfd, const char *name,
> > > +                                   int flags, mode_t mode)
> > >  {
> > > -    int fd, serrno, ret;
> > > +    int serrno, ret;
> > > +    QemuFd_t fd;
> > >  
> > >  #ifndef CONFIG_DARWIN
> > >  again:
> > >  #endif
> > >      fd = qemu_openat(dirfd, name, flags | O_NOFOLLOW | O_NOCTTY | O_NONBLOCK,
> > >                       mode);
> > > -    if (fd == -1) {
> > > +    if (qemu_fd_invalid(fd)) {
> > >  #ifndef CONFIG_DARWIN
> > >          if (errno == EPERM && (flags & O_NOATIME)) {
> > >              /*
> > > @@ -155,13 +156,13 @@ again:
> > >      return fd;
> > >  }
> > >  
> > > -ssize_t fgetxattrat_nofollow(int dirfd, const char *path, const char *name,
> > > -                             void *value, size_t size);
> > > -int fsetxattrat_nofollow(int dirfd, const char *path, const char *name,
> > > +ssize_t fgetxattrat_nofollow(QemuFd_t dirfd, const char *path,
> > > +                             const char *name, void *value, size_t size);
> > > +int fsetxattrat_nofollow(QemuFd_t dirfd, const char *path, const char *name,
> > >                           void *value, size_t size, int flags);
> > > -ssize_t flistxattrat_nofollow(int dirfd, const char *filename,
> > > +ssize_t flistxattrat_nofollow(QemuFd_t dirfd, const char *filename,
> > >                                char *list, size_t size);
> > > -ssize_t fremovexattrat_nofollow(int dirfd, const char *filename,
> > > +ssize_t fremovexattrat_nofollow(QemuFd_t dirfd, const char *filename,
> > >                                  const char *name);
> > >  
> > >  /*
> > > @@ -219,6 +220,7 @@ static inline struct dirent *qemu_dirent_dup(struct dirent *dent)
> > >  #if defined CONFIG_DARWIN && defined CONFIG_PTHREAD_FCHDIR_NP
> > >  int pthread_fchdir_np(int fd) __attribute__((weak_import));
> > >  #endif
> > > -int qemu_mknodat(int dirfd, const char *filename, mode_t mode, dev_t dev);
> > > +int qemu_mknodat(QemuFd_t dirfd, const char *filename, mode_t mode,
> > > +                 dev_t dev);
> > >  
> > >  #endif
> > > diff --git a/hw/9pfs/9p-local.c b/hw/9pfs/9p-local.c
> > > index d2246a3d7e..22377a3105 100644
> > > --- a/hw/9pfs/9p-local.c
> > > +++ b/hw/9pfs/9p-local.c
> > > @@ -54,18 +54,18 @@
> > >  #endif
> > >  
> > >  typedef struct {
> > > -    int mountfd;
> > > +    QemuFd_t mountfd;
> > >  } LocalData;
> > >  
> > > -int local_open_nofollow(FsContext *fs_ctx, const char *path, int flags,
> > > -                        mode_t mode)
> > > +QemuFd_t local_open_nofollow(FsContext *fs_ctx, const char *path, int flags,
> > > +                             mode_t mode)
> > >  {
> > >      LocalData *data = fs_ctx->private;
> > > -    int fd = data->mountfd;
> > > +    QemuFd_t fd = data->mountfd;
> > >  
> > > -    while (*path && fd != -1) {
> > > +    while (*path && !qemu_fd_invalid(fd)) {
> > >          const char *c;
> > > -        int next_fd;
> > > +        QemuFd_t next_fd;
> > >          char *head;
> > >  
> > >          /* Only relative paths without consecutive slashes */
> > > @@ -94,20 +94,21 @@ int local_open_nofollow(FsContext *fs_ctx, const char *path, int flags,
> > >      return fd;
> > >  }
> > >  
> > > -int local_opendir_nofollow(FsContext *fs_ctx, const char *path)
> > > +QemuFd_t local_opendir_nofollow(FsContext *fs_ctx, const char *path)
> > >  {
> > >      return local_open_nofollow(fs_ctx, path, O_DIRECTORY | O_RDONLY, 0);
> > >  }
> > >  
> > > -static void renameat_preserve_errno(int odirfd, const char *opath, int ndirfd,
> > > -                                    const char *npath)
> > > +static void renameat_preserve_errno(QemuFd_t odirfd, const char *opath,
> > > +                                    QemuFd_t ndirfd, const char *npath)
> > >  {
> > >      int serrno = errno;
> > >      qemu_renameat(odirfd, opath, ndirfd, npath);
> > >      errno = serrno;
> > >  }
> > >  
> > > -static void unlinkat_preserve_errno(int dirfd, const char *path, int flags)
> > > +static void unlinkat_preserve_errno(QemuFd_t dirfd, const char *path,
> > > +                                    int flags)
> > >  {
> > >      int serrno = errno;
> > >      qemu_unlinkat(dirfd, path, flags);
> > > @@ -117,9 +118,10 @@ static void unlinkat_preserve_errno(int dirfd, const char *path, int flags)
> > >  #define VIRTFS_META_DIR ".virtfs_metadata"
> > >  #define VIRTFS_META_ROOT_FILE VIRTFS_META_DIR "_root"
> > >  
> > > -static FILE *local_fopenat(int dirfd, const char *name, const char *mode)
> > > +static FILE *local_fopenat(QemuFd_t dirfd, const char *name, const char *mode)
> > >  {
> > > -    int fd, o_mode = 0;
> > > +    QemuFd_t fd;
> > > +    int o_mode = 0;
> > >      FILE *fp;
> > >      int flags;
> > >      /*
> > > @@ -134,7 +136,7 @@ static FILE *local_fopenat(int dirfd, const char *name, const char *mode)
> > >          return NULL;
> > >      }
> > >      fd = openat_file(dirfd, name, flags, o_mode);
> > > -    if (fd == -1) {
> > > +    if (qemu_fd_invalid(fd)) {
> > >          return NULL;
> > >      }
> > >      fp = fdopen(fd, mode);
> > > @@ -145,16 +147,16 @@ static FILE *local_fopenat(int dirfd, const char *name, const char *mode)
> > >  }
> > >  
> > >  #define ATTR_MAX 100
> > > -static void local_mapped_file_attr(int dirfd, const char *name,
> > > +static void local_mapped_file_attr(QemuFd_t dirfd, const char *name,
> > >                                     struct stat *stbuf)
> > >  {
> > >      FILE *fp;
> > >      char buf[ATTR_MAX];
> > > -    int map_dirfd;
> > > +    QemuFd_t map_dirfd;
> > >  
> > >      if (strcmp(name, ".")) {
> > >          map_dirfd = openat_dir(dirfd, VIRTFS_META_DIR);
> > > -        if (map_dirfd == -1) {
> > > +        if (qemu_fd_invalid(map_dirfd)) {
> > >              return;
> > >          }
> > >  
> > > @@ -187,10 +189,10 @@ static int local_lstat(FsContext *fs_ctx, V9fsPath *fs_path, struct stat *stbuf)
> > >      int err = -1;
> > >      char *dirpath = g_path_get_dirname(fs_path->data);
> > >      char *name = g_path_get_basename(fs_path->data);
> > > -    int dirfd;
> > > +    QemuFd_t dirfd;
> > >  
> > >      dirfd = local_opendir_nofollow(fs_ctx, dirpath);
> > > -    if (dirfd == -1) {
> > > +    if (qemu_fd_invalid(dirfd)) {
> > >          goto out;
> > >      }
> > >  
> > > @@ -233,14 +235,14 @@ out:
> > >      return err;
> > >  }
> > >  
> > > -static int local_set_mapped_file_attrat(int dirfd, const char *name,
> > > +static int local_set_mapped_file_attrat(QemuFd_t dirfd, const char *name,
> > >                                          FsCred *credp)
> > >  {
> > >      FILE *fp;
> > >      int ret;
> > >      char buf[ATTR_MAX];
> > >      int uid = -1, gid = -1, mode = -1, rdev = -1;
> > > -    int map_dirfd = -1, map_fd;
> > > +    QemuFd_t map_dirfd = QEMU_FD_INVALID, map_fd;
> > >      bool is_root = !strcmp(name, ".");
> > >  
> > >      if (is_root) {
> > > @@ -259,7 +261,7 @@ static int local_set_mapped_file_attrat(int dirfd, const char *name,
> > >          }
> > >  
> > >          map_dirfd = openat_dir(dirfd, VIRTFS_META_DIR);
> > > -        if (map_dirfd == -1) {
> > > +        if (qemu_fd_invalid(map_dirfd)) {
> > >              return -1;
> > >          }
> > >  
> > > @@ -296,7 +298,7 @@ update_map_file:
> > >          /* We can't go this far with map_dirfd not being a valid file descriptor
> > >           * but some versions of gcc aren't smart enough to see it.
> > >           */
> > > -        if (map_dirfd != -1) {
> > > +        if (!qemu_fd_invalid(map_dirfd)) {
> > >              close_preserve_errno(map_dirfd);
> > >          }
> > >      }
> > > @@ -305,7 +307,7 @@ update_map_file:
> > >      }
> > >  
> > >      map_fd = fileno(fp);
> > > -    assert(map_fd != -1);
> > > +    assert(!qemu_fd_invalid(map_fd));
> > >      ret = fchmod(map_fd, 0600);
> > >      assert(ret == 0);
> > >  
> > > @@ -339,10 +341,11 @@ update_map_file:
> > >      return 0;
> > >  }
> > >  
> > > -static int fchmodat_nofollow(int dirfd, const char *name, mode_t mode)
> > > +static int fchmodat_nofollow(QemuFd_t dirfd, const char *name, mode_t mode)
> > >  {
> > >      struct stat stbuf;
> > > -    int fd, ret;
> > > +    QemuFd_t fd;
> > > +    int ret;
> > >  
> > >      /* FIXME: this should be handled with fchmodat(AT_SYMLINK_NOFOLLOW).
> > >       * Unfortunately, the linux kernel doesn't implement it yet.
> > > @@ -362,16 +365,16 @@ static int fchmodat_nofollow(int dirfd, const char *name, mode_t mode)
> > >      /* Fallback for systems that don't support O_PATH: we depend on the file
> > >       * being readable or writable.
> > >       */
> > > -    if (fd == -1) {
> > > +    if (qemu_fd_invalid(fd)) {
> > >          /* In case the file is writable-only and isn't a directory. */
> > >          if (errno == EACCES) {
> > >              fd = openat_file(dirfd, name, O_WRONLY, 0);
> > >          }
> > > -        if (fd == -1 && errno == EISDIR) {
> > > +        if (qemu_fd_invalid(fd) && errno == EISDIR) {
> > >              errno = EACCES;
> > >          }
> > >      }
> > > -    if (fd == -1) {
> > > +    if (qemu_fd_invalid(fd)) {
> > >          return -1;
> > >      }
> > >      ret = fchmod(fd, mode);
> > > @@ -380,7 +383,7 @@ static int fchmodat_nofollow(int dirfd, const char *name, mode_t mode)
> > >       * link, O_PATH | O_NOFOLLOW causes openat(2) to return a file descriptor
> > >       * referring to the symbolic link.
> > >       */
> > > -    if (fd == -1) {
> > > +    if (qemu_fd_invalid(fd)) {
> > >          return -1;
> > >      }
> > >  
> > > @@ -401,7 +404,7 @@ static int fchmodat_nofollow(int dirfd, const char *name, mode_t mode)
> > >      return ret;
> > >  }
> > >  
> > > -static int local_set_xattrat(int dirfd, const char *path, FsCred *credp)
> > > +static int local_set_xattrat(QemuFd_t dirfd, const char *path, FsCred *credp)
> > >  {
> > >      int err;
> > >  
> > > @@ -440,7 +443,7 @@ static int local_set_xattrat(int dirfd, const char *path, FsCred *credp)
> > >      return 0;
> > >  }
> > >  
> > > -static int local_set_cred_passthrough(FsContext *fs_ctx, int dirfd,
> > > +static int local_set_cred_passthrough(FsContext *fs_ctx, QemuFd_t dirfd,
> > >                                        const char *name, FsCred *credp)
> > >  {
> > >      if (fchownat(dirfd, name, credp->fc_uid, credp->fc_gid,
> > > @@ -464,10 +467,10 @@ static ssize_t local_readlink(FsContext *fs_ctx, V9fsPath *fs_path,
> > >  
> > >      if ((fs_ctx->export_flags & V9FS_SM_MAPPED) ||
> > >          (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE)) {
> > > -        int fd;
> > > +        QemuFd_t fd;
> > >  
> > >          fd = local_open_nofollow(fs_ctx, fs_path->data, O_RDONLY, 0);
> > > -        if (fd == -1) {
> > > +        if (qemu_fd_invalid(fd)) {
> > >              return -1;
> > >          }
> > >          do {
> > > @@ -478,10 +481,10 @@ static ssize_t local_readlink(FsContext *fs_ctx, V9fsPath *fs_path,
> > >                 (fs_ctx->export_flags & V9FS_SM_NONE)) {
> > >          char *dirpath = g_path_get_dirname(fs_path->data);
> > >          char *name = g_path_get_basename(fs_path->data);
> > > -        int dirfd;
> > > +        QemuFd_t dirfd;
> > >  
> > >          dirfd = local_opendir_nofollow(fs_ctx, dirpath);
> > > -        if (dirfd == -1) {
> > > +        if (qemu_fd_invalid(dirfd)) {
> > >              goto out;
> > >          }
> > >  
> > > @@ -507,10 +510,10 @@ static int local_closedir(FsContext *ctx, V9fsFidOpenState *fs)
> > >  static int local_open(FsContext *ctx, V9fsPath *fs_path,
> > >                        int flags, V9fsFidOpenState *fs)
> > >  {
> > > -    int fd;
> > > +    QemuFd_t fd;
> > >  
> > >      fd = local_open_nofollow(ctx, fs_path->data, flags, 0);
> > > -    if (fd == -1) {
> > > +    if (qemu_fd_invalid(fd)) {
> > >          return -1;
> > >      }
> > >      fs->fd = fd;
> > > @@ -520,11 +523,11 @@ static int local_open(FsContext *ctx, V9fsPath *fs_path,
> > >  static int local_opendir(FsContext *ctx,
> > >                           V9fsPath *fs_path, V9fsFidOpenState *fs)
> > >  {
> > > -    int dirfd;
> > > +    QemuFd_t dirfd;
> > >      DIR *stream;
> > >  
> > >      dirfd = local_opendir_nofollow(ctx, fs_path->data);
> > > -    if (dirfd == -1) {
> > > +    if (qemu_fd_invalid(dirfd)) {
> > >          return -1;
> > >      }
> > >  
> > > @@ -640,10 +643,10 @@ static int local_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
> > >      char *dirpath = g_path_get_dirname(fs_path->data);
> > >      char *name = g_path_get_basename(fs_path->data);
> > >      int ret = -1;
> > > -    int dirfd;
> > > +    QemuFd_t dirfd;
> > >  
> > >      dirfd = local_opendir_nofollow(fs_ctx, dirpath);
> > > -    if (dirfd == -1) {
> > > +    if (qemu_fd_invalid(dirfd)) {
> > >          goto out;
> > >      }
> > >  
> > > @@ -667,7 +670,7 @@ static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path,
> > >                         const char *name, FsCred *credp)
> > >  {
> > >      int err = -1;
> > > -    int dirfd;
> > > +    QemuFd_t dirfd;
> > >  
> > >      if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE &&
> > >          local_is_mapped_file_metadata(fs_ctx, name)) {
> > > @@ -676,7 +679,7 @@ static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path,
> > >      }
> > >  
> > >      dirfd = local_opendir_nofollow(fs_ctx, dir_path->data);
> > > -    if (dirfd == -1) {
> > > +    if (qemu_fd_invalid(dirfd)) {
> > >          return -1;
> > >      }
> > >  
> > > @@ -719,7 +722,7 @@ static int local_mkdir(FsContext *fs_ctx, V9fsPath *dir_path,
> > >                         const char *name, FsCred *credp)
> > >  {
> > >      int err = -1;
> > > -    int dirfd;
> > > +    QemuFd_t dirfd;
> > >  
> > >      if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE &&
> > >          local_is_mapped_file_metadata(fs_ctx, name)) {
> > > @@ -728,7 +731,7 @@ static int local_mkdir(FsContext *fs_ctx, V9fsPath *dir_path,
> > >      }
> > >  
> > >      dirfd = local_opendir_nofollow(fs_ctx, dir_path->data);
> > > -    if (dirfd == -1) {
> > > +    if (qemu_fd_invalid(dirfd)) {
> > >          return -1;
> > >      }
> > >  
> > > @@ -816,9 +819,9 @@ static int local_fstat(FsContext *fs_ctx, int fid_type,
> > >  static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
> > >                         int flags, FsCred *credp, V9fsFidOpenState *fs)
> > >  {
> > > -    int fd = -1;
> > > +    QemuFd_t fd = QEMU_FD_INVALID;
> > >      int err = -1;
> > > -    int dirfd;
> > > +    QemuFd_t dirfd;
> > >  
> > >      if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE &&
> > >          local_is_mapped_file_metadata(fs_ctx, name)) {
> > > @@ -832,7 +835,7 @@ static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
> > >      flags |= O_NOFOLLOW;
> > >  
> > >      dirfd = local_opendir_nofollow(fs_ctx, dir_path->data);
> > > -    if (dirfd == -1) {
> > > +    if (qemu_fd_invalid(dirfd)) {
> > >          return -1;
> > >      }
> > >  
> > > @@ -840,7 +843,7 @@ static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
> > >      if (fs_ctx->export_flags & V9FS_SM_MAPPED ||
> > >          fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
> > >          fd = openat_file(dirfd, name, flags, fs_ctx->fmode);
> > > -        if (fd == -1) {
> > > +        if (qemu_fd_invalid(fd)) {
> > >              goto out;
> > >          }
> > >          credp->fc_mode = credp->fc_mode | S_IFREG;
> > > @@ -856,7 +859,7 @@ 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)) {
> > >          fd = openat_file(dirfd, name, flags, credp->fc_mode);
> > > -        if (fd == -1) {
> > > +        if (qemu_fd_invalid(fd)) {
> > >              goto out;
> > >          }
> > >          err = local_set_cred_passthrough(fs_ctx, dirfd, name, credp);
> > > @@ -882,7 +885,7 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath,
> > >                           V9fsPath *dir_path, const char *name, FsCred *credp)
> > >  {
> > >      int err = -1;
> > > -    int dirfd;
> > > +    QemuFd_t dirfd;
> > >  
> > >      if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE &&
> > >          local_is_mapped_file_metadata(fs_ctx, name)) {
> > > @@ -891,19 +894,19 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath,
> > >      }
> > >  
> > >      dirfd = local_opendir_nofollow(fs_ctx, dir_path->data);
> > > -    if (dirfd == -1) {
> > > +    if (qemu_fd_invalid(dirfd)) {
> > >          return -1;
> > >      }
> > >  
> > >      /* Determine the security model */
> > >      if (fs_ctx->export_flags & V9FS_SM_MAPPED ||
> > >          fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
> > > -        int fd;
> > > +        QemuFd_t fd;
> > >          ssize_t oldpath_size, write_size;
> > >  
> > >          fd = openat_file(dirfd, name, O_CREAT | O_EXCL | O_RDWR,
> > >                           fs_ctx->fmode);
> > > -        if (fd == -1) {
> > > +        if (qemu_fd_invalid(fd)) {
> > >              goto out;
> > >          }
> > >          /* Write the oldpath (target) to the file. */
> > > @@ -962,7 +965,7 @@ static int local_link(FsContext *ctx, V9fsPath *oldpath,
> > >      char *odirpath = g_path_get_dirname(oldpath->data);
> > >      char *oname = g_path_get_basename(oldpath->data);
> > >      int ret = -1;
> > > -    int odirfd, ndirfd;
> > > +    QemuFd_t odirfd, ndirfd;
> > >  
> > >      if (ctx->export_flags & V9FS_SM_MAPPED_FILE &&
> > >          local_is_mapped_file_metadata(ctx, name)) {
> > > @@ -971,12 +974,12 @@ static int local_link(FsContext *ctx, V9fsPath *oldpath,
> > >      }
> > >  
> > >      odirfd = local_opendir_nofollow(ctx, odirpath);
> > > -    if (odirfd == -1) {
> > > +    if (qemu_fd_invalid(odirfd)) {
> > >          goto out;
> > >      }
> > >  
> > >      ndirfd = local_opendir_nofollow(ctx, dirpath->data);
> > > -    if (ndirfd == -1) {
> > > +    if (qemu_fd_invalid(ndirfd)) {
> > >          close_preserve_errno(odirfd);
> > >          goto out;
> > >      }
> > > @@ -996,12 +999,12 @@ static int local_link(FsContext *ctx, V9fsPath *oldpath,
> > >          }
> > >  
> > >          omap_dirfd = openat_dir(odirfd, VIRTFS_META_DIR);
> > > -        if (omap_dirfd == -1) {
> > > +        if (qemu_fd_invalid(omap_dirfd)) {
> > >              goto err;
> > >          }
> > >  
> > >          nmap_dirfd = openat_dir(ndirfd, VIRTFS_META_DIR);
> > > -        if (nmap_dirfd == -1) {
> > > +        if (qemu_fd_invalid(nmap_dirfd)) {
> > >              close_preserve_errno(omap_dirfd);
> > >              goto err;
> > >          }
> > > @@ -1032,10 +1035,11 @@ out:
> > >  
> > >  static int local_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size)
> > >  {
> > > -    int fd, ret;
> > > +    QemuFd_t fd;
> > > +    int ret;
> > >  
> > >      fd = local_open_nofollow(ctx, fs_path->data, O_WRONLY, 0);
> > > -    if (fd == -1) {
> > > +    if (qemu_fd_invalid(fd)) {
> > >          return -1;
> > >      }
> > >      ret = ftruncate(fd, size);
> > > @@ -1048,10 +1052,10 @@ static int local_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
> > >      char *dirpath = g_path_get_dirname(fs_path->data);
> > >      char *name = g_path_get_basename(fs_path->data);
> > >      int ret = -1;
> > > -    int dirfd;
> > > +    QemuFd_t dirfd;
> > >  
> > >      dirfd = local_opendir_nofollow(fs_ctx, dirpath);
> > > -    if (dirfd == -1) {
> > > +    if (qemu_fd_invalid(dirfd)) {
> > >          goto out;
> > >      }
> > >  
> > > @@ -1078,10 +1082,11 @@ static int local_utimensat(FsContext *s, V9fsPath *fs_path,
> > >  {
> > >      char *dirpath = g_path_get_dirname(fs_path->data);
> > >      char *name = g_path_get_basename(fs_path->data);
> > > -    int dirfd, ret = -1;
> > > +    QemuFd_t dirfd;
> > > +    int ret = -1;
> > >  
> > >      dirfd = local_opendir_nofollow(s, dirpath);
> > > -    if (dirfd == -1) {
> > > +    if (qemu_fd_invalid(dirfd)) {
> > >          goto out;
> > >      }
> > >  
> > > @@ -1093,13 +1098,13 @@ out:
> > >      return ret;
> > >  }
> > >  
> > > -static int local_unlinkat_common(FsContext *ctx, int dirfd, const char *name,
> > > -                                 int flags)
> > > +static int local_unlinkat_common(FsContext *ctx, QemuFd_t dirfd,
> > > +                                 const char *name, int flags)
> > >  {
> > >      int ret;
> > >  
> > >      if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
> > > -        int map_dirfd;
> > > +        QemuFd_t map_dirfd;
> > >  
> > >          /* We need to remove the metadata as well:
> > >           * - the metadata directory if we're removing a directory
> > > @@ -1110,10 +1115,10 @@ static int local_unlinkat_common(FsContext *ctx, int dirfd, const char *name,
> > >           * mode. We just ignore the error.
> > >           */
> > >          if (flags == AT_REMOVEDIR) {
> > > -            int fd;
> > > +            QemuFd_t fd;
> > >  
> > >              fd = openat_dir(dirfd, name);
> > > -            if (fd == -1) {
> > > +            if (qemu_fd_invalid(fd)) {
> > >                  return -1;
> > >              }
> > >              ret = qemu_unlinkat(fd, VIRTFS_META_DIR, AT_REMOVEDIR);
> > > @@ -1123,7 +1128,7 @@ static int local_unlinkat_common(FsContext *ctx, int dirfd, const char *name,
> > >              }
> > >          }
> > >          map_dirfd = openat_dir(dirfd, VIRTFS_META_DIR);
> > > -        if (map_dirfd != -1) {
> > > +        if (!qemu_fd_invalid(map_dirfd)) {
> > >              ret = qemu_unlinkat(map_dirfd, name, 0);
> > >              close_preserve_errno(map_dirfd);
> > >              if (ret < 0 && errno != ENOENT) {
> > > @@ -1143,11 +1148,11 @@ static int local_remove(FsContext *ctx, const char *path)
> > >      char *dirpath = g_path_get_dirname(path);
> > >      char *name = g_path_get_basename(path);
> > >      int flags = 0;
> > > -    int dirfd;
> > > +    QemuFd_t dirfd;
> > >      int err = -1;
> > >  
> > >      dirfd = local_opendir_nofollow(ctx, dirpath);
> > > -    if (dirfd == -1) {
> > > +    if (qemu_fd_invalid(dirfd)) {
> > >          goto out;
> > >      }
> > >  
> > > @@ -1188,10 +1193,11 @@ static int local_fsync(FsContext *ctx, int fid_type,
> > >  
> > >  static int local_statfs(FsContext *s, V9fsPath *fs_path, struct statfs *stbuf)
> > >  {
> > > -    int fd, ret;
> > > +    QemuFd_t fd;
> > > +    int ret;
> > >  
> > >      fd = local_open_nofollow(s, fs_path->data, O_RDONLY, 0);
> > > -    if (fd == -1) {
> > > +    if (qemu_fd_invalid(fd)) {
> > >          return -1;
> > >      }
> > >      ret = fstatfs(fd, stbuf);
> > > @@ -1276,7 +1282,7 @@ static int local_renameat(FsContext *ctx, V9fsPath *olddir,
> > >                            const char *new_name)
> > >  {
> > >      int ret;
> > > -    int odirfd, ndirfd;
> > > +    QemuFd_t odirfd, ndirfd;
> > >  
> > >      if (ctx->export_flags & V9FS_SM_MAPPED_FILE &&
> > >          (local_is_mapped_file_metadata(ctx, old_name) ||
> > > @@ -1286,12 +1292,12 @@ static int local_renameat(FsContext *ctx, V9fsPath *olddir,
> > >      }
> > >  
> > >      odirfd = local_opendir_nofollow(ctx, olddir->data);
> > > -    if (odirfd == -1) {
> > > +    if (qemu_fd_invalid(odirfd)) {
> > >          return -1;
> > >      }
> > >  
> > >      ndirfd = local_opendir_nofollow(ctx, newdir->data);
> > > -    if (ndirfd == -1) {
> > > +    if (qemu_fd_invalid(ndirfd)) {
> > >          close_preserve_errno(odirfd);
> > >          return -1;
> > >      }
> > > @@ -1302,7 +1308,7 @@ static int local_renameat(FsContext *ctx, V9fsPath *olddir,
> > >      }
> > >  
> > >      if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
> > > -        int omap_dirfd, nmap_dirfd;
> > > +        QemuFd_t omap_dirfd, nmap_dirfd;
> > >  
> > >          ret = qemu_mkdirat(ndirfd, VIRTFS_META_DIR, 0700);
> > >          if (ret < 0 && errno != EEXIST) {
> > > @@ -1310,12 +1316,12 @@ static int local_renameat(FsContext *ctx, V9fsPath *olddir,
> > >          }
> > >  
> > >          omap_dirfd = openat_dir(odirfd, VIRTFS_META_DIR);
> > > -        if (omap_dirfd == -1) {
> > > +        if (qemu_fd_invalid(omap_dirfd)) {
> > >              goto err;
> > >          }
> > >  
> > >          nmap_dirfd = openat_dir(ndirfd, VIRTFS_META_DIR);
> > > -        if (nmap_dirfd == -1) {
> > > +        if (qemu_fd_invalid(nmap_dirfd)) {
> > >              close_preserve_errno(omap_dirfd);
> > >              goto err;
> > >          }
> > > @@ -1373,7 +1379,7 @@ static int local_unlinkat(FsContext *ctx, V9fsPath *dir,
> > >                            const char *name, int flags)
> > >  {
> > >      int ret;
> > > -    int dirfd;
> > > +    QemuFd_t dirfd;
> > >  
> > >      if (ctx->export_flags & V9FS_SM_MAPPED_FILE &&
> > >          local_is_mapped_file_metadata(ctx, name)) {
> > > @@ -1382,7 +1388,7 @@ static int local_unlinkat(FsContext *ctx, V9fsPath *dir,
> > >      }
> > >  
> > >      dirfd = local_opendir_nofollow(ctx, dir->data);
> > > -    if (dirfd == -1) {
> > > +    if (qemu_fd_invalid(dirfd)) {
> > >          return -1;
> > >      }
> > >  
> > > @@ -1446,7 +1452,7 @@ static int local_init(FsContext *ctx, Error **errp)
> > >      LocalData *data = g_malloc(sizeof(*data));
> > >  
> > >      data->mountfd = open(ctx->fs_root, O_DIRECTORY | O_RDONLY);
> > > -    if (data->mountfd == -1) {
> > > +    if (qemu_fd_invalid(data->mountfd)) {
> > >          error_setg_errno(errp, errno, "failed to open '%s'", ctx->fs_root);
> > >          goto err;
> > >      }
> > > diff --git a/hw/9pfs/9p-util-darwin.c b/hw/9pfs/9p-util-darwin.c
> > > index 95146e7354..f85cfd26bb 100644
> > > --- a/hw/9pfs/9p-util-darwin.c
> > > +++ b/hw/9pfs/9p-util-darwin.c
> > > @@ -11,8 +11,8 @@
> > >  #include "qemu/error-report.h"
> > >  #include "9p-util.h"
> > >  
> > > -ssize_t fgetxattrat_nofollow(int dirfd, const char *filename, const char *name,
> > > -                             void *value, size_t size)
> > > +ssize_t fgetxattrat_nofollow(QemuFd_t dirfd, const char *filename,
> > > +                             const char *name, void *value, size_t size)
> > >  {
> > >      int ret;
> > >      int fd = openat_file(dirfd, filename,
> > > @@ -25,7 +25,7 @@ ssize_t fgetxattrat_nofollow(int dirfd, const char *filename, const char *name,
> > >      return ret;
> > >  }
> > >  
> > > -ssize_t flistxattrat_nofollow(int dirfd, const char *filename,
> > > +ssize_t flistxattrat_nofollow(QemuFd_t dirfd, const char *filename,
> > >                                char *list, size_t size)
> > >  {
> > >      int ret;
> > > @@ -39,7 +39,7 @@ ssize_t flistxattrat_nofollow(int dirfd, const char *filename,
> > >      return ret;
> > >  }
> > >  
> > > -ssize_t fremovexattrat_nofollow(int dirfd, const char *filename,
> > > +ssize_t fremovexattrat_nofollow(QemuFd_t dirfd, const char *filename,
> > >                                  const char *name)
> > >  {
> > >      int ret;
> > > @@ -52,8 +52,8 @@ ssize_t fremovexattrat_nofollow(int dirfd, const char *filename,
> > >      return ret;
> > >  }
> > >  
> > > -int fsetxattrat_nofollow(int dirfd, const char *filename, const char *name,
> > > -                         void *value, size_t size, int flags)
> > > +int fsetxattrat_nofollow(QemuFd_t dirfd, const char *filename,
> > > +                         const char *name, void *value, size_t size, int flags)
> > >  {
> > >      int ret;
> > >      int fd = openat_file(dirfd, filename, O_PATH_9P_UTIL | O_NOFOLLOW, 0);
> > > @@ -110,7 +110,7 @@ out:
> > >      return err;
> > >  }
> > >  
> > > -int qemu_mknodat(int dirfd, const char *filename, mode_t mode, dev_t dev)
> > > +int qemu_mknodat(QemuFd_t dirfd, const char *filename, mode_t mode, dev_t dev)
> > >  {
> > >      int preserved_errno, err;
> > >  
> > > diff --git a/hw/9pfs/9p-util-linux.c b/hw/9pfs/9p-util-linux.c
> > > index db451b0784..8dd9da10b6 100644
> > > --- a/hw/9pfs/9p-util-linux.c
> > > +++ b/hw/9pfs/9p-util-linux.c
> > > @@ -19,8 +19,8 @@
> > >  #include "qemu/xattr.h"
> > >  #include "9p-util.h"
> > >  
> > > -ssize_t fgetxattrat_nofollow(int dirfd, const char *filename, const char *name,
> > > -                             void *value, size_t size)
> > > +ssize_t fgetxattrat_nofollow(QemuFd_t dirfd, const char *filename,
> > > +                             const char *name, void *value, size_t size)
> > >  {
> > >      char *proc_path = g_strdup_printf("/proc/self/fd/%d/%s", dirfd, filename);
> > >      int ret;
> > > @@ -30,7 +30,7 @@ ssize_t fgetxattrat_nofollow(int dirfd, const char *filename, const char *name,
> > >      return ret;
> > >  }
> > >  
> > > -ssize_t flistxattrat_nofollow(int dirfd, const char *filename,
> > > +ssize_t flistxattrat_nofollow(QemuFd_t dirfd, const char *filename,
> > >                                char *list, size_t size)
> > >  {
> > >      char *proc_path = g_strdup_printf("/proc/self/fd/%d/%s", dirfd, filename);
> > > @@ -41,7 +41,7 @@ ssize_t flistxattrat_nofollow(int dirfd, const char *filename,
> > >      return ret;
> > >  }
> > >  
> > > -ssize_t fremovexattrat_nofollow(int dirfd, const char *filename,
> > > +ssize_t fremovexattrat_nofollow(QemuFd_t dirfd, const char *filename,
> > >                                  const char *name)
> > >  {
> > >      char *proc_path = g_strdup_printf("/proc/self/fd/%d/%s", dirfd, filename);
> > > @@ -52,8 +52,8 @@ ssize_t fremovexattrat_nofollow(int dirfd, const char *filename,
> > >      return ret;
> > >  }
> > >  
> > > -int fsetxattrat_nofollow(int dirfd, const char *filename, const char *name,
> > > -                         void *value, size_t size, int flags)
> > > +int fsetxattrat_nofollow(QemuFd_t dirfd, const char *filename,
> > > +                         const char *name, void *value, size_t size, int flags)
> > >  {
> > >      char *proc_path = g_strdup_printf("/proc/self/fd/%d/%s", dirfd, filename);
> > >      int ret;
> > > @@ -64,7 +64,7 @@ int fsetxattrat_nofollow(int dirfd, const char *filename, const char *name,
> > >  
> > >  }
> > >  
> > > -int qemu_mknodat(int dirfd, const char *filename, mode_t mode, dev_t dev)
> > > +int qemu_mknodat(QemuFd_t dirfd, const char *filename, mode_t mode, dev_t dev)
> > >  {
> > >      return mknodat(dirfd, filename, mode, dev);
> > >  }
> > > diff --git a/hw/9pfs/9p-xattr.c b/hw/9pfs/9p-xattr.c
> > > index 9ae69dd8db..062bf2d1f0 100644
> > > --- a/hw/9pfs/9p-xattr.c
> > > +++ b/hw/9pfs/9p-xattr.c
> > > @@ -78,13 +78,13 @@ ssize_t v9fs_list_xattr(FsContext *ctx, const char *path,
> > >      char *orig_value, *orig_value_start;
> > >      ssize_t xattr_len, parsed_len = 0, attr_len;
> > >      char *dirpath, *name;
> > > -    int dirfd;
> > > +    QemuFd_t dirfd;
> > >  
> > >      /* Get the actual len */
> > >      dirpath = g_path_get_dirname(path);
> > >      dirfd = local_opendir_nofollow(ctx, dirpath);
> > >      g_free(dirpath);
> > > -    if (dirfd == -1) {
> > > +    if (qemu_fd_invalid(dirfd)) {
> > >          return -1;
> > >      }
> > >  
> > > @@ -168,11 +168,11 @@ ssize_t local_getxattr_nofollow(FsContext *ctx, const char *path,
> > >  {
> > >      char *dirpath = g_path_get_dirname(path);
> > >      char *filename = g_path_get_basename(path);
> > > -    int dirfd;
> > > +    QemuFd_t dirfd;
> > >      ssize_t ret = -1;
> > >  
> > >      dirfd = local_opendir_nofollow(ctx, dirpath);
> > > -    if (dirfd == -1) {
> > > +    if (qemu_fd_invalid(dirfd)) {
> > >          goto out;
> > >      }
> > >  
> > > @@ -196,11 +196,11 @@ ssize_t local_setxattr_nofollow(FsContext *ctx, const char *path,
> > >  {
> > >      char *dirpath = g_path_get_dirname(path);
> > >      char *filename = g_path_get_basename(path);
> > > -    int dirfd;
> > > +    QemuFd_t dirfd;
> > >      ssize_t ret = -1;
> > >  
> > >      dirfd = local_opendir_nofollow(ctx, dirpath);
> > > -    if (dirfd == -1) {
> > > +    if (qemu_fd_invalid(dirfd)) {
> > >          goto out;
> > >      }
> > >  
> > > @@ -223,11 +223,11 @@ ssize_t local_removexattr_nofollow(FsContext *ctx, const char *path,
> > >  {
> > >      char *dirpath = g_path_get_dirname(path);
> > >      char *filename = g_path_get_basename(path);
> > > -    int dirfd;
> > > +    QemuFd_t dirfd;
> > >      ssize_t ret = -1;
> > >  
> > >      dirfd = local_opendir_nofollow(ctx, dirpath);
> > > -    if (dirfd == -1) {
> > > +    if (qemu_fd_invalid(dirfd)) {
> > >          goto out;
> > >      }
> > >  
> > 
> > 
> > 
> 
> 



^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v2 05/19] hw/9pfs: Update 9pfs to use the new QemuFd_t type
  2022-11-19 10:19       ` Greg Kurz
@ 2022-11-19 15:22         ` Bin Meng
  0 siblings, 0 replies; 36+ messages in thread
From: Bin Meng @ 2022-11-19 15:22 UTC (permalink / raw)
  To: Greg Kurz; +Cc: Christian Schoenebeck, Bin Meng, qemu-devel

Hi Greg,

On Sat, Nov 19, 2022 at 6:20 PM Greg Kurz <groug@kaod.org> wrote:
>
> On Fri, 18 Nov 2022 14:38:00 +0100
> Christian Schoenebeck <qemu_oss@crudebyte.com> wrote:
>
> > On Friday, November 18, 2022 10:29:51 AM CET Greg Kurz wrote:
> > > On Fri, 11 Nov 2022 12:22:11 +0800
> > > Bin Meng <bin.meng@windriver.com> wrote:
> > >
> > > > With this new QemuFd_t type, it significantly reduces the number of
> > >
> > > I cannot find the definition of this type, nor the definition of
> > > qemu_fd_invalid(). Missing patch ?
> >
> > It's in patch 4. Looks like we were not CCed on that patch. :(
> >
>
> Oh I didn't check the numbering. I guess we were not CCed automatically...
>
> > https://lore.kernel.org/qemu-devel/20221111042225.1115931-5-bin.meng@windriver.com/
> >
>
> ... because this only touches include/qemu/osdep.h .
>
> Bin,
>
> Please ensure that the maintainers are in the Cc list for all
> patches in such a series, e.g. with explicit --cc arguments to
> git-send-email.

Sorry, I was only using the get maintainer script for each patch. Will
cc you explicitly next time.

>
> > > Anyway, IIUC this type is an int for linux and a HANDLE for windows,
> > > right ?
> > >
> > > According to win32 documentation at [1] :
> > >
> > > HANDLE
> > > A handle to an object.
> > >
> > > This type is declared in WinNT.h as follows:
> > >
> > > typedef PVOID HANDLE;
> > >
> > > and
> > >
> > > PVOID
> > > A pointer to any type.
> > >
> > > This type is declared in WinNT.h as follows:
> > >
> > > typedef void *PVOID;
> > >
> > > HANDLE is void *.
> > >
> > > From docs/devel/style.rst:
> > >
> > > Naming
> > > ======
> > >
> > > Variables are lower_case_with_underscores; easy to type and read.  Structured
> > > type names are in CamelCase; harder to type but standing out.  Enum type
> > > names and function type names should also be in CamelCase.  Scalar type
> > > names are lower_case_with_underscores_ending_with_a_t, like the POSIX
> > > uint64_t and family.  Note that this last convention contradicts POSIX
> > > and is therefore likely to be changed.
> > >
> > > Both int and void * are scalar types, so I'd rather name it qemu_fd_t,
> > > not using CamelCase at all so that it cannot be confused with a struct.
> > >
> > > [1] https://learn.microsoft.com/en-us/windows/win32/winprog/windows-data-types
> >
> > Not that I had a strong opinion about this issue (as in general with coding
> > style topics). It was one of my suggested type names. To make this type long-
> > term proof I suggested to handle it as if it was a truly opaque type in QEMU:
> >
>
> A true opaque type in C is implemented with a structured type and pointers
> to this type.
>
> > https://lore.kernel.org/qemu-devel/4620086.XpUeK0iDWE@silver/
> >
> > That is to explicitly not try to do things like:
> >
> >     if (fd == -1)
> >
> > at least not hard wired in user code. According to QEMU code style you should
> > probably then drop the trailing "_t" though.
> >
>
> Yes, either one is fine I guess. Most important part is to provide
> a documented API to manipulate that type since, no matter the name,
> it is still a scalar type that can be manipulated as such.
>

This patch will be dropped in the next version, that means we still
use the posix fd for the 9p helpers on different platforms, but on
Windows it will be translated to Windows HANDLE internally in the
helper.

Regards,
Bin


^ permalink raw reply	[flat|nested] 36+ messages in thread

end of thread, other threads:[~2022-11-19 15:23 UTC | newest]

Thread overview: 36+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-11-11  4:22 [PATCH v2 00/19] At present there is no Windows support for 9p file system Bin Meng
2022-11-11  4:22 ` [PATCH v2 01/19] qemu/xattr.h: Exclude <sys/xattr.h> for Windows Bin Meng
2022-11-11  4:22 ` [PATCH v2 02/19] hw/9pfs: Drop unnecessary *xattr wrapper API declarations Bin Meng
2022-11-18  8:42   ` Greg Kurz
2022-11-18 13:10     ` Christian Schoenebeck
2022-11-11  4:22 ` [PATCH v2 03/19] hw/9pfs: Replace the direct call to xxxat() APIs with a wrapper Bin Meng
2022-11-11  4:22 ` [PATCH v2 04/19] osdep.h: Introduce a QEMU file descriptor type Bin Meng
2022-11-11  9:07   ` Daniel P. Berrangé
2022-11-11  9:23     ` Bin Meng
2022-11-11  9:29       ` Daniel P. Berrangé
2022-11-11  4:22 ` [PATCH v2 05/19] hw/9pfs: Update 9pfs to use the new QemuFd_t type Bin Meng
2022-11-18  9:29   ` Greg Kurz
2022-11-18 13:38     ` Christian Schoenebeck
2022-11-19 10:19       ` Greg Kurz
2022-11-19 15:22         ` Bin Meng
2022-11-11  4:22 ` [PATCH v2 06/19] hw/9pfs: Add missing definitions for Windows Bin Meng
2022-11-14 16:40   ` Christian Schoenebeck
2022-11-16  9:01     ` Shi, Guohuai
2022-11-16 12:52       ` Christian Schoenebeck
2022-11-11  4:22 ` [PATCH v2 07/19] hw/9pfs: Implement Windows specific utilities functions for 9pfs Bin Meng
2022-11-17 15:55   ` Christian Schoenebeck
2022-11-17 16:38     ` Shi, Guohuai
2022-11-11  4:22 ` [PATCH v2 08/19] hw/9pfs: Update the local fs driver to support Windows Bin Meng
2022-11-11  4:22 ` [PATCH v2 09/19] hw/9pfs: Support getting current directory offset for Windows Bin Meng
2022-11-11  4:22 ` [PATCH v2 10/19] hw/9pfs: Add a helper qemu_stat_rdev() Bin Meng
2022-11-11  4:22 ` [PATCH v2 11/19] hw/9pfs: Add a helper qemu_stat_blksize() Bin Meng
2022-11-11  4:22 ` [PATCH v2 12/19] hw/9pfs: Disable unsupported flags and features for Windows Bin Meng
2022-11-11  4:22 ` [PATCH v2 13/19] hw/9pfs: Update v9fs_set_fd_limit() " Bin Meng
2022-11-11  4:22 ` [PATCH v2 14/19] hw/9pfs: Add Linux error number definition Bin Meng
2022-11-11  4:22 ` [PATCH v2 15/19] hw/9pfs: Translate Windows errno to Linux value Bin Meng
2022-11-11  4:22 ` [PATCH v2 16/19] fsdev: Disable proxy fs driver on Windows Bin Meng
2022-11-11  4:22 ` [PATCH v2 17/19] hw/9pfs: Update synth fs driver for Windows Bin Meng
2022-11-11 10:30   ` Philippe Mathieu-Daudé
2022-11-11  4:22 ` [PATCH v2 18/19] tests/qtest: virtio-9p-test: Adapt the case for win32 Bin Meng
2022-11-11  7:48   ` Thomas Huth
2022-11-11  4:22 ` [PATCH v2 19/19] meson.build: Turn on virtfs for Windows Bin Meng

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.