feat(libkernel): implement fchmod and sceKernelFchmod
This commit is contained in:
parent
964dd3c919
commit
eded1e010f
|
|
@ -14,6 +14,7 @@
|
|||
#include <cstring>
|
||||
#include <cstdarg>
|
||||
#include <filesystem>
|
||||
#include <optional>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#ifdef _WIN32
|
||||
|
|
@ -32,6 +33,30 @@ static int NativeMkdir(const std::filesystem::path& path, std::uint16_t mode) {
|
|||
static int NativeChmod(const std::filesystem::path& path, int mode) {
|
||||
return ::_wchmod(path.wstring().c_str(), mode);
|
||||
}
|
||||
static std::optional<std::filesystem::path> NativeDescriptorPath(int descriptor) {
|
||||
if (auto directory = File::DirectoryDescriptorPath(descriptor)) return directory;
|
||||
const auto handle = reinterpret_cast<HANDLE>(::_get_osfhandle(descriptor));
|
||||
if (handle == INVALID_HANDLE_VALUE) {
|
||||
errno = EBADF;
|
||||
return std::nullopt;
|
||||
}
|
||||
std::wstring path(MAX_PATH, L'\0');
|
||||
auto length = ::GetFinalPathNameByHandleW(handle, path.data(), static_cast<DWORD>(path.size()), FILE_NAME_NORMALIZED);
|
||||
if (length >= path.size()) {
|
||||
path.resize(length);
|
||||
length = ::GetFinalPathNameByHandleW(handle, path.data(), length, FILE_NAME_NORMALIZED);
|
||||
}
|
||||
if (length == 0 || length >= path.size()) {
|
||||
errno = EINVAL;
|
||||
return std::nullopt;
|
||||
}
|
||||
path.resize(length);
|
||||
return path;
|
||||
}
|
||||
static int NativeFchmod(int descriptor, int mode) {
|
||||
const auto path = NativeDescriptorPath(descriptor);
|
||||
return path ? NativeChmod(*path, mode) : -1;
|
||||
}
|
||||
static int NativeFtruncate(int descriptor, std::int64_t length) {
|
||||
return static_cast<int>(::_chsize_s(descriptor, length));
|
||||
}
|
||||
|
|
@ -99,6 +124,9 @@ static int NativeMkdir(const std::filesystem::path& path, std::uint16_t mode) {
|
|||
static int NativeChmod(const std::filesystem::path& path, int mode) {
|
||||
return ::chmod(path.c_str(), static_cast<mode_t>(mode));
|
||||
}
|
||||
static int NativeFchmod(int descriptor, int mode) {
|
||||
return ::fchmod(descriptor, static_cast<mode_t>(mode));
|
||||
}
|
||||
static int NativeFtruncate(int descriptor, std::int64_t length) {
|
||||
return ::ftruncate(descriptor, static_cast<off_t>(length));
|
||||
}
|
||||
|
|
@ -121,6 +149,7 @@ static std::int64_t NativePwrite(int descriptor, const void* buf, std::size_t nb
|
|||
|
||||
static constexpr int GUEST_ENOENT = 2;
|
||||
static constexpr int GUEST_EIO = 5;
|
||||
static constexpr int GUEST_EBADF = 9;
|
||||
static constexpr int GUEST_EFAULT = 14;
|
||||
static constexpr int GUEST_EEXIST = 17;
|
||||
static constexpr int GUEST_EINVAL = 22;
|
||||
|
|
@ -469,6 +498,16 @@ int APS5_VABI sceKernelChmod_nid_postfix(const char* path, std::uint16_t mode) {
|
|||
return chmod_nid_postfix(path, mode);
|
||||
}
|
||||
|
||||
int APS5_VABI sceKernelFchmod(int d, std::uint16_t mode) {
|
||||
if (d >= GuestSockets::FirstDescriptor) return SceErrorFromErrno(GuestSockets::IsOpen(d) ? GUEST_EINVAL : GUEST_EBADF);
|
||||
if (NativeFchmod(d, mode & 07777) != 0) return SceErrorFromErrno(errno);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI fchmod_nid_postfix(int d, int mode) {
|
||||
return PosixResult(sceKernelFchmod(d, static_cast<std::uint16_t>(mode)));
|
||||
}
|
||||
|
||||
int APS5_VABI sceKernelTruncate_nid_postfix(const char* path, std::int64_t length) {
|
||||
if (path == nullptr) throw std::invalid_argument("sceKernelTruncate: path is null");
|
||||
if (length < 0) return SceErrorFromErrno(GUEST_EINVAL);
|
||||
|
|
|
|||
|
|
@ -2,4 +2,5 @@
|
|||
namespace GuestSockets {
|
||||
constexpr int FirstDescriptor = 0x10000000;
|
||||
int Close(int descriptor);
|
||||
bool IsOpen(int descriptor);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -158,6 +158,11 @@ int GuestSockets::Close(int descriptor) {
|
|||
return sockets.erase(descriptor) ? 0 : Fail(9);
|
||||
}
|
||||
|
||||
bool GuestSockets::IsOpen(int descriptor) {
|
||||
std::lock_guard lock(socketsMutex);
|
||||
return sockets.contains(descriptor);
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
int APS5_VABI fcntl_nid_postfix(int descriptor, int command, ...) {
|
||||
const auto socket = Lookup(descriptor);
|
||||
|
|
|
|||
|
|
@ -27,16 +27,6 @@ int APS5_VABI pthread_cancel_nid_postfix(void) {
|
|||
NotImplemented_nid_no_patch("0D4-FVvEikw");
|
||||
return 0;
|
||||
}
|
||||
int APS5_VABI sceKernelFchmod(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI fchmod_nid_postfix(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI futimes_nid_postfix(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -9,6 +9,9 @@ extern "C" {
|
|||
int APS5_VABI remove_nid_postfix(const char*);
|
||||
int APS5_VABI rename_nid_postfix(const char*, const char*);
|
||||
int APS5_VABI sceKernelChmod_nid_postfix(const char*, unsigned short);
|
||||
int APS5_VABI sceKernelFchmod(int, unsigned short);
|
||||
int APS5_VABI fchmod_nid_postfix(int, int);
|
||||
int APS5_VABI socket_nid_postfix(int, int, int);
|
||||
int APS5_VABI sceKernelFsync(int);
|
||||
int APS5_VABI sceKernelFtruncate(int, long long);
|
||||
int APS5_VABI sceKernelTruncate_nid_postfix(const char*, long long);
|
||||
|
|
@ -74,9 +77,24 @@ int main() {
|
|||
const int descriptor = ::fileno(native);
|
||||
#endif
|
||||
Require(descriptor >= 0 && sceKernelFsync(descriptor) == 0);
|
||||
const auto ownerWrite = [&] {
|
||||
return (std::filesystem::status(sized).permissions() & std::filesystem::perms::owner_write) != std::filesystem::perms::none;
|
||||
};
|
||||
Require(sceKernelFchmod(descriptor, 0400) == 0 && !ownerWrite());
|
||||
Require(fchmod_nid_postfix(descriptor, 0600) == 0 && ownerWrite());
|
||||
Require(sceKernelFtruncate(descriptor, 3) == 0);
|
||||
Require(std::fclose(native) == 0);
|
||||
Require(std::filesystem::file_size(sized) == 3);
|
||||
#ifndef _WIN32
|
||||
Require(sceKernelFchmod(descriptor, 0600) == static_cast<int>(0x80020009u));
|
||||
Require(fchmod_nid_postfix(descriptor, 0600) == -1 && *__error_nid_postfix() == 9);
|
||||
#endif
|
||||
const int socket = socket_nid_postfix(2, 2, 0);
|
||||
Require(socket >= 0);
|
||||
Require(sceKernelFchmod(socket, 0600) == static_cast<int>(0x80020016u));
|
||||
Require(fchmod_nid_postfix(socket, 0600) == -1 && *__error_nid_postfix() == 22);
|
||||
Require(close_nid_postfix(socket) == 0);
|
||||
Require(fchmod_nid_postfix(socket, 0600) == -1 && *__error_nid_postfix() == 9);
|
||||
Require(remove_nid_postfix(sized.string().c_str()) == 0);
|
||||
const auto present = root / "present.txt";
|
||||
const auto presentName = present.string();
|
||||
|
|
|
|||
Loading…
Reference in New Issue