Separated virtual from "regular" files

Started adding proper size tracking for stat
Added av_contents to preinitialized fs
This commit is contained in:
Marek Ledworowski 2025-10-26 01:47:09 +02:00
parent 538ee9361d
commit c328815591
13 changed files with 227 additions and 139 deletions

View File

@ -669,8 +669,28 @@ set(QUASIFS src/core/file_sys/quasifs/src/quasifs.cpp
src/core/file_sys/quasifs/src/quasifs_inode_device.cpp
src/core/file_sys/quasifs/src/quasifs_inode_directory.cpp
src/core/file_sys/quasifs/src/quasifs_inode_regularfile.cpp
src/core/file_sys/quasifs/src/quasifs_inode_virtualfile.cpp
src/core/file_sys/quasifs/src/quasifs_inode_symlink.cpp
src/core/file_sys/quasifs/src/quasifs_partition.cpp
src/core/file_sys/quasifs/src/quasifs_partition.cpp
src/core/file_sys/devices/base_device.cpp
src/core/file_sys/devices/base_device.h
src/core/file_sys/devices/console_device.cpp
src/core/file_sys/devices/console_device.h
src/core/file_sys/devices/deci_tty6_device.cpp
src/core/file_sys/devices/deci_tty6_device.h
src/core/file_sys/devices/ioccom.h
src/core/file_sys/devices/logger.cpp
src/core/file_sys/devices/logger.h
src/core/file_sys/devices/nop_device.h
src/core/file_sys/devices/null_device.cpp
src/core/file_sys/devices/null_device.h
src/core/file_sys/devices/random_device.cpp
src/core/file_sys/devices/random_device.h
src/core/file_sys/devices/srandom_device.cpp
src/core/file_sys/devices/srandom_device.h
src/core/file_sys/devices/zero_device.cpp
src/core/file_sys/devices/zero_device.h
)
set(HOSTIO src/core/file_sys/hostio/src/host_io_base.cpp
@ -766,26 +786,6 @@ set(CORE src/core/aerolib/stubs.cpp
src/core/aerolib/aerolib.h
src/core/address_space.cpp
src/core/address_space.h
src/core/file_sys/devices/base_device.cpp
src/core/file_sys/devices/base_device.h
src/core/file_sys/devices/console_device.cpp
src/core/file_sys/devices/console_device.h
src/core/file_sys/devices/deci_tty6_device.cpp
src/core/file_sys/devices/deci_tty6_device.h
src/core/file_sys/devices/ioccom.h
src/core/file_sys/devices/logger.cpp
src/core/file_sys/devices/logger.h
src/core/file_sys/devices/nop_device.h
src/core/file_sys/devices/null_device.cpp
src/core/file_sys/devices/null_device.h
src/core/file_sys/devices/random_device.cpp
src/core/file_sys/devices/random_device.h
src/core/file_sys/devices/srandom_device.cpp
src/core/file_sys/devices/srandom_device.h
src/core/file_sys/devices/zero_device.cpp
src/core/file_sys/devices/zero_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

View File

@ -12,6 +12,7 @@
#include "../../quasifs/quasifs_inode_directory.h"
#include "../../quasifs/quasifs_inode_regularfile.h"
#include "../../quasifs/quasifs_inode_symlink.h"
#include "../../quasifs/quasifs_inode_virtualfile.h"
#include "../../quasifs/quasifs_partition.h"
#include "../host_io_virtual.h"
@ -41,24 +42,20 @@ int HostIO_Virtual::Open(const fs::path& path, int flags, u16 mode) {
if ((flags & QUASI_O_CREAT) == 0)
return -QUASI_ENOENT;
target = RegularFile::Create();
target =
this->host_bound ? QuasiFile::Create<RegularFile>() : QuasiFile::Create<VirtualFile>();
target->chmod(mode);
if (0 != part->touch(parent, this->res->leaf, target))
// touch failed in target directory, issue with resolve() most likely
// touch failed in target directory, issue with resolve() is most likely
return -QUASI_EFAULT;
this->res->node = target;
}
// at this point target should exist
if (flags & QUASI_O_TRUNC) {
if (target->is_file())
std::static_pointer_cast<RegularFile>(target)->ftruncate(0);
else if (target->is_dir())
return -QUASI_EISDIR;
else
return -QUASI_EINVAL;
if (int status = target->ftruncate(0); status != 0)
return status;
}
// if exists and is a directory, can't be opened with any kind of write
@ -84,7 +81,8 @@ int HostIO_Virtual::Creat(const fs::path& path, u16 mode) {
return -QUASI_ENOTDIR;
dir_ptr parent = std::static_pointer_cast<Directory>(this->res->node);
file_ptr new_file = RegularFile::Create();
file_ptr new_file =
this->host_bound ? QuasiFile::Create<RegularFile>() : QuasiFile::Create<VirtualFile>();
return this->res->mountpoint->touch(parent, path.filename(), new_file);
}
@ -171,10 +169,7 @@ int HostIO_Virtual::Truncate(const fs::path& path, u64 size) {
if (!node->is_file())
return -QUASI_EINVAL;
if (host_bound)
return std::static_pointer_cast<RegularFile>(handle->node)->MockTruncate(size);
else
return std::static_pointer_cast<RegularFile>(handle->node)->ftruncate(size);
return handle->node->ftruncate(size);
}
int HostIO_Virtual::FTruncate(const int fd, u64 size) {
@ -192,10 +187,7 @@ int HostIO_Virtual::FTruncate(const int fd, u64 size) {
if (!node->is_file())
return -QUASI_EINVAL;
if (host_bound)
return std::static_pointer_cast<RegularFile>(handle->node)->MockTruncate(size);
else
return std::static_pointer_cast<RegularFile>(handle->node)->ftruncate(size);
return handle->node->ftruncate(size);
}
u64 HostIO_Virtual::LSeek(const int fd, u64 offset, QuasiFS::SeekOrigin origin) {
@ -245,14 +237,7 @@ s64 HostIO_Virtual::PWrite(const int fd, const void* buf, u64 count, u64 offset)
if (handle->append)
offset = node->st.st_size;
s64 bw = 0;
if (this->host_bound && node->is_file()) {
bw = std::static_pointer_cast<RegularFile>(node)->MockWrite(offset, buf, count);
} else
bw = node->pwrite(buf, count, offset);
return bw;
return node->pwrite(buf, count, offset);
}
s64 HostIO_Virtual::Read(const int fd, void* buf, u64 count) {
@ -273,9 +258,6 @@ s64 HostIO_Virtual::PRead(const int fd, void* buf, u64 count, u64 offset) {
if (nullptr == node)
return -QUASI_EBADF;
if (this->host_bound && node->is_file())
return std::static_pointer_cast<RegularFile>(node)->MockRead(offset, buf, count);
return node->pread(buf, count, offset);
}

View File

@ -30,8 +30,8 @@ class Inode;
using inode_ptr = std::shared_ptr<Inode>;
class Partition;
using partition_ptr = std::shared_ptr<Partition>;
class RegularFile;
using file_ptr = std::shared_ptr<RegularFile>;
class QuasiFile;
using file_ptr = std::shared_ptr<QuasiFile>;
class Symlink;
using symlink_ptr = std::shared_ptr<Symlink>;
class Directory;

View File

@ -29,6 +29,9 @@ public:
// s64 pread(void* buf, size_t count, u64 offset) override;
// s64 pwrite(const void* buf, size_t count, u64 offset) override;
int ftruncate(s64 length) override {
return -QUASI_EISDIR;
}
int fstat(Libraries::Kernel::OrbisKernelStat* sb) override {
this->st.st_size = entries.size() * 32;

View File

@ -0,0 +1,29 @@
// INAA License @marecl 2025
#pragma once
#include "common/assert.h"
#include "quasi_types.h"
#include "quasifs_inode.h"
namespace QuasiFS {
class QuasiFile : public Inode {
public:
QuasiFile() {
st.st_mode = 0000755 | QUASI_S_IFREG;
st.st_nlink = 0;
};
~QuasiFile() = default;
template <typename T, typename... Args>
static file_ptr Create(Args&&... args) {
if constexpr (std::is_base_of_v<QuasiFile, T>)
return std::make_shared<T>(std::forward<Args>(args)...);
UNREACHABLE();
}
};
} // namespace QuasiFS

View File

@ -3,21 +3,16 @@
#pragma once
#include "quasi_types.h"
#include "quasifs_inode.h"
#include "quasifs_inode_file.h"
namespace QuasiFS {
class RegularFile final : public Inode {
std::vector<char> data{};
class RegularFile final : public QuasiFile {
public:
RegularFile();
RegularFile() = default;
~RegularFile() = default;
static file_ptr Create(void) {
return std::make_shared<RegularFile>();
}
//
// Working functions
//
@ -26,14 +21,6 @@ public:
s64 pread(void* buf, size_t count, u64 offset) override;
s64 pwrite(const void* buf, size_t count, u64 offset) override;
s32 ftruncate(s64 length) override;
//
// Mock functions
// Work normally, but don't write data to internal storage
//
s64 MockRead(u64 offset, void* buf, u64 count);
s64 MockWrite(u64 offset, const void* buf, u64 count);
int MockTruncate(u64 length);
};
} // namespace QuasiFS

View File

@ -0,0 +1,29 @@
// INAA License @marecl 2025
#pragma once
#include "common/assert.h"
#include "quasi_types.h"
#include "quasifs_inode_file.h"
namespace QuasiFS {
class VirtualFile final : public QuasiFile {
std::vector<char> data{};
public:
VirtualFile() = default;
~VirtualFile() = default;
//
// Working functions
//
s64 read(void* buf, size_t count) override;
s64 write(const void* buf, size_t count) override;
s64 pread(void* buf, size_t count, u64 offset) override;
s64 pwrite(const void* buf, size_t count, u64 offset) override;
s32 ftruncate(s64 length) override;
};
} // namespace QuasiFS

View File

@ -8,7 +8,7 @@
namespace QuasiFS {
typedef struct {
typedef struct _fsoptions_t {
fs::path host_root{};
int root_permissions = 0755;
@ -20,7 +20,8 @@ typedef struct {
* File can grow as big as it wants, st_blocks is updated only when it exceeds ioblock size
*/
u64 ioblock = 4096;
u32 block_size = 512;
u32 ioblock_size = 4096;
} fsoptions_t;
class Partition : public std::enable_shared_from_this<Partition> {
@ -32,20 +33,31 @@ private:
// file list
std::unordered_map<fileno_t, inode_ptr> inode_table{};
// root directory
dir_ptr root;
// next available fileno
fileno_t next_fileno = 2;
// technically it's a device+partition id, but block id is enough lmao
const blkid_t block_id;
static inline blkid_t next_block_id = 1;
// path to host's directory this will be bound to
const fs::path host_root{};
// IO block size, allocation unit (multiples of 512)
const u32 ioblock_size{4096};
// amount of raw on-disk blocks per io block
// this is pretty much so we don't recalculate it over and over and over
// and
const u32 block_size{512};
public:
// host-bound directory, permissions for root directory
Partition();
Partition(fsoptions_t options);
Partition(fsoptions_t options) = delete;
Partition(const fs::path& host_root = "", const int root_permissions = 0755,
const u32 ioblock_size = 4096);
const u32 block_size = 8, const u32 ioblock_size = 4096);
~Partition() = default;
template <typename... Args>

View File

@ -8,6 +8,7 @@
#include "core/file_sys/quasifs/quasifs_inode_directory.h"
#include "core/file_sys/quasifs/quasifs_inode_regularfile.h"
#include "core/file_sys/quasifs/quasifs_inode_symlink.h"
#include "core/file_sys/quasifs/quasifs_inode_virtualfile.h"
#include "core/file_sys/quasifs/quasifs_partition.h"
#include "../../quasi_log.h"
@ -408,7 +409,7 @@ void QFS::SyncHostImpl(partition_ptr part) {
new_inode = Directory::Create();
part->mkdir(parent_dir, leaf, std::static_pointer_cast<Directory>(new_inode));
} else if (entry->is_regular_file()) {
new_inode = RegularFile::Create();
new_inode = QuasiFile::Create<RegularFile>();
part->touch(parent_dir, leaf, std::static_pointer_cast<RegularFile>(new_inode));
} else {
LogError("Unsupported host file type: {}", entry_path.string());

View File

@ -7,11 +7,6 @@
namespace QuasiFS {
RegularFile::RegularFile() {
st.st_mode = 0000755 | QUASI_S_IFREG;
st.st_nlink = 0;
}
s64 RegularFile::read(void* buf, size_t count) {
return pread(buf, count, 0);
}
@ -21,63 +16,26 @@ s64 RegularFile::write(const void* buf, size_t count) {
}
s64 RegularFile::pread(void* buf, size_t count, u64 offset) {
s64 idx;
u64 read_amt = this->data.size() - offset - count;
auto size = &this->st.st_size;
auto end_pos = offset + count;
// if >= 0 - we're good to go
// <0 - n-bytes are missing, won't enter loop
read_amt = count + read_amt * (read_amt < 0);
for (idx = 0; idx < read_amt; idx++) {
char c = this->data.at(idx + offset);
static_cast<char*>(buf)[idx] = c;
}
return read_amt;
return end_pos > *size ? *size - offset : count;
}
s64 RegularFile::pwrite(const void* buf, size_t count, u64 offset) {
auto size = &this->st.st_size;
auto end_pos = offset + count;
*size = end_pos > *size ? end_pos : *size;
// size can only be greater, so it will always scale up
this->data.resize(*size, 0);
for (u64 idx = offset; idx < *size; idx++)
this->data[idx] = static_cast<const char*>(buf)[idx];
return count;
}
s32 RegularFile::ftruncate(s64 length) {
if (length < 0)
return -QUASI_EINVAL;
this->data.resize(length, 0);
this->st.st_size = length;
return 0;
}
s64 RegularFile::MockRead(u64 offset, void* buf, u64 count) {
auto size = &this->st.st_size;
auto end_pos = offset + count;
return end_pos > *size ? *size - offset : count;
}
s64 RegularFile::MockWrite(u64 offset, const void* buf, u64 count) {
auto size = &this->st.st_size;
auto end_pos = offset + count;
*size = end_pos > *size ? end_pos : *size;
return count;
}
int RegularFile::MockTruncate(u64 length) {
if (length < 0)
return -QUASI_EINVAL;
this->st.st_size = length;
return 0;
}
} // namespace QuasiFS

View File

@ -0,0 +1,56 @@
// INAA License @marecl 2025
#include <vector>
#include "../quasi_errno.h"
#include "core/file_sys/quasifs/quasifs_inode_virtualfile.h"
namespace QuasiFS {
s64 VirtualFile::read(void* buf, size_t count) {
return pread(buf, count, 0);
}
s64 VirtualFile::write(const void* buf, size_t count) {
return pwrite(buf, count, 0);
}
s64 VirtualFile::pread(void* buf, size_t count, u64 offset) {
s64 idx;
s64 read_amt = this->data.size() - offset - count;
// if >= 0 - we're good to go
// <0 - n-bytes are missing, won't enter loop
read_amt = count + read_amt * (read_amt < 0);
for (idx = 0; idx < read_amt; idx++) {
char c = this->data.at(idx + offset);
static_cast<char*>(buf)[idx] = c;
}
return read_amt;
}
s64 VirtualFile::pwrite(const void* buf, size_t count, u64 offset) {
auto size = &this->st.st_size;
auto end_pos = offset + count;
*size = end_pos > *size ? end_pos : *size;
// size can only be greater, so it will always scale up
this->data.resize(*size, 0);
for (u64 idx = offset; idx < *size; idx++)
this->data[idx] = static_cast<const char*>(buf)[idx];
return count;
}
s32 VirtualFile::ftruncate(s64 length) {
if (length < 0)
return -QUASI_EINVAL;
this->data.resize(length, 0);
this->st.st_size = length;
return 0;
}
} // namespace QuasiFS

View File

@ -12,10 +12,12 @@
namespace QuasiFS {
Partition::Partition() : Partition("", 0755, 4096) {}
Partition::Partition() : Partition("", 0755, 512, 4096) {}
Partition::Partition(const fs::path& host_root, const int root_permissions,const u32 ioblock_size)
: block_id(next_block_id++), host_root(host_root.lexically_normal()) {
Partition::Partition(const fs::path& host_root, const int root_permissions, const u32 blocks_per_io,
const u32 ioblock_size)
: block_id(next_block_id++), host_root(host_root.lexically_normal()),
block_size(block_size), ioblock_size(ioblock_size) {
this->root = Directory::Create();
// clear defaults, write
chmod(this->root, root_permissions);
@ -192,6 +194,15 @@ int Partition::touch(dir_ptr parent, const std::string& name, inode_ptr child) {
if (nullptr == parent)
return -QUASI_EINVAL;
// auto* csize = &child->st.st_size;
// auto* cbsize = &child->st.st_blksize;
// auto* cblks = &child->st.st_blocks;
// *cbsize = this->ioblock_size;
// *cblks = blocks_per_io * (*csize) / (*cbsize);
child->st.st_blksize = ioblock_size;
auto ret = parent->link(name, child);
if (ret == 0)
IndexInode(child);
@ -206,6 +217,7 @@ int Partition::mkdir(dir_ptr parent, const std::string& name, dir_ptr child) {
if (nullptr == parent)
return -QUASI_ENOENT;
child->st.st_blksize = ioblock_size;
int ret = parent->link(name, child);
if (ret == 0)

View File

@ -52,10 +52,10 @@
#include "core/file_sys/devices/deci_tty6_device.h"
#include "core/file_sys/devices/logger.h"
#include "core/file_sys/devices/nop_device.h"
#include "core/file_sys/devices/null_device.h"
#include "core/file_sys/devices/random_device.h"
#include "core/file_sys/devices/srandom_device.h"
#include "core/file_sys/devices/zero_device.h"
#include "core/file_sys/devices/null_device.h"
Frontend::WindowSDL* g_window = nullptr;
@ -95,18 +95,31 @@ void Emulator::LoadFilesystem(const std::filesystem::path& game_folder, const st
auto* qfs = Common::Singleton<QuasiFS::QFS>::Instance();
qfs->Operation.Chmod("/", 0777);
QuasiFS::partition_ptr partition_app0 = QuasiFS::Partition::Create(game_folder, 0555);
QuasiFS::partition_ptr partition_data = QuasiFS::Partition::Create(mount_data_dir, 777);
QuasiFS::partition_ptr partition_dev = QuasiFS::Partition::Create("", 0755);
QuasiFS::partition_ptr partition_av_contents = QuasiFS::Partition::Create("", 0775, 512, 16384);
QuasiFS::partition_ptr partition_av_contents_photo =
QuasiFS::Partition::Create("", 0755, 4096, 32768);
QuasiFS::partition_ptr partition_av_contents_thumbs =
QuasiFS::Partition::Create("", 0755, 4096, 32768);
QuasiFS::partition_ptr partition_av_contents_video =
QuasiFS::Partition::Create("", 0755, 4096, 32768);
QuasiFS::partition_ptr partition_app0 =
QuasiFS::Partition::Create(game_folder, 0555, 512, 65536);
QuasiFS::partition_ptr partition_data =
QuasiFS::Partition::Create(mount_data_dir, 0777, 4096, 32768);
QuasiFS::partition_ptr partition_dev = QuasiFS::Partition::Create("", 0755, 16384, 16384);
// no idea what are the block sizes for these 3
QuasiFS::partition_ptr partition_download =
QuasiFS::Partition::Create(mount_download_dir, 0777);
QuasiFS::partition_ptr partition_hostapp = QuasiFS::Partition::Create(game_folder, 0777);
QuasiFS::partition_ptr partition_temp = QuasiFS::Partition::Create(mount_temp_dir, 0777);
QuasiFS::Partition::Create(mount_download_dir, 0777, 512, 65536);
QuasiFS::partition_ptr partition_hostapp =
QuasiFS::Partition::Create(game_folder, 0777, 2048, 16384);
QuasiFS::partition_ptr partition_temp =
QuasiFS::Partition::Create(mount_temp_dir, 0777, 512, 16384);
qfs->Operation.MKDir("/av_contents", 0775);
qfs->Operation.MKDir("/av_contents/photo", 0755);
qfs->Operation.MKDir("/av_contents/video", 0755);
qfs->Operation.MKDir("/av_contents/thumbnails", 0755);
qfs->Operation.MKDir("/av_contents/video", 0755);
qfs->Operation.MKDir("/app0", 0555);
qfs->Operation.MKDir("/data", 0777);
qfs->Operation.MKDir("/dev", 0555);
@ -115,12 +128,18 @@ void Emulator::LoadFilesystem(const std::filesystem::path& game_folder, const st
qfs->Operation.MKDir("/temp", 0777);
qfs->Operation.MKDir("/temp0", 0777);
qfs->Mount("/av_contents", partition_av_contents, QuasiFS::MountOptions::MOUNT_RW);
qfs->Mount("/av_contents/photo", partition_av_contents_photo, QuasiFS::MountOptions::MOUNT_RW);
qfs->Mount("/av_contents/thumbnails", partition_av_contents_thumbs,
QuasiFS::MountOptions::MOUNT_RW);
qfs->Mount("/av_contents/video", partition_av_contents_video, QuasiFS::MountOptions::MOUNT_RW);
qfs->Mount("/app0", partition_app0, QuasiFS::MountOptions::MOUNT_NOOPT);
qfs->Mount("/data", partition_data, QuasiFS::MountOptions::MOUNT_RW);
qfs->Mount("/dev", partition_dev, QuasiFS::MountOptions::MOUNT_RW);
qfs->Mount("/download0", partition_download, QuasiFS::MountOptions::MOUNT_RW);
//qfs->Mount("/hostapp", partition_hostapp,
// QuasiFS::MountOptions::MOUNT_NOOPT | QuasiFS::MountOptions::MOUNT_BIND);
// qfs->Mount("/hostapp", partition_hostapp,
// QuasiFS::MountOptions::MOUNT_NOOPT | QuasiFS::MountOptions::MOUNT_BIND);
qfs->Mount("/temp", partition_temp, QuasiFS::MountOptions::MOUNT_RW);
qfs->Mount("/temp0", partition_temp,
QuasiFS::MountOptions::MOUNT_RW | QuasiFS::MountOptions::MOUNT_BIND);
@ -150,18 +169,18 @@ void Emulator::LoadFilesystem(const std::filesystem::path& game_folder, const st
qfs->ForceInsert("/dev", "zero", QuasiFS::Device::Create<Devices::ZeroDevice>());
qfs->ForceInsert("/dev", "null", QuasiFS::Device::Create<Devices::NullDevice>());
qfs->Operation.Chmod("/dev/deci_stderr",0666);
qfs->Operation.Chmod("/dev/deci_stdout",0666);
qfs->Operation.Chmod("/dev/random",0666);
qfs->Operation.Chmod("/dev/urandom",0666);
qfs->Operation.Chmod("/dev/srandom",0666);
qfs->Operation.Chmod("/dev/deci_stderr", 0666);
qfs->Operation.Chmod("/dev/deci_stdout", 0666);
qfs->Operation.Chmod("/dev/random", 0666);
qfs->Operation.Chmod("/dev/urandom", 0666);
qfs->Operation.Chmod("/dev/srandom", 0666);
if (int fd_dev = qfs->Operation.Open("/dev/stdin", QUASI_O_RDONLY); fd_dev != 0)
LOG_CRITICAL(Kernel_Fs, "XDXDXD 0");
if (int fd_dev = qfs->Operation.Open("/dev/stdout", QUASI_O_WRONLY); fd_dev != 1)
LOG_CRITICAL(Kernel_Fs, "XDXDXD 1 != {}",fd_dev);
LOG_CRITICAL(Kernel_Fs, "XDXDXD 1 != {}", fd_dev);
if (int fd_dev = qfs->Operation.Open("/dev/stderr", QUASI_O_WRONLY); fd_dev != 2)
LOG_CRITICAL(Kernel_Fs, "XDXDXD 2 != {}",fd_dev);
LOG_CRITICAL(Kernel_Fs, "XDXDXD 2 != {}", fd_dev);
//