mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-12-09 13:19:00 +00:00
Filesystem: Abstract handling of directory files (#3455)
* Rename SceKernelIovec to OrbisKernelIovec Fixes the naming scheme to match the rest of the project. * Type fixups Noticed this while working on the actual thing this PR is about. * More type fixups * Update file_system.cpp * Abstract directory handling * Clang * Directory fstat * Fix dirent loading logic * PfsDirectory size Seemed to be hardcoded when I ran tests, so I've hardcoded it here. Also fixed up the reclen-aligning logic based on hardware observations. * GetDents cleanup Bring back the bytes < 512 error return from before, as that's still something that can be checked for out here. I've also swapped the file type stuff to run from a switch case, so that the check for invalid file type can be used as the default case * Support reading directories * getdents For PfsDirectory, getdents behaves like read does on normal directories. Since dirents are stored internally with a different struct, this means getdents has to convert the dirents before returning data. For NormalDirectory, getdents is identical to read, so it can just call read and set the basep output. * Directory readv * Directory preadv Since the file mutex is locked before these calls, messing with dirents_index like this shouldn't cause any weird side effects. * return ORBIS_OK instead of 0 to better align with our coding standards. * Directory lseek * Un-modify CMakePresets.json I keep this modified locally for Linux, but accidentally pushed it. * Clang * Fix mac compile * Potential windows compile fix? * Filename fix * Fix normal directory d_reclen * Comment cleanup * Remove unnecessary dirent conversion logic On real hardware, the records are still returned with the same reclen, despite the change in structure. * PfsDirectory dirents_index fixes Some weird stuff happens once you reach eof on directories. Thankfully, PfsDirectories are rather tame in this regard. * Change comment * Rewrite normal directory reads The logic for these seems to behave like a normal file, so instead of tracking a dirents_index, keep an internal buffer representing the file contents, and copy that to output buffers as needed. * Update pfs_directory.cpp * Clang * Fix normal dirents When rewriting the code, I forgot to account for the increased reclen value for the last dirent in the buffer. * PfsDirectory::lseek fixes Based on some additional tests, it seems like lseek unconditionally returns dirents_index, not the actual file position. Also fixed some bugs with the logic for calculating the proper offset when games do wonky things, and fixed a potential area where games could crash. * Downgrade stat and fstat log to debug These functions can get pretty spammy. * PfsDirectory: Properly track if end of file is reached Using the metric `dirents_index < directory_content_size` fails when `directory_content_size` is larger than the actual directory size we report. Since, from what I can tell, PfsDirectories shouldn't ever report more than 0x10000 bytes for size, this change is necessary. * Revert "PfsDirectory: Properly track if end of file is reached" I need to do some hardware tests to see if all this excess logic is actually necessary. * Fix PfsDirectory directory_size Turns out, if your game has over 1000 files in a folder, it will actually cause the size to increase. * Update copyright date * Move devices and directories into file_sys I've also updated the copyright dates on all these files. * C++ style type casts * Remove unnecessary memset * Use a vector for the data buffer Simplifies logic for freeing the buffer, based on review suggestions. * Fix potential oob array access * Change type casts in Create function * Clang * std::memcpy instead of memcpy * NormalDirectory::lseek cleanup * Create constants for directory alignment values. * Use const wherever possible * Includes cleanup
This commit is contained in:
@@ -747,22 +747,28 @@ set(CORE src/core/aerolib/stubs.cpp
|
|||||||
src/core/aerolib/aerolib.h
|
src/core/aerolib/aerolib.h
|
||||||
src/core/address_space.cpp
|
src/core/address_space.cpp
|
||||||
src/core/address_space.h
|
src/core/address_space.h
|
||||||
src/core/devices/base_device.cpp
|
src/core/file_sys/devices/base_device.cpp
|
||||||
src/core/devices/base_device.h
|
src/core/file_sys/devices/base_device.h
|
||||||
src/core/devices/ioccom.h
|
src/core/file_sys/devices/ioccom.h
|
||||||
src/core/devices/logger.cpp
|
src/core/file_sys/devices/logger.cpp
|
||||||
src/core/devices/logger.h
|
src/core/file_sys/devices/logger.h
|
||||||
src/core/devices/nop_device.h
|
src/core/file_sys/devices/nop_device.h
|
||||||
src/core/devices/console_device.cpp
|
src/core/file_sys/devices/console_device.cpp
|
||||||
src/core/devices/console_device.h
|
src/core/file_sys/devices/console_device.h
|
||||||
src/core/devices/deci_tty6_device.cpp
|
src/core/file_sys/devices/deci_tty6_device.cpp
|
||||||
src/core/devices/deci_tty6_device.h
|
src/core/file_sys/devices/deci_tty6_device.h
|
||||||
src/core/devices/random_device.cpp
|
src/core/file_sys/devices/random_device.cpp
|
||||||
src/core/devices/random_device.h
|
src/core/file_sys/devices/random_device.h
|
||||||
src/core/devices/urandom_device.cpp
|
src/core/file_sys/devices/urandom_device.cpp
|
||||||
src/core/devices/urandom_device.h
|
src/core/file_sys/devices/urandom_device.h
|
||||||
src/core/devices/srandom_device.cpp
|
src/core/file_sys/devices/srandom_device.cpp
|
||||||
src/core/devices/srandom_device.h
|
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/pfs.h
|
||||||
src/core/file_format/psf.cpp
|
src/core/file_format/psf.cpp
|
||||||
src/core/file_format/psf.h
|
src/core/file_format/psf.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
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include "base_device.h"
|
#include "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
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
namespace Libraries::Kernel {
|
namespace Libraries::Kernel {
|
||||||
struct OrbisKernelStat;
|
struct OrbisKernelStat;
|
||||||
struct SceKernelIovec;
|
struct OrbisKernelIovec;
|
||||||
} // namespace Libraries::Kernel
|
} // namespace Libraries::Kernel
|
||||||
|
|
||||||
namespace Core::Devices {
|
namespace Core::Devices {
|
||||||
@@ -28,19 +28,19 @@ public:
|
|||||||
return ORBIS_KERNEL_ERROR_EBADF;
|
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;
|
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;
|
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;
|
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;
|
return ORBIS_KERNEL_ERROR_EBADF;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -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
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
@@ -21,17 +21,17 @@ s64 ConsoleDevice::write(const void* buf, size_t nbytes) {
|
|||||||
return 0;
|
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");
|
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||||
return 0;
|
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");
|
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||||
return 0;
|
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");
|
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -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
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
@@ -18,9 +18,9 @@ public:
|
|||||||
|
|
||||||
int ioctl(u64 cmd, Common::VaCtx* args) override;
|
int ioctl(u64 cmd, Common::VaCtx* args) override;
|
||||||
s64 write(const void* buf, size_t nbytes) override;
|
s64 write(const void* buf, size_t nbytes) override;
|
||||||
size_t readv(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) override;
|
size_t readv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) override;
|
||||||
size_t writev(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) override;
|
size_t writev(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) override;
|
||||||
s64 preadv(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt, u64 offset) override;
|
s64 preadv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt, u64 offset) override;
|
||||||
s64 lseek(s64 offset, int whence) override;
|
s64 lseek(s64 offset, int whence) override;
|
||||||
s64 read(void* buf, size_t nbytes) override;
|
s64 read(void* buf, size_t nbytes) override;
|
||||||
int fstat(Libraries::Kernel::OrbisKernelStat* sb) override;
|
int fstat(Libraries::Kernel::OrbisKernelStat* sb) override;
|
||||||
@@ -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
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
@@ -21,17 +21,17 @@ s64 DeciTty6Device::write(const void* buf, size_t nbytes) {
|
|||||||
return 0;
|
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");
|
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||||
return 0;
|
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");
|
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||||
return 0;
|
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");
|
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -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
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
@@ -18,9 +18,9 @@ public:
|
|||||||
|
|
||||||
int ioctl(u64 cmd, Common::VaCtx* args) override;
|
int ioctl(u64 cmd, Common::VaCtx* args) override;
|
||||||
s64 write(const void* buf, size_t nbytes) override;
|
s64 write(const void* buf, size_t nbytes) override;
|
||||||
size_t readv(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) override;
|
size_t readv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) override;
|
||||||
size_t writev(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) override;
|
size_t writev(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) override;
|
||||||
s64 preadv(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt, u64 offset) override;
|
s64 preadv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt, u64 offset) override;
|
||||||
s64 lseek(s64 offset, int whence) override;
|
s64 lseek(s64 offset, int whence) override;
|
||||||
s64 read(void* buf, size_t nbytes) override;
|
s64 read(void* buf, size_t nbytes) override;
|
||||||
int fstat(Libraries::Kernel::OrbisKernelStat* sb) override;
|
int fstat(Libraries::Kernel::OrbisKernelStat* sb) override;
|
||||||
@@ -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
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
@@ -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
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
@@ -16,7 +16,7 @@ s64 Logger::write(const void* buf, size_t nbytes) {
|
|||||||
return 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;
|
size_t total_written = 0;
|
||||||
for (int i = 0; i < iovcnt; i++) {
|
for (int i = 0; i < iovcnt; i++) {
|
||||||
log(static_cast<const char*>(iov[i].iov_base), iov[i].iov_len);
|
log(static_cast<const char*>(iov[i].iov_base), iov[i].iov_len);
|
||||||
@@ -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
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
@@ -24,7 +24,7 @@ public:
|
|||||||
~Logger() override;
|
~Logger() override;
|
||||||
|
|
||||||
s64 write(const void* buf, size_t nbytes) 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;
|
s64 pwrite(const void* buf, size_t nbytes, u64 offset) override;
|
||||||
|
|
||||||
s32 fsync() override;
|
s32 fsync() override;
|
||||||
@@ -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
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
@@ -22,15 +22,15 @@ public:
|
|||||||
return 0;
|
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;
|
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;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -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
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
@@ -24,17 +24,17 @@ s64 RandomDevice::write(const void* buf, size_t nbytes) {
|
|||||||
return 0;
|
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");
|
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||||
return 0;
|
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");
|
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||||
return 0;
|
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");
|
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -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
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
@@ -18,9 +18,9 @@ public:
|
|||||||
|
|
||||||
int ioctl(u64 cmd, Common::VaCtx* args) override;
|
int ioctl(u64 cmd, Common::VaCtx* args) override;
|
||||||
s64 write(const void* buf, size_t nbytes) override;
|
s64 write(const void* buf, size_t nbytes) override;
|
||||||
size_t readv(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) override;
|
size_t readv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) override;
|
||||||
size_t writev(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) override;
|
size_t writev(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) override;
|
||||||
s64 preadv(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt, u64 offset) override;
|
s64 preadv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt, u64 offset) override;
|
||||||
s64 lseek(s64 offset, int whence) override;
|
s64 lseek(s64 offset, int whence) override;
|
||||||
s64 read(void* buf, size_t nbytes) override;
|
s64 read(void* buf, size_t nbytes) override;
|
||||||
int fstat(Libraries::Kernel::OrbisKernelStat* sb) override;
|
int fstat(Libraries::Kernel::OrbisKernelStat* sb) override;
|
||||||
@@ -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
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
@@ -24,17 +24,17 @@ s64 SRandomDevice::write(const void* buf, size_t nbytes) {
|
|||||||
return 0;
|
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");
|
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||||
return 0;
|
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");
|
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||||
return 0;
|
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");
|
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -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
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
@@ -18,9 +18,9 @@ public:
|
|||||||
|
|
||||||
int ioctl(u64 cmd, Common::VaCtx* args) override;
|
int ioctl(u64 cmd, Common::VaCtx* args) override;
|
||||||
s64 write(const void* buf, size_t nbytes) override;
|
s64 write(const void* buf, size_t nbytes) override;
|
||||||
size_t readv(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) override;
|
size_t readv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) override;
|
||||||
size_t writev(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) override;
|
size_t writev(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) override;
|
||||||
s64 preadv(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt, u64 offset) override;
|
s64 preadv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt, u64 offset) override;
|
||||||
s64 lseek(s64 offset, int whence) override;
|
s64 lseek(s64 offset, int whence) override;
|
||||||
s64 read(void* buf, size_t nbytes) override;
|
s64 read(void* buf, size_t nbytes) override;
|
||||||
int fstat(Libraries::Kernel::OrbisKernelStat* sb) override;
|
int fstat(Libraries::Kernel::OrbisKernelStat* sb) override;
|
||||||
@@ -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
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
@@ -24,17 +24,17 @@ s64 URandomDevice::write(const void* buf, size_t nbytes) {
|
|||||||
return 0;
|
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");
|
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||||
return 0;
|
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");
|
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||||
return 0;
|
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");
|
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -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
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
@@ -18,9 +18,9 @@ public:
|
|||||||
|
|
||||||
int ioctl(u64 cmd, Common::VaCtx* args) override;
|
int ioctl(u64 cmd, Common::VaCtx* args) override;
|
||||||
s64 write(const void* buf, size_t nbytes) override;
|
s64 write(const void* buf, size_t nbytes) override;
|
||||||
size_t readv(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) override;
|
size_t readv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) override;
|
||||||
size_t writev(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) override;
|
size_t writev(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) override;
|
||||||
s64 preadv(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt, u64 offset) override;
|
s64 preadv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt, u64 offset) override;
|
||||||
s64 lseek(s64 offset, int whence) override;
|
s64 lseek(s64 offset, int whence) override;
|
||||||
s64 read(void* buf, size_t nbytes) override;
|
s64 read(void* buf, size_t nbytes) override;
|
||||||
int fstat(Libraries::Kernel::OrbisKernelStat* sb) override;
|
int fstat(Libraries::Kernel::OrbisKernelStat* sb) override;
|
||||||
15
src/core/file_sys/directories/base_directory.cpp
Normal file
15
src/core/file_sys/directories/base_directory.cpp
Normal file
@@ -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
|
||||||
52
src/core/file_sys/directories/base_directory.h
Normal file
52
src/core/file_sys/directories/base_directory.h
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string_view>
|
||||||
|
#include <vector>
|
||||||
|
#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
|
||||||
140
src/core/file_sys/directories/normal_directory.cpp
Normal file
140
src/core/file_sys/directories/normal_directory.cpp
Normal file
@@ -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<BaseDirectory> NormalDirectory::Create(std::string_view guest_directory) {
|
||||||
|
return std::static_pointer_cast<BaseDirectory>(
|
||||||
|
std::make_shared<NormalDirectory>(guest_directory));
|
||||||
|
}
|
||||||
|
|
||||||
|
NormalDirectory::NormalDirectory(std::string_view guest_directory) {
|
||||||
|
auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::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<NormalDirectoryDirent*>(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
|
||||||
45
src/core/file_sys/directories/normal_directory.h
Normal file
45
src/core/file_sys/directories/normal_directory.h
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <string_view>
|
||||||
|
#include <vector>
|
||||||
|
#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<BaseDirectory> 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<u8> data_buffer;
|
||||||
|
std::vector<NormalDirectoryDirent> dirents;
|
||||||
|
};
|
||||||
|
} // namespace Core::Directories
|
||||||
220
src/core/file_sys/directories/pfs_directory.cpp
Normal file
220
src/core/file_sys/directories/pfs_directory.cpp
Normal file
@@ -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<BaseDirectory> PfsDirectory::Create(std::string_view guest_directory) {
|
||||||
|
return std::static_pointer_cast<BaseDirectory>(std::make_shared<PfsDirectory>(guest_directory));
|
||||||
|
}
|
||||||
|
|
||||||
|
PfsDirectory::PfsDirectory(std::string_view guest_directory) {
|
||||||
|
auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::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<char*>(buf);
|
||||||
|
PfsDirectoryDirent dirent = dirents[dirents_index];
|
||||||
|
while (bytes_remaining > dirent.d_reclen) {
|
||||||
|
PfsDirectoryDirent* dirent_to_write = reinterpret_cast<PfsDirectoryDirent*>(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<char*>(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<NormalDirectoryDirent*>(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
|
||||||
53
src/core/file_sys/directories/pfs_directory.h
Normal file
53
src/core/file_sys/directories/pfs_directory.h
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <string_view>
|
||||||
|
#include <vector>
|
||||||
|
#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<BaseDirectory> 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<PfsDirectoryDirent> dirents;
|
||||||
|
};
|
||||||
|
} // namespace Core::Directories
|
||||||
@@ -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
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/error.h"
|
#include "common/error.h"
|
||||||
#include "core/file_sys/file.h"
|
|
||||||
|
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
#include <io.h>
|
#include <io.h>
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include "common/config.h"
|
#include "common/config.h"
|
||||||
#include "common/string_util.h"
|
#include "common/string_util.h"
|
||||||
#include "core/devices/logger.h"
|
#include "core/file_sys/devices/logger.h"
|
||||||
#include "core/devices/nop_device.h"
|
#include "core/file_sys/devices/nop_device.h"
|
||||||
#include "core/file_sys/fs.h"
|
#include "core/file_sys/fs.h"
|
||||||
|
|
||||||
namespace Core::FileSys {
|
namespace Core::FileSys {
|
||||||
|
|||||||
@@ -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
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
@@ -10,7 +10,8 @@
|
|||||||
#include <tsl/robin_map.h>
|
#include <tsl/robin_map.h>
|
||||||
#include "common/io_file.h"
|
#include "common/io_file.h"
|
||||||
#include "common/logging/formatter.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 {
|
namespace Libraries::Net {
|
||||||
struct Socket;
|
struct Socket;
|
||||||
@@ -72,11 +73,6 @@ private:
|
|||||||
std::mutex m_mutex;
|
std::mutex m_mutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DirEntry {
|
|
||||||
std::string name;
|
|
||||||
bool isFile;
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class FileType {
|
enum class FileType {
|
||||||
Regular, // standard file
|
Regular, // standard file
|
||||||
Directory,
|
Directory,
|
||||||
@@ -90,9 +86,8 @@ struct File {
|
|||||||
std::filesystem::path m_host_name;
|
std::filesystem::path m_host_name;
|
||||||
std::string m_guest_name;
|
std::string m_guest_name;
|
||||||
Common::FS::IOFile f;
|
Common::FS::IOFile f;
|
||||||
std::vector<DirEntry> dirents;
|
|
||||||
u32 dirents_index;
|
|
||||||
std::mutex m_mutex;
|
std::mutex m_mutex;
|
||||||
|
std::shared_ptr<Directories::BaseDirectory> directory; // only valid for type == Directory
|
||||||
std::shared_ptr<Devices::BaseDevice> device; // only valid for type == Device
|
std::shared_ptr<Devices::BaseDevice> device; // only valid for type == Device
|
||||||
std::shared_ptr<Libraries::Net::Socket> socket; // only valid for type == Socket
|
std::shared_ptr<Libraries::Net::Socket> socket; // only valid for type == Socket
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
@@ -9,13 +9,15 @@
|
|||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "common/scope_exit.h"
|
#include "common/scope_exit.h"
|
||||||
#include "common/singleton.h"
|
#include "common/singleton.h"
|
||||||
#include "core/devices/console_device.h"
|
#include "core/file_sys/devices/console_device.h"
|
||||||
#include "core/devices/deci_tty6_device.h"
|
#include "core/file_sys/devices/deci_tty6_device.h"
|
||||||
#include "core/devices/logger.h"
|
#include "core/file_sys/devices/logger.h"
|
||||||
#include "core/devices/nop_device.h"
|
#include "core/file_sys/devices/nop_device.h"
|
||||||
#include "core/devices/random_device.h"
|
#include "core/file_sys/devices/random_device.h"
|
||||||
#include "core/devices/srandom_device.h"
|
#include "core/file_sys/devices/srandom_device.h"
|
||||||
#include "core/devices/urandom_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/file_sys/fs.h"
|
||||||
#include "core/libraries/kernel/file_system.h"
|
#include "core/libraries/kernel/file_system.h"
|
||||||
#include "core/libraries/kernel/orbis_error.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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
file->type = Core::FileSys::FileType::Directory;
|
if (write || rdwr) {
|
||||||
|
|
||||||
// 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) {
|
|
||||||
// Cannot open directories with any type of write access
|
// Cannot open directories with any type of write access
|
||||||
h->DeleteHandle(handle);
|
h->DeleteHandle(handle);
|
||||||
*__Error() = POSIX_EISDIR;
|
*__Error() = POSIX_EISDIR;
|
||||||
return -1;
|
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) {
|
if (truncate) {
|
||||||
// Cannot open directories with truncate
|
// Cannot open directories with truncate
|
||||||
h->DeleteHandle(handle);
|
h->DeleteHandle(handle);
|
||||||
*__Error() = POSIX_EISDIR;
|
*__Error() = POSIX_EISDIR;
|
||||||
return -1;
|
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 {
|
} else {
|
||||||
file->type = Core::FileSys::FileType::Regular;
|
file->type = Core::FileSys::FileType::Regular;
|
||||||
|
|
||||||
@@ -289,7 +281,7 @@ s32 PS4_SYSV_ABI sceKernelClose(s32 fd) {
|
|||||||
return result;
|
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<Core::FileSys::HandleTable>::Instance();
|
auto* h = Common::Singleton<Core::FileSys::HandleTable>::Instance();
|
||||||
auto* file = h->GetFile(fd);
|
auto* file = h->GetFile(fd);
|
||||||
if (file == nullptr) {
|
if (file == nullptr) {
|
||||||
@@ -313,11 +305,11 @@ s64 PS4_SYSV_ABI write(s32 fd, const void* buf, size_t nbytes) {
|
|||||||
return file->f.WriteRaw<u8>(buf, nbytes);
|
return file->f.WriteRaw<u8>(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);
|
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);
|
s64 result = write(fd, buf, nbytes);
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
LOG_ERROR(Kernel_Fs, "error = {}", *__Error());
|
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;
|
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();
|
const auto* memory = Core::Memory::Instance();
|
||||||
// Invalidate up to the actual number of bytes that could be read.
|
// Invalidate up to the actual number of bytes that could be read.
|
||||||
const auto remaining = file.GetSize() - file.Tell();
|
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<u8>(buf, nbytes);
|
return file.ReadRaw<u8>(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<Core::FileSys::HandleTable>::Instance();
|
auto* h = Common::Singleton<Core::FileSys::HandleTable>::Instance();
|
||||||
auto* file = h->GetFile(fd);
|
auto* file = h->GetFile(fd);
|
||||||
if (file == nullptr) {
|
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};
|
std::scoped_lock lk{file->m_mutex};
|
||||||
if (file->type == Core::FileSys::FileType::Device) {
|
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) {
|
if (result < 0) {
|
||||||
ErrSceToPosix(result);
|
ErrSceToPosix(result);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
size_t total_read = 0;
|
s64 total_read = 0;
|
||||||
for (s32 i = 0; i < iovcnt; i++) {
|
for (s32 i = 0; i < iovcnt; i++) {
|
||||||
total_read += ReadFile(file->f, iov[i].iov_base, iov[i].iov_len);
|
total_read += ReadFile(file->f, iov[i].iov_base, iov[i].iov_len);
|
||||||
}
|
}
|
||||||
return total_read;
|
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);
|
return readv(fd, iov, iovcnt);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t PS4_SYSV_ABI sceKernelReadv(s32 fd, const SceKernelIovec* iov, s32 iovcnt) {
|
s64 PS4_SYSV_ABI sceKernelReadv(s32 fd, const OrbisKernelIovec* iov, s32 iovcnt) {
|
||||||
size_t result = readv(fd, iov, iovcnt);
|
s64 result = readv(fd, iov, iovcnt);
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
LOG_ERROR(Kernel_Fs, "error = {}", *__Error());
|
LOG_ERROR(Kernel_Fs, "error = {}", *__Error());
|
||||||
return ErrnoToSceKernelError(*__Error());
|
return ErrnoToSceKernelError(*__Error());
|
||||||
@@ -372,7 +371,7 @@ size_t PS4_SYSV_ABI sceKernelReadv(s32 fd, const SceKernelIovec* iov, s32 iovcnt
|
|||||||
return result;
|
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<Core::FileSys::HandleTable>::Instance();
|
auto* h = Common::Singleton<Core::FileSys::HandleTable>::Instance();
|
||||||
auto* file = h->GetFile(fd);
|
auto* file = h->GetFile(fd);
|
||||||
if (file == nullptr) {
|
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};
|
std::scoped_lock lk{file->m_mutex};
|
||||||
|
|
||||||
if (file->type == Core::FileSys::FileType::Device) {
|
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) {
|
if (result < 0) {
|
||||||
ErrSceToPosix(result);
|
ErrSceToPosix(result);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
size_t total_written = 0;
|
s64 total_written = 0;
|
||||||
for (s32 i = 0; i < iovcnt; i++) {
|
for (s32 i = 0; i < iovcnt; i++) {
|
||||||
total_written += file->f.WriteRaw<u8>(iov[i].iov_base, iov[i].iov_len);
|
total_written += file->f.WriteRaw<u8>(iov[i].iov_base, iov[i].iov_len);
|
||||||
}
|
}
|
||||||
return total_written;
|
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);
|
return writev(fd, iov, iovcnt);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t PS4_SYSV_ABI sceKernelWritev(s32 fd, const SceKernelIovec* iov, s32 iovcnt) {
|
s64 PS4_SYSV_ABI sceKernelWritev(s32 fd, const OrbisKernelIovec* iov, s32 iovcnt) {
|
||||||
size_t result = writev(fd, iov, iovcnt);
|
s64 result = writev(fd, iov, iovcnt);
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
LOG_ERROR(Kernel_Fs, "error = {}", *__Error());
|
LOG_ERROR(Kernel_Fs, "error = {}", *__Error());
|
||||||
return ErrnoToSceKernelError(*__Error());
|
return ErrnoToSceKernelError(*__Error());
|
||||||
@@ -426,6 +425,13 @@ s64 PS4_SYSV_ABI posix_lseek(s32 fd, s64 offset, s32 whence) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return result;
|
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{};
|
Common::FS::SeekOrigin origin{};
|
||||||
@@ -473,7 +479,7 @@ s64 PS4_SYSV_ABI sceKernelLseek(s32 fd, s64 offset, s32 whence) {
|
|||||||
return result;
|
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<Core::FileSys::HandleTable>::Instance();
|
auto* h = Common::Singleton<Core::FileSys::HandleTable>::Instance();
|
||||||
auto* file = h->GetFile(fd);
|
auto* file = h->GetFile(fd);
|
||||||
if (file == nullptr) {
|
if (file == nullptr) {
|
||||||
@@ -489,6 +495,13 @@ s64 PS4_SYSV_ABI read(s32 fd, void* buf, size_t nbytes) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return result;
|
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) {
|
} else if (file->type == Core::FileSys::FileType::Socket) {
|
||||||
// Socket functions handle errnos internally.
|
// Socket functions handle errnos internally.
|
||||||
return file->socket->ReceivePacket(buf, nbytes, 0, nullptr, 0);
|
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);
|
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);
|
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);
|
s64 result = read(fd, buf, nbytes);
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
LOG_ERROR(Kernel_Fs, "error = {}", *__Error());
|
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) {
|
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<Core::FileSys::MntPoints>::Instance();
|
auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance();
|
||||||
const auto path_name = mnt->GetHostPath(path);
|
const auto path_name = mnt->GetHostPath(path);
|
||||||
std::memset(sb, 0, sizeof(OrbisKernelStat));
|
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) {
|
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) {
|
if (sb == nullptr) {
|
||||||
*__Error() = POSIX_EFAULT;
|
*__Error() = POSIX_EFAULT;
|
||||||
return -1;
|
return -1;
|
||||||
@@ -677,12 +690,12 @@ s32 PS4_SYSV_ABI fstat(s32 fd, OrbisKernelStat* sb) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Core::FileSys::FileType::Directory: {
|
case Core::FileSys::FileType::Directory: {
|
||||||
sb->st_mode = 0000777u | 0040000u;
|
s32 result = file->directory->fstat(sb);
|
||||||
sb->st_size = 65536;
|
if (result < 0) {
|
||||||
sb->st_blksize = 65536;
|
ErrSceToPosix(result);
|
||||||
sb->st_blocks = 128;
|
return -1;
|
||||||
// TODO incomplete
|
}
|
||||||
break;
|
return result;
|
||||||
}
|
}
|
||||||
case Core::FileSys::FileType::Socket: {
|
case Core::FileSys::FileType::Socket: {
|
||||||
// Socket functions handle errnos internally
|
// Socket functions handle errnos internally
|
||||||
@@ -804,7 +817,7 @@ s32 PS4_SYSV_ABI sceKernelRename(const char* from, const char* to) {
|
|||||||
return result;
|
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) {
|
if (offset < 0) {
|
||||||
*__Error() = POSIX_EINVAL;
|
*__Error() = POSIX_EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
@@ -825,6 +838,13 @@ s64 PS4_SYSV_ABI posix_preadv(s32 fd, SceKernelIovec* iov, s32 iovcnt, s64 offse
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return result;
|
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();
|
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;
|
*__Error() = POSIX_EIO;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
size_t total_read = 0;
|
s64 total_read = 0;
|
||||||
for (int i = 0; i < iovcnt; i++) {
|
for (s32 i = 0; i < iovcnt; i++) {
|
||||||
total_read += ReadFile(file->f, iov[i].iov_base, iov[i].iov_len);
|
total_read += ReadFile(file->f, iov[i].iov_base, iov[i].iov_len);
|
||||||
}
|
}
|
||||||
return total_read;
|
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);
|
s64 result = posix_preadv(fd, iov, iovcnt, offset);
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
LOG_ERROR(Kernel_Fs, "error = {}", *__Error());
|
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;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
s64 PS4_SYSV_ABI posix_pread(s32 fd, void* buf, size_t nbytes, s64 offset) {
|
s64 PS4_SYSV_ABI posix_pread(s32 fd, void* buf, u64 nbytes, s64 offset) {
|
||||||
SceKernelIovec iovec{buf, nbytes};
|
OrbisKernelIovec iovec{buf, nbytes};
|
||||||
return posix_preadv(fd, &iovec, 1, offset);
|
return posix_preadv(fd, &iovec, 1, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
s64 PS4_SYSV_ABI sceKernelPread(s32 fd, void* buf, size_t nbytes, s64 offset) {
|
s64 PS4_SYSV_ABI sceKernelPread(s32 fd, void* buf, u64 nbytes, s64 offset) {
|
||||||
SceKernelIovec iovec{buf, nbytes};
|
OrbisKernelIovec iovec{buf, nbytes};
|
||||||
return sceKernelPreadv(fd, &iovec, 1, offset);
|
return sceKernelPreadv(fd, &iovec, 1, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -902,50 +922,36 @@ static s64 GetDents(s32 fd, char* buf, u64 nbytes, s64* basep) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (file->type == Core::FileSys::FileType::Device) {
|
if (nbytes < 512) {
|
||||||
s32 result = file->device->getdents(buf, nbytes, basep);
|
*__Error() = POSIX_EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (file->type) {
|
||||||
|
case Core::FileSys::FileType::Directory: {
|
||||||
|
s64 result = file->directory->getdents(buf, nbytes, basep);
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
ErrSceToPosix(result);
|
ErrSceToPosix(result);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
case Core::FileSys::FileType::Device: {
|
||||||
if (file->type != Core::FileSys::FileType::Directory || nbytes < 512 ||
|
s64 result = file->device->getdents(buf, nbytes, basep);
|
||||||
file->dirents_index > file->dirents.size()) {
|
if (result < 0) {
|
||||||
|
ErrSceToPosix(result);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
// Not directory or device
|
||||||
*__Error() = POSIX_EINVAL;
|
*__Error() = POSIX_EINVAL;
|
||||||
return -1;
|
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) {
|
return ORBIS_OK;
|
||||||
*basep = file->dirents_index;
|
|
||||||
}
|
|
||||||
|
|
||||||
return bytes_written;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
s64 PS4_SYSV_ABI posix_getdents(s32 fd, char* buf, u64 nbytes) {
|
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;
|
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) {
|
if (offset < 0) {
|
||||||
*__Error() = POSIX_EINVAL;
|
*__Error() = POSIX_EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
@@ -1009,19 +1015,19 @@ s64 PS4_SYSV_ABI posix_pwritev(s32 fd, const SceKernelIovec* iov, s32 iovcnt, s6
|
|||||||
*__Error() = POSIX_EIO;
|
*__Error() = POSIX_EIO;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
size_t total_written = 0;
|
s64 total_written = 0;
|
||||||
for (int i = 0; i < iovcnt; i++) {
|
for (s32 i = 0; i < iovcnt; i++) {
|
||||||
total_written += file->f.WriteRaw<u8>(iov[i].iov_base, iov[i].iov_len);
|
total_written += file->f.WriteRaw<u8>(iov[i].iov_base, iov[i].iov_len);
|
||||||
}
|
}
|
||||||
return total_written;
|
return total_written;
|
||||||
}
|
}
|
||||||
|
|
||||||
s64 PS4_SYSV_ABI posix_pwrite(s32 fd, void* buf, size_t nbytes, s64 offset) {
|
s64 PS4_SYSV_ABI posix_pwrite(s32 fd, void* buf, u64 nbytes, s64 offset) {
|
||||||
SceKernelIovec iovec{buf, nbytes};
|
OrbisKernelIovec iovec{buf, nbytes};
|
||||||
return posix_pwritev(fd, &iovec, 1, offset);
|
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);
|
s64 result = posix_pwrite(fd, buf, nbytes, offset);
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
LOG_ERROR(Kernel_Fs, "error = {}", *__Error());
|
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;
|
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);
|
s64 result = posix_pwritev(fd, iov, iovcnt, offset);
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
LOG_ERROR(Kernel_Fs, "error = {}", *__Error());
|
LOG_ERROR(Kernel_Fs, "error = {}", *__Error());
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ namespace Libraries::Kernel {
|
|||||||
|
|
||||||
constexpr int ORBIS_MAX_PATH = 255;
|
constexpr int ORBIS_MAX_PATH = 255;
|
||||||
|
|
||||||
struct SceKernelIovec {
|
struct OrbisKernelIovec {
|
||||||
void* iov_base;
|
void* iov_base;
|
||||||
std::size_t iov_len;
|
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_DIRECT = 0x00010000;
|
||||||
constexpr int ORBIS_KERNEL_O_DIRECTORY = 0x00020000;
|
constexpr int ORBIS_KERNEL_O_DIRECTORY = 0x00020000;
|
||||||
|
|
||||||
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 PS4_SYSV_ABI sceKernelRead(s32 fd, void* buf, size_t nbytes);
|
s64 PS4_SYSV_ABI sceKernelRead(s32 fd, void* buf, u64 nbytes);
|
||||||
s64 PS4_SYSV_ABI sceKernelPread(s32 fd, void* buf, size_t nbytes, s64 offset);
|
s64 PS4_SYSV_ABI sceKernelPread(s32 fd, void* buf, u64 nbytes, s64 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);
|
||||||
void RegisterFileSystem(Core::Loader::SymbolsResolver* sym);
|
void RegisterFileSystem(Core::Loader::SymbolsResolver* sym);
|
||||||
|
|
||||||
} // namespace Libraries::Kernel
|
} // namespace Libraries::Kernel
|
||||||
|
|||||||
Reference in New Issue
Block a user