mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-20 19:07:01 +02:00
Implement missing kernel and startup library imports (#772)
* Implement missing kernel and startup library imports * Remove chmod and test changes; guard vectored I/O size --------- Co-authored-by: nmzik <Nmzik@mail.ru>
This commit is contained in:
@@ -64,6 +64,7 @@ struct File {
|
||||
std::filesystem::path real_name;
|
||||
std::atomic_bool opened;
|
||||
std::atomic_bool directory;
|
||||
std::atomic_bool readable;
|
||||
std::atomic_bool writable;
|
||||
std::atomic_bool append;
|
||||
std::atomic_bool sync_writes;
|
||||
@@ -175,6 +176,7 @@ int FileDescriptors::CreateDescriptor() {
|
||||
auto* file = new File {};
|
||||
file->opened = false;
|
||||
file->directory = false;
|
||||
file->readable = false;
|
||||
file->writable = false;
|
||||
file->append = false;
|
||||
file->sync_writes = false;
|
||||
@@ -442,6 +444,7 @@ int KYTY_SYSV_ABI KernelOpen(const char* path, int flags, uint16_t mode) {
|
||||
EXIT_IF(file == nullptr || file->opened || file->directory);
|
||||
|
||||
file->name = path;
|
||||
file->readable = rw_mode != Common::File::Mode::Write;
|
||||
file->writable = rw_mode != Common::File::Mode::Read;
|
||||
file->append = append;
|
||||
file->sync_writes = fsync || sync || dsync;
|
||||
@@ -761,6 +764,106 @@ int64_t KYTY_SYSV_ABI KernelPread(int d, void* buf, size_t nbytes, int64_t offse
|
||||
return bytes_read;
|
||||
}
|
||||
|
||||
static int ValidateIovecs(const KernelIovec* iov, int iovcnt, int64_t offset,
|
||||
std::vector<KernelIovec>* buffers, size_t* total) {
|
||||
constexpr int MaxIov = 1024;
|
||||
if (iovcnt < 0 || iovcnt > MaxIov || offset < 0) {
|
||||
return KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
if (iov == nullptr && iovcnt != 0) {
|
||||
return KERNEL_ERROR_EFAULT;
|
||||
}
|
||||
|
||||
if (iovcnt != 0) {
|
||||
buffers->assign(iov, iov + iovcnt);
|
||||
}
|
||||
*total = 0;
|
||||
for (const auto& buffer: *buffers) {
|
||||
if (buffer.iov_len > INT_MAX - *total) {
|
||||
return KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
if (buffer.iov_base == nullptr && buffer.iov_len != 0) {
|
||||
return KERNEL_ERROR_EFAULT;
|
||||
}
|
||||
*total += buffer.iov_len;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
int64_t KYTY_SYSV_ABI KernelPreadv(int d, const KernelIovec* iov, int iovcnt, int64_t offset) {
|
||||
PRINT_NAME();
|
||||
|
||||
std::vector<KernelIovec> buffers;
|
||||
size_t total = 0;
|
||||
const int error = ValidateIovecs(iov, iovcnt, offset, &buffers, &total);
|
||||
if (error != OK) {
|
||||
return error;
|
||||
}
|
||||
|
||||
if (d < DESCRIPTOR_MIN) {
|
||||
return KERNEL_ERROR_EBADF;
|
||||
}
|
||||
if (::Libs::Network::Net::IsSocket(d)) {
|
||||
return KERNEL_ERROR_ESPIPE;
|
||||
}
|
||||
auto* file = g_files->GetFile(d);
|
||||
if (file == nullptr || !file->opened || !file->readable) {
|
||||
return KERNEL_ERROR_EBADF;
|
||||
}
|
||||
|
||||
Common::LockGuard lock(file->mutex);
|
||||
if (file->directory) {
|
||||
return KERNEL_ERROR_EISDIR;
|
||||
}
|
||||
if (total == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (file->special == SpecialFile::Random) {
|
||||
for (const auto& buffer: buffers) {
|
||||
if (buffer.iov_len != 0) {
|
||||
Memory::InvalidateMemory(reinterpret_cast<uint64_t>(buffer.iov_base),
|
||||
buffer.iov_len);
|
||||
FillRandomBuffer(buffer.iov_base, buffer.iov_len);
|
||||
}
|
||||
}
|
||||
return static_cast<int64_t>(total);
|
||||
}
|
||||
if (file->f.IsInvalid()) {
|
||||
return KERNEL_ERROR_EIO;
|
||||
}
|
||||
|
||||
const auto position = file->f.Tell();
|
||||
const auto file_size = file->f.Size();
|
||||
if (!file->f.Seek(static_cast<uint64_t>(offset))) {
|
||||
return KERNEL_ERROR_EIO;
|
||||
}
|
||||
auto remaining = static_cast<uint64_t>(offset) < file_size ? file_size - offset : 0;
|
||||
int64_t bytes_read = 0;
|
||||
for (const auto& buffer: buffers) {
|
||||
if (remaining == 0) {
|
||||
break;
|
||||
}
|
||||
if (buffer.iov_len == 0) {
|
||||
continue;
|
||||
}
|
||||
const auto count = static_cast<uint32_t>(std::min<uint64_t>(buffer.iov_len, remaining));
|
||||
Memory::InvalidateMemory(reinterpret_cast<uint64_t>(buffer.iov_base), count);
|
||||
uint32_t bytes = 0;
|
||||
file->f.Read(buffer.iov_base, count, &bytes);
|
||||
bytes_read += bytes;
|
||||
remaining -= bytes;
|
||||
if (bytes < count) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!file->f.Seek(position)) {
|
||||
return KERNEL_ERROR_EIO;
|
||||
}
|
||||
LOGF("\tReadv %" PRId64 " bytes (pos = %" PRId64 ", iovcnt = %d) from: %s\n", bytes_read,
|
||||
offset, iovcnt, Common::PathToString(file->real_name).c_str());
|
||||
return bytes_read;
|
||||
}
|
||||
|
||||
int64_t KYTY_SYSV_ABI KernelPwrite(int d, const void* buf, size_t nbytes, int64_t offset) {
|
||||
PRINT_NAME();
|
||||
|
||||
@@ -814,6 +917,72 @@ int64_t KYTY_SYSV_ABI KernelPwrite(int d, const void* buf, size_t nbytes, int64_
|
||||
return bytes_written;
|
||||
}
|
||||
|
||||
int64_t KYTY_SYSV_ABI KernelPwritev(int d, const KernelIovec* iov, int iovcnt, int64_t offset) {
|
||||
PRINT_NAME();
|
||||
|
||||
std::vector<KernelIovec> buffers;
|
||||
size_t total = 0;
|
||||
const int error = ValidateIovecs(iov, iovcnt, offset, &buffers, &total);
|
||||
if (error != OK) {
|
||||
return error;
|
||||
}
|
||||
|
||||
if (d < DESCRIPTOR_MIN) {
|
||||
return KERNEL_ERROR_EBADF;
|
||||
}
|
||||
if (::Libs::Network::Net::IsSocket(d)) {
|
||||
return KERNEL_ERROR_ESPIPE;
|
||||
}
|
||||
auto* file = g_files->GetFile(d);
|
||||
if (file == nullptr || !file->opened || !file->writable) {
|
||||
return KERNEL_ERROR_EBADF;
|
||||
}
|
||||
Common::LockGuard lock(file->mutex);
|
||||
if (file->directory) {
|
||||
return KERNEL_ERROR_EISDIR;
|
||||
}
|
||||
if (file->special != SpecialFile::None) {
|
||||
return KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
if (total == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (file->f.IsInvalid()) {
|
||||
return KERNEL_ERROR_EIO;
|
||||
}
|
||||
|
||||
const auto position = file->f.Tell();
|
||||
const auto target = (file->append ? file->f.Size() : static_cast<uint64_t>(offset));
|
||||
if (target > static_cast<uint64_t>(INT64_MAX) - total) {
|
||||
return KERNEL_ERROR_EFBIG;
|
||||
}
|
||||
if (!file->f.Seek(target)) {
|
||||
return KERNEL_ERROR_EIO;
|
||||
}
|
||||
|
||||
int64_t bytes_written = 0;
|
||||
for (const auto& buffer: buffers) {
|
||||
if (buffer.iov_len == 0) {
|
||||
continue;
|
||||
}
|
||||
uint32_t bytes = 0;
|
||||
file->f.Write(buffer.iov_base, static_cast<uint32_t>(buffer.iov_len), &bytes);
|
||||
bytes_written += bytes;
|
||||
if (bytes < buffer.iov_len) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
const bool flushed = !file->sync_writes || file->f.Flush();
|
||||
const bool restored = file->f.Seek(position);
|
||||
if (!flushed || !restored) {
|
||||
return KERNEL_ERROR_EIO;
|
||||
}
|
||||
|
||||
LOGF("\tWritev %" PRId64 " bytes (pos = %" PRId64 ", iovcnt = %d) to: %s\n", bytes_written,
|
||||
offset, iovcnt, Common::PathToString(file->real_name).c_str());
|
||||
return bytes_written;
|
||||
}
|
||||
|
||||
int64_t KYTY_SYSV_ABI KernelLseek(int d, int64_t offset, int whence) {
|
||||
PRINT_NAME();
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "common/stringUtils.h"
|
||||
#include "kernel/pthread.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <filesystem>
|
||||
|
||||
namespace Libs::LibKernel::FileSystem {
|
||||
@@ -32,6 +33,14 @@ struct FileStat {
|
||||
unsigned int: (8 / 2) * (16 - static_cast<int>(sizeof(KernelTimespec)));
|
||||
};
|
||||
|
||||
struct KernelIovec {
|
||||
void* iov_base;
|
||||
size_t iov_len;
|
||||
};
|
||||
|
||||
static_assert(sizeof(KernelIovec) == 16);
|
||||
static_assert(offsetof(KernelIovec, iov_len) == 8);
|
||||
|
||||
void Initialize();
|
||||
void Shutdown();
|
||||
void EmergencyShutdown();
|
||||
@@ -51,8 +60,10 @@ int KYTY_SYSV_ABI KernelOpen(const char* path, int flags, uint16_t mode);
|
||||
int KYTY_SYSV_ABI KernelClose(int d);
|
||||
int64_t KYTY_SYSV_ABI KernelRead(int d, void* buf, size_t nbytes);
|
||||
int64_t KYTY_SYSV_ABI KernelPread(int d, void* buf, size_t nbytes, int64_t offset);
|
||||
int64_t KYTY_SYSV_ABI KernelPreadv(int d, const KernelIovec* iov, int iovcnt, int64_t offset);
|
||||
int64_t KYTY_SYSV_ABI KernelWrite(int d, const void* buf, size_t nbytes);
|
||||
int64_t KYTY_SYSV_ABI KernelPwrite(int d, const void* buf, size_t nbytes, int64_t offset);
|
||||
int64_t KYTY_SYSV_ABI KernelPwritev(int d, const KernelIovec* iov, int iovcnt, int64_t offset);
|
||||
int64_t KYTY_SYSV_ABI KernelLseek(int d, int64_t offset, int whence);
|
||||
int KYTY_SYSV_ABI KernelStat(const char* path, FileStat* sb);
|
||||
int KYTY_SYSV_ABI KernelFstat(int d, FileStat* sb);
|
||||
|
||||
Reference in New Issue
Block a user