diff --git a/CHANGELOG.md b/CHANGELOG.md index 7aaee22c..14c5cff1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Added +- Added shared filesystem support for Windows (VirtIO 9PFS) ### Changed - Added a "--jobs" option to "uarch-riscv-tests.lua" test diff --git a/src/os-features.h b/src/os-features.h index 895b239e..ca2b2708 100644 --- a/src/os-features.h +++ b/src/os-features.h @@ -57,7 +57,7 @@ #define HAVE_SELECT #endif -#if !defined(NO_POSIX_FILE) && !defined(__wasi__) && !defined(_WIN32) +#if !defined(NO_POSIX_FILE) && !defined(__wasi__) #define HAVE_POSIX_FS #endif diff --git a/src/pma.h b/src/pma.h index e11e0ec9..a348c29b 100644 --- a/src/pma.h +++ b/src/pma.h @@ -17,6 +17,7 @@ #ifndef PMA_H #define PMA_H +#include #include #include #include diff --git a/src/virtio-p9fs.cpp b/src/virtio-p9fs.cpp index 31838ae8..32c4ea53 100644 --- a/src/virtio-p9fs.cpp +++ b/src/virtio-p9fs.cpp @@ -46,12 +46,103 @@ #ifdef __APPLE__ #include #include +#elif defined(_WIN32) +#define WIN32_LEAN_AND_MEAN +#include +#include +#include #else #include #include #endif #include +#ifdef _WIN32 +#define lstat stat +int fsync(int fd) { + HANDLE h = (HANDLE) _get_osfhandle(fd); + if (h == INVALID_HANDLE_VALUE) { + return -1; + } + if (!FlushFileBuffers(h)) { + return -1; + } + return 0; +} + +static inline void timespec_to_filetime(const struct timespec tv, FILETIME *ft) { + long long winTime = tv.tv_sec * 10000000LL + tv.tv_nsec / 100LL + 116444736000000000LL; + ft->dwLowDateTime = winTime; + ft->dwHighDateTime = winTime >> 32; +} + +ssize_t pread(int fd, void *buf, size_t count, uint64_t offset) { + HANDLE hFile = (HANDLE) _get_osfhandle(fd); + DWORD dwBytesRead = 0; + OVERLAPPED ovl = {0}; + ovl.Offset = (DWORD) offset; + ovl.OffsetHigh = (DWORD) (offset >> 32); + SetLastError(0); + if (!ReadFile(hFile, buf, (DWORD) count, &dwBytesRead, &ovl) && GetLastError() != ERROR_HANDLE_EOF) { + errno = GetLastError(); + return -1; + } + return dwBytesRead; +} + +ssize_t pwrite(int fd, const void *buf, size_t count, uint64_t offset) { + HANDLE hFile = (HANDLE) _get_osfhandle(fd); + DWORD dwBytesWritten = 0; + OVERLAPPED ovl = {0}; + ovl.Offset = (DWORD) offset; + ovl.OffsetHigh = (DWORD) (offset >> 32); + SetLastError(0); + if (!WriteFile(hFile, buf, (DWORD) count, &dwBytesWritten, &ovl) && GetLastError() != ERROR_HANDLE_EOF) { + errno = GetLastError(); + return -1; + } + return dwBytesWritten; +} + +#define UTIME_NOW -1 +#define UTIME_OMIT -2 + +static int futimens(int fd, const struct timespec times[2]) { + HANDLE hFile = (HANDLE) _get_osfhandle(fd); + if (hFile == INVALID_HANDLE_VALUE) { + errno = EBADF; + return -1; + } + FILETIME now{}, aft{}, mft{}; + FILETIME *pft[2] = {&aft, &mft}; + GetSystemTimeAsFileTime(&now); + if (times) { + for (int i = 0; i < 2; ++i) { + if (times[i].tv_nsec == UTIME_NOW) { + *pft[i] = now; + } else if (times[i].tv_nsec == UTIME_OMIT) { + pft[i] = NULL; + } else if (times[i].tv_nsec >= 0 && times[i].tv_nsec < 1000000000L) { + long long winTime = times[i].tv_sec * 10000000LL + times[i].tv_nsec / 100LL + 116444736000000000LL; + pft[i]->dwLowDateTime = winTime; + pft[i]->dwHighDateTime = winTime >> 32; + } else { + errno = EINVAL; + return -1; + } + } + } else { + aft = mft = now; + } + if (!SetFileTime(hFile, NULL, pft[0], pft[1])) { + errno = GetLastError(); + return -1; + } + return 0; +} + +#endif // _WIN32 + namespace cartesi { // Aliases for struct names that conflicts with function names @@ -60,281 +151,676 @@ using statfs_t = struct statfs; using flock_t = struct flock; static p9_error host_errno_to_p9(int err) { - switch (err) { - case 0: - return P9_EOK; - case EPERM: - return P9_EPERM; - case ENOENT: - return P9_ENOENT; - case ESRCH: - return P9_ESRCH; - case EINTR: - return P9_EINTR; - case EIO: - return P9_EIO; - case ENXIO: - return P9_ENXIO; - case E2BIG: - return P9_E2BIG; - case ENOEXEC: - return P9_ENOEXEC; - case EBADF: - return P9_EBADF; - case ECHILD: - return P9_ECHILD; - case EAGAIN: - return P9_EAGAIN; - case ENOMEM: - return P9_ENOMEM; - case EACCES: - return P9_EACCES; - case EFAULT: - return P9_EFAULT; - case ENOTBLK: - return P9_ENOTBLK; - case EBUSY: - return P9_EBUSY; - case EEXIST: - return P9_EEXIST; - case EXDEV: - return P9_EXDEV; - case ENODEV: - return P9_ENODEV; - case ENOTDIR: - return P9_ENOTDIR; - case EISDIR: - return P9_EISDIR; - case EINVAL: - return P9_EINVAL; - case ENFILE: - return P9_ENFILE; - case EMFILE: - return P9_EMFILE; - case ENOTTY: - return P9_ENOTTY; - case ETXTBSY: - return P9_ETXTBSY; - case EFBIG: - return P9_EFBIG; - case ENOSPC: - return P9_ENOSPC; - case ESPIPE: - return P9_ESPIPE; - case EROFS: - return P9_EROFS; - case EMLINK: - return P9_EMLINK; - case EPIPE: - return P9_EPIPE; - case EDOM: - return P9_EDOM; - case ERANGE: - return P9_ERANGE; - case EDEADLK: - return P9_EDEADLK; - case ENAMETOOLONG: - return P9_ENAMETOOLONG; - case ENOLCK: - return P9_ENOLCK; - case ENOSYS: - return P9_ENOSYS; - case ENOTEMPTY: - return P9_ENOTEMPTY; - case ELOOP: - return P9_ELOOP; - case ENOMSG: - return P9_ENOMSG; - case EIDRM: - return P9_EIDRM; - case ENOSTR: - return P9_ENOSTR; - case ENODATA: - return P9_ENODATA; - case ETIME: - return P9_ETIME; - case ENOSR: - return P9_ENOSR; - case EREMOTE: - return P9_EREMOTE; - case ENOLINK: - return P9_ENOLINK; - case EPROTO: - return P9_EPROTO; - case EMULTIHOP: - return P9_EMULTIHOP; - case EBADMSG: - return P9_EBADMSG; - case EOVERFLOW: - return P9_EOVERFLOW; - case EILSEQ: - return P9_EILSEQ; - case EUSERS: - return P9_EUSERS; - case ENOTSOCK: - return P9_ENOTSOCK; - case EDESTADDRREQ: - return P9_EDESTADDRREQ; - case EMSGSIZE: - return P9_EMSGSIZE; - case EPROTOTYPE: - return P9_EPROTOTYPE; - case ENOPROTOOPT: - return P9_ENOPROTOOPT; - case EPROTONOSUPPORT: - return P9_EPROTONOSUPPORT; - case ESOCKTNOSUPPORT: - return P9_ESOCKTNOSUPPORT; - case EOPNOTSUPP: - return P9_EOPNOTSUPP; - case EPFNOSUPPORT: - return P9_EPFNOSUPPORT; - case EAFNOSUPPORT: - return P9_EAFNOSUPPORT; - case EADDRINUSE: - return P9_EADDRINUSE; - case EADDRNOTAVAIL: - return P9_EADDRNOTAVAIL; - case ENETDOWN: - return P9_ENETDOWN; - case ENETUNREACH: - return P9_ENETUNREACH; - case ENETRESET: - return P9_ENETRESET; - case ECONNABORTED: - return P9_ECONNABORTED; - case ECONNRESET: - return P9_ECONNRESET; - case ENOBUFS: - return P9_ENOBUFS; - case EISCONN: - return P9_EISCONN; - case ENOTCONN: - return P9_ENOTCONN; - case ESHUTDOWN: - return P9_ESHUTDOWN; - case ETOOMANYREFS: - return P9_ETOOMANYREFS; - case ETIMEDOUT: - return P9_ETIMEDOUT; - case ECONNREFUSED: - return P9_ECONNREFUSED; - case EHOSTDOWN: - return P9_EHOSTDOWN; - case EHOSTUNREACH: - return P9_EHOSTUNREACH; - case EALREADY: - return P9_EALREADY; - case EINPROGRESS: - return P9_EINPROGRESS; - case ESTALE: - return P9_ESTALE; - case EDQUOT: - return P9_EDQUOT; - case ECANCELED: - return P9_ECANCELED; - case EOWNERDEAD: - return P9_EOWNERDEAD; - case ENOTRECOVERABLE: - return P9_ENOTRECOVERABLE; -#ifdef __APPLE__ - case ENOATTR: - return P9_ENODATA; - case ENOTSUP: - return P9_EOPNOTSUPP; -#else - case ECHRNG: - return P9_ECHRNG; - case EL2NSYNC: - return P9_EL2NSYNC; - case EL3HLT: - return P9_EL3HLT; - case EL3RST: - return P9_EL3RST; - case ELNRNG: - return P9_ELNRNG; - case EUNATCH: - return P9_EUNATCH; - case ENOCSI: - return P9_ENOCSI; - case EL2HLT: - return P9_EL2HLT; - case EBADE: - return P9_EBADE; - case EBADR: - return P9_EBADR; - case EXFULL: - return P9_EXFULL; - case ENOANO: - return P9_ENOANO; - case EBADRQC: - return P9_EBADRQC; - case EBADSLT: - return P9_EBADSLT; - case EBFONT: - return P9_EBFONT; - case ENONET: - return P9_ENONET; - case ENOPKG: - return P9_ENOPKG; - case EADV: - return P9_EADV; - case ESRMNT: - return P9_ESRMNT; - case ECOMM: - return P9_ECOMM; - case EDOTDOT: - return P9_EDOTDOT; - case ENOTUNIQ: - return P9_ENOTUNIQ; - case EBADFD: - return P9_EBADFD; - case EREMCHG: - return P9_EREMCHG; - case ELIBACC: - return P9_ELIBACC; - case ELIBBAD: - return P9_ELIBBAD; - case ELIBSCN: - return P9_ELIBSCN; - case ELIBMAX: - return P9_ELIBMAX; - case ELIBEXEC: - return P9_ELIBEXEC; - case ERESTART: - return P9_ERESTART; - case ESTRPIPE: - return P9_ESTRPIPE; - case EUCLEAN: - return P9_EUCLEAN; - case ENOTNAM: - return P9_ENOTNAM; - case ENAVAIL: - return P9_ENAVAIL; - case EISNAM: - return P9_EISNAM; - case EREMOTEIO: - return P9_EREMOTEIO; - case ENOMEDIUM: - return P9_ENOMEDIUM; - case EMEDIUMTYPE: - return P9_EMEDIUMTYPE; - case ENOKEY: - return P9_ENOKEY; - case EKEYEXPIRED: - return P9_EKEYEXPIRED; - case EKEYREVOKED: - return P9_EKEYREVOKED; - case EKEYREJECTED: - return P9_EKEYREJECTED; - case ERFKILL: - return P9_ERFKILL; - case EHWPOISON: - return P9_EHWPOISON; + // Use ifs instead of a switch here so it can compile with cosmopolitan toolchain + if (err == 0) { + return P9_EOK; + } +#if defined(EPERM) + if (err == EPERM) { + return P9_EPERM; + } #endif - default: - return P9_EINVAL; +#if defined(ENOENT) + if (err == ENOENT) { + return P9_ENOENT; + } +#endif +#if defined(ESRCH) + if (err == ESRCH) { + return P9_ESRCH; + } +#endif +#if defined(EINTR) + if (err == EINTR) { + return P9_EINTR; + } +#endif +#if defined(EIO) + if (err == EIO) { + return P9_EIO; + } +#endif +#if defined(ENXIO) + if (err == ENXIO) { + return P9_ENXIO; + } +#endif +#if defined(E2BIG) + if (err == E2BIG) { + return P9_E2BIG; + } +#endif +#if defined(ENOEXEC) + if (err == ENOEXEC) { + return P9_ENOEXEC; + } +#endif +#if defined(EBADF) + if (err == EBADF) { + return P9_EBADF; + } +#endif +#if defined(ECHILD) + if (err == ECHILD) { + return P9_ECHILD; + } +#endif +#if defined(EAGAIN) + if (err == EAGAIN) { + return P9_EAGAIN; + } +#endif +#if defined(ENOMEM) + if (err == ENOMEM) { + return P9_ENOMEM; + } +#endif +#if defined(EACCES) + if (err == EACCES) { + return P9_EACCES; + } +#endif +#if defined(EFAULT) + if (err == EFAULT) { + return P9_EFAULT; + } +#endif +#if defined(ENOTBLK) + if (err == ENOTBLK) { + return P9_ENOTBLK; + } +#endif +#if defined(EBUSY) + if (err == EBUSY) { + return P9_EBUSY; + } +#endif +#if defined(EEXIST) + if (err == EEXIST) { + return P9_EEXIST; + } +#endif +#if defined(EXDEV) + if (err == EXDEV) { + return P9_EXDEV; + } +#endif +#if defined(ENODEV) + if (err == ENODEV) { + return P9_ENODEV; + } +#endif +#if defined(ENOTDIR) + if (err == ENOTDIR) { + return P9_ENOTDIR; + } +#endif +#if defined(EISDIR) + if (err == EISDIR) { + return P9_EISDIR; + } +#endif +#if defined(EINVAL) + if (err == EINVAL) { + return P9_EINVAL; + } +#endif +#if defined(ENFILE) + if (err == ENFILE) { + return P9_ENFILE; + } +#endif +#if defined(EMFILE) + if (err == EMFILE) { + return P9_EMFILE; + } +#endif +#if defined(ENOTTY) + if (err == ENOTTY) { + return P9_ENOTTY; + } +#endif +#if defined(ETXTBSY) + if (err == ETXTBSY) { + return P9_ETXTBSY; + } +#endif +#if defined(EFBIG) + if (err == EFBIG) { + return P9_EFBIG; + } +#endif +#if defined(ENOSPC) + if (err == ENOSPC) { + return P9_ENOSPC; + } +#endif +#if defined(ESPIPE) + if (err == ESPIPE) { + return P9_ESPIPE; + } +#endif +#if defined(EROFS) + if (err == EROFS) { + return P9_EROFS; + } +#endif +#if defined(EMLINK) + if (err == EMLINK) { + return P9_EMLINK; + } +#endif +#if defined(EPIPE) + if (err == EPIPE) { + return P9_EPIPE; + } +#endif +#if defined(EDOM) + if (err == EDOM) { + return P9_EDOM; + } +#endif +#if defined(ERANGE) + if (err == ERANGE) { + return P9_ERANGE; + } +#endif +#if defined(EDEADLK) + if (err == EDEADLK) { + return P9_EDEADLK; + } +#endif +#if defined(ENAMETOOLONG) + if (err == ENAMETOOLONG) { + return P9_ENAMETOOLONG; + } +#endif +#if defined(ENOLCK) + if (err == ENOLCK) { + return P9_ENOLCK; + } +#endif +#if defined(ENOSYS) + if (err == ENOSYS) { + return P9_ENOSYS; + } +#endif +#if defined(ENOTEMPTY) + if (err == ENOTEMPTY) { + return P9_ENOTEMPTY; + } +#endif +#if defined(ELOOP) + if (err == ELOOP) { + return P9_ELOOP; + } +#endif +#if defined(ENOMSG) + if (err == ENOMSG) { + return P9_ENOMSG; + } +#endif +#if defined(EIDRM) + if (err == EIDRM) { + return P9_EIDRM; + } +#endif +#if defined(ENOSTR) + if (err == ENOSTR) { + return P9_ENOSTR; + } +#endif +#if defined(ENODATA) + if (err == ENODATA) { + return P9_ENODATA; + } +#endif +#if defined(ETIME) + if (err == ETIME) { + return P9_ETIME; + } +#endif +#if defined(ENOSR) + if (err == ENOSR) { + return P9_ENOSR; + } +#endif +#if defined(EREMOTE) + if (err == EREMOTE) { + return P9_EREMOTE; + } +#endif +#if defined(ENOLINK) + if (err == ENOLINK) { + return P9_ENOLINK; + } +#endif +#if defined(EPROTO) + if (err == EPROTO) { + return P9_EPROTO; + } +#endif +#if defined(EMULTIHOP) + if (err == EMULTIHOP) { + return P9_EMULTIHOP; + } +#endif +#if defined(EBADMSG) + if (err == EBADMSG) { + return P9_EBADMSG; + } +#endif +#if defined(EOVERFLOW) + if (err == EOVERFLOW) { + return P9_EOVERFLOW; + } +#endif +#if defined(EILSEQ) + if (err == EILSEQ) { + return P9_EILSEQ; + } +#endif +#if defined(EUSERS) + if (err == EUSERS) { + return P9_EUSERS; + } +#endif +#if defined(ENOTSOCK) + if (err == ENOTSOCK) { + return P9_ENOTSOCK; + } +#endif +#if defined(EDESTADDRREQ) + if (err == EDESTADDRREQ) { + return P9_EDESTADDRREQ; + } +#endif +#if defined(EMSGSIZE) + if (err == EMSGSIZE) { + return P9_EMSGSIZE; + } +#endif +#if defined(EPROTOTYPE) + if (err == EPROTOTYPE) { + return P9_EPROTOTYPE; + } +#endif +#if defined(ENOPROTOOPT) + if (err == ENOPROTOOPT) { + return P9_ENOPROTOOPT; + } +#endif +#if defined(EPROTONOSUPPORT) + if (err == EPROTONOSUPPORT) { + return P9_EPROTONOSUPPORT; + } +#endif +#if defined(ESOCKTNOSUPPORT) + if (err == ESOCKTNOSUPPORT) { + return P9_ESOCKTNOSUPPORT; + } +#endif +#if defined(EOPNOTSUPP) + if (err == EOPNOTSUPP) { + return P9_EOPNOTSUPP; + } +#endif +#if defined(EPFNOSUPPORT) + if (err == EPFNOSUPPORT) { + return P9_EPFNOSUPPORT; + } +#endif +#if defined(EAFNOSUPPORT) + if (err == EAFNOSUPPORT) { + return P9_EAFNOSUPPORT; + } +#endif +#if defined(EADDRINUSE) + if (err == EADDRINUSE) { + return P9_EADDRINUSE; + } +#endif +#if defined(EADDRNOTAVAIL) + if (err == EADDRNOTAVAIL) { + return P9_EADDRNOTAVAIL; + } +#endif +#if defined(ENETDOWN) + if (err == ENETDOWN) { + return P9_ENETDOWN; + } +#endif +#if defined(ENETUNREACH) + if (err == ENETUNREACH) { + return P9_ENETUNREACH; + } +#endif +#if defined(ENETRESET) + if (err == ENETRESET) { + return P9_ENETRESET; + } +#endif +#if defined(ECONNABORTED) + if (err == ECONNABORTED) { + return P9_ECONNABORTED; + } +#endif +#if defined(ECONNRESET) + if (err == ECONNRESET) { + return P9_ECONNRESET; + } +#endif +#if defined(ENOBUFS) + if (err == ENOBUFS) { + return P9_ENOBUFS; + } +#endif +#if defined(EISCONN) + if (err == EISCONN) { + return P9_EISCONN; + } +#endif +#if defined(ENOTCONN) + if (err == ENOTCONN) { + return P9_ENOTCONN; + } +#endif +#if defined(ESHUTDOWN) + if (err == ESHUTDOWN) { + return P9_ESHUTDOWN; + } +#endif +#if defined(ETOOMANYREFS) + if (err == ETOOMANYREFS) { + return P9_ETOOMANYREFS; + } +#endif +#if defined(ETIMEDOUT) + if (err == ETIMEDOUT) { + return P9_ETIMEDOUT; + } +#endif +#if defined(ECONNREFUSED) + if (err == ECONNREFUSED) { + return P9_ECONNREFUSED; + } +#endif +#if defined(EHOSTDOWN) + if (err == EHOSTDOWN) { + return P9_EHOSTDOWN; + } +#endif +#if defined(EHOSTUNREACH) + if (err == EHOSTUNREACH) { + return P9_EHOSTUNREACH; + } +#endif +#if defined(EALREADY) + if (err == EALREADY) { + return P9_EALREADY; + } +#endif +#if defined(EINPROGRESS) + if (err == EINPROGRESS) { + return P9_EINPROGRESS; + } +#endif +#if defined(ESTALE) + if (err == ESTALE) { + return P9_ESTALE; + } +#endif +#if defined(EDQUOT) + if (err == EDQUOT) { + return P9_EDQUOT; + } +#endif +#if defined(ECANCELED) + if (err == ECANCELED) { + return P9_ECANCELED; + } +#endif +#if defined(EOWNERDEAD) + if (err == EOWNERDEAD) { + return P9_EOWNERDEAD; } +#endif +#if defined(ENOTRECOVERABLE) + if (err == ENOTRECOVERABLE) { + return P9_ENOTRECOVERABLE; + } +#endif +#if defined(ENOATTR) + if (err == ENOATTR) { + return P9_ENODATA; + } +#endif +#if defined(ENOTSUP) && (!defined(EOPNOTSUPP) || EOPNOTSUPP != ENOTSUP) + if (err == ENOTSUP) { + return P9_EOPNOTSUPP; + } +#endif +#if defined(ECHRNG) + if (err == ECHRNG) { + return P9_ECHRNG; + } +#endif +#if defined(EL2NSYNC) + if (err == EL2NSYNC) { + return P9_EL2NSYNC; + } +#endif +#if defined(EL3HLT) + if (err == EL3HLT) { + return P9_EL3HLT; + } +#endif +#if defined(EL3RST) + if (err == EL3RST) { + return P9_EL3RST; + } +#endif +#if defined(ELNRNG) + if (err == ELNRNG) { + return P9_ELNRNG; + } +#endif +#if defined(EUNATCH) + if (err == EUNATCH) { + return P9_EUNATCH; + } +#endif +#if defined(ENOCSI) + if (err == ENOCSI) { + return P9_ENOCSI; + } +#endif +#if defined(EL2HLT) + if (err == EL2HLT) { + return P9_EL2HLT; + } +#endif +#if defined(EBADE) + if (err == EBADE) { + return P9_EBADE; + } +#endif +#if defined(EBADR) + if (err == EBADR) { + return P9_EBADR; + } +#endif +#if defined(EXFULL) + if (err == EXFULL) { + return P9_EXFULL; + } +#endif +#if defined(ENOANO) + if (err == ENOANO) { + return P9_ENOANO; + } +#endif +#if defined(EBADRQC) + if (err == EBADRQC) { + return P9_EBADRQC; + } +#endif +#if defined(EBADSLT) + if (err == EBADSLT) { + return P9_EBADSLT; + } +#endif +#if defined(EBFONT) + if (err == EBFONT) { + return P9_EBFONT; + } +#endif +#if defined(ENONET) + if (err == ENONET) { + return P9_ENONET; + } +#endif +#if defined(ENOPKG) + if (err == ENOPKG) { + return P9_ENOPKG; + } +#endif +#if defined(EADV) + if (err == EADV) { + return P9_EADV; + } +#endif +#if defined(ESRMNT) + if (err == ESRMNT) { + return P9_ESRMNT; + } +#endif +#if defined(ECOMM) + if (err == ECOMM) { + return P9_ECOMM; + } +#endif +#if defined(EDOTDOT) + if (err == EDOTDOT) { + return P9_EDOTDOT; + } +#endif +#if defined(ENOTUNIQ) + if (err == ENOTUNIQ) { + return P9_ENOTUNIQ; + } +#endif +#if defined(EBADFD) + if (err == EBADFD) { + return P9_EBADFD; + } +#endif +#if defined(EREMCHG) + if (err == EREMCHG) { + return P9_EREMCHG; + } +#endif +#if defined(ELIBACC) + if (err == ELIBACC) { + return P9_ELIBACC; + } +#endif +#if defined(ELIBBAD) + if (err == ELIBBAD) { + return P9_ELIBBAD; + } +#endif +#if defined(ELIBSCN) + if (err == ELIBSCN) { + return P9_ELIBSCN; + } +#endif +#if defined(ELIBMAX) + if (err == ELIBMAX) { + return P9_ELIBMAX; + } +#endif +#if defined(ELIBEXEC) + if (err == ELIBEXEC) { + return P9_ELIBEXEC; + } +#endif +#if defined(ERESTART) + if (err == ERESTART) { + return P9_ERESTART; + } +#endif +#if defined(ESTRPIPE) + if (err == ESTRPIPE) { + return P9_ESTRPIPE; + } +#endif +#if defined(EUCLEAN) + if (err == EUCLEAN) { + return P9_EUCLEAN; + } +#endif +#if defined(ENOTNAM) + if (err == ENOTNAM) { + return P9_ENOTNAM; + } +#endif +#if defined(ENAVAIL) + if (err == ENAVAIL) { + return P9_ENAVAIL; + } +#endif +#if defined(EISNAM) + if (err == EISNAM) { + return P9_EISNAM; + } +#endif +#if defined(EREMOTEIO) + if (err == EREMOTEIO) { + return P9_EREMOTEIO; + } +#endif +#if defined(ENOMEDIUM) + if (err == ENOMEDIUM) { + return P9_ENOMEDIUM; + } +#endif +#if defined(EMEDIUMTYPE) + if (err == EMEDIUMTYPE) { + return P9_EMEDIUMTYPE; + } +#endif +#if defined(ENOKEY) + if (err == ENOKEY) { + return P9_ENOKEY; + } +#endif +#if defined(EKEYEXPIRED) + if (err == EKEYEXPIRED) { + return P9_EKEYEXPIRED; + } +#endif +#if defined(EKEYREVOKED) + if (err == EKEYREVOKED) { + return P9_EKEYREVOKED; + } +#endif +#if defined(EKEYREJECTED) + if (err == EKEYREJECTED) { + return P9_EKEYREJECTED; + } +#endif +#if defined(ERFKILL) + if (err == ERFKILL) { + return P9_ERFKILL; + } +#endif +#if defined(EHWPOISON) + if (err == EHWPOISON) { + return P9_EHWPOISON; + } +#endif + return P9_EINVAL; } static int p9_open_flags_to_host(uint32_t flags) { @@ -357,43 +843,63 @@ static int p9_open_flags_to_host(uint32_t flags) { case P9_O_EXCL: oflags |= O_EXCL; break; - case P9_O_NOCTTY: - oflags |= O_NOCTTY; - break; case P9_O_TRUNC: oflags |= O_TRUNC; break; case P9_O_APPEND: oflags |= O_APPEND; break; +#if defined(O_NOCTTY) + case P9_O_NOCTTY: + oflags |= O_NOCTTY; + break; +#endif +#if defined(O_NONBLOCK) case P9_O_NONBLOCK: oflags |= O_NONBLOCK; break; +#endif +#if defined(O_DSYNC) case P9_O_DSYNC: oflags |= O_DSYNC; break; +#endif +#if defined(FASYNC) case P9_O_FASYNC: oflags |= FASYNC; break; +#endif +#if defined(O_DIRECTORY) case P9_O_DIRECTORY: oflags |= O_DIRECTORY; break; +#endif +#if defined(O_NOFOLLOW) case P9_O_NOFOLLOW: oflags |= O_NOFOLLOW; break; +#endif +#if defined(O_CLOEXEC) case P9_O_CLOEXEC: oflags |= O_CLOEXEC; break; +#endif +#if defined(O_SYNC) case P9_O_SYNC: oflags |= O_SYNC; break; -#ifndef __APPLE__ +#endif +#if defined(O_DIRECT) case P9_O_DIRECT: oflags |= O_DIRECT; break; +#endif +#if defined(O_LARGEFILE) case P9_O_LARGEFILE: oflags |= O_LARGEFILE; break; +#endif +#if defined(O_NOATIME) case P9_O_NOATIME: oflags |= O_NOATIME; break; @@ -403,12 +909,23 @@ static int p9_open_flags_to_host(uint32_t flags) { } } } + // On always open as binary on windows +#ifdef _WIN32 + oflags |= O_BINARY; +#endif // Filter non-supported flags - oflags &= ~(O_NOCTTY | O_ASYNC | O_CREAT); +#ifdef O_NOCTTY + oflags &= ~O_NOCTTY; +#endif +#ifdef O_ASYNC + oflags &= ~O_ASYNC; +#endif + oflags &= ~O_CREAT; return oflags; } -static short p9_lock_type_to_host(uint8_t type) { +#if defined(F_SETLK) && defined(F_SETLKW) +static uint32_t p9_lock_type_to_host(uint8_t type) { switch (type) { case P9_LOCK_TYPE_RDLCK: return F_RDLCK; @@ -421,7 +938,7 @@ static short p9_lock_type_to_host(uint8_t type) { } } -static uint8_t host_lock_type_to_p9(short type) { +static uint8_t host_lock_type_to_p9(uint32_t type) { switch (type) { case F_RDLCK: return P9_LOCK_TYPE_RDLCK; @@ -433,6 +950,16 @@ static uint8_t host_lock_type_to_p9(short type) { return 0xff; } } +#endif + +static uint32_t host_mode_to_p9(mode_t mode) { +#ifdef _WIN32 + // On Windows there we have to show files as executable to be able to execute them + return static_cast(mode) | 0b001001001; +#else + return static_cast(mode); +#endif +} static p9_qid stat_to_qid(const stat_t &st) { p9_qid qid{}; @@ -440,11 +967,17 @@ static p9_qid stat_to_qid(const stat_t &st) { if (S_ISDIR(st.st_mode)) { qid.type |= P9_QID_DIR; } +#ifdef _WIN32 + // On Windows there is no concept of inode for stat(), so we have to fake it. + static uint64_t fake_inode = 0; + qid.inode = ++fake_inode; +#else + qid.inode = st.st_ino; if (S_ISLNK(st.st_mode)) { qid.type |= P9_QID_SYMLINK; } +#endif qid.version = 0; // No caching - qid.path = st.st_ino; return qid; } @@ -660,6 +1193,7 @@ bool virtio_p9fs_device::op_statfs(virtq_unserializer &&msg, uint16_t tag) { #ifdef DEBUG_VIRTIO_P9FS (void) fprintf(stderr, "p9fs statfs: tag=%d fid=%d\n", tag, fid); #endif +#ifndef _WIN32 // Get the fid state p9_fid_state *fidp = get_fid_state(fid); if (!fidp) { @@ -699,6 +1233,9 @@ bool virtio_p9fs_device::op_statfs(virtq_unserializer &&msg, uint16_t tag) { return send_error(msg, tag, P9_EPROTO); } return send_reply(std::move(out_msg), tag, P9_RSTATFS); +#else + return send_error(msg, tag, P9_EOPNOTSUPP); +#endif } bool virtio_p9fs_device::op_lopen(virtq_unserializer &&msg, uint16_t tag) { @@ -722,25 +1259,53 @@ bool virtio_p9fs_device::op_lopen(virtq_unserializer &&msg, uint16_t tag) { // Open the file const int oflags = p9_open_flags_to_host(flags); const int fd = open(fidp->path.c_str(), oflags); + const int open_errno = errno; + // On Windows open may fail for directories, so ignore it +#ifndef _WIN32 if (fd < 0) { - return send_error(msg, tag, host_errno_to_p9(errno)); + return send_error(msg, tag, host_errno_to_p9(open_errno)); } - // Get the path qid - stat_t st{}; - if (fstat(fd, &st) != 0) { - (void) close(fd); - return send_error(msg, tag, host_errno_to_p9(errno)); +#endif + // Get the file qid + p9_qid qid{}; + if (fd >= 0) { + stat_t st{}; + // Get the path qid from fd + if (fstat(fd, &st) != 0) { + (void) close(fd); + return send_error(msg, tag, host_errno_to_p9(open_errno)); + } + qid = stat_to_qid(st); + } +#ifdef _WIN32 + // In case file could not be open, on Windows assume it's a directory + if (fd < 0 && flags & P9_O_DIRECTORY) { + // Get the path qid from path + const std::string path = fidp->path; + stat_t st{}; + if (lstat(path.c_str(), &st) != 0) { + return send_error(msg, tag, host_errno_to_p9(open_errno)); + } + qid = stat_to_qid(st); + // Fail in case it's not a directory + if (qid.type != P9_QID_DIR) { + return send_error(msg, tag, host_errno_to_p9(open_errno)); + } } - p9_qid qid = stat_to_qid(st); +#endif // Reply uint32_t iounit = get_iounit(); virtq_serializer out_msg(msg.a, msg.vq, msg.queue_idx, msg.desc_idx, P9_OUT_MSG_OFFSET); if (!out_msg.pack(&qid, &iounit)) { - (void) close(fd); + if (fd >= 0) { + (void) close(fd); + } return send_error(msg, tag, P9_EPROTO); } if (!send_reply(std::move(out_msg), tag, P9_RLOPEN)) { - (void) close(fd); + if (fd >= 0) { + (void) close(fd); + } return false; } // Update fid @@ -782,10 +1347,12 @@ bool virtio_p9fs_device::op_lcreate(virtq_unserializer &&msg, uint16_t tag) { if (fd < 0) { return send_error(msg, tag, host_errno_to_p9(errno)); } +#ifndef _WIN32 // If we fail to change ownership, we silent ignore the error if (fchown(fd, static_cast(fidp->uid), static_cast(gid)) != 0) { errno = 0; } +#endif // Get the path qid stat_t st{}; if (fstat(fd, &st) != 0) { @@ -824,6 +1391,7 @@ bool virtio_p9fs_device::op_symlink(virtq_unserializer &&msg, uint16_t tag) { #ifdef DEBUG_VIRTIO_P9FS (void) fprintf(stderr, "p9fs symlink: tag=%d dfid=%d name=%s symtgt=%s gid=%d\n", tag, dfid, name, symtgt, gid); #endif +#ifndef _WIN32 // Check if name is valid if (!is_name_legal(name)) { return send_error(msg, tag, P9_ENOENT); @@ -860,6 +1428,9 @@ bool virtio_p9fs_device::op_symlink(virtq_unserializer &&msg, uint16_t tag) { return false; } return true; +#else + return send_error(msg, tag, P9_EOPNOTSUPP); +#endif } bool virtio_p9fs_device::op_mknod(virtq_unserializer &&msg, uint16_t tag) { @@ -876,6 +1447,7 @@ bool virtio_p9fs_device::op_mknod(virtq_unserializer &&msg, uint16_t tag) { (void) fprintf(stderr, "p9fs mknod: tag=%d dfid=%d name=%s mode=%d major=%d minor=%d gid=%d\n", tag, dfid, name, mode, major, minor, gid); #endif +#ifndef _WIN32 // Check if name is valid if (!is_name_legal(name)) { return send_error(msg, tag, P9_ENOENT); @@ -913,6 +1485,9 @@ bool virtio_p9fs_device::op_mknod(virtq_unserializer &&msg, uint16_t tag) { return false; } return true; +#else + return send_error(msg, tag, P9_EOPNOTSUPP); +#endif } bool virtio_p9fs_device::op_setattr(virtq_unserializer &&msg, uint16_t tag) { @@ -943,6 +1518,7 @@ bool virtio_p9fs_device::op_setattr(virtq_unserializer &&msg, uint16_t tag) { bool ctime_updated = false; // Modify ownership if (mask & (P9_SETATTR_UID | P9_SETATTR_GID)) { +#ifndef _WIN32 const uid_t newuid = (mask & P9_SETATTR_UID) ? static_cast(uid) : -1; const gid_t newgid = (mask & P9_SETATTR_GID) ? static_cast(gid) : -1; // Use fd when available, because its path might have been removed while fd still open @@ -956,9 +1532,13 @@ bool virtio_p9fs_device::op_setattr(virtq_unserializer &&msg, uint16_t tag) { } } ctime_updated = true; +#else + return send_error(msg, tag, P9_EOPNOTSUPP); +#endif } // Modify mode if (mask & P9_SETATTR_MODE) { +#ifndef _WIN32 // Use fd when available, because its path might have been removed while fd still open if (fidp->fd >= 0) { if (fchmod(fidp->fd, static_cast(mode)) != 0) { @@ -970,6 +1550,9 @@ bool virtio_p9fs_device::op_setattr(virtq_unserializer &&msg, uint16_t tag) { } } ctime_updated = true; +#else + return send_error(msg, tag, P9_EOPNOTSUPP); +#endif } // Modify size if (mask & P9_SETATTR_SIZE) { @@ -1018,14 +1601,19 @@ bool virtio_p9fs_device::op_setattr(virtq_unserializer &&msg, uint16_t tag) { return send_error(msg, tag, host_errno_to_p9(errno)); } } else { +#ifdef _WIN32 + // Silently ignore directory access time changes on Windows +#else if (utimensat(AT_FDCWD, fidp->path.c_str(), ts, AT_SYMLINK_NOFOLLOW) != 0) { return send_error(msg, tag, host_errno_to_p9(errno)); } +#endif } ctime_updated = true; } // Modify change time if ((mask & P9_SETATTR_CTIME) && !ctime_updated) { +#ifndef _WIN32 // Use fd when available, because its path might have been removed while fd still open if (fidp->fd >= 0) { if (fchown(fidp->fd, -1, -1) != 0) { @@ -1036,6 +1624,7 @@ bool virtio_p9fs_device::op_setattr(virtq_unserializer &&msg, uint16_t tag) { return send_error(msg, tag, host_errno_to_p9(errno)); } } +#endif } // Reply return send_ok(msg, tag, P9_RSETATTR); @@ -1049,6 +1638,7 @@ bool virtio_p9fs_device::op_readlink(virtq_unserializer &&msg, uint16_t tag) { #ifdef DEBUG_VIRTIO_P9FS (void) fprintf(stderr, "p9fs readlink: tag=%d fid=%d\n", tag, fid); #endif +#ifndef _WIN32 // Get the fid state const p9_fid_state *fidp = get_fid_state(fid); if (!fidp) { @@ -1067,6 +1657,9 @@ bool virtio_p9fs_device::op_readlink(virtq_unserializer &&msg, uint16_t tag) { return send_error(msg, tag, P9_EPROTO); } return send_reply(std::move(out_msg), tag, P9_RREADLINK); +#else + return send_error(msg, tag, P9_EOPNOTSUPP); +#endif } bool virtio_p9fs_device::op_getattr(virtq_unserializer &&msg, uint16_t tag) { @@ -1101,7 +1694,7 @@ bool virtio_p9fs_device::op_getattr(virtq_unserializer &&msg, uint16_t tag) { // Fill stat attributes p9_stat rstat{}; if (mask & P9_GETATTR_MODE) { - rstat.mode = st.st_mode; + rstat.mode = host_mode_to_p9(st.st_mode); } if (mask & P9_GETATTR_UID) { rstat.uid = st.st_uid; @@ -1119,8 +1712,14 @@ bool virtio_p9fs_device::op_getattr(virtq_unserializer &&msg, uint16_t tag) { rstat.size = st.st_size; } if (mask & P9_GETATTR_BLOCKS) { +#ifdef _WIN32 + // Windows has no blocks, fake it + rstat.blksize = 512; + rstat.blocks = (st.st_size + 511) / 512; +#else rstat.blksize = st.st_blksize; rstat.blocks = st.st_blocks; +#endif } #ifdef __APPLE__ if (mask & P9_GETATTR_ATIME) { @@ -1135,6 +1734,19 @@ bool virtio_p9fs_device::op_getattr(virtq_unserializer &&msg, uint16_t tag) { rstat.ctime_sec = st.st_ctimespec.tv_sec; rstat.ctime_nsec = st.st_ctimespec.tv_nsec; } +#elif defined(_WIN32) + if (mask & P9_GETATTR_ATIME) { + rstat.atime_sec = static_cast(st.st_atime); + rstat.atime_nsec = 0; + } + if (mask & P9_GETATTR_MTIME) { + rstat.mtime_sec = static_cast(st.st_mtime); + rstat.mtime_nsec = 0; + } + if (mask & P9_GETATTR_CTIME) { + rstat.ctime_sec = static_cast(st.st_ctime); + rstat.ctime_nsec = 0; + } #else if (mask & P9_GETATTR_ATIME) { rstat.atime_sec = st.st_atim.tv_sec; @@ -1174,6 +1786,7 @@ bool virtio_p9fs_device::op_lock(virtq_unserializer &&msg, uint16_t tag) { (void) fprintf(stderr, "p9fs lock: tag=%d fid=%d type=%d flags=%d start=%ld length=%ld proc_id=%d client_id=%s\n", tag, fid, type, flags, start, length, proc_id, client_id); #endif +#if defined(F_SETLK) && defined(F_SETLKW) // Only block flag is supported if (flags > P9_LOCK_FLAGS_BLOCK) { return send_error(msg, tag, P9_EINVAL); @@ -1209,6 +1822,9 @@ bool virtio_p9fs_device::op_lock(virtq_unserializer &&msg, uint16_t tag) { return send_error(msg, tag, P9_EPROTO); } return send_reply(std::move(out_msg), tag, P9_RLOCK); +#else + return send_error(msg, tag, P9_EOPNOTSUPP); +#endif } bool virtio_p9fs_device::op_getlock(virtq_unserializer &&msg, uint16_t tag) { @@ -1225,6 +1841,7 @@ bool virtio_p9fs_device::op_getlock(virtq_unserializer &&msg, uint16_t tag) { (void) fprintf(stderr, "p9fs getlock: tag=%d fid=%d type=%d start=%ld length=%ld proc_id=%d client_id=%s\n", tag, fid, type, start, length, proc_id, client_id); #endif +#if defined(F_SETLK) && defined(F_SETLKW) // Get the fid state p9_fid_state *fidp = get_fid_state(fid); if (!fidp || fidp->fd < 0) { @@ -1248,6 +1865,9 @@ bool virtio_p9fs_device::op_getlock(virtq_unserializer &&msg, uint16_t tag) { return send_error(msg, tag, P9_EPROTO); } return send_reply(std::move(out_msg), tag, P9_RGETLOCK); +#else + return send_error(msg, tag, P9_EOPNOTSUPP); +#endif } bool virtio_p9fs_device::op_readdir(virtq_unserializer &&msg, uint16_t tag) { @@ -1299,7 +1919,7 @@ bool virtio_p9fs_device::op_readdir(virtq_unserializer &&msg, uint16_t tag) { // Check if there is enough space to add this entry const uint32_t data_len = out_msg.offset - start_offset; const uint32_t entry_len = - sizeof(p9_qid) + sizeof(uint64_t) + sizeof(uint8_t) + +sizeof(uint16_t) + strlen(name); + sizeof(p9_qid) + sizeof(uint64_t) + sizeof(uint8_t) + sizeof(uint16_t) + strlen(name); if (data_len + entry_len > count) { break; } @@ -1313,9 +1933,25 @@ bool virtio_p9fs_device::op_readdir(virtq_unserializer &&msg, uint16_t tag) { } // Get entry qid and type p9_qid qid{}; - uint8_t type = dir_entry->d_type; + bool take_qid_from_stat = false; + uint8_t type = 0; +#if defined(DT_UNKNOWN) && defined(DT_DIR) && defined(DT_LNK) // In some filesystems dtype may be DT_UNKNOWN as an optimization to save lstat() calls - if (type == DT_UNKNOWN) { + if (dir_entry->d_type == DT_UNKNOWN) { + take_qid_from_stat = true; + } else { + type = dir_entry->d_type; + if (type == DT_DIR) { + qid.type = P9_QID_DIR; + } else if (type == DT_LNK) { + qid.type = P9_QID_SYMLINK; + } else { + qid.type = P9_QID_FILE; + } + qid.inode = dir_entry->d_ino; + } +#endif + if (take_qid_from_stat) { stat_t st{}; const std::string path = join_path_name(fidp->path, dir_entry->d_name); if (lstat(path.c_str(), &st) < 0) { @@ -1324,17 +1960,8 @@ bool virtio_p9fs_device::op_readdir(virtq_unserializer &&msg, uint16_t tag) { } break; } - type = st.st_mode >> 12; + type = host_mode_to_p9(st.st_mode) >> 12; qid = stat_to_qid(st); - } else { - if (type == DT_DIR) { - qid.type = P9_QID_DIR; - } else if (type == DT_LNK) { - qid.type = P9_QID_SYMLINK; - } else { - qid.type = P9_QID_FILE; - } - qid.path = dir_entry->d_ino; } // Add the entry to our reply uint64_t off = static_cast(entry_off); @@ -1382,6 +2009,7 @@ bool virtio_p9fs_device::op_link(virtq_unserializer &&msg, uint16_t tag) { #ifdef DEBUG_VIRTIO_P9FS (void) fprintf(stderr, "p9fs link: tag=%d dfid=%d fid=%d name=%s\n", tag, dfid, fid, name); #endif +#ifndef _WIN32 // Check if name is valid if (!is_name_legal(name)) { return send_error(msg, tag, P9_ENOENT); @@ -1403,6 +2031,9 @@ bool virtio_p9fs_device::op_link(virtq_unserializer &&msg, uint16_t tag) { return false; } return true; +#else + return send_error(msg, tag, P9_EOPNOTSUPP); +#endif } bool virtio_p9fs_device::op_mkdir(virtq_unserializer &&msg, uint16_t tag) { @@ -1427,6 +2058,11 @@ bool virtio_p9fs_device::op_mkdir(virtq_unserializer &&msg, uint16_t tag) { } // Create the directory const std::string path = join_path_name(dfidp->path, name); +#ifdef _WIN32 + if (_mkdir(path.c_str()) != 0) { + return send_error(msg, tag, host_errno_to_p9(errno)); + } +#else if (mkdir(path.c_str(), static_cast(mode)) != 0) { return send_error(msg, tag, host_errno_to_p9(errno)); } @@ -1434,6 +2070,7 @@ bool virtio_p9fs_device::op_mkdir(virtq_unserializer &&msg, uint16_t tag) { if (lchown(path.c_str(), static_cast(dfidp->uid), static_cast(gid)) != 0) { errno = 0; } +#endif // Get the path qid stat_t st{}; if (lstat(path.c_str(), &st) != 0) { diff --git a/src/virtio-p9fs.h b/src/virtio-p9fs.h index 00c4a7d6..86787cab 100644 --- a/src/virtio-p9fs.h +++ b/src/virtio-p9fs.h @@ -120,140 +120,140 @@ enum p9_opcode : uint8_t { /// \brief 9P2000.L errors enum p9_error : uint32_t { - P9_EOK = 0, ///< No error - P9_EPERM = 1, ///< Operation not permitted - P9_ENOENT = 2, ///< No such file or directory - P9_ESRCH = 3, ///< No such process - P9_EINTR = 4, ///< Interrupted system call - P9_EIO = 5, ///< I/O error - P9_ENXIO = 6, ///< No such device or address - P9_E2BIG = 7, ///< Argument list too long - P9_ENOEXEC = 8, ///< Exec format error - P9_EBADF = 9, ///< Bad file number - P9_ECHILD = 10, ///< No child processes - P9_EAGAIN = 11, ///< Try again - P9_ENOMEM = 12, ///< Out of memory - P9_EACCES = 13, ///< Permission denied - P9_EFAULT = 14, ///< Bad address - P9_ENOTBLK = 15, ///< Block device required - P9_EBUSY = 16, ///< Device or resource busy - P9_EEXIST = 17, ///< File exists - P9_EXDEV = 18, ///< Cross-device link - P9_ENODEV = 19, ///< No such device - P9_ENOTDIR = 20, ///< Not a directory - P9_EISDIR = 21, ///< Is a directory - P9_EINVAL = 22, ///< Invalid argument - P9_ENFILE = 23, ///< File table overflow - P9_EMFILE = 24, ///< Too many open files - P9_ENOTTY = 25, ///< Not a typewriter - P9_ETXTBSY = 26, ///< Text file busy - P9_EFBIG = 27, ///< File too large - P9_ENOSPC = 28, ///< No space left on device - P9_ESPIPE = 29, ///< Illegal seek - P9_EROFS = 30, ///< Read-only file system - P9_EMLINK = 31, ///< Too many links - P9_EPIPE = 32, ///< Broken pipe - P9_EDOM = 33, ///< Math argument out of domain of func - P9_ERANGE = 34, ///< Math result not representable - P9_EDEADLK = 35, ///< Resource deadlock would occur - P9_ENAMETOOLONG = 36, ///< File name too long - P9_ENOLCK = 37, ///< No record locks available - P9_ENOSYS = 38, ///< Invalid system call number - P9_ENOTEMPTY = 39, ///< Directory not empty - P9_ELOOP = 40, ///< Too many symbolic links encountered - P9_EWOULDBLOCK = EAGAIN, ///< Operation would block - P9_ENOMSG = 42, ///< No message of desired type - P9_EIDRM = 43, ///< Identifier removed - P9_ECHRNG = 44, ///< Channel number out of range - P9_EL2NSYNC = 45, ///< Level 2 not synchronized - P9_EL3HLT = 46, ///< Level 3 halted - P9_EL3RST = 47, ///< Level 3 reset - P9_ELNRNG = 48, ///< Link number out of range - P9_EUNATCH = 49, ///< Protocol driver not attached - P9_ENOCSI = 50, ///< No CSI structure available - P9_EL2HLT = 51, ///< Level 2 halted - P9_EBADE = 52, ///< Invalid exchange - P9_EBADR = 53, ///< Invalid request descriptor - P9_EXFULL = 54, ///< Exchange full - P9_ENOANO = 55, ///< No anode - P9_EBADRQC = 56, ///< Invalid request code - P9_EBADSLT = 57, ///< Invalid slot - P9_EDEADLOCK = EDEADLK, - P9_EBFONT = 59, ///< Bad font file format - P9_ENOSTR = 60, ///< Device not a stream - P9_ENODATA = 61, ///< No data available - P9_ETIME = 62, ///< Timer expired - P9_ENOSR = 63, ///< Out of streams resources - P9_ENONET = 64, ///< Machine is not on the network - P9_ENOPKG = 65, ///< Package not installed - P9_EREMOTE = 66, ///< Object is remote - P9_ENOLINK = 67, ///< Link has been severed - P9_EADV = 68, ///< Advertise error - P9_ESRMNT = 69, ///< Srmount error - P9_ECOMM = 70, ///< Communication error on send - P9_EPROTO = 71, ///< Protocol error - P9_EMULTIHOP = 72, ///< Multihop attempted - P9_EDOTDOT = 73, ///< RFS specific error - P9_EBADMSG = 74, ///< Not a data message - P9_EOVERFLOW = 75, ///< Value too large for defined data type - P9_ENOTUNIQ = 76, ///< Name not unique on network - P9_EBADFD = 77, ///< File descriptor in bad state - P9_EREMCHG = 78, ///< Remote address changed - P9_ELIBACC = 79, ///< Can not access a needed shared library - P9_ELIBBAD = 80, ///< Accessing a corrupted shared library - P9_ELIBSCN = 81, ///< .lib section in a.out corrupted - P9_ELIBMAX = 82, ///< Attempting to link in too many shared libraries - P9_ELIBEXEC = 83, ///< Cannot exec a shared library directly - P9_EILSEQ = 84, ///< Illegal byte sequence - P9_ERESTART = 85, ///< Interrupted system call should be restarted - P9_ESTRPIPE = 86, ///< Streams pipe error - P9_EUSERS = 87, ///< Too many users - P9_ENOTSOCK = 88, ///< Socket operation on non-socket - P9_EDESTADDRREQ = 89, ///< Destination address required - P9_EMSGSIZE = 90, ///< Message too long - P9_EPROTOTYPE = 91, ///< Protocol wrong type for socket - P9_ENOPROTOOPT = 92, ///< Protocol not available - P9_EPROTONOSUPPORT = 93, ///< Protocol not supported - P9_ESOCKTNOSUPPORT = 94, ///< Socket type not supported - P9_EOPNOTSUPP = 95, ///< Operation not supported on transport endpoint - P9_EPFNOSUPPORT = 96, ///< Protocol family not supported - P9_EAFNOSUPPORT = 97, ///< Address family not supported by protocol - P9_EADDRINUSE = 98, ///< Address already in use - P9_EADDRNOTAVAIL = 99, ///< Cannot assign requested address - P9_ENETDOWN = 100, ///< Network is down - P9_ENETUNREACH = 101, ///< Network is unreachable - P9_ENETRESET = 102, ///< Network dropped connection because of reset - P9_ECONNABORTED = 103, ///< Software caused connection abort - P9_ECONNRESET = 104, ///< Connection reset by peer - P9_ENOBUFS = 105, ///< No buffer space available - P9_EISCONN = 106, ///< Transport endpoint is already connected - P9_ENOTCONN = 107, ///< Transport endpoint is not connected - P9_ESHUTDOWN = 108, ///< Cannot send after transport endpoint shutdown - P9_ETOOMANYREFS = 109, ///< Too many references: cannot splice - P9_ETIMEDOUT = 110, ///< Connection timed out - P9_ECONNREFUSED = 111, ///< Connection refused - P9_EHOSTDOWN = 112, ///< Host is down - P9_EHOSTUNREACH = 113, ///< No route to host - P9_EALREADY = 114, ///< Operation already in progress - P9_EINPROGRESS = 115, ///< Operation now in progress - P9_ESTALE = 116, ///< Stale file handle - P9_EUCLEAN = 117, ///< Structure needs cleaning - P9_ENOTNAM = 118, ///< Not a XENIX named type file - P9_ENAVAIL = 119, ///< No XENIX semaphores available - P9_EISNAM = 120, ///< Is a named type file - P9_EREMOTEIO = 121, ///< Remote I/O error - P9_EDQUOT = 122, ///< Quota exceeded - P9_ENOMEDIUM = 123, ///< No medium found - P9_EMEDIUMTYPE = 124, ///< Wrong medium type - P9_ECANCELED = 125, ///< Operation Canceled - P9_ENOKEY = 126, ///< Required key not available - P9_EKEYEXPIRED = 127, ///< Key has expired - P9_EKEYREVOKED = 128, ///< Key has been revoked - P9_EKEYREJECTED = 129, ///< Key was rejected by service - P9_EOWNERDEAD = 130, ///< Owner died - P9_ENOTRECOVERABLE = 131, ///< State not recoverable - P9_ERFKILL = 132, ///< Operation not possible due to RF-kill - P9_EHWPOISON = 133 ///< Memory page has hardware error + P9_EOK = 0, ///< No error + P9_EPERM = 1, ///< Operation not permitted + P9_ENOENT = 2, ///< No such file or directory + P9_ESRCH = 3, ///< No such process + P9_EINTR = 4, ///< Interrupted system call + P9_EIO = 5, ///< I/O error + P9_ENXIO = 6, ///< No such device or address + P9_E2BIG = 7, ///< Argument list too long + P9_ENOEXEC = 8, ///< Exec format error + P9_EBADF = 9, ///< Bad file number + P9_ECHILD = 10, ///< No child processes + P9_EAGAIN = 11, ///< Try again + P9_ENOMEM = 12, ///< Out of memory + P9_EACCES = 13, ///< Permission denied + P9_EFAULT = 14, ///< Bad address + P9_ENOTBLK = 15, ///< Block device required + P9_EBUSY = 16, ///< Device or resource busy + P9_EEXIST = 17, ///< File exists + P9_EXDEV = 18, ///< Cross-device link + P9_ENODEV = 19, ///< No such device + P9_ENOTDIR = 20, ///< Not a directory + P9_EISDIR = 21, ///< Is a directory + P9_EINVAL = 22, ///< Invalid argument + P9_ENFILE = 23, ///< File table overflow + P9_EMFILE = 24, ///< Too many open files + P9_ENOTTY = 25, ///< Not a typewriter + P9_ETXTBSY = 26, ///< Text file busy + P9_EFBIG = 27, ///< File too large + P9_ENOSPC = 28, ///< No space left on device + P9_ESPIPE = 29, ///< Illegal seek + P9_EROFS = 30, ///< Read-only file system + P9_EMLINK = 31, ///< Too many links + P9_EPIPE = 32, ///< Broken pipe + P9_EDOM = 33, ///< Math argument out of domain of func + P9_ERANGE = 34, ///< Math result not representable + P9_EDEADLK = 35, ///< Resource deadlock would occur + P9_ENAMETOOLONG = 36, ///< File name too long + P9_ENOLCK = 37, ///< No record locks available + P9_ENOSYS = 38, ///< Invalid system call number + P9_ENOTEMPTY = 39, ///< Directory not empty + P9_ELOOP = 40, ///< Too many symbolic links encountered + P9_EWOULDBLOCK = P9_EAGAIN, ///< Operation would block + P9_ENOMSG = 42, ///< No message of desired type + P9_EIDRM = 43, ///< Identifier removed + P9_ECHRNG = 44, ///< Channel number out of range + P9_EL2NSYNC = 45, ///< Level 2 not synchronized + P9_EL3HLT = 46, ///< Level 3 halted + P9_EL3RST = 47, ///< Level 3 reset + P9_ELNRNG = 48, ///< Link number out of range + P9_EUNATCH = 49, ///< Protocol driver not attached + P9_ENOCSI = 50, ///< No CSI structure available + P9_EL2HLT = 51, ///< Level 2 halted + P9_EBADE = 52, ///< Invalid exchange + P9_EBADR = 53, ///< Invalid request descriptor + P9_EXFULL = 54, ///< Exchange full + P9_ENOANO = 55, ///< No anode + P9_EBADRQC = 56, ///< Invalid request code + P9_EBADSLT = 57, ///< Invalid slot + P9_EDEADLOCK = P9_EDEADLK, ///< Resource deadlock would occur + P9_EBFONT = 59, ///< Bad font file format + P9_ENOSTR = 60, ///< Device not a stream + P9_ENODATA = 61, ///< No data available + P9_ETIME = 62, ///< Timer expired + P9_ENOSR = 63, ///< Out of streams resources + P9_ENONET = 64, ///< Machine is not on the network + P9_ENOPKG = 65, ///< Package not installed + P9_EREMOTE = 66, ///< Object is remote + P9_ENOLINK = 67, ///< Link has been severed + P9_EADV = 68, ///< Advertise error + P9_ESRMNT = 69, ///< Srmount error + P9_ECOMM = 70, ///< Communication error on send + P9_EPROTO = 71, ///< Protocol error + P9_EMULTIHOP = 72, ///< Multihop attempted + P9_EDOTDOT = 73, ///< RFS specific error + P9_EBADMSG = 74, ///< Not a data message + P9_EOVERFLOW = 75, ///< Value too large for defined data type + P9_ENOTUNIQ = 76, ///< Name not unique on network + P9_EBADFD = 77, ///< File descriptor in bad state + P9_EREMCHG = 78, ///< Remote address changed + P9_ELIBACC = 79, ///< Can not access a needed shared library + P9_ELIBBAD = 80, ///< Accessing a corrupted shared library + P9_ELIBSCN = 81, ///< .lib section in a.out corrupted + P9_ELIBMAX = 82, ///< Attempting to link in too many shared libraries + P9_ELIBEXEC = 83, ///< Cannot exec a shared library directly + P9_EILSEQ = 84, ///< Illegal byte sequence + P9_ERESTART = 85, ///< Interrupted system call should be restarted + P9_ESTRPIPE = 86, ///< Streams pipe error + P9_EUSERS = 87, ///< Too many users + P9_ENOTSOCK = 88, ///< Socket operation on non-socket + P9_EDESTADDRREQ = 89, ///< Destination address required + P9_EMSGSIZE = 90, ///< Message too long + P9_EPROTOTYPE = 91, ///< Protocol wrong type for socket + P9_ENOPROTOOPT = 92, ///< Protocol not available + P9_EPROTONOSUPPORT = 93, ///< Protocol not supported + P9_ESOCKTNOSUPPORT = 94, ///< Socket type not supported + P9_EOPNOTSUPP = 95, ///< Operation not supported on transport endpoint + P9_EPFNOSUPPORT = 96, ///< Protocol family not supported + P9_EAFNOSUPPORT = 97, ///< Address family not supported by protocol + P9_EADDRINUSE = 98, ///< Address already in use + P9_EADDRNOTAVAIL = 99, ///< Cannot assign requested address + P9_ENETDOWN = 100, ///< Network is down + P9_ENETUNREACH = 101, ///< Network is unreachable + P9_ENETRESET = 102, ///< Network dropped connection because of reset + P9_ECONNABORTED = 103, ///< Software caused connection abort + P9_ECONNRESET = 104, ///< Connection reset by peer + P9_ENOBUFS = 105, ///< No buffer space available + P9_EISCONN = 106, ///< Transport endpoint is already connected + P9_ENOTCONN = 107, ///< Transport endpoint is not connected + P9_ESHUTDOWN = 108, ///< Cannot send after transport endpoint shutdown + P9_ETOOMANYREFS = 109, ///< Too many references: cannot splice + P9_ETIMEDOUT = 110, ///< Connection timed out + P9_ECONNREFUSED = 111, ///< Connection refused + P9_EHOSTDOWN = 112, ///< Host is down + P9_EHOSTUNREACH = 113, ///< No route to host + P9_EALREADY = 114, ///< Operation already in progress + P9_EINPROGRESS = 115, ///< Operation now in progress + P9_ESTALE = 116, ///< Stale file handle + P9_EUCLEAN = 117, ///< Structure needs cleaning + P9_ENOTNAM = 118, ///< Not a XENIX named type file + P9_ENAVAIL = 119, ///< No XENIX semaphores available + P9_EISNAM = 120, ///< Is a named type file + P9_EREMOTEIO = 121, ///< Remote I/O error + P9_EDQUOT = 122, ///< Quota exceeded + P9_ENOMEDIUM = 123, ///< No medium found + P9_EMEDIUMTYPE = 124, ///< Wrong medium type + P9_ECANCELED = 125, ///< Operation Canceled + P9_ENOKEY = 126, ///< Required key not available + P9_EKEYEXPIRED = 127, ///< Key has expired + P9_EKEYREVOKED = 128, ///< Key has been revoked + P9_EKEYREJECTED = 129, ///< Key was rejected by service + P9_EOWNERDEAD = 130, ///< Owner died + P9_ENOTRECOVERABLE = 131, ///< State not recoverable + P9_ERFKILL = 132, ///< Operation not possible due to RF-kill + P9_EHWPOISON = 133 ///< Memory page has hardware error }; /// \brief 9P2000.L qid type @@ -350,7 +350,7 @@ enum p9_lock_type : uint8_t { struct p9_qid { uint8_t type; ///< File type (directory/symlink/file) uint32_t version; ///< Cache version - uint64_t path; ///< The inode representing the path + uint64_t inode; ///< The inode representing the path }; /// \brief 9P2000.L file stat