[rpcsx-os] Initial sys_rename, sys_mkdir, sys_rmdir implementation

vfs: implement overlapped mounts
This commit is contained in:
DH 2023-10-29 12:30:37 +03:00
parent 3232e57445
commit 60e11486f4
8 changed files with 280 additions and 63 deletions

View file

@ -41,7 +41,8 @@ struct ProcessOps {
SysResult (*shm_open)(Thread *thread, const char *path, sint flags, sint mode,
Ref<File> *file);
SysResult (*mkdir)(Thread *thread, ptr<const char> path, sint mode);
SysResult (*rmdir)(Thread *thread, ptr<const char> path) = nullptr;
SysResult (*rmdir)(Thread *thread, ptr<const char> path);
SysResult (*rename)(Thread *thread, ptr<const char> from, ptr<const char> to);
SysResult (*blockpool_open)(Thread *thread, Ref<File> *file);
SysResult (*blockpool_map)(Thread *thread, caddr_t addr, size_t len,
sint prot, sint flags);

View file

@ -285,6 +285,9 @@ orbis::SysResult orbis::sys_freebsd6_truncate(Thread *thread, ptr<char> path,
orbis::SysResult orbis::sys_fsync(Thread *thread, sint fd) { return {}; }
orbis::SysResult orbis::sys_rename(Thread *thread, ptr<char> from,
ptr<char> to) {
if (auto rename = thread->tproc->ops->rename) {
return rename(thread, from, to);
}
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_renameat(Thread *thread, sint oldfd, ptr<char> old,

View file

@ -8,6 +8,7 @@
#include <cerrno>
#include <dirent.h>
#include <fcntl.h>
#include <filesystem>
#include <span>
#include <string>
#include <sys/mman.h>
@ -45,8 +46,98 @@ struct HostFsDevice : IoDevice {
orbis::ErrorCode open(orbis::Ref<orbis::File> *file, const char *path,
std::uint32_t flags, std::uint32_t mode,
orbis::Thread *thread) override;
orbis::ErrorCode mkdir(const char *path, int mode, orbis::Thread *thread) override;
orbis::ErrorCode rmdir(const char *path, orbis::Thread *thread) override;
orbis::ErrorCode rename(const char *from, const char *to, orbis::Thread *thread) override;
};
static orbis::ErrorCode convertErrc(std::errc errc) {
if (errc == std::errc{}) {
return{};
}
switch (errc) {
case std::errc::address_family_not_supported: return orbis::ErrorCode::AFNOSUPPORT;
case std::errc::address_in_use: return orbis::ErrorCode::ADDRINUSE;
case std::errc::address_not_available: return orbis::ErrorCode::ADDRNOTAVAIL;
case std::errc::already_connected: return orbis::ErrorCode::ISCONN;
case std::errc::argument_out_of_domain: return orbis::ErrorCode::DOM;
case std::errc::bad_address: return orbis::ErrorCode::FAULT;
case std::errc::bad_file_descriptor: return orbis::ErrorCode::BADF;
case std::errc::bad_message: return orbis::ErrorCode::BADMSG;
case std::errc::broken_pipe: return orbis::ErrorCode::PIPE;
case std::errc::connection_aborted: return orbis::ErrorCode::CONNABORTED;
case std::errc::connection_already_in_progress: return orbis::ErrorCode::ALREADY;
case std::errc::connection_refused: return orbis::ErrorCode::CONNREFUSED;
case std::errc::connection_reset: return orbis::ErrorCode::CONNRESET;
case std::errc::cross_device_link: return orbis::ErrorCode::XDEV;
case std::errc::destination_address_required: return orbis::ErrorCode::DESTADDRREQ;
case std::errc::device_or_resource_busy: return orbis::ErrorCode::BUSY;
case std::errc::directory_not_empty: return orbis::ErrorCode::NOTEMPTY;
case std::errc::executable_format_error: return orbis::ErrorCode::NOEXEC;
case std::errc::file_exists: return orbis::ErrorCode::EXIST;
case std::errc::file_too_large: return orbis::ErrorCode::FBIG;
case std::errc::filename_too_long: return orbis::ErrorCode::NAMETOOLONG;
case std::errc::function_not_supported: return orbis::ErrorCode::NOSYS;
case std::errc::host_unreachable: return orbis::ErrorCode::HOSTUNREACH;
case std::errc::identifier_removed: return orbis::ErrorCode::IDRM;
case std::errc::illegal_byte_sequence: return orbis::ErrorCode::ILSEQ;
case std::errc::inappropriate_io_control_operation: return orbis::ErrorCode::NOTTY;
case std::errc::interrupted: return orbis::ErrorCode::INTR;
case std::errc::invalid_argument: return orbis::ErrorCode::INVAL;
case std::errc::invalid_seek: return orbis::ErrorCode::SPIPE;
case std::errc::io_error: return orbis::ErrorCode::IO;
case std::errc::is_a_directory: return orbis::ErrorCode::ISDIR;
case std::errc::message_size: return orbis::ErrorCode::MSGSIZE;
case std::errc::network_down: return orbis::ErrorCode::NETDOWN;
case std::errc::network_reset: return orbis::ErrorCode::NETRESET;
case std::errc::network_unreachable: return orbis::ErrorCode::NETUNREACH;
case std::errc::no_buffer_space: return orbis::ErrorCode::NOBUFS;
case std::errc::no_child_process: return orbis::ErrorCode::CHILD;
case std::errc::no_link: return orbis::ErrorCode::NOLINK;
case std::errc::no_lock_available: return orbis::ErrorCode::NOLCK;
case std::errc::no_message: return orbis::ErrorCode::NOMSG;
case std::errc::no_protocol_option: return orbis::ErrorCode::NOPROTOOPT;
case std::errc::no_space_on_device: return orbis::ErrorCode::NOSPC;
case std::errc::no_such_device_or_address: return orbis::ErrorCode::NXIO;
case std::errc::no_such_device: return orbis::ErrorCode::NODEV;
case std::errc::no_such_file_or_directory: return orbis::ErrorCode::NOENT;
case std::errc::no_such_process: return orbis::ErrorCode::SRCH;
case std::errc::not_a_directory: return orbis::ErrorCode::NOTDIR;
case std::errc::not_a_socket: return orbis::ErrorCode::NOTSOCK;
case std::errc::not_connected: return orbis::ErrorCode::NOTCONN;
case std::errc::not_enough_memory: return orbis::ErrorCode::NOMEM;
case std::errc::not_supported: return orbis::ErrorCode::NOTSUP;
case std::errc::operation_canceled: return orbis::ErrorCode::CANCELED;
case std::errc::operation_in_progress: return orbis::ErrorCode::INPROGRESS;
case std::errc::operation_not_permitted: return orbis::ErrorCode::PERM;
case std::errc::operation_would_block: return orbis::ErrorCode::WOULDBLOCK;
case std::errc::permission_denied: return orbis::ErrorCode::ACCES;
case std::errc::protocol_error: return orbis::ErrorCode::PROTO;
case std::errc::protocol_not_supported: return orbis::ErrorCode::PROTONOSUPPORT;
case std::errc::read_only_file_system: return orbis::ErrorCode::ROFS;
case std::errc::resource_deadlock_would_occur: return orbis::ErrorCode::DEADLK;
case std::errc::result_out_of_range: return orbis::ErrorCode::RANGE;
case std::errc::text_file_busy: return orbis::ErrorCode::TXTBSY;
case std::errc::timed_out: return orbis::ErrorCode::TIMEDOUT;
case std::errc::too_many_files_open_in_system: return orbis::ErrorCode::NFILE;
case std::errc::too_many_files_open: return orbis::ErrorCode::MFILE;
case std::errc::too_many_links: return orbis::ErrorCode::MLINK;
case std::errc::too_many_symbolic_link_levels: return orbis::ErrorCode::LOOP;
case std::errc::value_too_large: return orbis::ErrorCode::OVERFLOW;
case std::errc::wrong_protocol_type: return orbis::ErrorCode::PROTOTYPE;
default:
return orbis::ErrorCode::FAULT;
}
}
static orbis::ErrorCode convertErrorCode(const std::error_code &code) {
if (!code) {
return{};
}
return convertErrc(static_cast<std::errc>(code.value()));
}
static orbis::ErrorCode convertErrno() {
switch (auto error = errno) {
case EPERM:
@ -254,6 +345,10 @@ static const orbis::FileOps socketOps = {
};
IoDevice *createHostIoDevice(orbis::kstring hostPath) {
while (hostPath.size() > 1 && hostPath.ends_with("/")) {
hostPath.resize(hostPath.size() - 1);
}
return orbis::knew<HostFsDevice>(std::move(hostPath));
}
@ -329,7 +424,7 @@ orbis::ErrorCode HostFsDevice::open(orbis::Ref<orbis::File> *file,
if (hostFd < 0) {
auto error = convertErrno();
ORBIS_LOG_ERROR("host_open failed", realPath, error);
ORBIS_LOG_ERROR("host_open failed", path, realPath, error);
return error;
}
@ -366,6 +461,22 @@ orbis::ErrorCode HostFsDevice::open(orbis::Ref<orbis::File> *file,
return {};
}
orbis::ErrorCode HostFsDevice::mkdir(const char *path, int mode, orbis::Thread *thread) {
std::error_code ec;
std::filesystem::create_directories(hostPath + "/" + path, ec);
return convertErrorCode(ec);
}
orbis::ErrorCode HostFsDevice::rmdir(const char *path, orbis::Thread *thread) {
std::error_code ec;
std::filesystem::remove(hostPath + "/" + path, ec);
return convertErrorCode(ec);
}
orbis::ErrorCode HostFsDevice::rename(const char *from, const char *to, orbis::Thread *thread) {
std::error_code ec;
std::filesystem::rename(hostPath + "/" + from, hostPath + "/" + to, ec);
return convertErrorCode(ec);
}
orbis::File *createHostFile(int hostFd, orbis::Ref<IoDevice> device) {
auto newFile = orbis::knew<HostFile>();
newFile->hostFd = hostFd;

View file

@ -30,6 +30,15 @@ struct IoDevice : orbis::RcBase {
virtual orbis::ErrorCode unlink(const char *path, orbis::Thread *thread) {
return orbis::ErrorCode::NOTSUP;
}
virtual orbis::ErrorCode mkdir(const char *path, int mode, orbis::Thread *thread) {
return orbis::ErrorCode::NOTSUP;
}
virtual orbis::ErrorCode rmdir(const char *path, orbis::Thread *thread) {
return orbis::ErrorCode::NOTSUP;
}
virtual orbis::ErrorCode rename(const char *from, const char *to, orbis::Thread *thread) {
return orbis::ErrorCode::NOTSUP;
}
};
IoDevice *createHostIoDevice(orbis::kstring hostPath);

View file

@ -322,30 +322,30 @@ static int ps4Exec(orbis::Thread *mainThread,
auto dmem1 = createDmemCharacterDevice(1);
orbis::g_context.dmemDevice = dmem1;
rx::vfs::mount("/dev/dmem0", createDmemCharacterDevice(0));
rx::vfs::mount("/dev/npdrm", createNpdrmCharacterDevice());
rx::vfs::mount("/dev/icc_configuration", createIccConfigurationCharacterDevice());
rx::vfs::mount("/dev/console", createConsoleCharacterDevice());
rx::vfs::mount("/dev/camera", createCameraCharacterDevice());
rx::vfs::mount("/dev/dmem1", dmem1);
rx::vfs::mount("/dev/dmem2", createDmemCharacterDevice(2));
rx::vfs::mount("/dev/stdout", createFdWrapDevice(STDOUT_FILENO));
rx::vfs::mount("/dev/stderr", createFdWrapDevice(STDERR_FILENO));
rx::vfs::mount("/dev/stdin", createFdWrapDevice(STDIN_FILENO));
rx::vfs::mount("/dev/zero", createZeroCharacterDevice());
rx::vfs::mount("/dev/null", createNullCharacterDevice());
rx::vfs::mount("/dev/dipsw", createDipswCharacterDevice());
rx::vfs::mount("/dev/dce", createDceCharacterDevice());
rx::vfs::mount("/dev/hmd_cmd", createHmdCmdCharacterDevice());
rx::vfs::mount("/dev/hmd_snsr", createHmdSnsrCharacterDevice());
rx::vfs::mount("/dev/hmd_3da", createHmd3daCharacterDevice());
rx::vfs::mount("/dev/hmd_dist", createHmdMmapCharacterDevice());
rx::vfs::mount("/dev/hid", createHidCharacterDevice());
rx::vfs::mount("/dev/gc", createGcCharacterDevice());
rx::vfs::mount("/dev/rng", createRngCharacterDevice());
rx::vfs::mount("/dev/sbl_srv", createSblSrvCharacterDevice());
rx::vfs::mount("/dev/ajm", createAjmCharacterDevice());
rx::vfs::mount("/dev/urandom", createUrandomCharacterDevice());
rx::vfs::addDevice("dmem0", createDmemCharacterDevice(0));
rx::vfs::addDevice("npdrm", createNpdrmCharacterDevice());
rx::vfs::addDevice("icc_configuration", createIccConfigurationCharacterDevice());
rx::vfs::addDevice("console", createConsoleCharacterDevice());
rx::vfs::addDevice("camera", createCameraCharacterDevice());
rx::vfs::addDevice("dmem1", dmem1);
rx::vfs::addDevice("dmem2", createDmemCharacterDevice(2));
rx::vfs::addDevice("stdout", createFdWrapDevice(STDOUT_FILENO));
rx::vfs::addDevice("stderr", createFdWrapDevice(STDERR_FILENO));
rx::vfs::addDevice("stdin", createFdWrapDevice(STDIN_FILENO));
rx::vfs::addDevice("zero", createZeroCharacterDevice());
rx::vfs::addDevice("null", createNullCharacterDevice());
rx::vfs::addDevice("dipsw", createDipswCharacterDevice());
rx::vfs::addDevice("dce", createDceCharacterDevice());
rx::vfs::addDevice("hmd_cmd", createHmdCmdCharacterDevice());
rx::vfs::addDevice("hmd_snsr", createHmdSnsrCharacterDevice());
rx::vfs::addDevice("hmd_3da", createHmd3daCharacterDevice());
rx::vfs::addDevice("hmd_dist", createHmdMmapCharacterDevice());
rx::vfs::addDevice("hid", createHidCharacterDevice());
rx::vfs::addDevice("gc", createGcCharacterDevice());
rx::vfs::addDevice("rng", createRngCharacterDevice());
rx::vfs::addDevice("sbl_srv", createSblSrvCharacterDevice());
rx::vfs::addDevice("ajm", createAjmCharacterDevice());
rx::vfs::addDevice("urandom", createUrandomCharacterDevice());
orbis::Ref<orbis::File> stdinFile;
orbis::Ref<orbis::File> stdoutFile;

View file

@ -274,6 +274,19 @@ orbis::SysResult shm_open(orbis::Thread *thread, const char *path,
return dev->open(file, path, flags, mode, thread);
}
orbis::SysResult mkdir(Thread *thread, ptr<const char> path, sint mode) {
ORBIS_LOG_TODO(__FUNCTION__, path, mode);
return rx::vfs::mkdir(path, mode, thread);
}
orbis::SysResult rmdir(Thread *thread, ptr<const char> path) {
ORBIS_LOG_TODO(__FUNCTION__, path);
return rx::vfs::rmdir(path, thread);
}
orbis::SysResult rename(Thread *thread, ptr<const char> from, ptr<const char> to) {
ORBIS_LOG_TODO(__FUNCTION__, from, to);
return rx::vfs::rename(from, to, thread);
}
orbis::SysResult blockpool_open(orbis::Thread *thread,
orbis::Ref<orbis::File> *file) {
auto dev = static_cast<IoDevice *>(orbis::g_context.blockpoolDevice.get());
@ -633,6 +646,9 @@ ProcessOps rx::procOpsTable = {
.query_memory_protection = query_memory_protection,
.open = open,
.shm_open = shm_open,
.mkdir = mkdir,
.rmdir = rmdir,
.rename = rename,
.blockpool_open = blockpool_open,
.blockpool_map = blockpool_map,
.blockpool_unmap = blockpool_unmap,

View file

@ -6,17 +6,80 @@
#include "orbis/error/SysResult.hpp"
#include <filesystem>
#include <map>
#include <optional>
#include <string_view>
static std::map<std::string, orbis::Ref<IoDevice>> sMountsMap;
static std::map<std::string, orbis::Ref<IoDevice>, std::greater<>> sMountsMap;
void rx::vfs::initialize() {}
void rx::vfs::deinitialize() { sMountsMap.clear(); }
struct DevFs : IoDevice {
std::map<std::string, orbis::Ref<IoDevice>> devices;
orbis::ErrorCode open(orbis::Ref<orbis::File> *file, const char *path,
std::uint32_t flags, std::uint32_t mode,
orbis::Thread *thread) override {
if (auto it = devices.find(path); it != devices.end()) {
return it->second->open(file, path, flags, mode, thread);
}
std::fprintf(stderr, "device %s not exists\n", path);
return orbis::ErrorCode::NOENT;
}
};
static orbis::Ref<DevFs> sDevFs;
struct ProcFs : IoDevice {
orbis::ErrorCode open(orbis::Ref<orbis::File> *file, const char *path,
std::uint32_t flags, std::uint32_t mode,
orbis::Thread *thread) override {
std::fprintf(stderr, "procfs access: %s\n", path);
std::abort();
return orbis::ErrorCode::NOENT;
}
};
void rx::vfs::initialize() {
sDevFs = orbis::knew<DevFs>();
sMountsMap.emplace("/dev/", sDevFs);
sMountsMap.emplace("/proc/", orbis::knew<ProcFs>());
}
void rx::vfs::deinitialize() {
sDevFs = nullptr;
sMountsMap.clear();
}
void rx::vfs::addDevice(std::string name, IoDevice *device) {
sDevFs->devices[std::move(name)] = device;
}
static std::pair<orbis::Ref<IoDevice>, std::string>
get(const std::filesystem::path &guestPath) {
std::string normalPath = std::filesystem::path(guestPath).lexically_normal();
std::string_view path = normalPath;
orbis::Ref<IoDevice> device;
std::string_view prefix;
for (auto &mount : sMountsMap) {
if (!path.starts_with(mount.first)) {
continue;
}
device = mount.second;
path.remove_prefix(mount.first.length());
return {mount.second, std::string(path)};
}
return {};
}
orbis::SysResult rx::vfs::mount(const std::filesystem::path &guestPath,
IoDevice *dev) {
auto [it, inserted] =
sMountsMap.emplace(guestPath.lexically_normal().string(), dev);
auto mp = guestPath.lexically_normal().string();
if (!mp.ends_with("/")) {
mp += "/";
}
auto [it, inserted] = sMountsMap.emplace(std::move(mp), dev);
if (!inserted) {
return orbis::ErrorCode::EXIST;
@ -28,37 +91,47 @@ orbis::SysResult rx::vfs::mount(const std::filesystem::path &guestPath,
orbis::SysResult rx::vfs::open(std::string_view path, int flags, int mode,
orbis::Ref<orbis::File> *file,
orbis::Thread *thread) {
orbis::Ref<IoDevice> device;
bool isCharacterDevice = path.starts_with("/dev/");
for (auto &mount : sMountsMap) {
if (!path.starts_with(mount.first)) {
continue;
}
path.remove_prefix(mount.first.length());
device = mount.second;
break;
auto [device, devPath] = get(path);
if (device == nullptr) {
return orbis::ErrorCode::NOENT;
}
if (isCharacterDevice && device != nullptr) {
if (!path.empty()) {
std::fprintf(stderr,
"vfs::open: access to character device subentry '%s' (%s)\n",
path.data(), std::string(path).c_str());
return orbis::ErrorCode::NOENT;
}
}
if (device != nullptr) {
return (orbis::ErrorCode)device->open(file, std::string(path).c_str(),
flags, mode, thread);
}
if (isCharacterDevice) {
std::fprintf(stderr, "vfs::open: character device '%s' not found.\n",
std::string(path).c_str());
}
return orbis::ErrorCode::NOENT;
return device->open(file, devPath.c_str(), flags, mode, thread);
}
orbis::SysResult rx::vfs::mkdir(std::string_view path, int mode,
orbis::Thread *thread) {
auto [device, devPath] = get(path);
if (device == nullptr) {
return orbis::ErrorCode::NOENT;
}
return device->mkdir(devPath.c_str(), mode, thread);
}
orbis::SysResult rx::vfs::rmdir(std::string_view path, orbis::Thread *thread) {
auto [device, devPath] = get(path);
if (device == nullptr) {
return orbis::ErrorCode::NOENT;
}
return device->rmdir(devPath.c_str(), thread);
}
orbis::SysResult rx::vfs::rename(std::string_view from, std::string_view to,
orbis::Thread *thread) {
auto [fromDevice, fromDevPath] = get(from);
if (fromDevice == nullptr) {
return orbis::ErrorCode::NOENT;
}
auto [toDevice, toDevPath] = get(to);
if (toDevice == nullptr) {
return orbis::ErrorCode::NOENT;
}
if (fromDevice != toDevice) {
std::fprintf(stderr, "cross fs rename operation: %s -> %s\n",
std::string(from).c_str(), std::string(to).c_str());
std::abort();
}
return fromDevice->rename(fromDevPath.c_str(), toDevPath.c_str(), thread);
}

View file

@ -10,7 +10,11 @@ struct IoDevice;
namespace rx::vfs {
void initialize();
void deinitialize();
void addDevice(std::string name, IoDevice *device);
orbis::SysResult mount(const std::filesystem::path &guestPath, IoDevice *dev);
orbis::SysResult open(std::string_view path, int flags, int mode,
orbis::Ref<orbis::File> *file, orbis::Thread *thread);
orbis::SysResult mkdir(std::string_view path, int mode, orbis::Thread *thread);
orbis::SysResult rmdir(std::string_view path, orbis::Thread *thread);
orbis::SysResult rename(std::string_view from, std::string_view to, orbis::Thread *thread);
} // namespace rx::vfs