2023-06-23 02:28:14 +02:00
|
|
|
#include "io-device.hpp"
|
2023-07-04 18:19:17 +02:00
|
|
|
#include "orbis/KernelAllocator.hpp"
|
2023-07-29 18:53:34 +02:00
|
|
|
#include "orbis/file.hpp"
|
|
|
|
|
#include "orbis/stat.hpp"
|
|
|
|
|
#include "orbis/uio.hpp"
|
2023-07-19 17:04:26 +02:00
|
|
|
#include "orbis/utils/Logs.hpp"
|
2023-07-29 21:46:28 +02:00
|
|
|
#include "vm.hpp"
|
2023-07-29 18:53:34 +02:00
|
|
|
#include <cerrno>
|
2023-08-14 22:58:28 +02:00
|
|
|
#include <dirent.h>
|
2023-06-23 02:28:14 +02:00
|
|
|
#include <fcntl.h>
|
2023-10-29 10:30:37 +01:00
|
|
|
#include <filesystem>
|
2023-07-29 18:53:34 +02:00
|
|
|
#include <span>
|
2023-06-23 02:28:14 +02:00
|
|
|
#include <string>
|
2023-07-29 21:46:28 +02:00
|
|
|
#include <sys/mman.h>
|
2023-07-19 17:04:26 +02:00
|
|
|
#include <sys/socket.h>
|
2023-07-29 18:53:34 +02:00
|
|
|
#include <sys/stat.h>
|
|
|
|
|
#include <sys/uio.h>
|
2023-06-23 02:28:14 +02:00
|
|
|
#include <unistd.h>
|
2023-07-29 18:53:34 +02:00
|
|
|
#include <vector>
|
2023-06-23 02:28:14 +02:00
|
|
|
|
2023-07-29 18:53:34 +02:00
|
|
|
struct HostFile : orbis::File {
|
|
|
|
|
int hostFd = -1;
|
2023-10-31 23:58:03 +01:00
|
|
|
bool closeOnExit = true;
|
2023-06-23 02:28:14 +02:00
|
|
|
|
2023-07-29 18:53:34 +02:00
|
|
|
~HostFile() {
|
2023-10-31 23:58:03 +01:00
|
|
|
if (hostFd > 0 && closeOnExit) {
|
2023-07-29 18:53:34 +02:00
|
|
|
::close(hostFd);
|
|
|
|
|
}
|
2023-06-23 02:28:14 +02:00
|
|
|
}
|
2023-07-29 18:53:34 +02:00
|
|
|
};
|
2023-06-23 02:28:14 +02:00
|
|
|
|
2023-07-29 18:53:34 +02:00
|
|
|
struct SocketFile : orbis::File {
|
|
|
|
|
orbis::utils::kstring name;
|
|
|
|
|
int hostFd = -1;
|
2023-06-23 02:28:14 +02:00
|
|
|
|
2023-07-29 18:53:34 +02:00
|
|
|
~SocketFile() {
|
|
|
|
|
if (hostFd > 0) {
|
|
|
|
|
::close(hostFd);
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-06-23 02:28:14 +02:00
|
|
|
};
|
|
|
|
|
|
2023-07-29 18:53:34 +02:00
|
|
|
struct HostFsDevice : IoDevice {
|
|
|
|
|
orbis::kstring hostPath;
|
2023-06-23 02:28:14 +02:00
|
|
|
|
2023-07-29 18:53:34 +02:00
|
|
|
explicit HostFsDevice(orbis::kstring path) : hostPath(std::move(path)) {}
|
|
|
|
|
orbis::ErrorCode open(orbis::Ref<orbis::File> *file, const char *path,
|
2023-07-29 21:46:28 +02:00
|
|
|
std::uint32_t flags, std::uint32_t mode,
|
|
|
|
|
orbis::Thread *thread) override;
|
2023-11-11 15:52:27 +01:00
|
|
|
orbis::ErrorCode unlink(const char *path, bool recursive,
|
|
|
|
|
orbis::Thread *thread) override;
|
|
|
|
|
orbis::ErrorCode createSymlink(const char *target, const char *linkPath,
|
|
|
|
|
orbis::Thread *thread) override;
|
2023-10-31 23:58:03 +01:00
|
|
|
orbis::ErrorCode mkdir(const char *path, int mode,
|
|
|
|
|
orbis::Thread *thread) override;
|
2023-10-29 10:30:37 +01:00
|
|
|
orbis::ErrorCode rmdir(const char *path, orbis::Thread *thread) override;
|
2023-10-31 23:58:03 +01:00
|
|
|
orbis::ErrorCode rename(const char *from, const char *to,
|
|
|
|
|
orbis::Thread *thread) override;
|
2023-07-19 17:04:26 +02:00
|
|
|
};
|
|
|
|
|
|
2023-10-29 10:30:37 +01:00
|
|
|
static orbis::ErrorCode convertErrc(std::errc errc) {
|
|
|
|
|
if (errc == std::errc{}) {
|
2023-10-31 23:58:03 +01:00
|
|
|
return {};
|
2023-10-29 10:30:37 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (errc) {
|
2023-10-31 23:58:03 +01:00
|
|
|
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;
|
2023-10-29 10:30:37 +01:00
|
|
|
default:
|
|
|
|
|
return orbis::ErrorCode::FAULT;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static orbis::ErrorCode convertErrorCode(const std::error_code &code) {
|
|
|
|
|
if (!code) {
|
2023-10-31 23:58:03 +01:00
|
|
|
return {};
|
2023-10-29 10:30:37 +01:00
|
|
|
}
|
|
|
|
|
return convertErrc(static_cast<std::errc>(code.value()));
|
|
|
|
|
}
|
|
|
|
|
|
2023-11-11 18:31:12 +01:00
|
|
|
orbis::ErrorCode convertErrno() {
|
2023-07-29 18:53:34 +02:00
|
|
|
switch (auto error = errno) {
|
|
|
|
|
case EPERM:
|
|
|
|
|
return orbis::ErrorCode::PERM;
|
|
|
|
|
case ENOENT:
|
|
|
|
|
return orbis::ErrorCode::NOENT;
|
|
|
|
|
case EBADF:
|
|
|
|
|
return orbis::ErrorCode::BADF;
|
|
|
|
|
case EIO:
|
|
|
|
|
return orbis::ErrorCode::IO;
|
|
|
|
|
case EACCES:
|
|
|
|
|
return orbis::ErrorCode::ACCES;
|
|
|
|
|
case EEXIST:
|
|
|
|
|
return orbis::ErrorCode::EXIST;
|
|
|
|
|
case EBUSY:
|
|
|
|
|
return orbis::ErrorCode::BUSY;
|
|
|
|
|
case ENOTDIR:
|
|
|
|
|
return orbis::ErrorCode::NOTDIR;
|
|
|
|
|
case EISDIR:
|
|
|
|
|
return orbis::ErrorCode::ISDIR;
|
|
|
|
|
case EFBIG:
|
|
|
|
|
return orbis::ErrorCode::FBIG;
|
|
|
|
|
case ENOSPC:
|
|
|
|
|
return orbis::ErrorCode::NOSPC;
|
|
|
|
|
case ESPIPE:
|
|
|
|
|
return orbis::ErrorCode::SPIPE;
|
|
|
|
|
case EPIPE:
|
|
|
|
|
return orbis::ErrorCode::PIPE;
|
2023-07-29 23:34:52 +02:00
|
|
|
case EINVAL:
|
|
|
|
|
return orbis::ErrorCode::INVAL;
|
2023-07-29 18:53:34 +02:00
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
ORBIS_LOG_ERROR("Unconverted errno", error);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return orbis::ErrorCode::IO;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static orbis::ErrorCode host_read(orbis::File *file, orbis::Uio *uio,
|
|
|
|
|
orbis::Thread *) {
|
|
|
|
|
auto hostFile = static_cast<HostFile *>(file);
|
2023-08-14 22:58:28 +02:00
|
|
|
if (!hostFile->dirEntries.empty())
|
|
|
|
|
return orbis::ErrorCode::ISDIR;
|
|
|
|
|
|
2023-07-29 18:53:34 +02:00
|
|
|
std::vector<iovec> vec;
|
|
|
|
|
for (auto entry : std::span(uio->iov, uio->iovcnt)) {
|
|
|
|
|
vec.push_back({.iov_base = entry.base, .iov_len = entry.len});
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-29 19:45:16 +02:00
|
|
|
ssize_t cnt = 0;
|
2023-07-29 18:53:34 +02:00
|
|
|
if (hostFile->hostFd == 0) {
|
2023-07-29 19:45:16 +02:00
|
|
|
for (auto io : vec) {
|
|
|
|
|
cnt += ::read(hostFile->hostFd, io.iov_base, io.iov_len);
|
|
|
|
|
|
|
|
|
|
if (cnt != io.iov_len) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-07-29 18:53:34 +02:00
|
|
|
} else {
|
|
|
|
|
cnt = ::preadv(hostFile->hostFd, vec.data(), vec.size(), uio->offset);
|
|
|
|
|
}
|
|
|
|
|
if (cnt < 0) {
|
|
|
|
|
return convertErrno();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uio->resid -= cnt;
|
|
|
|
|
uio->offset += cnt;
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static orbis::ErrorCode host_write(orbis::File *file, orbis::Uio *uio,
|
|
|
|
|
orbis::Thread *) {
|
|
|
|
|
auto hostFile = static_cast<HostFile *>(file);
|
2023-08-14 22:58:28 +02:00
|
|
|
if (!hostFile->dirEntries.empty())
|
|
|
|
|
return orbis::ErrorCode::ISDIR;
|
|
|
|
|
|
2023-07-29 18:53:34 +02:00
|
|
|
std::vector<iovec> vec;
|
|
|
|
|
for (auto entry : std::span(uio->iov, uio->iovcnt)) {
|
|
|
|
|
vec.push_back({.iov_base = entry.base, .iov_len = entry.len});
|
|
|
|
|
}
|
|
|
|
|
|
2023-11-11 15:52:27 +01:00
|
|
|
ssize_t cnt =
|
|
|
|
|
::pwritev(hostFile->hostFd, vec.data(), vec.size(), uio->offset);
|
2023-10-31 23:58:03 +01:00
|
|
|
|
|
|
|
|
if (cnt < 0) {
|
2023-07-29 19:45:16 +02:00
|
|
|
for (auto io : vec) {
|
2023-10-31 23:58:03 +01:00
|
|
|
auto result = ::write(hostFile->hostFd, io.iov_base, io.iov_len);
|
|
|
|
|
if (result < 0) {
|
|
|
|
|
return convertErrno();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cnt += result;
|
2023-07-29 19:45:16 +02:00
|
|
|
|
|
|
|
|
if (cnt != io.iov_len) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-07-29 18:53:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uio->resid -= cnt;
|
|
|
|
|
uio->offset += cnt;
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-29 21:46:28 +02:00
|
|
|
static orbis::ErrorCode host_mmap(orbis::File *file, void **address,
|
|
|
|
|
std::uint64_t size, std::int32_t prot,
|
|
|
|
|
std::int32_t flags, std::int64_t offset,
|
|
|
|
|
orbis::Thread *thread) {
|
|
|
|
|
auto hostFile = static_cast<HostFile *>(file);
|
2023-08-14 22:58:28 +02:00
|
|
|
if (!hostFile->dirEntries.empty())
|
|
|
|
|
return orbis::ErrorCode::ISDIR;
|
2023-07-29 21:46:28 +02:00
|
|
|
|
|
|
|
|
auto result =
|
|
|
|
|
rx::vm::map(*address, size, prot, flags, rx::vm::kMapInternalReserveOnly);
|
|
|
|
|
|
|
|
|
|
if (result == (void *)-1) {
|
|
|
|
|
return orbis::ErrorCode::NOMEM;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
result = ::mmap(result, size, prot & rx::vm::kMapProtCpuAll,
|
|
|
|
|
MAP_SHARED | MAP_FIXED, hostFile->hostFd, offset);
|
|
|
|
|
if (result == (void *)-1) {
|
|
|
|
|
auto result = convertErrno();
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::printf("shm mapped at %p-%p\n", result, (char *)result + size);
|
|
|
|
|
|
|
|
|
|
*address = result;
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-29 18:53:34 +02:00
|
|
|
static orbis::ErrorCode host_stat(orbis::File *file, orbis::Stat *sb,
|
|
|
|
|
orbis::Thread *thread) {
|
|
|
|
|
auto hostFile = static_cast<HostFile *>(file);
|
|
|
|
|
struct stat hostStat;
|
|
|
|
|
::fstat(hostFile->hostFd, &hostStat);
|
|
|
|
|
sb->dev = hostStat.st_dev; // TODO
|
|
|
|
|
sb->ino = hostStat.st_ino;
|
|
|
|
|
sb->mode = hostStat.st_mode;
|
|
|
|
|
sb->nlink = hostStat.st_nlink;
|
|
|
|
|
sb->uid = hostStat.st_uid;
|
|
|
|
|
sb->gid = hostStat.st_gid;
|
|
|
|
|
sb->rdev = hostStat.st_rdev;
|
|
|
|
|
sb->atim = {
|
|
|
|
|
.sec = static_cast<uint64_t>(hostStat.st_atim.tv_sec),
|
|
|
|
|
.nsec = static_cast<uint64_t>(hostStat.st_atim.tv_nsec),
|
|
|
|
|
};
|
|
|
|
|
sb->mtim = {
|
|
|
|
|
.sec = static_cast<uint64_t>(hostStat.st_mtim.tv_sec),
|
|
|
|
|
.nsec = static_cast<uint64_t>(hostStat.st_mtim.tv_nsec),
|
|
|
|
|
};
|
|
|
|
|
sb->ctim = {
|
|
|
|
|
.sec = static_cast<uint64_t>(hostStat.st_mtim.tv_sec),
|
|
|
|
|
.nsec = static_cast<uint64_t>(hostStat.st_mtim.tv_nsec),
|
|
|
|
|
};
|
|
|
|
|
sb->size = hostStat.st_size;
|
|
|
|
|
sb->blocks = hostStat.st_blocks;
|
|
|
|
|
sb->blksize = hostStat.st_blksize;
|
|
|
|
|
// TODO
|
|
|
|
|
sb->flags = 0;
|
|
|
|
|
sb->gen = 0;
|
|
|
|
|
sb->lspare = 0;
|
|
|
|
|
sb->birthtim = {
|
|
|
|
|
.sec = static_cast<uint64_t>(hostStat.st_mtim.tv_sec),
|
|
|
|
|
.nsec = static_cast<uint64_t>(hostStat.st_mtim.tv_nsec),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return {};
|
2023-06-23 02:28:14 +02:00
|
|
|
}
|
|
|
|
|
|
2023-07-29 18:53:34 +02:00
|
|
|
static orbis::ErrorCode host_truncate(orbis::File *file, std::uint64_t len,
|
|
|
|
|
orbis::Thread *thread) {
|
|
|
|
|
auto hostFile = static_cast<HostFile *>(file);
|
2023-08-14 22:58:28 +02:00
|
|
|
if (!hostFile->dirEntries.empty())
|
|
|
|
|
return orbis::ErrorCode::ISDIR;
|
|
|
|
|
|
2023-08-13 22:46:03 +02:00
|
|
|
// hack for audio control shared memory
|
|
|
|
|
std::uint64_t realLen = len;
|
|
|
|
|
if (len == 3880) {
|
|
|
|
|
realLen = 0x10000;
|
|
|
|
|
}
|
|
|
|
|
if (::ftruncate(hostFile->hostFd, realLen)) {
|
2023-07-29 18:53:34 +02:00
|
|
|
return convertErrno();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static orbis::ErrorCode socket_ioctl(orbis::File *file, std::uint64_t request,
|
|
|
|
|
void *argp, orbis::Thread *thread) {
|
|
|
|
|
auto soc = static_cast<SocketFile *>(file);
|
|
|
|
|
ORBIS_LOG_FATAL("Unhandled socket ioctl", request, soc->name);
|
|
|
|
|
return {};
|
2023-06-23 02:28:14 +02:00
|
|
|
}
|
|
|
|
|
|
2023-07-29 18:53:34 +02:00
|
|
|
static const orbis::FileOps hostOps = {
|
|
|
|
|
.read = host_read,
|
|
|
|
|
.write = host_write,
|
|
|
|
|
.truncate = host_truncate,
|
|
|
|
|
.stat = host_stat,
|
2023-07-29 21:46:28 +02:00
|
|
|
.mmap = host_mmap,
|
2023-07-29 18:53:34 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const orbis::FileOps socketOps = {
|
|
|
|
|
.ioctl = socket_ioctl,
|
|
|
|
|
};
|
2023-06-23 02:28:14 +02:00
|
|
|
|
2023-07-29 18:53:34 +02:00
|
|
|
IoDevice *createHostIoDevice(orbis::kstring hostPath) {
|
2023-10-29 10:30:37 +01:00
|
|
|
while (hostPath.size() > 1 && hostPath.ends_with("/")) {
|
|
|
|
|
hostPath.resize(hostPath.size() - 1);
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-29 18:53:34 +02:00
|
|
|
return orbis::knew<HostFsDevice>(std::move(hostPath));
|
2023-06-23 02:28:14 +02:00
|
|
|
}
|
|
|
|
|
|
2023-07-29 18:53:34 +02:00
|
|
|
orbis::ErrorCode createSocket(orbis::Ref<orbis::File> *file,
|
|
|
|
|
orbis::kstring name, int dom, int type,
|
|
|
|
|
int prot) {
|
|
|
|
|
auto fd = ::socket(dom, type, prot);
|
2023-10-30 23:07:52 +01:00
|
|
|
// if (fd < 0) {
|
|
|
|
|
// return convertErrno();
|
|
|
|
|
// }
|
2023-07-29 18:53:34 +02:00
|
|
|
|
|
|
|
|
auto s = orbis::knew<SocketFile>();
|
|
|
|
|
s->name = std::move(name);
|
|
|
|
|
s->hostFd = fd;
|
|
|
|
|
s->ops = &socketOps;
|
|
|
|
|
*file = s;
|
|
|
|
|
return {};
|
2023-06-23 02:28:14 +02:00
|
|
|
}
|
|
|
|
|
|
2023-07-29 18:53:34 +02:00
|
|
|
orbis::ErrorCode HostFsDevice::open(orbis::Ref<orbis::File> *file,
|
|
|
|
|
const char *path, std::uint32_t flags,
|
2023-07-29 21:46:28 +02:00
|
|
|
std::uint32_t mode, orbis::Thread *thread) {
|
2023-07-29 18:53:34 +02:00
|
|
|
auto realPath = hostPath + "/" + path;
|
2023-06-23 02:28:14 +02:00
|
|
|
|
|
|
|
|
int realFlags = flags & O_ACCMODE;
|
|
|
|
|
flags &= ~O_ACCMODE;
|
|
|
|
|
|
|
|
|
|
if ((flags & kOpenFlagAppend) != 0) {
|
|
|
|
|
realFlags |= O_APPEND;
|
|
|
|
|
flags &= ~kOpenFlagAppend;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((flags & kOpenFlagNonBlock) != 0) {
|
|
|
|
|
realFlags |= O_NONBLOCK;
|
|
|
|
|
flags &= ~kOpenFlagNonBlock;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((flags & kOpenFlagFsync) != 0) {
|
|
|
|
|
realFlags |= O_FSYNC;
|
|
|
|
|
flags &= ~kOpenFlagFsync;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((flags & kOpenFlagAsync) != 0) {
|
|
|
|
|
realFlags |= O_ASYNC;
|
|
|
|
|
flags &= ~kOpenFlagAsync;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((flags & kOpenFlagTrunc) != 0) {
|
|
|
|
|
realFlags |= O_TRUNC;
|
|
|
|
|
flags &= ~kOpenFlagTrunc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((flags & kOpenFlagCreat) != 0) {
|
|
|
|
|
realFlags |= O_CREAT;
|
|
|
|
|
flags &= ~kOpenFlagCreat;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((flags & kOpenFlagExcl) != 0) {
|
|
|
|
|
realFlags |= O_EXCL;
|
|
|
|
|
flags &= ~kOpenFlagExcl;
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-29 18:53:34 +02:00
|
|
|
if ((flags & kOpenFlagDirectory) != 0) {
|
|
|
|
|
realFlags |= O_DIRECTORY;
|
|
|
|
|
flags &= ~kOpenFlagDirectory;
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-23 02:28:14 +02:00
|
|
|
if (flags != 0) {
|
2023-07-29 18:53:34 +02:00
|
|
|
ORBIS_LOG_ERROR("host_open: ***ERROR*** Unhandled open flags", flags);
|
2023-06-23 02:28:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int hostFd = ::open(realPath.c_str(), realFlags, 0777);
|
|
|
|
|
|
|
|
|
|
if (hostFd < 0) {
|
2023-07-29 18:53:34 +02:00
|
|
|
auto error = convertErrno();
|
2023-10-29 10:30:37 +01:00
|
|
|
ORBIS_LOG_ERROR("host_open failed", path, realPath, error);
|
2023-07-29 18:53:34 +02:00
|
|
|
return error;
|
2023-06-23 02:28:14 +02:00
|
|
|
}
|
|
|
|
|
|
2023-08-14 22:58:28 +02:00
|
|
|
// Assume the file is a directory and try to read direntries
|
|
|
|
|
orbis::utils::kvector<orbis::Dirent> dirEntries;
|
|
|
|
|
while (true) {
|
|
|
|
|
::dirent64 hostEntry{};
|
|
|
|
|
auto r = getdents64(hostFd, &hostEntry, sizeof(hostEntry));
|
|
|
|
|
if (r <= 0)
|
|
|
|
|
break;
|
|
|
|
|
|
2023-11-10 19:15:10 +01:00
|
|
|
if (hostEntry.d_name == std::string_view("..")) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-14 22:58:28 +02:00
|
|
|
auto &entry = dirEntries.emplace_back();
|
|
|
|
|
entry.fileno = dirEntries.size(); // TODO
|
|
|
|
|
entry.reclen = sizeof(entry);
|
|
|
|
|
entry.namlen = std::strlen(hostEntry.d_name);
|
|
|
|
|
std::strncpy(entry.name, hostEntry.d_name, sizeof(entry.name));
|
|
|
|
|
if (hostEntry.d_type == DT_REG)
|
|
|
|
|
entry.type = orbis::kDtReg;
|
|
|
|
|
else if (hostEntry.d_type == DT_DIR || hostEntry.d_type == DT_LNK)
|
|
|
|
|
entry.type = orbis::kDtDir; // Assume symlinks to be dirs
|
|
|
|
|
else {
|
|
|
|
|
ORBIS_LOG_ERROR("host_open: unknown directory entry d_type", realPath,
|
|
|
|
|
hostEntry.d_name, hostEntry.d_type);
|
|
|
|
|
dirEntries.pop_back();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-29 18:53:34 +02:00
|
|
|
auto newFile = orbis::knew<HostFile>();
|
|
|
|
|
newFile->hostFd = hostFd;
|
2023-08-14 22:58:28 +02:00
|
|
|
newFile->dirEntries = std::move(dirEntries);
|
2023-07-29 18:53:34 +02:00
|
|
|
newFile->ops = &hostOps;
|
|
|
|
|
newFile->device = this;
|
|
|
|
|
*file = newFile;
|
|
|
|
|
return {};
|
2023-06-23 02:28:14 +02:00
|
|
|
}
|
|
|
|
|
|
2023-11-11 15:52:27 +01:00
|
|
|
orbis::ErrorCode HostFsDevice::unlink(const char *path, bool recursive,
|
|
|
|
|
orbis::Thread *thread) {
|
|
|
|
|
std::error_code ec;
|
|
|
|
|
|
|
|
|
|
if (recursive) {
|
|
|
|
|
std::filesystem::remove_all(hostPath + "/" + path, ec);
|
|
|
|
|
} else {
|
|
|
|
|
std::filesystem::remove(hostPath + "/" + path, ec);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return convertErrorCode(ec);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
orbis::ErrorCode HostFsDevice::createSymlink(const char *linkPath,
|
|
|
|
|
const char *target,
|
|
|
|
|
orbis::Thread *thread) {
|
|
|
|
|
std::error_code ec;
|
|
|
|
|
std::filesystem::create_symlink(
|
|
|
|
|
std::filesystem::absolute(hostPath + "/" + linkPath),
|
|
|
|
|
hostPath + "/" + target, ec);
|
|
|
|
|
return convertErrorCode(ec);
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-31 23:58:03 +01:00
|
|
|
orbis::ErrorCode HostFsDevice::mkdir(const char *path, int mode,
|
|
|
|
|
orbis::Thread *thread) {
|
2023-10-29 10:30:37 +01:00
|
|
|
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);
|
|
|
|
|
}
|
2023-10-31 23:58:03 +01:00
|
|
|
orbis::ErrorCode HostFsDevice::rename(const char *from, const char *to,
|
|
|
|
|
orbis::Thread *thread) {
|
2023-10-29 10:30:37 +01:00
|
|
|
std::error_code ec;
|
|
|
|
|
std::filesystem::rename(hostPath + "/" + from, hostPath + "/" + to, ec);
|
|
|
|
|
return convertErrorCode(ec);
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-29 18:53:34 +02:00
|
|
|
orbis::File *createHostFile(int hostFd, orbis::Ref<IoDevice> device) {
|
|
|
|
|
auto newFile = orbis::knew<HostFile>();
|
|
|
|
|
newFile->hostFd = hostFd;
|
|
|
|
|
newFile->ops = &hostOps;
|
|
|
|
|
newFile->device = device;
|
|
|
|
|
return newFile;
|
2023-06-23 02:28:14 +02:00
|
|
|
}
|
2023-07-19 17:04:26 +02:00
|
|
|
|
2023-07-29 18:53:34 +02:00
|
|
|
struct FdWrapDevice : public IoDevice {
|
|
|
|
|
int fd;
|
2023-07-19 17:04:26 +02:00
|
|
|
|
2023-07-29 18:53:34 +02:00
|
|
|
orbis::ErrorCode open(orbis::Ref<orbis::File> *file, const char *path,
|
2023-07-29 21:46:28 +02:00
|
|
|
std::uint32_t flags, std::uint32_t mode,
|
|
|
|
|
orbis::Thread *thread) override {
|
2023-07-29 18:53:34 +02:00
|
|
|
*file = createHostFile(fd, this);
|
2023-10-31 23:58:03 +01:00
|
|
|
static_cast<HostFile *>(file->get())->closeOnExit = false;
|
2023-07-29 18:53:34 +02:00
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
};
|
2023-07-19 17:04:26 +02:00
|
|
|
|
2023-07-29 18:53:34 +02:00
|
|
|
IoDevice *createFdWrapDevice(int fd) {
|
|
|
|
|
auto result = orbis::knew<FdWrapDevice>();
|
|
|
|
|
result->fd = fd;
|
|
|
|
|
return result;
|
2023-07-19 17:04:26 +02:00
|
|
|
}
|