From 8d4197e71a39e7fdab5ec3da9ed4f3fb2fceafa9 Mon Sep 17 00:00:00 2001 From: marecl Date: Mon, 24 Nov 2025 14:30:45 +0100 Subject: [PATCH] Implemented some link() on windows Added copy/move/rename Added cloning FS objects (deep-copy) --- src/core/file_sys/hostio/host_io_posix.h | 6 +- src/core/file_sys/hostio/host_io_virtual.h | 9 +- src/core/file_sys/hostio/host_io_win32.h | 11 +- src/core/file_sys/hostio/src/host_io_base.cpp | 10 +- src/core/file_sys/hostio/src/host_io_base.h | 8 +- .../file_sys/hostio/src/host_io_linux2bsd.h | 482 +++++++----------- .../file_sys/hostio/src/host_io_posix.cpp | 60 ++- .../file_sys/hostio/src/host_io_virtual.cpp | 33 +- .../file_sys/hostio/src/host_io_win2bsd.h | 31 ++ .../file_sys/hostio/src/host_io_win32.cpp | 87 +++- src/core/file_sys/quasifs/quasifs.h | 28 +- src/core/file_sys/quasifs/quasifs_inode.h | 7 + .../quasifs/quasifs_inode_quasi_device.h | 7 + .../quasifs/quasifs_inode_quasi_directory.h | 7 + .../quasifs_inode_quasi_directory_pfs.h | 7 + .../quasifs/quasifs_inode_quasi_file.h | 7 + .../quasifs_inode_quasi_file_virtual.h | 10 +- .../quasifs/quasifs_inode_quasi_socket.h | 7 + .../file_sys/quasifs/quasifs_inode_symlink.h | 7 + .../file_sys/quasifs/src/quasifs_vdriver.cpp | 143 +++--- src/core/libraries/kernel/posix_error.h | 4 +- 21 files changed, 522 insertions(+), 449 deletions(-) create mode 100644 src/core/file_sys/hostio/src/host_io_win2bsd.h diff --git a/src/core/file_sys/hostio/host_io_posix.h b/src/core/file_sys/hostio/host_io_posix.h index a187e1a88..e5ea413b4 100644 --- a/src/core/file_sys/hostio/host_io_posix.h +++ b/src/core/file_sys/hostio/host_io_posix.h @@ -89,8 +89,9 @@ public: s32 Close(const s32 fd) override; s32 Link(const fs::path& src, const fs::path& dst) override; - s32 Unlink(const fs::path& path) override; s32 LinkSymbolic(const fs::path& src, const fs::path& dst) override; + s32 Unlink(const fs::path& path) override; + s32 Remove(const fs::path& path) override; s32 Flush(const s32 fd) override; s32 FSync(const s32 fd) override; @@ -118,6 +119,9 @@ public: s32 Chmod(const fs::path& path, u16 mode) override; s32 FChmod(const s32 fd, u16 mode) override; + + s32 Copy(const char* src, const char* dst) override; + s32 Move(const fs::path& src, const fs::path& dst, bool fail_if_exists) override; }; } // namespace HostIODriver diff --git a/src/core/file_sys/hostio/host_io_virtual.h b/src/core/file_sys/hostio/host_io_virtual.h index f88380343..d23972aa1 100644 --- a/src/core/file_sys/hostio/host_io_virtual.h +++ b/src/core/file_sys/hostio/host_io_virtual.h @@ -50,8 +50,9 @@ public: s32 Close(const s32 fd) override; s32 Link(const fs::path& src, const fs::path& dst) override; - s32 Unlink(const fs::path& path) override; s32 LinkSymbolic(const fs::path& src, const fs::path& dst) override; + s32 Unlink(const fs::path& path) override; + s32 Remove(const fs::path& path) override; s32 Flush(const s32 fd) override; s32 FSync(const s32 fd) override; @@ -81,8 +82,8 @@ public: s32 FChmod(const s32 fd, u16 mode) override; s64 GetDents(const s32 fd, void* buf, u64 count, s64* basep) override; - // - // Derived, complex functions are to be handled by main FS class - // + + s32 Copy(const fs::path& src, const fs::path& dst, bool fail_if_exists) override; + s32 Move(const fs::path& src, const fs::path& dst, bool fail_if_exists) override; }; } // namespace HostIODriver \ No newline at end of file diff --git a/src/core/file_sys/hostio/host_io_win32.h b/src/core/file_sys/hostio/host_io_win32.h index 4138868aa..a86d263dc 100644 --- a/src/core/file_sys/hostio/host_io_win32.h +++ b/src/core/file_sys/hostio/host_io_win32.h @@ -4,10 +4,7 @@ #ifdef _WIN32 -// #error unimplemented - #include -#include #include #include @@ -79,9 +76,10 @@ public: s32 Creat(const fs::path& path, u16 mode = 0755) override; s32 Close(const s32 fd) override; - // s32 Link(const fs::path& src, const fs::path& dst) override; - // s32 Unlink(const fs::path& path) override; + s32 Link(const fs::path& src, const fs::path& dst) override; // s32 LinkSymbolic(const fs::path& src, const fs::path& dst) override; + s32 Unlink(const fs::path& path) override; + s32 Remove(const fs::path& path) override; s32 Flush(const s32 fd) override; s32 FSync(const s32 fd) override; @@ -109,6 +107,9 @@ public: // s32 Chmod(const fs::path& path, u16 mode) override; // s32 FChmod(const s32 fd, u16 mode) override; + + s32 Copy(const fs::path& src, const fs::path& dst, bool fail_if_exists) override; + s32 Move(const fs::path& src, const fs::path& dst, bool fail_if_exists) override; }; } // namespace HostIODriver diff --git a/src/core/file_sys/hostio/src/host_io_base.cpp b/src/core/file_sys/hostio/src/host_io_base.cpp index a8396e39a..4143004e0 100644 --- a/src/core/file_sys/hostio/src/host_io_base.cpp +++ b/src/core/file_sys/hostio/src/host_io_base.cpp @@ -21,8 +21,9 @@ s32 HostIO_Base::Creat(const fs::path& path, u16 mode) { STUB(); } s32 HostIO_Base::Close(const s32 fd) { STUB(); } s32 HostIO_Base::Link(const fs::path& src, const fs::path& dst) { STUB(); } -s32 HostIO_Base::Unlink(const fs::path& path) { STUB(); } s32 HostIO_Base::LinkSymbolic(const fs::path& src, const fs::path& dst) { STUB(); } +s32 HostIO_Base::Unlink(const fs::path& path) { STUB(); } +s32 HostIO_Base::Remove(const fs::path& path) { STUB(); } s32 HostIO_Base::Flush(const s32 fd) { STUB(); } s32 HostIO_Base::FSync(const s32 fd) { STUB(); } @@ -54,6 +55,13 @@ s32 HostIO_Base::Chmod(const fs::path& path, u16 mode) { STUB(); } s32 HostIO_Base::FChmod(const s32 fd, u16 mode) { STUB(); } s64 HostIO_Base::GetDents(const s32 fd, void* buf, u64 count, s64* basep) { STUB(); } + +s32 HostIO_Base::Copy(const fs::path& src, const fs::path& dst, bool fail_if_exists) { STUB(); } +s32 HostIO_Base::Move(const fs::path& src, const fs::path& dst, bool fail_if_exists) { STUB(); } // clang-format on +s32 HostIO_Base::Rename(const fs::path& src, const fs::path& dst_name, bool fail_if_exists) { + return Move(src, src.parent_path() / dst_name, fail_if_exists); +} + } // namespace HostIODriver \ No newline at end of file diff --git a/src/core/file_sys/hostio/src/host_io_base.h b/src/core/file_sys/hostio/src/host_io_base.h index 34ca4679c..7bd9cbc73 100644 --- a/src/core/file_sys/hostio/src/host_io_base.h +++ b/src/core/file_sys/hostio/src/host_io_base.h @@ -27,9 +27,11 @@ public: virtual s32 Creat(const fs::path& path, u16 mode = 0755); virtual s32 Close(const s32 fd); - virtual s32 LinkSymbolic(const fs::path& src, const fs::path& dst); virtual s32 Link(const fs::path& src, const fs::path& dst); + virtual s32 LinkSymbolic(const fs::path& src, const fs::path& dst); virtual s32 Unlink(const fs::path& path); + virtual s32 Remove(const fs::path& path); + virtual s32 Flush(const s32 fd); virtual s32 FSync(const s32 fd); virtual s32 Truncate(const fs::path& path, u64 size); @@ -57,6 +59,10 @@ public: virtual s32 FChmod(const s32 fd, u16 mode); virtual s64 GetDents(const s32 fd, void* buf, u64 count, s64* basep); + + virtual s32 Copy(const fs::path& src, const fs::path& dst, bool fail_if_exists); + virtual s32 Move(const fs::path& src, const fs::path& dst, bool fail_if_exists); + s32 Rename(const fs::path& src, const fs::path& dst_name, bool fail_if_exists); // // Derived, complex functions are to be handled by main FS class // diff --git a/src/core/file_sys/hostio/src/host_io_linux2bsd.h b/src/core/file_sys/hostio/src/host_io_linux2bsd.h index ff4cc00ad..c3c7a80ac 100644 --- a/src/core/file_sys/hostio/src/host_io_linux2bsd.h +++ b/src/core/file_sys/hostio/src/host_io_linux2bsd.h @@ -1,4 +1,9 @@ -#include +// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include #include "common/assert.h" #include "core/libraries/kernel/posix_error.h" @@ -6,394 +11,291 @@ // Convert linux/unix errno to FreeBSD errno // They differ in higher errno numbers, which may throw Orbis off quite a bit -s32 posix2bsd(s32 id) { +s32 unix2bsd(s32 id) { switch (id) { default: UNREACHABLE_MSG("Unknown POSIX errno"); - case: - POSIX_EPERM: + case POSIX_EPERM: return EPERM; - case: - POSIX_ENOENT: + case POSIX_ENOENT: return ENOENT; - case: - POSIX_ESRCH: + case POSIX_ESRCH: return ESRCH; - case: - POSIX_EINTR: + case POSIX_EINTR: return EINTR; - case: - POSIX_EIO: + case POSIX_EIO: return EIO; - case: - POSIX_ENXIO: + case POSIX_ENXIO: return ENXIO; - case: - POSIX_E2BIG: + case POSIX_E2BIG: return E2BIG; - case: - POSIX_ENOEXEC: + case POSIX_ENOEXEC: return ENOEXEC; - case: - POSIX_EBADF: + case POSIX_EBADF: return EBADF; - case: - POSIX_ECHILD: + case POSIX_ECHILD: return ECHILD; - case: - POSIX_EDEADLK: + case POSIX_EDEADLK: return EDEADLK; - case: - POSIX_ENOMEM: + case POSIX_ENOMEM: return ENOMEM; - case: - POSIX_EACCES: + case POSIX_EACCES: return EACCES; - case: - POSIX_EFAULT: + case POSIX_EFAULT: return EFAULT; - // case: - // POSIX_ENOTBLK: - // return ENOTBLK; - - case: - POSIX_ENOTBLK: - return ENODEV; //? +#ifndef _WIN32 + case POSIX_ENOTBLK: + return ENOTBLK; +#endif - case: - POSIX_EBUSY: + case POSIX_EBUSY: return EBUSY; - case: - POSIX_EEXIST: + case POSIX_EEXIST: return EEXIST; - case: - POSIX_EXDEV: + case POSIX_EXDEV: return EXDEV; - case: - POSIX_ENODEV: + case POSIX_ENODEV: return ENODEV; - case: - POSIX_ENOTDIR: + case POSIX_ENOTDIR: return ENOTDIR; - case: - POSIX_EISDIR: + case POSIX_EISDIR: return EISDIR; - case: - POSIX_EINVAL: + case POSIX_EINVAL: return EINVAL; - case: - POSIX_ENFILE: + case POSIX_ENFILE: return ENFILE; - case: - POSIX_EMFILE: + case POSIX_EMFILE: return EMFILE; - case: - POSIX_ENOTTY: + case POSIX_ENOTTY: return ENOTTY; - case: - POSIX_ETXTBSY: + case POSIX_ETXTBSY: return ETXTBSY; - case: - POSIX_EFBIG: + case POSIX_EFBIG: return EFBIG; - case: - POSIX_ENOSPC: + case POSIX_ENOSPC: return ENOSPC; - case: - POSIX_ESPIPE: + case POSIX_ESPIPE: return ESPIPE; - case: - POSIX_EROFS: + case POSIX_EROFS: return EROFS; - case: - POSIX_EMLINK: + case POSIX_EMLINK: return EMLINK; - case: - POSIX_EPIPE: + case POSIX_EPIPE: return EPIPE; - case: - POSIX_EDOM: + case POSIX_EDOM: return EDOM; - case: - POSIX_ERANGE: + case POSIX_ERANGE: return ERANGE; - case: - POSIX_EAGAIN: + case POSIX_EAGAIN: return EAGAIN; - case: - POSIX_EWOULDBLOCK: - return EWOULDBLOCK; - case: - POSIX_EINPROGRESS: + // same as POSIX_EAGAIN + // case POSIX_EWOULDBLOCK: + // return EWOULDBLOCK; + case POSIX_EINPROGRESS: return EINPROGRESS; - case: - POSIX_EALREADY: + case POSIX_EALREADY: return EALREADY; - case: - POSIX_ENOTSOCK: + case POSIX_ENOTSOCK: return ENOTSOCK; - case: - POSIX_EDESTADDRREQ: + case POSIX_EDESTADDRREQ: return EDESTADDRREQ; - case: - POSIX_EMSGSIZE: + case POSIX_EMSGSIZE: return EMSGSIZE; - case: - POSIX_EPROTOTYPE: + case POSIX_EPROTOTYPE: return EPROTOTYPE; - case: - POSIX_ENOPROTOOPT: + case POSIX_ENOPROTOOPT: return ENOPROTOOPT; - case: - POSIX_EPROTONOSUPPORT: + case POSIX_EPROTONOSUPPORT: return EPROTONOSUPPORT; - // case: - // POSIX_ESOCKTNOSUPPORT: - // return ESOCKTNOSUPPORT; // ? +#ifndef _WIN32 + case POSIX_ESOCKTNOSUPPORT: + return ESOCKTNOSUPPORT; +#endif - case: - POSIX_EOPNOTSUPP: + case POSIX_EOPNOTSUPP: return EOPNOTSUPP; - case: - POSIX_ENOTSUP: - return ENOTSUP; + // same as POSIX_EOPNOTSUPP + // case POSIX_ENOTSUP: + // return ENOTSUP; - // case: - // POSIX_EPFNOSUPPORT: - // return EPFNOSUPPORT; //? +#ifndef _WIN32 + case POSIX_EPFNOSUPPORT: + return EPFNOSUPPORT; +#endif - case: - POSIX_EAFNOSUPPORT: + case POSIX_EAFNOSUPPORT: return EAFNOSUPPORT; - case: - POSIX_EADDRINUSE: + case POSIX_EADDRINUSE: return EADDRINUSE; - case: - POSIX_EADDRNOTAVAIL: + case POSIX_EADDRNOTAVAIL: return EADDRNOTAVAIL; - case: - POSIX_ENETDOWN: + case POSIX_ENETDOWN: return ENETDOWN; - case: - POSIX_ENETUNREACH: + case POSIX_ENETUNREACH: return ENETUNREACH; - case: - POSIX_ENETRESET: + case POSIX_ENETRESET: return ENETRESET; - case: - POSIX_ECONNABORTED: + case POSIX_ECONNABORTED: return ECONNABORTED; - case: - POSIX_ECONNRESET: + case POSIX_ECONNRESET: return ECONNRESET; - case: - POSIX_ENOBUFS: + case POSIX_ENOBUFS: return ENOBUFS; - case: - POSIX_EISCONN: + case POSIX_EISCONN: return EISCONN; - case: - POSIX_ENOTCONN: + case POSIX_ENOTCONN: return ENOTCONN; - // case: - // POSIX_ESHUTDOWN: - // return ESHUTDOWN; // ? +#ifndef _WIN32 + case POSIX_ESHUTDOWN: + return ESHUTDOWN; + case POSIX_ETOOMANYREFS: + return ETOOMANYREFS; +#endif - // case: - // POSIX_ETOOMANYREFS: - // return ETOOMANYREFS; // ? - - case: - POSIX_ETIMEDOUT: + case POSIX_ETIMEDOUT: return ETIMEDOUT; - case: - POSIX_ECONNREFUSED: + case POSIX_ECONNREFUSED: return ECONNREFUSED; - case: - POSIX_ELOOP: + case POSIX_ELOOP: return ELOOP; - case: - POSIX_ENAMETOOLONG: + case POSIX_ENAMETOOLONG: return ENAMETOOLONG; - // case: - // POSIX_EHOSTDOWN: - // return EHOSTDOWN; // ? +#ifndef _WIN32 + case POSIX_EHOSTDOWN: + return EHOSTDOWN; +#endif - case: - POSIX_EHOSTUNREACH: + case POSIX_EHOSTUNREACH: return EHOSTUNREACH; - case: - POSIX_ENOTEMPTY: + case POSIX_ENOTEMPTY: return ENOTEMPTY; - // case: - // POSIX_EPROCLIM: - // return EPROCLIM; - // case: - // POSIX_EUSERS: - // return EUSERS; - // case: - // POSIX_EDQUOT: - // return EDQUOT; - // case: - // POSIX_ESTALE: - // return ESTALE; - // case: - // POSIX_EREMOTE: - // return EREMOTE; - // case: - // POSIX_EBADRPC: - // return EBADRPC; - // case: - // POSIX_ERPCMISMATCH: - // return ERPCMISMATCH; - // case: - // POSIX_EPROGUNAVAIL: - // return EPROGUNAVAIL; - // case: - // POSIX_EPROGMISMATCH: - // return EPROGMISMATCH; - // case: - // POSIX_EPROCUNAVAIL: - // return EPROCUNAVAIL; +#ifndef _WIN32 + case POSIX_EPROCLIM: + return EPROCLIM; + case POSIX_EUSERS: + return EUSERS; + case POSIX_EDQUOT: + return EDQUOT; + case POSIX_ESTALE: + return ESTALE; + case POSIX_EREMOTE: + return EREMOTE; + case POSIX_EBADRPC: + return EBADRPC; + case POSIX_ERPCMISMATCH: + return ERPCMISMATCH; + case POSIX_EPROGUNAVAIL: + return EPROGUNAVAIL; + case POSIX_EPROGMISMATCH: + return EPROGMISMATCH; + case POSIX_EPROCUNAVAIL: + return EPROCUNAVAIL; +#endif - case: - POSIX_ENOLCK: + case POSIX_ENOLCK: return ENOLCK; - case: - POSIX_ENOSYS: + case POSIX_ENOSYS: return ENOSYS; - // case: - // POSIX_EFTYPE: - // return EFTYPE; - // case: - // POSIX_EAUTH: - // return EAUTH; - // case: - // POSIX_ENEEDAUTH: - // return ENEEDAUTH; +#ifndef _WIN32 + case POSIX_EFTYPE: + return EFTYPE; + case POSIX_EAUTH: + return EAUTH; + case POSIX_ENEEDAUTH: + return ENEEDAUTH; +#endif - case: - POSIX_EIDRM: + case POSIX_EIDRM: return EIDRM; - case: - POSIX_ENOMSG: + case POSIX_ENOMSG: return ENOMSG; - case: - POSIX_EOVERFLOW: + case POSIX_EOVERFLOW: return EOVERFLOW; - case: - POSIX_ECANCELED: + case POSIX_ECANCELED: return ECANCELED; - case: - POSIX_EILSEQ: + case POSIX_EILSEQ: return EILSEQ; - // case: - // POSIX_ENOATTR: - // return ENOATTR; - // case: - // POSIX_EDOOFUS: - // return EDOOFUS; +#ifndef _WIN32 + case POSIX_ENOATTR: + return ENOATTR; + case POSIX_EDOOFUS: + return EDOOFUS; +#endif - case: - POSIX_EBADMSG: + case POSIX_EBADMSG: return EBADMSG; - // case: - // POSIX_EMULTIHOP: - // return EMULTIHOP; +#ifndef _WIN32 + case POSIX_EMULTIHOP: + return EMULTIHOP; +#endif - case: - POSIX_ENOLINK: + case POSIX_ENOLINK: return ENOLINK; - case: - POSIX_EPROTO: + case POSIX_EPROTO: return EPROTO; - // case: - // POSIX_ENOTCAPABLE: - // return ENOTCAPABLE; - // case: - // POSIX_ECAPMODE: - // return ECAPMODE; - // case: - // POSIX_ENOBLK: - // return ENOBLK; - // case: - // POSIX_EICV: - // return EICV; - // case: - // POSIX_ENOPLAYGOENT: - // return ENOPLAYGOENT; - // case: - // POSIX_EREVOKE: - // return EREVOKE; - // case: - // POSIX_ESDKVERSION: - // return ESDKVERSION; - // case: - // POSIX_ESTART: - // return ESTART; - // case: - // POSIX_ESTOP: - // return ESTOP; - // case: - // POSIX_EINVALID2MB: - // return EINVALID2MB; - // case: - // POSIX_ELAST: - // return ELAST; - // case: - // POSIX_EADHOC: - // return EADHOC; - // case: - // POSIX_EINACTIVEDISABLED: - // return EINACTIVEDISABLED; - // case: - // POSIX_ENETNODATA: - // return ENETNODATA; - // case: - // POSIX_ENETDESC: - // return ENETDESC; - // case: - // POSIX_ENETDESCTIMEDOUT: - // return ENETDESCTIMEDOUT; - // case: - // POSIX_ENETINTR: - // return ENETINTR; - // case: - // POSIX_ERETURN: - // return ERETURN; - // case: - // POSIX_EFPOS: - // return EFPOS; +#ifndef _WIN32 + case POSIX_ENOTCAPABLE: + return ENOTCAPABLE; + case POSIX_ECAPMODE: + return ECAPMODE; + case POSIX_ENOBLK: + return ENOBLK; + case POSIX_EICV: + return EICV; + case POSIX_ENOPLAYGOENT: + return ENOPLAYGOENT; + case POSIX_EREVOKE: + return EREVOKE; + case POSIX_ESDKVERSION: + return ESDKVERSION; + case POSIX_ESTART: + return ESTART; + case POSIX_ESTOP: + return ESTOP; + case POSIX_EINVALID2MB: + return EINVALID2MB; + case POSIX_ELAST: + return ELAST; + case POSIX_EADHOC: + return EADHOC; + case POSIX_EINACTIVEDISABLED: + return EINACTIVEDISABLED; + case POSIX_ENETNODATA: + return ENETNODATA; + case POSIX_ENETDESC: + return ENETDESC; + case POSIX_ENETDESCTIMEDOUT: + return ENETDESCTIMEDOUT; + case POSIX_ENETINTR: + return ENETINTR; + case POSIX_ERETURN: + return ERETURN; + case POSIX_EFPOS: + return EFPOS; +#endif - case: - POSIX_ENODATA: + case POSIX_ENODATA: return ENODATA; - case: - POSIX_ENOSR: + case POSIX_ENOSR: return ENOSR; - case: - POSIX_ENOSTR: + case POSIX_ENOSTR: return ENOSTR; - case: - POSIX_ENOTRECOVERABLE: + case POSIX_ENOTRECOVERABLE: return ENOTRECOVERABLE; - case: - POSIX_EOTHER: + case POSIX_EOTHER: return EOTHER; - case: - POSIX_EOWNERDEAD: + case POSIX_EOWNERDEAD: return EOWNERDEAD; - case: - POSIX_ETIME: + case POSIX_ETIME: return ETIME; } } \ No newline at end of file diff --git a/src/core/file_sys/hostio/src/host_io_posix.cpp b/src/core/file_sys/hostio/src/host_io_posix.cpp index 5bbad39ea..7ca701a10 100644 --- a/src/core/file_sys/hostio/src/host_io_posix.cpp +++ b/src/core/file_sys/hostio/src/host_io_posix.cpp @@ -25,37 +25,43 @@ namespace HostIODriver { s32 HostIO_POSIX::Open(const fs::path& path, s32 flags, u16 mode) { errno = 0; s32 status = open(path.c_str(), ToPOSIXOpenFlags(flags), mode); - return status >= 0 ? status : -errno; + return status >= 0 ? status : -unix2bsd(errno); } s32 HostIO_POSIX::Creat(const fs::path& path, u16 mode) { errno = 0; s32 status = creat(path.c_str(), mode); - return status >= 0 ? status : -errno; + return status >= 0 ? status : -unix2bsd(errno); } s32 HostIO_POSIX::Close(const s32 fd) { errno = 0; s32 status = close(fd); - return 0 == status ? status : -errno; + return 0 == status ? status : -unix2bsd(errno); } s32 HostIO_POSIX::Link(const fs::path& src, const fs::path& dst) { errno = 0; s32 status = link(src.c_str(), dst.c_str()); - return 0 == status ? status : -errno; -} - -s32 HostIO_POSIX::Unlink(const fs::path& path) { - errno = 0; - s32 status = unlink(path.c_str()); - return 0 == status ? status : -errno; + return 0 == status ? status : -unix2bsd(errno); } s32 HostIO_POSIX::LinkSymbolic(const fs::path& src, const fs::path& dst) { errno = 0; s32 status = symlink(src.c_str(), dst.c_str()); - return 0 == status ? status : -errno; + return 0 == status ? status : -unix2bsd(errno); +} + +s32 HostIO_POSIX::Unlink(const fs::path& path) { + errno = 0; + s32 status = unlink(path.c_str()); + return 0 == status ? status : -unix2bsd(errno); +} + +s32 HostIO_POSIX::Remove(const fs::path& path) { + errno = 0; + s32 status = remove(path.c_str()); + return 0 == status ? status : -unix2bsd(errno); } s32 HostIO_POSIX::Flush(const s32 fd) { @@ -66,13 +72,13 @@ s32 HostIO_POSIX::Flush(const s32 fd) { s32 HostIO_POSIX::FSync(const s32 fd) { errno = 0; s32 status = fsync(fd); - return 0 == status ? status : -errno; + return 0 == status ? status : -unix2bsd(errno); } s64 HostIO_POSIX::LSeek(const s32 fd, s64 offset, s32 whence) { errno = 0; s32 status = lseek(fd, offset, ToPOSIXSeekOrigin(whence)); - return status >= 0 ? status : -errno; + return status >= 0 ? status : -unix2bsd(errno); } s64 HostIO_POSIX::Tell(const s32 fd) { @@ -82,25 +88,25 @@ s64 HostIO_POSIX::Tell(const s32 fd) { s32 HostIO_POSIX::Truncate(const fs::path& path, u64 size) { errno = 0; s32 status = truncate(path.c_str(), size); - return status >= 0 ? status : -errno; + return status >= 0 ? status : -unix2bsd(errno); } s32 HostIO_POSIX::FTruncate(const s32 fd, u64 size) { errno = 0; s32 status = ftruncate(fd, size); - return status >= 0 ? status : -errno; + return status >= 0 ? status : -unix2bsd(errno); } s64 HostIO_POSIX::Read(const s32 fd, void* buf, u64 count) { errno = 0; s32 status = read(fd, buf, count); - return status >= 0 ? status : -errno; + return status >= 0 ? status : -unix2bsd(errno); } s64 HostIO_POSIX::PRead(const s32 fd, void* buf, u64 count, s64 offset) { errno = 0; s32 status = pread(fd, buf, count, offset); - return status >= 0 ? status : -errno; + return status >= 0 ? status : -unix2bsd(errno); } s64 HostIO_POSIX::ReadV(const s32 fd, OrbisKernelIovec* iov, u32 iovcnt) { @@ -132,13 +138,13 @@ s64 HostIO_POSIX::PReadV(const s32 fd, OrbisKernelIovec* iov, u32 iovcnt, s64 of s64 HostIO_POSIX::Write(const s32 fd, const void* buf, u64 count) { errno = 0; s32 status = write(fd, buf, count); - return status >= 0 ? status : -errno; + return status >= 0 ? status : -unix2bsd(errno); } s64 HostIO_POSIX::PWrite(const s32 fd, const void* buf, u64 count, s64 offset) { errno = 0; s32 status = pwrite(fd, buf, count, offset); - return status >= 0 ? status : -errno; + return status >= 0 ? status : -unix2bsd(errno); } s64 HostIO_POSIX::WriteV(const s32 fd, const OrbisKernelIovec* iov, u32 iovcnt) { @@ -170,13 +176,13 @@ s64 HostIO_POSIX::PWriteV(const s32 fd, const OrbisKernelIovec* iov, u32 iovcnt, s32 HostIO_POSIX::MKDir(const fs::path& path, u16 mode) { errno = 0; s32 status = mkdir(path.c_str(), mode); - return 0 == status ? status : -errno; + return 0 == status ? status : -unix2bsd(errno); } s32 HostIO_POSIX::RMDir(const fs::path& path) { errno = 0; s32 status = rmdir(path.c_str()); - return 0 == status ? status : -errno; + return 0 == status ? status : -unix2bsd(errno); } s32 HostIO_POSIX::Stat(const fs::path& path, OrbisKernelStat* statbuf) { @@ -251,13 +257,21 @@ s32 HostIO_POSIX::FStat(const s32 fd, OrbisKernelStat* statbuf) { s32 HostIO_POSIX::Chmod(const fs::path& path, u16 mode) { errno = 0; s32 status = chmod(path.c_str(), mode); - return 0 == status ? status : -errno; + return 0 == status ? status : -unix2bsd(errno); } s32 HostIO_POSIX::FChmod(const s32 fd, u16 mode) { errno = 0; s32 status = fchmod(fd, mode); - return 0 == status ? status : -errno; + return 0 == status ? status : -unix2bsd(errno); +} + +s32 HostIO_POSIX::Copy(const fs::path& src, const fs::path& dst, bool fail_if_exists) { + return -unix2bsd(ENOSYS); +} + +s32 HostIO_POSIX::Move(const fs::path& src, const fs::path& dst, bool fail_if_exists) { + return -unix2bsd(ENOSYS); } // s32 HostIO_POSIX::GetDents(void* buf, u32 count, s64* basep) { return -POSIX_ENOSYS; } diff --git a/src/core/file_sys/hostio/src/host_io_virtual.cpp b/src/core/file_sys/hostio/src/host_io_virtual.cpp index 9d847ca05..1612b679f 100644 --- a/src/core/file_sys/hostio/src/host_io_virtual.cpp +++ b/src/core/file_sys/hostio/src/host_io_virtual.cpp @@ -104,6 +104,17 @@ s32 HostIO_Virtual::Link(const fs::path& src, const fs::path& dst) { return part->link(src_node, dst_parent, dst_name); } +s32 HostIO_Virtual::LinkSymbolic(const fs::path& src, const fs::path& dst) { + if (nullptr == this->res) + return -POSIX_EINVAL; + + symlink_ptr sym = Symlink::Create(src); + // symlink counter is never increased + sym->st.st_nlink = 1; + + return this->res->mountpoint->touch(this->res->parent, dst.filename().string(), sym); +} + s32 HostIO_Virtual::Unlink(const fs::path& path) { if (nullptr == this->res) return -POSIX_EINVAL; @@ -118,15 +129,8 @@ s32 HostIO_Virtual::Unlink(const fs::path& path) { return part->unlink(parent, this->res->leaf); } -s32 HostIO_Virtual::LinkSymbolic(const fs::path& src, const fs::path& dst) { - if (nullptr == this->res) - return -POSIX_EINVAL; - - symlink_ptr sym = Symlink::Create(src); - // symlink counter is never increased - sym->st.st_nlink = 1; - - return this->res->mountpoint->touch(this->res->parent, dst.filename().string(), sym); +s32 HostIO_Virtual::Remove(const fs::path& path) { + return -POSIX_ENOSYS; } s32 HostIO_Virtual::Flush(const s32 fd) { @@ -387,8 +391,7 @@ s64 HostIO_Virtual::GetDents(const s32 fd, void* buf, u64 count, s64* basep) { // In most cases it's 512 bytes // Not sure yet if other partitions share the same size if (count < 512) { - LOG_ERROR(Kernel_Fs, - "(Partial STUB) check for block size associated. Read size must be greater"); + LOG_ERROR(Kernel_Fs, "Read size must be greater than sector size (512B)"); return -POSIX_EINVAL; } @@ -400,4 +403,12 @@ s64 HostIO_Virtual::GetDents(const s32 fd, void* buf, u64 count, s64* basep) { return br; } +s32 HostIO_Virtual::Copy(const fs::path& src, const fs::path& dst, bool fail_if_exists) { + return POSIX_ENOSYS; +} + +s32 HostIO_Virtual::Move(const fs::path& src, const fs::path& dst, bool fail_if_exists) { + return POSIX_ENOSYS; +} + } // namespace HostIODriver diff --git a/src/core/file_sys/hostio/src/host_io_win2bsd.h b/src/core/file_sys/hostio/src/host_io_win2bsd.h new file mode 100644 index 000000000..09e2cff0a --- /dev/null +++ b/src/core/file_sys/hostio/src/host_io_win2bsd.h @@ -0,0 +1,31 @@ +// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#ifdef _WIN32 + +#include +#include + +#include "common/assert.h" +#include "core/libraries/kernel/posix_error.h" + +// Convert linux/unix errno to FreeBSD errno +// They differ in higher errno numbers, which may throw Orbis off quite a bit + +s32 win2bsd(s32 id) { + switch (id) { + default: + return EIO; + case ERROR_FILE_NOT_FOUND: + case ERROR_PATH_NOT_FOUND: + return ENOENT; + case ERROR_ALREADY_EXISTS: + return EEXIST; + case ERROR_ACCESS_DENIED: + return EACCES; + } +} + +#endif \ No newline at end of file diff --git a/src/core/file_sys/hostio/src/host_io_win32.cpp b/src/core/file_sys/hostio/src/host_io_win32.cpp index 9dc4d2637..4d570ab48 100644 --- a/src/core/file_sys/hostio/src/host_io_win32.cpp +++ b/src/core/file_sys/hostio/src/host_io_win32.cpp @@ -2,10 +2,14 @@ #include #include +#include #include "common/logging/log.h" #include "src/core/file_sys/hostio/host_io_win32.h" +#include "host_io_linux2bsd.h" +#include "host_io_win2bsd.h" + namespace HostIODriver { HostIO_Win32::HostIO_Win32() = default; @@ -14,39 +18,55 @@ HostIO_Win32::~HostIO_Win32() = default; s32 HostIO_Win32::Open(const fs::path& path, s32 flags, u16 mode) { errno = 0; s32 status = _wopen(path.c_str(), ToWIN32OpenFlags(flags), mode); - return status >= 0 ? status : -errno; + return status >= 0 ? status : -unix2bsd(errno); } s32 HostIO_Win32::Creat(const fs::path& path, u16 mode) { errno = 0; s32 status = _wcreat(path.c_str(), mode); - return status >= 0 ? status : -errno; + return status >= 0 ? status : -unix2bsd(errno); } s32 HostIO_Win32::Close(const s32 fd) { errno = 0; s32 status = _close(fd); - return 0 == status ? 0 : -errno; + return 0 == status ? 0 : -unix2bsd(errno); } -// s32 HostIO_Win32::Link(const fs::path& src, const fs::path& dst) { -// // errno = 0; -// // s32 status = link(src.c_str(), dst.c_str()); -// // return 0 == status ? 0 : -errno; -// } - -// s32 HostIO_Win32::Unlink(const fs::path& path) { -// // errno = 0; -// // s32 status = unlink(path.c_str()); -// // return 0 == status ? 0 : -errno; -// } +s32 HostIO_Win32::Link(const fs::path& src, const fs::path& dst) { + errno = 0; + s32 status = CreateHardLinkW(dst.c_str(), src.c_str(), nullptr); + return 0 == status ? 0 : -win2bsd(GetLastError()); +} // s32 HostIO_Win32::LinkSymbolic(const fs::path& src, const fs: // // errno = 0; // // s32 status = symlink(src.c_str(), dst.c_str()); -// // return 0 == status ? 0 : -errno; +// // return 0 == status ? 0 :-unix2bsd(errno); // } +s32 HostIO_Win32::Unlink(const fs::path& path) { + errno = 0; + s32 status = DeleteFileW(path.c_str()); + + return status > 0 ? status : -win2bsd(GetLastError()); +} + +s32 HostIO_Win32::Remove(const fs::path& path) { + errno = 0; + if (int status = DeleteFileW(path.c_str()); status > 0) + return 0; + auto last_error = GetLastError(); + // no idea if these are correlated (yet) + LOG_CRITICAL(Kernel_Fs, "XDXDXDXD {} vs {}", errno, last_error); + + // existence is found with both + if (last_error == ERROR_FILE_NOT_FOUND || last_error == ERROR_PATH_NOT_FOUND) + return false; + + return RemoveDirectoryW(path.c_str()); +} + s32 HostIO_Win32::Flush(const s32 fd) { errno = 0; return 0; @@ -55,13 +75,13 @@ s32 HostIO_Win32::Flush(const s32 fd) { s32 HostIO_Win32::FSync(const s32 fd) { errno = 0; s32 status = _commit(fd); - return 0 == status ? 0 : -errno; + return 0 == status ? 0 : -unix2bsd(errno); } s64 HostIO_Win32::LSeek(const s32 fd, s64 offset, s32 whence) { errno = 0; s32 status = _lseeki64(fd, offset, ToWIN32SeekOrigin(whence)); - return status >= 0 ? status : -errno; + return status >= 0 ? status : -unix2bsd(errno); } s64 HostIO_Win32::Tell(const s32 fd) { @@ -72,35 +92,35 @@ int HostIO_Win32::Truncate(const fs::path& path, u64 size) { errno = 0; s32 fd = _wopen(path.c_str(), _O_RDONLY); if (fd < 0) - return -errno; + return -unix2bsd(errno); s32 status = _chsize_s(fd, size); _close(fd); - return status >= 0 ? status : -errno; + return status >= 0 ? status : -unix2bsd(errno); } int HostIO_Win32::FTruncate(const s32 fd, u64 size) { errno = 0; s32 status = _chsize_s(fd, size); - return status >= 0 ? status : -errno; + return status >= 0 ? status : -unix2bsd(errno); } s64 HostIO_Win32::Read(const s32 fd, void* buf, u64 count) { errno = 0; s32 status = _read(fd, buf, count); - return status >= 0 ? status : -errno; + return status >= 0 ? status : -unix2bsd(errno); } s64 HostIO_Win32::PRead(const s32 fd, void* buf, u64 count, s64 offset) { errno = 0; s64 bak = LSeek(fd, 0, SeekOrigin::CURRENT); if (bak < 0) - return -errno; + return -unix2bsd(errno); LSeek(fd, offset, SeekOrigin::ORIGIN); s32 status = _read(fd, buf, count); LSeek(fd, bak, SeekOrigin::ORIGIN); - return status >= 0 ? status : -errno; + return status >= 0 ? status : -unix2bsd(errno); } s64 HostIO_Win32::ReadV(const s32 fd, OrbisKernelIovec* iov, u32 iovcnt) { @@ -113,20 +133,20 @@ s64 HostIO_Win32::PReadV(const s32 fd, OrbisKernelIovec* iov, u32 iovcnt, s64 of s64 HostIO_Win32::Write(const s32 fd, const void* buf, u64 count) { errno = 0; s32 status = _write(fd, buf, count); - return status >= 0 ? status : -errno; + return status >= 0 ? status : -unix2bsd(errno); } s64 HostIO_Win32::PWrite(const s32 fd, const void* buf, u64 count, s64 offset) { errno = 0; s64 bak = LSeek(fd, 0, SeekOrigin::CURRENT); if (bak < 0) - return -errno; + return -unix2bsd(errno); LSeek(fd, offset, SeekOrigin::ORIGIN); s32 status = _write(fd, buf, count); LSeek(fd, bak, SeekOrigin::ORIGIN); - return status >= 0 ? status : -errno; + return status >= 0 ? status : -unix2bsd(errno); } s64 HostIO_Win32::WriteV(const s32 fd, const OrbisKernelIovec* iov, u32 iovcnt) { @@ -139,13 +159,13 @@ s64 HostIO_Win32::PWriteV(const s32 fd, const OrbisKernelIovec* iov, u32 iovcnt, s32 HostIO_Win32::MKDir(const fs::path& path, u16 mode) { errno = 0; s32 status = _wmkdir(path.c_str()); - return status >= 0 ? status : -errno; + return status >= 0 ? status : -unix2bsd(errno); } s32 HostIO_Win32::RMDir(const fs::path& path) { errno = 0; s32 status = _wrmdir(path.c_str()); - return status >= 0 ? status : -errno; + return status >= 0 ? status : -unix2bsd(errno); } // s32 HostIO_Win32::Stat(const fs::path& path, Libraries::Kernel::OrbisKernelStat* statbuf) {} @@ -154,4 +174,15 @@ s32 HostIO_Win32::RMDir(const fs::path& path) { // s32 HostIO_Win32::Chmod(const fs::path& path, u16 mode) {} // s32 HostIO_Win32::FChmod(const s32 fd, u16 mode) {} +s32 HostIO_Win32::Copy(const fs::path& src, const fs::path& dst, bool fail_if_exists) { + errno = 0; + auto status = CopyFileW(src.c_str(), dst.c_str(), fail_if_exists); + return status > 0 ? status : -unix2bsd(GetLastError()); +} + +s32 HostIO_Win32::Move(const fs::path& src, const fs::path& dst, bool fail_if_exists) { + errno = 0; + return -unix2bsd(ENOSYS); +} + } // namespace HostIODriver \ No newline at end of file diff --git a/src/core/file_sys/quasifs/quasifs.h b/src/core/file_sys/quasifs/quasifs.h index cf7b4e41f..bd3abd9de 100644 --- a/src/core/file_sys/quasifs/quasifs.h +++ b/src/core/file_sys/quasifs/quasifs.h @@ -66,9 +66,12 @@ private: s32 Open(const fs::path& path, int flags, u16 mode = 0755) override; s32 Creat(const fs::path& path, u16 mode = 0755) override; s32 Close(const s32 fd) override; - s32 LinkSymbolic(const fs::path& src, const fs::path& dst) override; + s32 Link(const fs::path& src, const fs::path& dst) override; + s32 LinkSymbolic(const fs::path& src, const fs::path& dst) override; s32 Unlink(const fs::path& path) override; + s32 Remove(const fs::path& path) override; + s32 Flush(const s32 fd) override; s32 FSync(const s32 fd) override; s32 Truncate(const fs::path& path, u64 size) override; @@ -99,6 +102,9 @@ private: s32 FChmod(const s32 fd, u16 mode) override; s64 GetDents(const s32 fd, void* buf, u64 count, s64* basep) override; + + s32 Copy(const fs::path& src, const fs::path& dst, bool fail_if_exists) override; + s32 Move(const fs::path& src, const fs::path& dst, bool fail_if_exists) override; }; public: @@ -211,23 +217,11 @@ public: fs::path AbsolutePath(const fs::path& path, std::error_code& ec) noexcept { return ""; }; - bool Remove(const fs::path& path) { - return -POSIX_EINVAL; - }; - bool Remove(const fs::path& path, std::error_code& ec) noexcept { - return -POSIX_EINVAL; - }; - uint64_t RemoveAll(const fs::path& path) = delete; - uint64_t RemoveAll(const fs::path& path, std::error_code& ec) noexcept = delete; - uint64_t CurrentPath(const fs::path& path) = delete; - uint64_t CurrentPath(const fs::path& path, std::error_code& ec) noexcept = delete; - bool Copy(const fs::path& from, const fs::path& to) = delete; - bool Copy(const fs::path& from, const fs::path& to, std::error_code& ec) noexcept = delete; - bool Copy(const fs::path& from, const fs::path& to, - std::filesystem::copy_options options) = delete; - bool Copy(const fs::path& from, const fs::path& to, std::filesystem::copy_options options, - std::error_code& ec) noexcept = delete; + // uint64_t RemoveAll(const fs::path& path) = delete; + // uint64_t RemoveAll(const fs::path& path, std::error_code& ec) noexcept = delete; + // uint64_t CurrentPath(const fs::path& path) = delete; + // uint64_t CurrentPath(const fs::path& path, std::error_code& ec) noexcept = delete; // 0777 to mimic default C++ mode (std::filesystem::perms::all) bool CreateDirectory(const fs::path& path, int mode = 0777) { diff --git a/src/core/file_sys/quasifs/quasifs_inode.h b/src/core/file_sys/quasifs/quasifs_inode.h index a97c0f414..efb901fed 100644 --- a/src/core/file_sys/quasifs/quasifs_inode.h +++ b/src/core/file_sys/quasifs/quasifs_inode.h @@ -38,6 +38,13 @@ public: virtual ~Inode() = default; + inode_ptr Clone() const { + auto _out = std::make_shared(*this); + _out->fileno = -1; + _out->st.st_nlink = 0; + return _out; + } + virtual s32 ioctl(u64 cmd, Common::VaCtx* args) { return -POSIX_ENOTTY; } diff --git a/src/core/file_sys/quasifs/quasifs_inode_quasi_device.h b/src/core/file_sys/quasifs/quasifs_inode_quasi_device.h index a538d10ff..0753bb295 100644 --- a/src/core/file_sys/quasifs/quasifs_inode_quasi_device.h +++ b/src/core/file_sys/quasifs/quasifs_inode_quasi_device.h @@ -19,6 +19,13 @@ public: return std::make_shared(); } + dev_ptr Clone() const { + auto _out = std::make_shared(*this); + _out->fileno = -1; + _out->st.st_nlink = 0; + return _out; + } + virtual s64 read(void* buf, u64 count); virtual s64 write(const void* buf, u64 count); diff --git a/src/core/file_sys/quasifs/quasifs_inode_quasi_directory.h b/src/core/file_sys/quasifs/quasifs_inode_quasi_directory.h index 4557976cc..ffb66eae2 100644 --- a/src/core/file_sys/quasifs/quasifs_inode_quasi_directory.h +++ b/src/core/file_sys/quasifs/quasifs_inode_quasi_directory.h @@ -56,6 +56,13 @@ public: return std::make_shared(); } + dir_ptr Clone() const { + auto _out = std::make_shared(*this); + _out->fileno = -1; + _out->st.st_nlink = 0; + return _out; + } + // // Inode overrides // diff --git a/src/core/file_sys/quasifs/quasifs_inode_quasi_directory_pfs.h b/src/core/file_sys/quasifs/quasifs_inode_quasi_directory_pfs.h index c32f134c2..012090f0c 100644 --- a/src/core/file_sys/quasifs/quasifs_inode_quasi_directory_pfs.h +++ b/src/core/file_sys/quasifs/quasifs_inode_quasi_directory_pfs.h @@ -44,6 +44,13 @@ public: return std::make_shared(); } + dir_ptr Clone() const { + auto _out = std::make_shared(*this); + _out->fileno = -1; + _out->st.st_nlink = 0; + return _out; + } + s64 pread(void* buf, u64 count, s64 offset) override; s64 lseek(s64 current, s64 offset, s32 whence) override; diff --git a/src/core/file_sys/quasifs/quasifs_inode_quasi_file.h b/src/core/file_sys/quasifs/quasifs_inode_quasi_file.h index 0d0c7c4d7..9ebd10d58 100644 --- a/src/core/file_sys/quasifs/quasifs_inode_quasi_file.h +++ b/src/core/file_sys/quasifs/quasifs_inode_quasi_file.h @@ -22,6 +22,13 @@ public: return std::make_shared(); } + file_ptr Clone() const { + auto _out = std::make_shared(*this); + _out->fileno = -1; + _out->st.st_nlink = 0; + return _out; + } + s64 pread(void* buf, size_t count, s64 offset) override; s64 pwrite(const void* buf, size_t count, s64 offset) override; diff --git a/src/core/file_sys/quasifs/quasifs_inode_quasi_file_virtual.h b/src/core/file_sys/quasifs/quasifs_inode_quasi_file_virtual.h index 6c723db88..8d998860e 100644 --- a/src/core/file_sys/quasifs/quasifs_inode_quasi_file_virtual.h +++ b/src/core/file_sys/quasifs/quasifs_inode_quasi_file_virtual.h @@ -20,9 +20,13 @@ public: return std::make_shared(); } - // - // Working functions - // + file_ptr Clone() const { + auto _out = std::make_shared(*this); + _out->fileno = -1; + _out->st.st_nlink = 0; + return _out; + } + s64 pread(void* buf, size_t count, s64 offset) override; s64 pwrite(const void* buf, size_t count, s64 offset) override; s32 ftruncate(s64 length) override; diff --git a/src/core/file_sys/quasifs/quasifs_inode_quasi_socket.h b/src/core/file_sys/quasifs/quasifs_inode_quasi_socket.h index 777b6ee02..c8b1c2c6d 100644 --- a/src/core/file_sys/quasifs/quasifs_inode_quasi_socket.h +++ b/src/core/file_sys/quasifs/quasifs_inode_quasi_socket.h @@ -18,6 +18,13 @@ public: static socket_ptr Create() { return std::make_shared(); } + + socket_ptr Clone() const { + auto _out = std::make_shared(*this); + _out->fileno = -1; + _out->st.st_nlink = 0; + return _out; + } }; } // namespace QuasiFS \ No newline at end of file diff --git a/src/core/file_sys/quasifs/quasifs_inode_symlink.h b/src/core/file_sys/quasifs/quasifs_inode_symlink.h index 26240d644..e83953823 100644 --- a/src/core/file_sys/quasifs/quasifs_inode_symlink.h +++ b/src/core/file_sys/quasifs/quasifs_inode_symlink.h @@ -18,6 +18,13 @@ public: return std::make_shared(target); } + symlink_ptr Clone() const { + auto _out = std::make_shared(*this); + _out->fileno = -1; + _out->st.st_nlink = 0; + return _out; + } + // symlinked path fs::path follow(void); }; diff --git a/src/core/file_sys/quasifs/src/quasifs_vdriver.cpp b/src/core/file_sys/quasifs/src/quasifs_vdriver.cpp index 02dda4502..245eb9314 100644 --- a/src/core/file_sys/quasifs/src/quasifs_vdriver.cpp +++ b/src/core/file_sys/quasifs/src/quasifs_vdriver.cpp @@ -134,14 +134,19 @@ s32 QFS::OperationImpl::Close(s32 fd) { LOG_ERROR(Kernel_Fs, "Closing std stream, this will have consequences fd={}", fd); // if it fails, it fails + bool host_used = false; int hio_status = 0; - if (handle->host_fd >= 0) + if (handle->host_fd >= 0) { hio_status = qfs.hio_driver.Close(handle->host_fd); + host_used = true; + } { std::lock_guard lock(c_mutex); // no further action is required, this is pro-forma + qfs.vio_driver.SetCtx(nullptr, host_used, handle); qfs.vio_driver.Close(fd); + qfs.vio_driver.ClearCtx(); } // if it's the last entry, remove it to avoid blowing up fd table @@ -155,6 +160,68 @@ s32 QFS::OperationImpl::Close(s32 fd) { return hio_status; } +s32 QFS::OperationImpl::Link(const fs::path& src, const fs::path& dst) { + Resolved src_res; + Resolved dst_res; + int status_what = qfs.Resolve(src, src_res); + int status_where = qfs.Resolve(dst, dst_res); + + if (0 != status_what) + return status_what; + if (0 == status_where) + return -POSIX_EEXIST; + + // cross-partition linking is not supported + if (src_res.mountpoint != dst_res.mountpoint) + return -POSIX_EXDEV; + + partition_ptr src_part = src_res.mountpoint; + partition_ptr dst_part = dst_res.mountpoint; + + if (src_part != dst_part) { + LOG_ERROR(Kernel_Fs, "Hard links can only be created within one partition"); + // I think this is the right error + return -POSIX_ENOSYS; + } + + if (qfs.IsPartitionRO(dst_part)) + return -POSIX_EROFS; + + bool host_used = false; + int hio_status = 0; + int vio_status = 0; + + if (dst_part->IsHostMounted()) { + fs::path host_path_src{}; + fs::path host_path_dst{}; + + if (int hostpath_status = src_part->GetHostPath(host_path_src, src_res.local_path); + hostpath_status != 0) + return hostpath_status; + if (int hostpath_status = dst_part->GetHostPath(host_path_dst, dst_res.local_path); + hostpath_status != 0) + return hostpath_status; + + if (hio_status = qfs.hio_driver.Link(host_path_src, host_path_dst); hio_status < 0) + // hosts operation must succeed in order to continue + return hio_status; + host_used = true; + } + + { + std::lock_guard lock(c_mutex); + qfs.vio_driver.SetCtx(&src_res, host_used, nullptr); + vio_status = qfs.vio_driver.Link(src_res.local_path, dst_res.local_path); + qfs.vio_driver.ClearCtx(); + } + + if (host_used && (hio_status != vio_status)) + LOG_ERROR(Kernel_Fs, "Host returned {}, but virtual driver returned {}", hio_status, + vio_status); + + return vio_status; +} + s32 QFS::OperationImpl::LinkSymbolic(const fs::path& src, const fs::path& dst) { Resolved src_res; Resolved dst_res; @@ -221,68 +288,6 @@ s32 QFS::OperationImpl::LinkSymbolic(const fs::path& src, const fs::path& dst) { return vio_status; } -s32 QFS::OperationImpl::Link(const fs::path& src, const fs::path& dst) { - Resolved src_res; - Resolved dst_res; - int status_what = qfs.Resolve(src, src_res); - int status_where = qfs.Resolve(dst, dst_res); - - if (0 != status_what) - return status_what; - if (0 == status_where) - return -POSIX_EEXIST; - - // cross-partition linking is not supported - if (src_res.mountpoint != dst_res.mountpoint) - return -POSIX_EXDEV; - - partition_ptr src_part = src_res.mountpoint; - partition_ptr dst_part = dst_res.mountpoint; - - if (src_part != dst_part) { - LOG_ERROR(Kernel_Fs, "Hard links can only be created within one partition"); - // I think this is the right error - return -POSIX_ENOSYS; - } - - if (qfs.IsPartitionRO(dst_part)) - return -POSIX_EROFS; - - bool host_used = false; - int hio_status = 0; - int vio_status = 0; - - if (dst_part->IsHostMounted()) { - fs::path host_path_src{}; - fs::path host_path_dst{}; - - if (int hostpath_status = src_part->GetHostPath(host_path_src, src_res.local_path); - hostpath_status != 0) - return hostpath_status; - if (int hostpath_status = dst_part->GetHostPath(host_path_dst, dst_res.local_path); - hostpath_status != 0) - return hostpath_status; - - if (hio_status = qfs.hio_driver.Link(host_path_src, host_path_dst); hio_status < 0) - // hosts operation must succeed in order to continue - return hio_status; - host_used = true; - } - - { - std::lock_guard lock(c_mutex); - qfs.vio_driver.SetCtx(&src_res, host_used, nullptr); - vio_status = qfs.vio_driver.Link(src_res.local_path, dst_res.local_path); - qfs.vio_driver.ClearCtx(); - } - - if (host_used && (hio_status != vio_status)) - LOG_ERROR(Kernel_Fs, "Host returned {}, but virtual driver returned {}", hio_status, - vio_status); - - return vio_status; -} - s32 QFS::OperationImpl::Unlink(const fs::path& path) { Resolved res; int resolve_status; @@ -346,6 +351,10 @@ s32 QFS::OperationImpl::Unlink(const fs::path& path) { return vio_status; } +s32 QFS::OperationImpl::Remove(const fs::path& path) { + return -POSIX_ENOSYS; +} + s32 QFS::OperationImpl::Flush(const s32 fd) { if (fd < 0) return -POSIX_EBADF; @@ -1022,4 +1031,12 @@ s64 QFS::OperationImpl::GetDents(const s32 fd, void* buf, u64 count, s64* basep) return vio_status; } +s32 QFS::OperationImpl::Copy(const fs::path& src, const fs::path& dst, bool fail_if_exists) { + return -POSIX_ENOSYS; +} + +s32 QFS::OperationImpl::Move(const fs::path& src, const fs::path& dst, bool fail_if_exists) { + return -POSIX_ENOSYS; +} + } // namespace QuasiFS \ No newline at end of file diff --git a/src/core/libraries/kernel/posix_error.h b/src/core/libraries/kernel/posix_error.h index 0f7cf3e50..b40ce5acc 100644 --- a/src/core/libraries/kernel/posix_error.h +++ b/src/core/libraries/kernel/posix_error.h @@ -1,11 +1,11 @@ -// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once #include "core/libraries/error_codes.h" -// Posix error codes +// BSD error codes constexpr int POSIX_EPERM = 1; constexpr int POSIX_ENOENT = 2; constexpr int POSIX_ESRCH = 3;