Implemented some link() on windows

Added copy/move/rename
Added cloning FS objects (deep-copy)
This commit is contained in:
marecl 2025-11-24 14:30:45 +01:00
parent 7a59a19bda
commit 8d4197e71a
21 changed files with 522 additions and 449 deletions

View File

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

View File

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

View File

@ -4,10 +4,7 @@
#ifdef _WIN32
// #error unimplemented
#include <cstdint>
#include <unordered_map>
#include <fcntl.h>
#include <windows.h>
@ -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

View File

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

View File

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

View File

@ -1,4 +1,9 @@
#include <sys/fcntl.h>
// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <errno.h>
#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;
}
}

View File

@ -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; }

View File

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

View File

@ -0,0 +1,31 @@
// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#ifdef _WIN32
#include <windows.h>
#include <winerror.h>
#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

View File

@ -2,10 +2,14 @@
#include <errno.h>
#include <io.h>
#include <winerror.h>
#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

View File

@ -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) {

View File

@ -38,6 +38,13 @@ public:
virtual ~Inode() = default;
inode_ptr Clone() const {
auto _out = std::make_shared<Inode>(*this);
_out->fileno = -1;
_out->st.st_nlink = 0;
return _out;
}
virtual s32 ioctl(u64 cmd, Common::VaCtx* args) {
return -POSIX_ENOTTY;
}

View File

@ -19,6 +19,13 @@ public:
return std::make_shared<Device>();
}
dev_ptr Clone() const {
auto _out = std::make_shared<Device>(*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);

View File

@ -56,6 +56,13 @@ public:
return std::make_shared<QuasiDirectory>();
}
dir_ptr Clone() const {
auto _out = std::make_shared<QuasiDirectory>(*this);
_out->fileno = -1;
_out->st.st_nlink = 0;
return _out;
}
//
// Inode overrides
//

View File

@ -44,6 +44,13 @@ public:
return std::make_shared<DirectoryPFS>();
}
dir_ptr Clone() const {
auto _out = std::make_shared<DirectoryPFS>(*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;

View File

@ -22,6 +22,13 @@ public:
return std::make_shared<QuasiFile>();
}
file_ptr Clone() const {
auto _out = std::make_shared<QuasiFile>(*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;

View File

@ -20,9 +20,13 @@ public:
return std::make_shared<VirtualFile>();
}
//
// Working functions
//
file_ptr Clone() const {
auto _out = std::make_shared<VirtualFile>(*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;

View File

@ -18,6 +18,13 @@ public:
static socket_ptr Create() {
return std::make_shared<Socket>();
}
socket_ptr Clone() const {
auto _out = std::make_shared<Socket>(*this);
_out->fileno = -1;
_out->st.st_nlink = 0;
return _out;
}
};
} // namespace QuasiFS

View File

@ -18,6 +18,13 @@ public:
return std::make_shared<Symlink>(target);
}
symlink_ptr Clone() const {
auto _out = std::make_shared<Symlink>(*this);
_out->fileno = -1;
_out->st.st_nlink = 0;
return _out;
}
// symlinked path
fs::path follow(void);
};

View File

@ -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<std::mutex> 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<std::mutex> 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<std::mutex> 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

View File

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