diff --git a/CMakeLists.txt b/CMakeLists.txt index 23a205249..1778e5582 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -747,22 +747,28 @@ set(CORE src/core/aerolib/stubs.cpp src/core/aerolib/aerolib.h src/core/address_space.cpp src/core/address_space.h - src/core/devices/base_device.cpp - src/core/devices/base_device.h - src/core/devices/ioccom.h - src/core/devices/logger.cpp - src/core/devices/logger.h - src/core/devices/nop_device.h - src/core/devices/console_device.cpp - src/core/devices/console_device.h - src/core/devices/deci_tty6_device.cpp - src/core/devices/deci_tty6_device.h - src/core/devices/random_device.cpp - src/core/devices/random_device.h - src/core/devices/urandom_device.cpp - src/core/devices/urandom_device.h - src/core/devices/srandom_device.cpp - src/core/devices/srandom_device.h + src/core/file_sys/devices/base_device.cpp + src/core/file_sys/devices/base_device.h + src/core/file_sys/devices/ioccom.h + src/core/file_sys/devices/logger.cpp + src/core/file_sys/devices/logger.h + src/core/file_sys/devices/nop_device.h + src/core/file_sys/devices/console_device.cpp + src/core/file_sys/devices/console_device.h + src/core/file_sys/devices/deci_tty6_device.cpp + src/core/file_sys/devices/deci_tty6_device.h + src/core/file_sys/devices/random_device.cpp + src/core/file_sys/devices/random_device.h + src/core/file_sys/devices/urandom_device.cpp + src/core/file_sys/devices/urandom_device.h + src/core/file_sys/devices/srandom_device.cpp + src/core/file_sys/devices/srandom_device.h + src/core/file_sys/directories/base_directory.cpp + src/core/file_sys/directories/base_directory.h + src/core/file_sys/directories/normal_directory.cpp + src/core/file_sys/directories/normal_directory.h + src/core/file_sys/directories/pfs_directory.cpp + src/core/file_sys/directories/pfs_directory.h src/core/file_format/pfs.h src/core/file_format/psf.cpp src/core/file_format/psf.h diff --git a/src/core/devices/base_device.cpp b/src/core/file_sys/devices/base_device.cpp similarity index 76% rename from src/core/devices/base_device.cpp rename to src/core/file_sys/devices/base_device.cpp index fc2a98a29..8c69a35cf 100644 --- a/src/core/devices/base_device.cpp +++ b/src/core/file_sys/devices/base_device.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #include "base_device.h" diff --git a/src/core/devices/base_device.h b/src/core/file_sys/devices/base_device.h similarity index 76% rename from src/core/devices/base_device.h rename to src/core/file_sys/devices/base_device.h index 0cbbd3a00..3e1dc1172 100644 --- a/src/core/devices/base_device.h +++ b/src/core/file_sys/devices/base_device.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once @@ -9,7 +9,7 @@ namespace Libraries::Kernel { struct OrbisKernelStat; -struct SceKernelIovec; +struct OrbisKernelIovec; } // namespace Libraries::Kernel namespace Core::Devices { @@ -28,19 +28,19 @@ public: return ORBIS_KERNEL_ERROR_EBADF; } - virtual size_t readv(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) { + virtual size_t readv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) { return ORBIS_KERNEL_ERROR_EBADF; } - virtual size_t writev(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) { + virtual size_t writev(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) { return ORBIS_KERNEL_ERROR_EBADF; } - virtual s64 preadv(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt, u64 offset) { + virtual s64 preadv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt, u64 offset) { return ORBIS_KERNEL_ERROR_EBADF; } - virtual size_t pwritev(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt, u64 offset) { + virtual size_t pwritev(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt, u64 offset) { return ORBIS_KERNEL_ERROR_EBADF; } diff --git a/src/core/devices/console_device.cpp b/src/core/file_sys/devices/console_device.cpp similarity index 82% rename from src/core/devices/console_device.cpp rename to src/core/file_sys/devices/console_device.cpp index f109cadb9..a9148473d 100644 --- a/src/core/devices/console_device.cpp +++ b/src/core/file_sys/devices/console_device.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #include "common/logging/log.h" @@ -21,17 +21,17 @@ s64 ConsoleDevice::write(const void* buf, size_t nbytes) { return 0; } -size_t ConsoleDevice::writev(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) { +size_t ConsoleDevice::writev(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) { LOG_ERROR(Kernel_Pthread, "(STUBBED) called"); return 0; } -size_t ConsoleDevice::readv(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) { +size_t ConsoleDevice::readv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) { LOG_ERROR(Kernel_Pthread, "(STUBBED) called"); return 0; } -s64 ConsoleDevice::preadv(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt, u64 offset) { +s64 ConsoleDevice::preadv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt, u64 offset) { LOG_ERROR(Kernel_Pthread, "(STUBBED) called"); return 0; } diff --git a/src/core/devices/console_device.h b/src/core/file_sys/devices/console_device.h similarity index 72% rename from src/core/devices/console_device.h rename to src/core/file_sys/devices/console_device.h index d4b590ba0..762f3c10c 100644 --- a/src/core/devices/console_device.h +++ b/src/core/file_sys/devices/console_device.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once @@ -18,9 +18,9 @@ public: int ioctl(u64 cmd, Common::VaCtx* args) override; s64 write(const void* buf, size_t nbytes) override; - size_t readv(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) override; - size_t writev(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) override; - s64 preadv(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt, u64 offset) override; + size_t readv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) override; + size_t writev(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) override; + s64 preadv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt, u64 offset) override; s64 lseek(s64 offset, int whence) override; s64 read(void* buf, size_t nbytes) override; int fstat(Libraries::Kernel::OrbisKernelStat* sb) override; diff --git a/src/core/devices/deci_tty6_device.cpp b/src/core/file_sys/devices/deci_tty6_device.cpp similarity index 82% rename from src/core/devices/deci_tty6_device.cpp rename to src/core/file_sys/devices/deci_tty6_device.cpp index e7a5fd4fc..f61a2f177 100644 --- a/src/core/devices/deci_tty6_device.cpp +++ b/src/core/file_sys/devices/deci_tty6_device.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #include "common/logging/log.h" @@ -21,17 +21,17 @@ s64 DeciTty6Device::write(const void* buf, size_t nbytes) { return 0; } -size_t DeciTty6Device::writev(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) { +size_t DeciTty6Device::writev(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) { LOG_ERROR(Kernel_Pthread, "(STUBBED) called"); return 0; } -size_t DeciTty6Device::readv(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) { +size_t DeciTty6Device::readv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) { LOG_ERROR(Kernel_Pthread, "(STUBBED) called"); return 0; } -s64 DeciTty6Device::preadv(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt, u64 offset) { +s64 DeciTty6Device::preadv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt, u64 offset) { LOG_ERROR(Kernel_Pthread, "(STUBBED) called"); return 0; } diff --git a/src/core/devices/deci_tty6_device.h b/src/core/file_sys/devices/deci_tty6_device.h similarity index 72% rename from src/core/devices/deci_tty6_device.h rename to src/core/file_sys/devices/deci_tty6_device.h index b8bd48556..50a8a7484 100644 --- a/src/core/devices/deci_tty6_device.h +++ b/src/core/file_sys/devices/deci_tty6_device.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once @@ -18,9 +18,9 @@ public: int ioctl(u64 cmd, Common::VaCtx* args) override; s64 write(const void* buf, size_t nbytes) override; - size_t readv(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) override; - size_t writev(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) override; - s64 preadv(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt, u64 offset) override; + size_t readv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) override; + size_t writev(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) override; + s64 preadv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt, u64 offset) override; s64 lseek(s64 offset, int whence) override; s64 read(void* buf, size_t nbytes) override; int fstat(Libraries::Kernel::OrbisKernelStat* sb) override; diff --git a/src/core/devices/ioccom.h b/src/core/file_sys/devices/ioccom.h similarity index 97% rename from src/core/devices/ioccom.h rename to src/core/file_sys/devices/ioccom.h index 2ded90bd8..639d84319 100644 --- a/src/core/devices/ioccom.h +++ b/src/core/file_sys/devices/ioccom.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once diff --git a/src/core/devices/logger.cpp b/src/core/file_sys/devices/logger.cpp similarity index 91% rename from src/core/devices/logger.cpp rename to src/core/file_sys/devices/logger.cpp index 8dcb24a3b..ede8feb98 100644 --- a/src/core/devices/logger.cpp +++ b/src/core/file_sys/devices/logger.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #include "common/logging/log.h" @@ -16,7 +16,7 @@ s64 Logger::write(const void* buf, size_t nbytes) { return nbytes; } -size_t Logger::writev(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) { +size_t Logger::writev(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) { size_t total_written = 0; for (int i = 0; i < iovcnt; i++) { log(static_cast(iov[i].iov_base), iov[i].iov_len); diff --git a/src/core/devices/logger.h b/src/core/file_sys/devices/logger.h similarity index 81% rename from src/core/devices/logger.h rename to src/core/file_sys/devices/logger.h index eef17bc4b..88422b785 100644 --- a/src/core/devices/logger.h +++ b/src/core/file_sys/devices/logger.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once @@ -24,7 +24,7 @@ public: ~Logger() override; s64 write(const void* buf, size_t nbytes) override; - size_t writev(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) override; + size_t writev(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) override; s64 pwrite(const void* buf, size_t nbytes, u64 offset) override; s32 fsync() override; diff --git a/src/core/devices/nop_device.h b/src/core/file_sys/devices/nop_device.h similarity index 76% rename from src/core/devices/nop_device.h rename to src/core/file_sys/devices/nop_device.h index da9a3fc82..08fbc1523 100644 --- a/src/core/devices/nop_device.h +++ b/src/core/file_sys/devices/nop_device.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once @@ -22,15 +22,15 @@ public: return 0; } - size_t readv(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) override { + size_t readv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) override { return 0; } - size_t writev(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) override { + size_t writev(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) override { return 0; } - s64 preadv(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt, u64 offset) override { + s64 preadv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt, u64 offset) override { return 0; } diff --git a/src/core/devices/random_device.cpp b/src/core/file_sys/devices/random_device.cpp similarity index 83% rename from src/core/devices/random_device.cpp rename to src/core/file_sys/devices/random_device.cpp index b2754fe58..f5833e96a 100644 --- a/src/core/devices/random_device.cpp +++ b/src/core/file_sys/devices/random_device.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #include @@ -24,17 +24,17 @@ s64 RandomDevice::write(const void* buf, size_t nbytes) { return 0; } -size_t RandomDevice::writev(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) { +size_t RandomDevice::writev(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) { LOG_ERROR(Kernel_Pthread, "(STUBBED) called"); return 0; } -size_t RandomDevice::readv(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) { +size_t RandomDevice::readv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) { LOG_ERROR(Kernel_Pthread, "(STUBBED) called"); return 0; } -s64 RandomDevice::preadv(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt, u64 offset) { +s64 RandomDevice::preadv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt, u64 offset) { LOG_ERROR(Kernel_Pthread, "(STUBBED) called"); return 0; } diff --git a/src/core/devices/random_device.h b/src/core/file_sys/devices/random_device.h similarity index 72% rename from src/core/devices/random_device.h rename to src/core/file_sys/devices/random_device.h index a5c8e9845..d25b2a168 100644 --- a/src/core/devices/random_device.h +++ b/src/core/file_sys/devices/random_device.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once @@ -18,9 +18,9 @@ public: int ioctl(u64 cmd, Common::VaCtx* args) override; s64 write(const void* buf, size_t nbytes) override; - size_t readv(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) override; - size_t writev(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) override; - s64 preadv(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt, u64 offset) override; + size_t readv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) override; + size_t writev(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) override; + s64 preadv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt, u64 offset) override; s64 lseek(s64 offset, int whence) override; s64 read(void* buf, size_t nbytes) override; int fstat(Libraries::Kernel::OrbisKernelStat* sb) override; diff --git a/src/core/devices/srandom_device.cpp b/src/core/file_sys/devices/srandom_device.cpp similarity index 84% rename from src/core/devices/srandom_device.cpp rename to src/core/file_sys/devices/srandom_device.cpp index 5e51b1c39..dae1d7254 100644 --- a/src/core/devices/srandom_device.cpp +++ b/src/core/file_sys/devices/srandom_device.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #include @@ -24,17 +24,17 @@ s64 SRandomDevice::write(const void* buf, size_t nbytes) { return 0; } -size_t SRandomDevice::writev(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) { +size_t SRandomDevice::writev(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) { LOG_ERROR(Kernel_Pthread, "(STUBBED) called"); return 0; } -size_t SRandomDevice::readv(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) { +size_t SRandomDevice::readv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) { LOG_ERROR(Kernel_Pthread, "(STUBBED) called"); return 0; } -s64 SRandomDevice::preadv(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt, u64 offset) { +s64 SRandomDevice::preadv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt, u64 offset) { LOG_ERROR(Kernel_Pthread, "(STUBBED) called"); return 0; } diff --git a/src/core/devices/srandom_device.h b/src/core/file_sys/devices/srandom_device.h similarity index 72% rename from src/core/devices/srandom_device.h rename to src/core/file_sys/devices/srandom_device.h index cd32f7289..812367f54 100644 --- a/src/core/devices/srandom_device.h +++ b/src/core/file_sys/devices/srandom_device.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once @@ -18,9 +18,9 @@ public: int ioctl(u64 cmd, Common::VaCtx* args) override; s64 write(const void* buf, size_t nbytes) override; - size_t readv(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) override; - size_t writev(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) override; - s64 preadv(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt, u64 offset) override; + size_t readv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) override; + size_t writev(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) override; + s64 preadv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt, u64 offset) override; s64 lseek(s64 offset, int whence) override; s64 read(void* buf, size_t nbytes) override; int fstat(Libraries::Kernel::OrbisKernelStat* sb) override; diff --git a/src/core/devices/urandom_device.cpp b/src/core/file_sys/devices/urandom_device.cpp similarity index 84% rename from src/core/devices/urandom_device.cpp rename to src/core/file_sys/devices/urandom_device.cpp index 7318a6ff7..538d2b22d 100644 --- a/src/core/devices/urandom_device.cpp +++ b/src/core/file_sys/devices/urandom_device.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #include @@ -24,17 +24,17 @@ s64 URandomDevice::write(const void* buf, size_t nbytes) { return 0; } -size_t URandomDevice::writev(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) { +size_t URandomDevice::writev(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) { LOG_ERROR(Kernel_Pthread, "(STUBBED) called"); return 0; } -size_t URandomDevice::readv(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) { +size_t URandomDevice::readv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) { LOG_ERROR(Kernel_Pthread, "(STUBBED) called"); return 0; } -s64 URandomDevice::preadv(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt, u64 offset) { +s64 URandomDevice::preadv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt, u64 offset) { LOG_ERROR(Kernel_Pthread, "(STUBBED) called"); return 0; } diff --git a/src/core/devices/urandom_device.h b/src/core/file_sys/devices/urandom_device.h similarity index 72% rename from src/core/devices/urandom_device.h rename to src/core/file_sys/devices/urandom_device.h index b8a854cc0..46c1c7b33 100644 --- a/src/core/devices/urandom_device.h +++ b/src/core/file_sys/devices/urandom_device.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once @@ -18,9 +18,9 @@ public: int ioctl(u64 cmd, Common::VaCtx* args) override; s64 write(const void* buf, size_t nbytes) override; - size_t readv(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) override; - size_t writev(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) override; - s64 preadv(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt, u64 offset) override; + size_t readv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) override; + size_t writev(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) override; + s64 preadv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt, u64 offset) override; s64 lseek(s64 offset, int whence) override; s64 read(void* buf, size_t nbytes) override; int fstat(Libraries::Kernel::OrbisKernelStat* sb) override; diff --git a/src/core/file_sys/directories/base_directory.cpp b/src/core/file_sys/directories/base_directory.cpp new file mode 100644 index 000000000..c709da6a2 --- /dev/null +++ b/src/core/file_sys/directories/base_directory.cpp @@ -0,0 +1,15 @@ +// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/logging/log.h" +#include "common/singleton.h" +#include "core/file_sys/directories/base_directory.h" +#include "core/file_sys/fs.h" + +namespace Core::Directories { + +BaseDirectory::BaseDirectory() = default; + +BaseDirectory::~BaseDirectory() = default; + +} // namespace Core::Directories \ No newline at end of file diff --git a/src/core/file_sys/directories/base_directory.h b/src/core/file_sys/directories/base_directory.h new file mode 100644 index 000000000..8900ac32b --- /dev/null +++ b/src/core/file_sys/directories/base_directory.h @@ -0,0 +1,52 @@ +// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include +#include +#include "common/types.h" +#include "common/va_ctx.h" +#include "core/libraries/kernel/file_system.h" +#include "core/libraries/kernel/orbis_error.h" + +namespace Libraries::Kernel { +struct OrbisKernelStat; +struct OrbisKernelIovec; +struct OrbisKernelDirent; +} // namespace Libraries::Kernel + +namespace Core::Directories { + +class BaseDirectory { +public: + explicit BaseDirectory(); + + virtual ~BaseDirectory() = 0; + + virtual s64 read(void* buf, u64 nbytes) { + return ORBIS_KERNEL_ERROR_EBADF; + } + + virtual s64 readv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) { + return ORBIS_KERNEL_ERROR_EBADF; + } + + virtual s64 preadv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt, s64 offset) { + return ORBIS_KERNEL_ERROR_EBADF; + } + + virtual s64 lseek(s64 offset, s32 whence) { + return ORBIS_KERNEL_ERROR_EBADF; + } + + virtual s32 fstat(Libraries::Kernel::OrbisKernelStat* stat) { + return ORBIS_KERNEL_ERROR_EBADF; + } + + virtual s64 getdents(void* buf, u64 nbytes, s64* basep) { + return ORBIS_KERNEL_ERROR_EBADF; + } +}; + +} // namespace Core::Directories \ No newline at end of file diff --git a/src/core/file_sys/directories/normal_directory.cpp b/src/core/file_sys/directories/normal_directory.cpp new file mode 100644 index 000000000..a7d76074a --- /dev/null +++ b/src/core/file_sys/directories/normal_directory.cpp @@ -0,0 +1,140 @@ +// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/alignment.h" +#include "common/assert.h" +#include "common/logging/log.h" +#include "common/singleton.h" +#include "core/file_sys/directories/normal_directory.h" +#include "core/file_sys/fs.h" + +namespace Core::Directories { + +std::shared_ptr NormalDirectory::Create(std::string_view guest_directory) { + return std::static_pointer_cast( + std::make_shared(guest_directory)); +} + +NormalDirectory::NormalDirectory(std::string_view guest_directory) { + auto* mnt = Common::Singleton::Instance(); + + static s32 fileno = 0; + mnt->IterateDirectory(guest_directory, [this](const auto& ent_path, const auto ent_is_file) { + auto& dirent = dirents.emplace_back(); + dirent.d_fileno = ++fileno; + dirent.d_type = (ent_is_file ? 8 : 4); + strncpy(dirent.d_name, ent_path.filename().string().data(), MAX_LENGTH + 1); + dirent.d_namlen = ent_path.filename().string().size(); + + // Calculate the appropriate length for this dirent. + // Account for the null terminator in d_name too. + dirent.d_reclen = Common::AlignUp(sizeof(dirent.d_fileno) + sizeof(dirent.d_type) + + sizeof(dirent.d_namlen) + sizeof(dirent.d_reclen) + + (dirent.d_namlen + 1), + 4); + + directory_size += dirent.d_reclen; + }); + + // The last entry of a normal directory should have d_reclen covering the remaining data. + // Since the dirents of a folder are constant by this point, we can modify the last dirent + // before creating the emulated file buffer. + const u64 filler_count = Common::AlignUp(directory_size, DIRECTORY_ALIGNMENT) - directory_size; + dirents[dirents.size() - 1].d_reclen += filler_count; + + // Reading from standard directories seems to be based around file pointer logic. + // Keep an internal buffer representing the raw contents of this file descriptor, + // then emulate the various read functions with that. + directory_size = Common::AlignUp(directory_size, DIRECTORY_ALIGNMENT); + data_buffer.reserve(directory_size); + memset(data_buffer.data(), 0, directory_size); + + u8* current_dirent = data_buffer.data(); + for (const NormalDirectoryDirent& dirent : dirents) { + NormalDirectoryDirent* dirent_to_write = + reinterpret_cast(current_dirent); + dirent_to_write->d_fileno = dirent.d_fileno; + + // Using size d_namlen + 1 to account for null terminator. + strncpy(dirent_to_write->d_name, dirent.d_name, dirent.d_namlen + 1); + dirent_to_write->d_namlen = dirent.d_namlen; + dirent_to_write->d_reclen = dirent.d_reclen; + dirent_to_write->d_type = dirent.d_type; + + current_dirent += dirent.d_reclen; + } +} + +s64 NormalDirectory::read(void* buf, u64 nbytes) { + // Nothing left to read. + if (file_offset >= directory_size) { + return ORBIS_OK; + } + + const s64 remaining_data = directory_size - file_offset; + const s64 bytes = nbytes > remaining_data ? remaining_data : nbytes; + + std::memcpy(buf, data_buffer.data() + file_offset, bytes); + + file_offset += bytes; + return bytes; +} + +s64 NormalDirectory::readv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) { + s64 bytes_read = 0; + for (s32 i = 0; i < iovcnt; i++) { + const s64 result = read(iov[i].iov_base, iov[i].iov_len); + if (result < 0) { + return result; + } + bytes_read += result; + } + return bytes_read; +} + +s64 NormalDirectory::preadv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt, + s64 offset) { + const u64 old_file_pointer = file_offset; + file_offset = offset; + const s64 bytes_read = readv(iov, iovcnt); + file_offset = old_file_pointer; + return bytes_read; +} + +s64 NormalDirectory::lseek(s64 offset, s32 whence) { + switch (whence) { + case 0: { + file_offset = offset; + break; + } + case 1: { + file_offset += offset; + break; + } + case 2: { + file_offset = directory_size + offset; + break; + } + default: { + UNREACHABLE_MSG("lseek with unknown whence {}", whence); + } + } + return file_offset; +} + +s32 NormalDirectory::fstat(Libraries::Kernel::OrbisKernelStat* stat) { + stat->st_mode = 0000777u | 0040000u; + stat->st_size = directory_size; + stat->st_blksize = 0x8000; + stat->st_blocks = 8; + return ORBIS_OK; +} + +s64 NormalDirectory::getdents(void* buf, u64 nbytes, s64* basep) { + if (basep != nullptr) { + *basep = file_offset; + } + // read behaves identically to getdents for normal directories. + return read(buf, nbytes); +} +} // namespace Core::Directories \ No newline at end of file diff --git a/src/core/file_sys/directories/normal_directory.h b/src/core/file_sys/directories/normal_directory.h new file mode 100644 index 000000000..70e52f581 --- /dev/null +++ b/src/core/file_sys/directories/normal_directory.h @@ -0,0 +1,45 @@ +// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include +#include +#include +#include "common/types.h" +#include "core/file_sys/directories/base_directory.h" +#include "core/libraries/kernel/orbis_error.h" + +namespace Core::Directories { + +class NormalDirectory final : public BaseDirectory { +public: + static std::shared_ptr Create(std::string_view guest_path); + explicit NormalDirectory(std::string_view guest_path); + ~NormalDirectory() override = default; + + virtual s64 read(void* buf, u64 nbytes) override; + virtual s64 readv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) override; + virtual s64 preadv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt, + s64 offset) override; + virtual s64 lseek(s64 offset, s32 whence) override; + virtual s32 fstat(Libraries::Kernel::OrbisKernelStat* stat) override; + virtual s64 getdents(void* buf, u64 nbytes, s64* basep) override; + +private: + static constexpr s32 MAX_LENGTH = 255; + static constexpr s64 DIRECTORY_ALIGNMENT = 0x200; + struct NormalDirectoryDirent { + u32 d_fileno; + u16 d_reclen; + u8 d_type; + u8 d_namlen; + char d_name[MAX_LENGTH + 1]; + }; + + u64 directory_size = 0; + s64 file_offset = 0; + std::vector data_buffer; + std::vector dirents; +}; +} // namespace Core::Directories diff --git a/src/core/file_sys/directories/pfs_directory.cpp b/src/core/file_sys/directories/pfs_directory.cpp new file mode 100644 index 000000000..fbd97c019 --- /dev/null +++ b/src/core/file_sys/directories/pfs_directory.cpp @@ -0,0 +1,220 @@ +// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/alignment.h" +#include "common/assert.h" +#include "common/logging/log.h" +#include "common/singleton.h" +#include "core/file_sys/directories/pfs_directory.h" +#include "core/file_sys/fs.h" + +namespace Core::Directories { + +std::shared_ptr PfsDirectory::Create(std::string_view guest_directory) { + return std::static_pointer_cast(std::make_shared(guest_directory)); +} + +PfsDirectory::PfsDirectory(std::string_view guest_directory) { + auto* mnt = Common::Singleton::Instance(); + + static s32 fileno = 0; + mnt->IterateDirectory(guest_directory, [this](const auto& ent_path, const auto ent_is_file) { + auto& dirent = dirents.emplace_back(); + dirent.d_fileno = ++fileno; + dirent.d_type = (ent_is_file ? 8 : 4); + strncpy(dirent.d_name, ent_path.filename().string().data(), MAX_LENGTH + 1); + dirent.d_namlen = ent_path.filename().string().size(); + + // Calculate the appropriate length for this dirent. + // Account for the null terminator in d_name too. + dirent.d_reclen = Common::AlignUp(sizeof(dirent.d_fileno) + sizeof(dirent.d_type) + + sizeof(dirent.d_namlen) + sizeof(dirent.d_reclen) + + (dirent.d_namlen + 1), + 8); + + // To handle some obscure dirents_index behavior, + // keep track of the "actual" length of this directory. + directory_content_size += dirent.d_reclen; + }); + + directory_size = Common::AlignUp(directory_content_size, DIRECTORY_ALIGNMENT); +} + +s64 PfsDirectory::read(void* buf, u64 nbytes) { + if (dirents_index >= dirents.size()) { + if (dirents_index < directory_content_size) { + // We need to find the appropriate dirents_index to start from. + s64 data_to_skip = dirents_index; + u64 corrected_index = 0; + while (data_to_skip > 0) { + const auto dirent = dirents[corrected_index++]; + data_to_skip -= dirent.d_reclen; + } + dirents_index = corrected_index; + } else { + // Nothing left to read. + return ORBIS_OK; + } + } + + s64 bytes_remaining = nbytes > directory_size ? directory_size : nbytes; + // read on PfsDirectories will always return the maximum possible value. + const u64 bytes_written = bytes_remaining; + memset(buf, 0, bytes_remaining); + + char* current_dirent = static_cast(buf); + PfsDirectoryDirent dirent = dirents[dirents_index]; + while (bytes_remaining > dirent.d_reclen) { + PfsDirectoryDirent* dirent_to_write = reinterpret_cast(current_dirent); + dirent_to_write->d_fileno = dirent.d_fileno; + + // Using size d_namlen + 1 to account for null terminator. + strncpy(dirent_to_write->d_name, dirent.d_name, dirent.d_namlen + 1); + dirent_to_write->d_namlen = dirent.d_namlen; + dirent_to_write->d_reclen = dirent.d_reclen; + dirent_to_write->d_type = dirent.d_type; + + current_dirent += dirent.d_reclen; + bytes_remaining -= dirent.d_reclen; + + if (dirents_index == dirents.size() - 1) { + // Currently at the last dirent, so break out of the loop. + dirents_index++; + break; + } + dirent = dirents[++dirents_index]; + } + + return bytes_written; +} + +s64 PfsDirectory::readv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) { + s64 bytes_read = 0; + for (s32 i = 0; i < iovcnt; i++) { + const s64 result = read(iov[i].iov_base, iov[i].iov_len); + if (result < 0) { + return result; + } + bytes_read += result; + } + return bytes_read; +} + +s64 PfsDirectory::preadv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt, s64 offset) { + const u64 old_dirent_index = dirents_index; + dirents_index = 0; + s64 data_to_skip = offset; + // If offset is part-way through one dirent, that dirent is skipped. + while (data_to_skip > 0) { + const auto dirent = dirents[dirents_index++]; + data_to_skip -= dirent.d_reclen; + if (dirents_index == dirents.size()) { + // We've reached the end of the dirents, nothing more can be skipped. + break; + } + } + + const s64 bytes_read = readv(iov, iovcnt); + dirents_index = old_dirent_index; + return bytes_read; +} + +s64 PfsDirectory::lseek(s64 offset, s32 whence) { + switch (whence) { + // Seek start + case 0: { + dirents_index = 0; + } + case 1: { + // There aren't any dirents left to pass through. + if (dirents_index >= dirents.size()) { + dirents_index = dirents_index + offset; + break; + } + s64 data_to_skip = offset; + while (data_to_skip > 0) { + const auto dirent = dirents[dirents_index++]; + data_to_skip -= dirent.d_reclen; + if (dirents_index == dirents.size()) { + // We've passed through all file dirents. + // Set dirents_index to directory_size + remaining_offset instead. + dirents_index = directory_content_size + data_to_skip; + break; + } + } + break; + } + case 2: { + // Seems like real hardware gives up on tracking dirents_index if you go this route. + dirents_index = directory_size + offset; + break; + } + default: { + UNREACHABLE_MSG("lseek with unknown whence {}", whence); + } + } + + return dirents_index; +} + +s32 PfsDirectory::fstat(Libraries::Kernel::OrbisKernelStat* stat) { + stat->st_mode = 0000777u | 0040000u; + stat->st_size = directory_size; + stat->st_blksize = 0x10000; + stat->st_blocks = 0x80; + return ORBIS_OK; +} + +s64 PfsDirectory::getdents(void* buf, u64 nbytes, s64* basep) { + // basep is set at the start of the function. + if (basep != nullptr) { + *basep = dirents_index; + } + + if (dirents_index >= dirents.size()) { + if (dirents_index < directory_content_size) { + // We need to find the appropriate dirents_index to start from. + s64 data_to_skip = dirents_index; + u64 corrected_index = 0; + while (data_to_skip > 0) { + const auto dirent = dirents[corrected_index++]; + data_to_skip -= dirent.d_reclen; + } + dirents_index = corrected_index; + } else { + // Nothing left to read. + return ORBIS_OK; + } + } + + s64 bytes_remaining = nbytes > directory_size ? directory_size : nbytes; + memset(buf, 0, bytes_remaining); + + u64 bytes_written = 0; + char* current_dirent = static_cast(buf); + // getdents has to convert pfs dirents to normal dirents + PfsDirectoryDirent dirent = dirents[dirents_index]; + while (bytes_remaining > dirent.d_reclen) { + NormalDirectoryDirent* dirent_to_write = + reinterpret_cast(current_dirent); + dirent_to_write->d_fileno = dirent.d_fileno; + strncpy(dirent_to_write->d_name, dirent.d_name, dirent.d_namlen + 1); + dirent_to_write->d_namlen = dirent.d_namlen; + dirent_to_write->d_reclen = dirent.d_reclen; + dirent_to_write->d_type = dirent.d_type; + + current_dirent += dirent.d_reclen; + bytes_remaining -= dirent.d_reclen; + bytes_written += dirent.d_reclen; + + if (dirents_index == dirents.size() - 1) { + // Currently at the last dirent, so set dirents_index appropriately and break. + dirents_index = directory_size; + break; + } + dirent = dirents[++dirents_index]; + } + + return bytes_written; +} +} // namespace Core::Directories \ No newline at end of file diff --git a/src/core/file_sys/directories/pfs_directory.h b/src/core/file_sys/directories/pfs_directory.h new file mode 100644 index 000000000..8f3e8d1f5 --- /dev/null +++ b/src/core/file_sys/directories/pfs_directory.h @@ -0,0 +1,53 @@ +// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include +#include +#include +#include "common/types.h" +#include "core/file_sys/directories/base_directory.h" +#include "core/libraries/kernel/orbis_error.h" + +namespace Core::Directories { + +class PfsDirectory final : public BaseDirectory { +public: + static std::shared_ptr Create(std::string_view guest_path); + explicit PfsDirectory(std::string_view guest_path); + ~PfsDirectory() override = default; + + virtual s64 read(void* buf, u64 nbytes) override; + virtual s64 readv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) override; + virtual s64 preadv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt, + s64 offset) override; + virtual s64 lseek(s64 offset, s32 whence) override; + virtual s32 fstat(Libraries::Kernel::OrbisKernelStat* stat) override; + virtual s64 getdents(void* buf, u64 nbytes, s64* basep) override; + +private: + static constexpr s32 MAX_LENGTH = 255; + static constexpr s32 DIRECTORY_ALIGNMENT = 0x10000; + struct PfsDirectoryDirent { + u32 d_fileno; + u32 d_type; + u32 d_namlen; + u32 d_reclen; + char d_name[MAX_LENGTH + 1]; + }; + + struct NormalDirectoryDirent { + u32 d_fileno; + u16 d_reclen; + u8 d_type; + u8 d_namlen; + char d_name[MAX_LENGTH + 1]; + }; + + u64 directory_size = 0; + u64 directory_content_size = 0; + s64 dirents_index = 0; + std::vector dirents; +}; +} // namespace Core::Directories diff --git a/src/core/file_sys/file.cpp b/src/core/file_sys/file.cpp index be6bc76bb..637cbfb52 100644 --- a/src/core/file_sys/file.cpp +++ b/src/core/file_sys/file.cpp @@ -1,9 +1,8 @@ -// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #include "common/assert.h" #include "common/error.h" -#include "core/file_sys/file.h" #ifdef _WIN64 #include diff --git a/src/core/file_sys/fs.cpp b/src/core/file_sys/fs.cpp index a6d57daa8..aa9feb1cc 100644 --- a/src/core/file_sys/fs.cpp +++ b/src/core/file_sys/fs.cpp @@ -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 #include #include "common/config.h" #include "common/string_util.h" -#include "core/devices/logger.h" -#include "core/devices/nop_device.h" +#include "core/file_sys/devices/logger.h" +#include "core/file_sys/devices/nop_device.h" #include "core/file_sys/fs.h" namespace Core::FileSys { diff --git a/src/core/file_sys/fs.h b/src/core/file_sys/fs.h index a57469e70..a4dd86ff9 100644 --- a/src/core/file_sys/fs.h +++ b/src/core/file_sys/fs.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once @@ -10,7 +10,8 @@ #include #include "common/io_file.h" #include "common/logging/formatter.h" -#include "core/devices/base_device.h" +#include "core/file_sys/devices/base_device.h" +#include "core/file_sys/directories/base_directory.h" namespace Libraries::Net { struct Socket; @@ -72,11 +73,6 @@ private: std::mutex m_mutex; }; -struct DirEntry { - std::string name; - bool isFile; -}; - enum class FileType { Regular, // standard file Directory, @@ -90,11 +86,10 @@ struct File { std::filesystem::path m_host_name; std::string m_guest_name; Common::FS::IOFile f; - std::vector dirents; - u32 dirents_index; std::mutex m_mutex; - std::shared_ptr device; // only valid for type == Device - std::shared_ptr socket; // only valid for type == Socket + std::shared_ptr directory; // only valid for type == Directory + std::shared_ptr device; // only valid for type == Device + std::shared_ptr socket; // only valid for type == Socket }; class HandleTable { diff --git a/src/core/libraries/kernel/file_system.cpp b/src/core/libraries/kernel/file_system.cpp index 0a11bfc83..1b92a9b0d 100644 --- a/src/core/libraries/kernel/file_system.cpp +++ b/src/core/libraries/kernel/file_system.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #include @@ -9,13 +9,15 @@ #include "common/logging/log.h" #include "common/scope_exit.h" #include "common/singleton.h" -#include "core/devices/console_device.h" -#include "core/devices/deci_tty6_device.h" -#include "core/devices/logger.h" -#include "core/devices/nop_device.h" -#include "core/devices/random_device.h" -#include "core/devices/srandom_device.h" -#include "core/devices/urandom_device.h" +#include "core/file_sys/devices/console_device.h" +#include "core/file_sys/devices/deci_tty6_device.h" +#include "core/file_sys/devices/logger.h" +#include "core/file_sys/devices/nop_device.h" +#include "core/file_sys/devices/random_device.h" +#include "core/file_sys/devices/srandom_device.h" +#include "core/file_sys/devices/urandom_device.h" +#include "core/file_sys/directories/normal_directory.h" +#include "core/file_sys/directories/pfs_directory.h" #include "core/file_sys/fs.h" #include "core/libraries/kernel/file_system.h" #include "core/libraries/kernel/orbis_error.h" @@ -159,38 +161,28 @@ s32 PS4_SYSV_ABI open(const char* raw_path, s32 flags, u16 mode) { return -1; } - file->type = Core::FileSys::FileType::Directory; - - // Populate directory contents - mnt->IterateDirectory(file->m_guest_name, - [&file](const auto& ent_path, const auto ent_is_file) { - auto& dir_entry = file->dirents.emplace_back(); - dir_entry.name = ent_path.filename().string(); - dir_entry.isFile = ent_is_file; - }); - file->dirents_index = 0; - - if (read) { - e = file->f.Open(file->m_host_name, Common::FS::FileAccessMode::Read); - } else if (write || rdwr) { + if (write || rdwr) { // Cannot open directories with any type of write access h->DeleteHandle(handle); *__Error() = POSIX_EISDIR; return -1; } - if (e == EACCES) { - // Hack to bypass some platform limitations, ignore the error and continue as normal. - LOG_WARNING(Kernel_Fs, "Opening directories is not fully supported on this platform"); - e = 0; - } - if (truncate) { // Cannot open directories with truncate h->DeleteHandle(handle); *__Error() = POSIX_EISDIR; return -1; } + + file->type = Core::FileSys::FileType::Directory; + file->is_opened = true; + if (file->m_guest_name.starts_with("/app0")) { + // TODO: Properly identify type for paths like "/app0/.." + file->directory = Core::Directories::PfsDirectory::Create(file->m_guest_name); + } else { + file->directory = Core::Directories::NormalDirectory::Create(file->m_guest_name); + } } else { file->type = Core::FileSys::FileType::Regular; @@ -289,7 +281,7 @@ s32 PS4_SYSV_ABI sceKernelClose(s32 fd) { return result; } -s64 PS4_SYSV_ABI write(s32 fd, const void* buf, size_t nbytes) { +s64 PS4_SYSV_ABI write(s32 fd, const void* buf, u64 nbytes) { auto* h = Common::Singleton::Instance(); auto* file = h->GetFile(fd); if (file == nullptr) { @@ -313,11 +305,11 @@ s64 PS4_SYSV_ABI write(s32 fd, const void* buf, size_t nbytes) { return file->f.WriteRaw(buf, nbytes); } -s64 PS4_SYSV_ABI posix_write(s32 fd, const void* buf, size_t nbytes) { +s64 PS4_SYSV_ABI posix_write(s32 fd, const void* buf, u64 nbytes) { return write(fd, buf, nbytes); } -s64 PS4_SYSV_ABI sceKernelWrite(s32 fd, const void* buf, size_t nbytes) { +s64 PS4_SYSV_ABI sceKernelWrite(s32 fd, const void* buf, u64 nbytes) { s64 result = write(fd, buf, nbytes); if (result < 0) { LOG_ERROR(Kernel_Fs, "error = {}", *__Error()); @@ -326,7 +318,7 @@ s64 PS4_SYSV_ABI sceKernelWrite(s32 fd, const void* buf, size_t nbytes) { return result; } -size_t ReadFile(Common::FS::IOFile& file, void* buf, size_t nbytes) { +s64 ReadFile(Common::FS::IOFile& file, void* buf, u64 nbytes) { const auto* memory = Core::Memory::Instance(); // Invalidate up to the actual number of bytes that could be read. const auto remaining = file.GetSize() - file.Tell(); @@ -335,7 +327,7 @@ size_t ReadFile(Common::FS::IOFile& file, void* buf, size_t nbytes) { return file.ReadRaw(buf, nbytes); } -size_t PS4_SYSV_ABI readv(s32 fd, const SceKernelIovec* iov, s32 iovcnt) { +s64 PS4_SYSV_ABI readv(s32 fd, const OrbisKernelIovec* iov, s32 iovcnt) { auto* h = Common::Singleton::Instance(); auto* file = h->GetFile(fd); if (file == nullptr) { @@ -345,26 +337,33 @@ size_t PS4_SYSV_ABI readv(s32 fd, const SceKernelIovec* iov, s32 iovcnt) { std::scoped_lock lk{file->m_mutex}; if (file->type == Core::FileSys::FileType::Device) { - size_t result = file->device->readv(iov, iovcnt); + s64 result = file->device->readv(iov, iovcnt); + if (result < 0) { + ErrSceToPosix(result); + return -1; + } + return result; + } else if (file->type == Core::FileSys::FileType::Directory) { + s64 result = file->directory->readv(iov, iovcnt); if (result < 0) { ErrSceToPosix(result); return -1; } return result; } - size_t total_read = 0; + s64 total_read = 0; for (s32 i = 0; i < iovcnt; i++) { total_read += ReadFile(file->f, iov[i].iov_base, iov[i].iov_len); } return total_read; } -size_t PS4_SYSV_ABI posix_readv(s32 fd, const SceKernelIovec* iov, s32 iovcnt) { +s64 PS4_SYSV_ABI posix_readv(s32 fd, const OrbisKernelIovec* iov, s32 iovcnt) { return readv(fd, iov, iovcnt); } -size_t PS4_SYSV_ABI sceKernelReadv(s32 fd, const SceKernelIovec* iov, s32 iovcnt) { - size_t result = readv(fd, iov, iovcnt); +s64 PS4_SYSV_ABI sceKernelReadv(s32 fd, const OrbisKernelIovec* iov, s32 iovcnt) { + s64 result = readv(fd, iov, iovcnt); if (result < 0) { LOG_ERROR(Kernel_Fs, "error = {}", *__Error()); return ErrnoToSceKernelError(*__Error()); @@ -372,7 +371,7 @@ size_t PS4_SYSV_ABI sceKernelReadv(s32 fd, const SceKernelIovec* iov, s32 iovcnt return result; } -size_t PS4_SYSV_ABI writev(s32 fd, const SceKernelIovec* iov, s32 iovcnt) { +s64 PS4_SYSV_ABI writev(s32 fd, const OrbisKernelIovec* iov, s32 iovcnt) { auto* h = Common::Singleton::Instance(); auto* file = h->GetFile(fd); if (file == nullptr) { @@ -383,26 +382,26 @@ size_t PS4_SYSV_ABI writev(s32 fd, const SceKernelIovec* iov, s32 iovcnt) { std::scoped_lock lk{file->m_mutex}; if (file->type == Core::FileSys::FileType::Device) { - size_t result = file->device->writev(iov, iovcnt); + s64 result = file->device->writev(iov, iovcnt); if (result < 0) { ErrSceToPosix(result); return -1; } return result; } - size_t total_written = 0; + s64 total_written = 0; for (s32 i = 0; i < iovcnt; i++) { total_written += file->f.WriteRaw(iov[i].iov_base, iov[i].iov_len); } return total_written; } -size_t PS4_SYSV_ABI posix_writev(s32 fd, const SceKernelIovec* iov, s32 iovcnt) { +s64 PS4_SYSV_ABI posix_writev(s32 fd, const OrbisKernelIovec* iov, s32 iovcnt) { return writev(fd, iov, iovcnt); } -size_t PS4_SYSV_ABI sceKernelWritev(s32 fd, const SceKernelIovec* iov, s32 iovcnt) { - size_t result = writev(fd, iov, iovcnt); +s64 PS4_SYSV_ABI sceKernelWritev(s32 fd, const OrbisKernelIovec* iov, s32 iovcnt) { + s64 result = writev(fd, iov, iovcnt); if (result < 0) { LOG_ERROR(Kernel_Fs, "error = {}", *__Error()); return ErrnoToSceKernelError(*__Error()); @@ -426,6 +425,13 @@ s64 PS4_SYSV_ABI posix_lseek(s32 fd, s64 offset, s32 whence) { return -1; } return result; + } else if (file->type == Core::FileSys::FileType::Directory) { + s64 result = file->directory->lseek(offset, whence); + if (result < 0) { + ErrSceToPosix(result); + return -1; + } + return result; } Common::FS::SeekOrigin origin{}; @@ -473,7 +479,7 @@ s64 PS4_SYSV_ABI sceKernelLseek(s32 fd, s64 offset, s32 whence) { return result; } -s64 PS4_SYSV_ABI read(s32 fd, void* buf, size_t nbytes) { +s64 PS4_SYSV_ABI read(s32 fd, void* buf, u64 nbytes) { auto* h = Common::Singleton::Instance(); auto* file = h->GetFile(fd); if (file == nullptr) { @@ -489,6 +495,13 @@ s64 PS4_SYSV_ABI read(s32 fd, void* buf, size_t nbytes) { return -1; } return result; + } else if (file->type == Core::FileSys::FileType::Directory) { + s64 result = file->directory->read(buf, nbytes); + if (result < 0) { + ErrSceToPosix(result); + return -1; + } + return result; } else if (file->type == Core::FileSys::FileType::Socket) { // Socket functions handle errnos internally. return file->socket->ReceivePacket(buf, nbytes, 0, nullptr, 0); @@ -496,11 +509,11 @@ s64 PS4_SYSV_ABI read(s32 fd, void* buf, size_t nbytes) { return ReadFile(file->f, buf, nbytes); } -s64 PS4_SYSV_ABI posix_read(s32 fd, void* buf, size_t nbytes) { +s64 PS4_SYSV_ABI posix_read(s32 fd, void* buf, u64 nbytes) { return read(fd, buf, nbytes); } -s64 PS4_SYSV_ABI sceKernelRead(s32 fd, void* buf, size_t nbytes) { +s64 PS4_SYSV_ABI sceKernelRead(s32 fd, void* buf, u64 nbytes) { s64 result = read(fd, buf, nbytes); if (result < 0) { LOG_ERROR(Kernel_Fs, "error = {}", *__Error()); @@ -594,7 +607,7 @@ s32 PS4_SYSV_ABI sceKernelRmdir(const char* path) { } s32 PS4_SYSV_ABI posix_stat(const char* path, OrbisKernelStat* sb) { - LOG_INFO(Kernel_Fs, "(PARTIAL) path = {}", path); + LOG_DEBUG(Kernel_Fs, "(PARTIAL) path = {}", path); auto* mnt = Common::Singleton::Instance(); const auto path_name = mnt->GetHostPath(path); std::memset(sb, 0, sizeof(OrbisKernelStat)); @@ -646,7 +659,7 @@ s32 PS4_SYSV_ABI sceKernelCheckReachability(const char* path) { } s32 PS4_SYSV_ABI fstat(s32 fd, OrbisKernelStat* sb) { - LOG_INFO(Kernel_Fs, "(PARTIAL) fd = {}", fd); + LOG_DEBUG(Kernel_Fs, "(PARTIAL) fd = {}", fd); if (sb == nullptr) { *__Error() = POSIX_EFAULT; return -1; @@ -677,12 +690,12 @@ s32 PS4_SYSV_ABI fstat(s32 fd, OrbisKernelStat* sb) { break; } case Core::FileSys::FileType::Directory: { - sb->st_mode = 0000777u | 0040000u; - sb->st_size = 65536; - sb->st_blksize = 65536; - sb->st_blocks = 128; - // TODO incomplete - break; + s32 result = file->directory->fstat(sb); + if (result < 0) { + ErrSceToPosix(result); + return -1; + } + return result; } case Core::FileSys::FileType::Socket: { // Socket functions handle errnos internally @@ -804,7 +817,7 @@ s32 PS4_SYSV_ABI sceKernelRename(const char* from, const char* to) { return result; } -s64 PS4_SYSV_ABI posix_preadv(s32 fd, SceKernelIovec* iov, s32 iovcnt, s64 offset) { +s64 PS4_SYSV_ABI posix_preadv(s32 fd, OrbisKernelIovec* iov, s32 iovcnt, s64 offset) { if (offset < 0) { *__Error() = POSIX_EINVAL; return -1; @@ -825,6 +838,13 @@ s64 PS4_SYSV_ABI posix_preadv(s32 fd, SceKernelIovec* iov, s32 iovcnt, s64 offse return -1; } return result; + } else if (file->type == Core::FileSys::FileType::Directory) { + s64 result = file->directory->preadv(iov, iovcnt, offset); + if (result < 0) { + ErrSceToPosix(result); + return -1; + } + return result; } const s64 pos = file->f.Tell(); @@ -835,14 +855,14 @@ s64 PS4_SYSV_ABI posix_preadv(s32 fd, SceKernelIovec* iov, s32 iovcnt, s64 offse *__Error() = POSIX_EIO; return -1; } - size_t total_read = 0; - for (int i = 0; i < iovcnt; i++) { + s64 total_read = 0; + for (s32 i = 0; i < iovcnt; i++) { total_read += ReadFile(file->f, iov[i].iov_base, iov[i].iov_len); } return total_read; } -s64 PS4_SYSV_ABI sceKernelPreadv(s32 fd, SceKernelIovec* iov, s32 iovcnt, s64 offset) { +s64 PS4_SYSV_ABI sceKernelPreadv(s32 fd, OrbisKernelIovec* iov, s32 iovcnt, s64 offset) { s64 result = posix_preadv(fd, iov, iovcnt, offset); if (result < 0) { LOG_ERROR(Kernel_Fs, "error = {}", *__Error()); @@ -851,13 +871,13 @@ s64 PS4_SYSV_ABI sceKernelPreadv(s32 fd, SceKernelIovec* iov, s32 iovcnt, s64 of return result; } -s64 PS4_SYSV_ABI posix_pread(s32 fd, void* buf, size_t nbytes, s64 offset) { - SceKernelIovec iovec{buf, nbytes}; +s64 PS4_SYSV_ABI posix_pread(s32 fd, void* buf, u64 nbytes, s64 offset) { + OrbisKernelIovec iovec{buf, nbytes}; return posix_preadv(fd, &iovec, 1, offset); } -s64 PS4_SYSV_ABI sceKernelPread(s32 fd, void* buf, size_t nbytes, s64 offset) { - SceKernelIovec iovec{buf, nbytes}; +s64 PS4_SYSV_ABI sceKernelPread(s32 fd, void* buf, u64 nbytes, s64 offset) { + OrbisKernelIovec iovec{buf, nbytes}; return sceKernelPreadv(fd, &iovec, 1, offset); } @@ -902,50 +922,36 @@ static s64 GetDents(s32 fd, char* buf, u64 nbytes, s64* basep) { return -1; } - if (file->type == Core::FileSys::FileType::Device) { - s32 result = file->device->getdents(buf, nbytes, basep); + if (nbytes < 512) { + *__Error() = POSIX_EINVAL; + return -1; + } + + switch (file->type) { + case Core::FileSys::FileType::Directory: { + s64 result = file->directory->getdents(buf, nbytes, basep); if (result < 0) { ErrSceToPosix(result); return -1; } return result; } - - if (file->type != Core::FileSys::FileType::Directory || nbytes < 512 || - file->dirents_index > file->dirents.size()) { + case Core::FileSys::FileType::Device: { + s64 result = file->device->getdents(buf, nbytes, basep); + if (result < 0) { + ErrSceToPosix(result); + return -1; + } + return result; + } + default: { + // Not directory or device *__Error() = POSIX_EINVAL; return -1; } - - s64 bytes_to_write = nbytes; - char* buf_to_write = buf; - u64 bytes_written = 0; - while (bytes_to_write >= sizeof(OrbisKernelDirent)) { - if (file->dirents_index == file->dirents.size()) { - break; - } - const auto& entry = file->dirents.at(file->dirents_index++); - auto str = entry.name; - static int fileno = 1000; // random - OrbisKernelDirent* sce_ent = (OrbisKernelDirent*)buf_to_write; - // TODO this should be unique, maybe switch to a hash or something? - sce_ent->d_fileno = fileno++; - sce_ent->d_reclen = sizeof(OrbisKernelDirent); - sce_ent->d_type = (entry.isFile ? 8 : 4); - sce_ent->d_namlen = str.size(); - strncpy(sce_ent->d_name, str.c_str(), ORBIS_MAX_PATH); - sce_ent->d_name[ORBIS_MAX_PATH] = '\0'; - - buf_to_write += sizeof(OrbisKernelDirent); - bytes_to_write -= sizeof(OrbisKernelDirent); - bytes_written += sizeof(OrbisKernelDirent); } - if (basep != nullptr) { - *basep = file->dirents_index; - } - - return bytes_written; + return ORBIS_OK; } s64 PS4_SYSV_ABI posix_getdents(s32 fd, char* buf, u64 nbytes) { @@ -978,7 +984,7 @@ s64 PS4_SYSV_ABI sceKernelGetdirentries(s32 fd, char* buf, u64 nbytes, s64* base return result; } -s64 PS4_SYSV_ABI posix_pwritev(s32 fd, const SceKernelIovec* iov, s32 iovcnt, s64 offset) { +s64 PS4_SYSV_ABI posix_pwritev(s32 fd, const OrbisKernelIovec* iov, s32 iovcnt, s64 offset) { if (offset < 0) { *__Error() = POSIX_EINVAL; return -1; @@ -1009,19 +1015,19 @@ s64 PS4_SYSV_ABI posix_pwritev(s32 fd, const SceKernelIovec* iov, s32 iovcnt, s6 *__Error() = POSIX_EIO; return -1; } - size_t total_written = 0; - for (int i = 0; i < iovcnt; i++) { + s64 total_written = 0; + for (s32 i = 0; i < iovcnt; i++) { total_written += file->f.WriteRaw(iov[i].iov_base, iov[i].iov_len); } return total_written; } -s64 PS4_SYSV_ABI posix_pwrite(s32 fd, void* buf, size_t nbytes, s64 offset) { - SceKernelIovec iovec{buf, nbytes}; +s64 PS4_SYSV_ABI posix_pwrite(s32 fd, void* buf, u64 nbytes, s64 offset) { + OrbisKernelIovec iovec{buf, nbytes}; return posix_pwritev(fd, &iovec, 1, offset); } -s64 PS4_SYSV_ABI sceKernelPwrite(s32 fd, void* buf, size_t nbytes, s64 offset) { +s64 PS4_SYSV_ABI sceKernelPwrite(s32 fd, void* buf, u64 nbytes, s64 offset) { s64 result = posix_pwrite(fd, buf, nbytes, offset); if (result < 0) { LOG_ERROR(Kernel_Fs, "error = {}", *__Error()); @@ -1030,7 +1036,7 @@ s64 PS4_SYSV_ABI sceKernelPwrite(s32 fd, void* buf, size_t nbytes, s64 offset) { return result; } -s64 PS4_SYSV_ABI sceKernelPwritev(s32 fd, const SceKernelIovec* iov, s32 iovcnt, s64 offset) { +s64 PS4_SYSV_ABI sceKernelPwritev(s32 fd, const OrbisKernelIovec* iov, s32 iovcnt, s64 offset) { s64 result = posix_pwritev(fd, iov, iovcnt, offset); if (result < 0) { LOG_ERROR(Kernel_Fs, "error = {}", *__Error()); diff --git a/src/core/libraries/kernel/file_system.h b/src/core/libraries/kernel/file_system.h index 77ce3ec3d..507f0952c 100644 --- a/src/core/libraries/kernel/file_system.h +++ b/src/core/libraries/kernel/file_system.h @@ -14,7 +14,7 @@ namespace Libraries::Kernel { constexpr int ORBIS_MAX_PATH = 255; -struct SceKernelIovec { +struct OrbisKernelIovec { void* iov_base; std::size_t iov_len; }; @@ -65,10 +65,10 @@ constexpr int ORBIS_KERNEL_O_DSYNC = 0x1000; constexpr int ORBIS_KERNEL_O_DIRECT = 0x00010000; constexpr int ORBIS_KERNEL_O_DIRECTORY = 0x00020000; -s64 PS4_SYSV_ABI sceKernelWrite(s32 fd, const void* buf, size_t nbytes); -s64 PS4_SYSV_ABI sceKernelRead(s32 fd, void* buf, size_t nbytes); -s64 PS4_SYSV_ABI sceKernelPread(s32 fd, void* buf, size_t nbytes, s64 offset); -s64 PS4_SYSV_ABI sceKernelPwrite(s32 fd, void* buf, size_t nbytes, s64 offset); +s64 PS4_SYSV_ABI sceKernelWrite(s32 fd, const void* buf, u64 nbytes); +s64 PS4_SYSV_ABI sceKernelRead(s32 fd, void* buf, u64 nbytes); +s64 PS4_SYSV_ABI sceKernelPread(s32 fd, void* buf, u64 nbytes, s64 offset); +s64 PS4_SYSV_ABI sceKernelPwrite(s32 fd, void* buf, u64 nbytes, s64 offset); void RegisterFileSystem(Core::Loader::SymbolsResolver* sym); } // namespace Libraries::Kernel