mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2026-04-26 04:35:24 -06:00
Implemented dirents (normal)
Minor movements
This commit is contained in:
parent
4e07f5c2e1
commit
5abfa01ccd
@ -659,6 +659,7 @@ set(QUASIFS src/core/file_sys/quasifs/src/quasifs.cpp
|
||||
src/core/file_sys/quasifs/src/quasifs_vdriver.cpp
|
||||
src/core/file_sys/quasifs/src/quasifs_inode_quasi_device.cpp
|
||||
src/core/file_sys/quasifs/src/quasifs_inode_quasi_directory.cpp
|
||||
src/core/file_sys/quasifs/src/quasifs_inode_quasi_directory_pfs.cpp
|
||||
src/core/file_sys/quasifs/src/quasifs_inode_quasi_file.cpp
|
||||
src/core/file_sys/quasifs/src/quasifs_inode_quasi_socket.cpp
|
||||
src/core/file_sys/quasifs/src/quasifs_inode_quasi_file_virtual.cpp
|
||||
|
||||
@ -30,7 +30,7 @@ public:
|
||||
s32 fstat(Libraries::Kernel::OrbisKernelStat* sb) override { DEVICE_STUB(); };
|
||||
s32 fsync() override { DEVICE_STUB(); };
|
||||
s32 ftruncate(s64 length) override { DEVICE_STUB(); };
|
||||
s64 getdents(void* buf, u32 nbytes, s64* basep) override { DEVICE_STUB(); };
|
||||
s64 getdents(void* buf, u32 nbytes, s64 offset, s64* basep) override { DEVICE_STUB(); };
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
|
||||
@ -30,7 +30,7 @@ public:
|
||||
s32 fstat(Libraries::Kernel::OrbisKernelStat* sb) override { DEVICE_STUB(); };
|
||||
s32 fsync() override { DEVICE_STUB(); };
|
||||
s32 ftruncate(s64 length) override { DEVICE_STUB(); };
|
||||
s64 getdents(void* buf, u32 nbytes, s64* basep) override { DEVICE_STUB(); };
|
||||
s64 getdents(void* buf, u32 nbytes, s64 offset, s64* basep) override { DEVICE_STUB(); };
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
|
||||
@ -39,7 +39,7 @@ public:
|
||||
s64 lseek(s64 offset, int whence) override { DEVICE_STUB(); }
|
||||
s32 fstat(Libraries::Kernel::OrbisKernelStat* sb) override { DEVICE_STUB(); }
|
||||
s32 ftruncate(s64 length) override { DEVICE_STUB(); }
|
||||
s64 getdents(void* buf, u32 nbytes, s64* basep) override { DEVICE_STUB(); }
|
||||
s64 getdents(void* buf, u32 nbytes, s64 offset, s64* basep) override { DEVICE_STUB(); }
|
||||
// clang-format on
|
||||
|
||||
private:
|
||||
|
||||
@ -23,7 +23,7 @@ public:
|
||||
s32 fstat(Libraries::Kernel::OrbisKernelStat* sb) override { return 0; };
|
||||
s32 fsync() override { return 0; };
|
||||
s32 ftruncate(s64 length) override { return 0; };
|
||||
s64 getdents(void* buf, u32 nbytes, s64* basep) override { return 0; };
|
||||
s64 getdents(void* buf, u32 nbytes, s64 offset, s64* basep) override { return 0; };
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
|
||||
@ -30,7 +30,7 @@ public:
|
||||
s32 fstat(Libraries::Kernel::OrbisKernelStat* sb) override { DEVICE_STUB(); }
|
||||
s32 fsync() override { DEVICE_STUB(); }
|
||||
s32 ftruncate(s64 length) override { DEVICE_STUB(); }
|
||||
s64 getdents(void* buf, u32 nbytes, s64* basep) override { DEVICE_STUB(); }
|
||||
s64 getdents(void* buf, u32 nbytes, s64 offset, s64* basep) override { DEVICE_STUB(); }
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
|
||||
@ -29,7 +29,7 @@ public:
|
||||
s32 fstat(Libraries::Kernel::OrbisKernelStat* sb) override { DEVICE_STUB(); }
|
||||
s32 fsync() override { DEVICE_STUB(); }
|
||||
s32 ftruncate(s64 length) override { DEVICE_STUB(); }
|
||||
s64 getdents(void* buf, u32 nbytes, s64* basep) override { DEVICE_STUB(); }
|
||||
s64 getdents(void* buf, u32 nbytes, s64 offset, s64* basep) override { DEVICE_STUB(); }
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
|
||||
@ -30,7 +30,7 @@ public:
|
||||
s32 fstat(Libraries::Kernel::OrbisKernelStat* sb) override { DEVICE_STUB(); }
|
||||
s32 fsync() override { DEVICE_STUB(); }
|
||||
s32 ftruncate(s64 length) override { DEVICE_STUB(); }
|
||||
s64 getdents(void* buf, u32 nbytes, s64* basep) override { DEVICE_STUB(); }
|
||||
s64 getdents(void* buf, u32 nbytes, s64 offset, s64* basep) override { DEVICE_STUB(); }
|
||||
// clang-format on
|
||||
|
||||
private:
|
||||
|
||||
@ -30,7 +30,7 @@ public:
|
||||
s32 fstat(Libraries::Kernel::OrbisKernelStat* sb) override { DEVICE_STUB(); }
|
||||
s32 fsync() override { DEVICE_STUB(); }
|
||||
s32 ftruncate(s64 length) override { DEVICE_STUB(); }
|
||||
s64 getdents(void* buf, u32 nbytes, s64* basep) override { DEVICE_STUB(); }
|
||||
s64 getdents(void* buf, u32 nbytes, s64 offset, s64* basep) override { DEVICE_STUB(); }
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
|
||||
@ -30,7 +30,7 @@ public:
|
||||
s32 fstat(Libraries::Kernel::OrbisKernelStat* sb) override { DEVICE_STUB(); }
|
||||
s32 fsync() override { DEVICE_STUB(); }
|
||||
s32 ftruncate(s64 length) override { DEVICE_STUB(); }
|
||||
s64 getdents(void* buf, u32 nbytes, s64* basep) override { DEVICE_STUB(); }
|
||||
s64 getdents(void* buf, u32 nbytes, s64 offset, s64* basep) override { DEVICE_STUB(); }
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
|
||||
@ -18,13 +18,13 @@ public:
|
||||
explicit NormalDirectory(std::string_view guest_path);
|
||||
~NormalDirectory() override = default;
|
||||
|
||||
virtual s64 read(void* buf, u64 nbytes) override;
|
||||
virtual s64 read(void* buf, u64 count) override;
|
||||
virtual s64 readv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) override;
|
||||
virtual s64 preadv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt,
|
||||
s64 offset) override;
|
||||
virtual s64 lseek(s64 offset, s32 whence) override;
|
||||
virtual s32 fstat(Libraries::Kernel::OrbisKernelStat* stat) override;
|
||||
virtual s64 getdents(void* buf, u64 nbytes, s64* basep) override;
|
||||
virtual s64 getdents(void* buf, u64 count, s64* basep) override;
|
||||
|
||||
private:
|
||||
static constexpr s32 MAX_LENGTH = 255;
|
||||
|
||||
@ -80,7 +80,7 @@ public:
|
||||
s32 Chmod(const fs::path& path, u16 mode) override;
|
||||
s32 FChmod(const s32 fd, u16 mode) override;
|
||||
|
||||
s64 GetDents(s32 fd, void* buf, u32 nbytes, s64* basep) override;
|
||||
s64 GetDents(const s32 fd, void* buf, u64 count, s64* basep) override;
|
||||
//
|
||||
// Derived, complex functions are to be handled by main FS class
|
||||
//
|
||||
|
||||
@ -53,9 +53,7 @@ s32 HostIO_Base::FStat(const s32 fd, OrbisKernelStat* statbuf) { STUB(); }
|
||||
s32 HostIO_Base::Chmod(const fs::path& path, u16 mode) { STUB(); }
|
||||
s32 HostIO_Base::FChmod(const s32 fd, u16 mode) { STUB(); }
|
||||
|
||||
s64 HostIO_Base::GetDents(s32 fd, void* buf, u32 nbytes, s64* basep) {
|
||||
STUB()
|
||||
}
|
||||
s64 HostIO_Base::GetDents(const s32 fd, void* buf, u64 count, s64* basep) { STUB(); }
|
||||
// clang-format on
|
||||
|
||||
} // namespace HostIODriver
|
||||
@ -56,7 +56,7 @@ public:
|
||||
virtual s32 Chmod(const fs::path& path, u16 mode);
|
||||
virtual s32 FChmod(const s32 fd, u16 mode);
|
||||
|
||||
virtual s64 GetDents(s32 fd, void* buf, u32 nbytes, s64* basep);
|
||||
virtual s64 GetDents(const s32 fd, void* buf, u64 count, s64* basep);
|
||||
//
|
||||
// Derived, complex functions are to be handled by main FS class
|
||||
//
|
||||
|
||||
@ -259,6 +259,6 @@ s32 HostIO_POSIX::FChmod(const s32 fd, u16 mode) {
|
||||
return 0 == status ? status : -errno;
|
||||
}
|
||||
|
||||
// s64 HostIO_POSIX::GetDents(void* buf, u32 nbytes, s64* basep) { return -QUASI_ENOSYS; }
|
||||
// s32 HostIO_POSIX::GetDents(void* buf, u32 count, s64* basep) { return -QUASI_ENOSYS; }
|
||||
|
||||
} // namespace HostIODriver
|
||||
@ -380,7 +380,7 @@ s32 HostIO_Virtual::FChmod(const s32 fd, u16 mode) {
|
||||
return Partition::chmod(node, mode);
|
||||
}
|
||||
|
||||
s64 HostIO_Virtual::GetDents(s32 fd, void* buf, u32 nbytes, s64* basep) {
|
||||
s64 HostIO_Virtual::GetDents(const s32 fd, void* buf, u64 count, s64* basep) {
|
||||
if (nullptr == this->handle)
|
||||
return -QUASI_EINVAL;
|
||||
|
||||
@ -389,10 +389,8 @@ s64 HostIO_Virtual::GetDents(s32 fd, void* buf, u32 nbytes, s64* basep) {
|
||||
if (nullptr == node)
|
||||
return -QUASI_EBADF;
|
||||
|
||||
if (nullptr != basep)
|
||||
*basep = handle->pos;
|
||||
s64 br = node->getdents(buf, count, handle->pos, basep);
|
||||
|
||||
s64 br = node->getdents(static_cast<char*>(buf) + handle->pos, nbytes, basep);
|
||||
if (br > 0)
|
||||
handle->pos += br;
|
||||
|
||||
|
||||
@ -20,4 +20,7 @@
|
||||
#define __QUASI_O_ALLFLAGS_AT_ONCE \
|
||||
(QUASI_O_RDONLY | QUASI_O_WRONLY | QUASI_O_RDWR | QUASI_O_NONBLOCK | QUASI_O_APPEND | \
|
||||
QUASI_O_FSYNC | QUASI_O_SYNC | QUASI_O_CREAT | QUASI_O_TRUNC | QUASI_O_EXCL | QUASI_O_DSYNC | \
|
||||
QUASI_O_DIRECT | QUASI_O_DIRECTORY)
|
||||
QUASI_O_DIRECT | QUASI_O_DIRECTORY)
|
||||
|
||||
// not implemented
|
||||
#define QUASI_O_CLOEXEC 0x100000
|
||||
|
||||
@ -58,12 +58,12 @@ using fd_handle_ptr = std::shared_ptr<File>;
|
||||
struct File {
|
||||
File() = default;
|
||||
~File() = default;
|
||||
int host_fd{-1}; // fd if opened with HostIO
|
||||
s32 host_fd{-1}; // fd if opened with HostIO
|
||||
inode_ptr node{nullptr}; // inode
|
||||
bool read{false}; // read permission
|
||||
bool write{false}; // write permission
|
||||
bool append{false}; // append
|
||||
u64 pos{0}; // cursor offset
|
||||
s64 pos{0}; // cursor offset
|
||||
|
||||
static fd_handle_ptr Create() {
|
||||
return std::shared_ptr<File>(new File());
|
||||
|
||||
@ -96,7 +96,7 @@ private:
|
||||
s32 Chmod(const fs::path& path, u16 mode) override;
|
||||
s32 FChmod(const s32 fd, u16 mode) override;
|
||||
|
||||
s64 GetDents(s32 fd, void* buf, u32 nbytes, s64* basep) override;
|
||||
s64 GetDents(const s32 fd, void* buf, u64 count, s64* basep) override;
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
@ -89,7 +89,7 @@ public:
|
||||
return -QUASI_EINVAL;
|
||||
}
|
||||
|
||||
virtual s64 getdents(void* buf, u32 nbytes, s64* basep) {
|
||||
virtual s64 getdents(void* buf, u32 count, s64 offset, s64* basep) {
|
||||
return -QUASI_EINVAL;
|
||||
}
|
||||
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/logging/log.h"
|
||||
|
||||
#include "quasi_types.h"
|
||||
#include "quasifs_inode.h"
|
||||
@ -16,23 +17,21 @@ namespace QuasiFS {
|
||||
// Directory
|
||||
class QuasiDirectory : public Inode {
|
||||
|
||||
private:
|
||||
std::map<std::string, inode_ptr> entries{};
|
||||
|
||||
time_t last_dirent_rebuild_time{0};
|
||||
void RebuildDirents(void);
|
||||
static constexpr s32 MAX_LENGTH = 255;
|
||||
static constexpr s64 DIRECTORY_ALIGNMENT = 0x200;
|
||||
|
||||
protected:
|
||||
#pragma pack(push, 1)
|
||||
typedef struct dirent_t {
|
||||
quasi_ino_t d_ino{};
|
||||
u64 d_off{};
|
||||
unsigned short d_reclen{};
|
||||
unsigned char d_type{};
|
||||
char d_name[256]{};
|
||||
u32 d_fileno;
|
||||
u16 d_reclen;
|
||||
u8 d_type;
|
||||
u8 d_namlen;
|
||||
char d_name[256];
|
||||
} dirent_t;
|
||||
#pragma pack(pop)
|
||||
std::map<std::string, inode_ptr> entries{};
|
||||
|
||||
void RebuildDirents(void);
|
||||
time_t last_dirent_rebuild_time{0};
|
||||
std::map<s64, dirent_t> dirent_cache{};
|
||||
|
||||
public:
|
||||
dir_ptr mounted_root = nullptr;
|
||||
@ -58,17 +57,13 @@ public:
|
||||
// Inode overrides
|
||||
//
|
||||
|
||||
// s64 pread(void* buf, size_t count, u64 offset) override;
|
||||
s64 pread(void* buf, u64 count, s64 offset) override;
|
||||
// s64 pwrite(const void* buf, size_t count, u64 offset) override;
|
||||
s32 ftruncate(s64 length) final override {
|
||||
return -QUASI_EISDIR;
|
||||
}
|
||||
|
||||
s32 fstat(Libraries::Kernel::OrbisKernelStat* sb) override {
|
||||
this->st.st_size = entries.size() * 32;
|
||||
*sb = st;
|
||||
return 0;
|
||||
}
|
||||
s32 ftruncate(s64 length) final override;
|
||||
s32 fstat(Libraries::Kernel::OrbisKernelStat* sb) override;
|
||||
|
||||
s64 getdents(void* buf, u32 count, s64 offset, s64* basep) override;
|
||||
|
||||
//
|
||||
// Dir-specific
|
||||
|
||||
@ -16,23 +16,29 @@ namespace QuasiFS {
|
||||
|
||||
// Directory
|
||||
class DirectoryPFS final : public QuasiDirectory {
|
||||
private:
|
||||
static constexpr s32 MAX_LENGTH = 255;
|
||||
static constexpr s32 DIRECTORY_ALIGNMENT = 0x10000;
|
||||
|
||||
protected:
|
||||
#pragma pack(push, 1)
|
||||
typedef struct dirent_pfs_t {
|
||||
u32 d_fileno;
|
||||
u32 d_type;
|
||||
u32 d_namlen;
|
||||
u32 d_reclen;
|
||||
char d_name[MAX_LENGTH + 1];
|
||||
char d_name[256];
|
||||
} dirent_pfs_t;
|
||||
#pragma pack(pop)
|
||||
|
||||
private:
|
||||
// void RebuildDirents(void);
|
||||
|
||||
public:
|
||||
DirectoryPFS() = default;
|
||||
~DirectoryPFS() = default;
|
||||
DirectoryPFS();
|
||||
~DirectoryPFS();
|
||||
|
||||
s64 pread(void* buf, u64 count, s64 offset) override;
|
||||
|
||||
s64 getdents(void* buf, u32 count, s64 offset, s64* basep) override;
|
||||
|
||||
};
|
||||
|
||||
} // namespace QuasiFS
|
||||
@ -4,6 +4,9 @@
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#include "common/alignment.h"
|
||||
#include "core/file_sys/quasifs/quasifs_inode_quasi_directory.h"
|
||||
|
||||
#include "quasi_types.h"
|
||||
|
||||
namespace QuasiFS {
|
||||
@ -31,16 +34,15 @@ private:
|
||||
|
||||
// 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(const fs::path& host_root = "", const int root_permissions = 0755,
|
||||
const u32 block_size = 512, const u32 ioblock_size = 4096);
|
||||
const u32 ioblock_size = 4096);
|
||||
Partition(dir_ptr root_directory = Directory::Create<Directory>(),
|
||||
const fs::path& host_root = "", const int root_permissions = 0755,
|
||||
const u32 ioblock_size = 4096);
|
||||
~Partition() = default;
|
||||
|
||||
template <typename... Args>
|
||||
@ -62,11 +64,6 @@ public:
|
||||
blkid_t GetBlkId(void) {
|
||||
return this->block_id;
|
||||
}
|
||||
void AdjustStat(Libraries::Kernel::OrbisKernelStat* statbuf) {
|
||||
auto& s = statbuf->st_size;
|
||||
statbuf->st_blksize = this->block_size;
|
||||
statbuf->st_blocks = (1 + (s / this->ioblock_size)) * this->ioblock_size / this->block_size;
|
||||
}
|
||||
inode_ptr GetInodeByFileno(fileno_t fileno);
|
||||
|
||||
int Resolve(fs::path& path, Resolved& res);
|
||||
|
||||
@ -114,7 +114,7 @@ void printTree(const dir_ptr& node, const std::string& name, int depth) {
|
||||
}
|
||||
|
||||
QFS::QFS(const fs::path& host_path) {
|
||||
this->rootfs = Partition::Create(host_path);
|
||||
this->rootfs = Partition::Create(Directory::Create<Directory>(), host_path);
|
||||
this->root = rootfs->GetRoot();
|
||||
|
||||
mount_t mount_options = {
|
||||
@ -435,7 +435,9 @@ void QFS::SyncHostImpl(partition_ptr part) {
|
||||
LOG_ERROR(Kernel_Fs, "Cannot stat file: {}", entry_path.string());
|
||||
continue;
|
||||
}
|
||||
part->AdjustStat(&new_inode->st);
|
||||
new_inode->st.st_blocks =
|
||||
Common::AlignUp(static_cast<u64>(new_inode->st.st_size), new_inode->st.st_blksize) /
|
||||
512;
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
LOG_CRITICAL(Kernel_Fs, "An error occurred when syncing [{}]: {}", host_path.string(),
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "common/alignment.h"
|
||||
#include "core/file_sys/quasifs/quasi_errno.h"
|
||||
#include "core/file_sys/quasifs/quasifs_inode_quasi_directory.h"
|
||||
|
||||
@ -12,11 +13,59 @@ QuasiDirectory::QuasiDirectory() {
|
||||
st.st_mode |= QUASI_S_IFDIR;
|
||||
}
|
||||
|
||||
s64 QuasiDirectory::pread(void* buf, u64 count, s64 offset) {
|
||||
return getdents(buf, count, offset, nullptr);
|
||||
}
|
||||
|
||||
s32 QuasiDirectory::ftruncate(s64 length) {
|
||||
return -QUASI_EISDIR;
|
||||
}
|
||||
|
||||
s32 QuasiDirectory::fstat(Libraries::Kernel::OrbisKernelStat* sb) {
|
||||
RebuildDirents();
|
||||
*sb = st;
|
||||
return 0;
|
||||
}
|
||||
|
||||
s64 QuasiDirectory::getdents(void* buf, u32 count, s64 offset, s64* basep) {
|
||||
RebuildDirents();
|
||||
|
||||
auto it = dirent_cache.lower_bound(offset);
|
||||
|
||||
if (it == dirent_cache.end())
|
||||
return 0;
|
||||
|
||||
u64 cumulative_offset = 0;
|
||||
u16 last_reclen = 0;
|
||||
for (; it != dirent_cache.end(); it++) {
|
||||
auto dirent = it->second;
|
||||
|
||||
if (dirent.d_reclen + cumulative_offset > count)
|
||||
break;
|
||||
|
||||
memcpy(static_cast<u8*>(buf) + cumulative_offset, &dirent, dirent.d_reclen);
|
||||
last_reclen = dirent.d_reclen;
|
||||
cumulative_offset += last_reclen;
|
||||
}
|
||||
|
||||
if (basep)
|
||||
*basep = cumulative_offset;
|
||||
// offset of the last reclen
|
||||
auto _val = cumulative_offset - last_reclen + 4;
|
||||
// pointer to last reclen in buffer
|
||||
u8* placement = static_cast<u8*>(buf) + _val;
|
||||
// casting buffer to u16 to write whole value at once (2 bytes)
|
||||
u16* pos = reinterpret_cast<u16*>(placement);
|
||||
*pos += Common::AlignUp(cumulative_offset, count) - cumulative_offset;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
inode_ptr QuasiDirectory::lookup(const std::string& name) {
|
||||
st.st_atim.tv_sec = time(0);
|
||||
auto it = entries.find(name);
|
||||
if (it == entries.end())
|
||||
return nullptr;
|
||||
st.st_atim.tv_sec = time(0);
|
||||
return it->second;
|
||||
}
|
||||
|
||||
@ -69,9 +118,35 @@ std::vector<std::string> QuasiDirectory::list() {
|
||||
}
|
||||
|
||||
void QuasiDirectory::RebuildDirents(void) {
|
||||
// adding/removing entries changes mtime
|
||||
if (this->st.st_mtim.tv_sec == this->last_dirent_rebuild_time)
|
||||
return;
|
||||
this->last_dirent_rebuild_time = this->st.st_mtim.tv_sec;
|
||||
|
||||
u64 dirent_size = 0;
|
||||
this->dirent_cache.clear();
|
||||
|
||||
for (auto entry = entries.begin(); entry != entries.end(); ++entry) {
|
||||
dirent_t tmp{};
|
||||
inode_ptr node = entry->second;
|
||||
std::string name = entry->first;
|
||||
|
||||
tmp.d_fileno = node->fileno;
|
||||
tmp.d_namlen = name.size();
|
||||
strncpy(tmp.d_name, name.data(), tmp.d_namlen + 1);
|
||||
tmp.d_type = node->type() >> 12;
|
||||
tmp.d_reclen =
|
||||
Common::AlignUp(sizeof(tmp.d_fileno) + sizeof(tmp.d_type) + sizeof(tmp.d_namlen) +
|
||||
sizeof(tmp.d_reclen) + (tmp.d_namlen + 1),
|
||||
4);
|
||||
|
||||
dirent_cache[dirent_size] = tmp;
|
||||
dirent_size += tmp.d_reclen;
|
||||
}
|
||||
|
||||
this->st.st_size = dirent_size;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
} // namespace QuasiFS
|
||||
@ -0,0 +1,84 @@
|
||||
// INAA License @marecl 2025
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "common/alignment.h"
|
||||
#include "core/file_sys/quasifs/quasi_errno.h"
|
||||
#include "core/file_sys/quasifs/quasifs_inode_quasi_directory_pfs.h"
|
||||
|
||||
namespace QuasiFS {
|
||||
|
||||
DirectoryPFS::DirectoryPFS() {
|
||||
this->st.st_size = 65536;
|
||||
}
|
||||
|
||||
DirectoryPFS::~DirectoryPFS() = default;
|
||||
|
||||
s64 DirectoryPFS::pread(void* buf, u64 count, s64 offset) {
|
||||
RebuildDirents();
|
||||
|
||||
auto it = dirent_cache.lower_bound(offset);
|
||||
|
||||
if (it == dirent_cache.end())
|
||||
return 0;
|
||||
|
||||
u64 cumulative_offset = 0;
|
||||
u16 last_reclen = 0;
|
||||
for (; it != dirent_cache.end(); it++) {
|
||||
auto dirent = it->second;
|
||||
|
||||
if (dirent.d_reclen + cumulative_offset > count)
|
||||
break;
|
||||
|
||||
memcpy(static_cast<u8*>(buf) + cumulative_offset, &dirent, dirent.d_reclen);
|
||||
last_reclen = dirent.d_reclen;
|
||||
cumulative_offset += last_reclen;
|
||||
}
|
||||
|
||||
// offset of the last reclen
|
||||
auto _val = cumulative_offset - last_reclen + 4;
|
||||
// pointer to last reclen in buffer
|
||||
u8* placement = static_cast<u8*>(buf) + _val;
|
||||
// casting buffer to u16 to write whole value at once (2 bytes)
|
||||
u16* pos = reinterpret_cast<u16*>(placement);
|
||||
*pos += Common::AlignUp(cumulative_offset, count) - cumulative_offset;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
s64 DirectoryPFS::getdents(void* buf, u32 count, s64 offset, s64* basep) {
|
||||
RebuildDirents();
|
||||
|
||||
auto it = dirent_cache.lower_bound(offset);
|
||||
|
||||
if (it == dirent_cache.end())
|
||||
return 0;
|
||||
|
||||
u64 cumulative_offset = 0;
|
||||
u16 last_reclen = 0;
|
||||
for (; it != dirent_cache.end(); it++) {
|
||||
auto dirent = it->second;
|
||||
|
||||
if (dirent.d_reclen + cumulative_offset > count)
|
||||
break;
|
||||
|
||||
memcpy(static_cast<u8*>(buf) + cumulative_offset, &dirent, dirent.d_reclen);
|
||||
last_reclen = dirent.d_reclen;
|
||||
cumulative_offset += last_reclen;
|
||||
}
|
||||
|
||||
if (basep)
|
||||
*basep = cumulative_offset;
|
||||
// offset of the last reclen
|
||||
auto _val = cumulative_offset - last_reclen + 4;
|
||||
// pointer to last reclen in buffer
|
||||
u8* placement = static_cast<u8*>(buf) + _val;
|
||||
// casting buffer to u16 to write whole value at once (2 bytes)
|
||||
u16* pos = reinterpret_cast<u16*>(placement);
|
||||
*pos += Common::AlignUp(cumulative_offset, count) - cumulative_offset;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
} // namespace QuasiFS
|
||||
@ -12,11 +12,14 @@
|
||||
|
||||
namespace QuasiFS {
|
||||
|
||||
Partition::Partition() : Partition("", 0755, 512, 4096) {}
|
||||
Partition::Partition() : Partition(Directory::Create<Directory>(), "", 0755, 4096) {}
|
||||
|
||||
Partition::Partition(const fs::path& host_root, const int root_permissions, const u32 block_size,
|
||||
Partition::Partition(const fs::path& host_root, const int root_permissions, const u32 ioblock_size)
|
||||
: Partition(Directory::Create<Directory>(), host_root, root_permissions, ioblock_size) {}
|
||||
|
||||
Partition::Partition(dir_ptr root_directory, const fs::path& host_root, const int root_permissions,
|
||||
const u32 ioblock_size)
|
||||
: block_id(next_block_id++), host_root(host_root.lexically_normal()), block_size(block_size),
|
||||
: block_id(next_block_id++), host_root(host_root.lexically_normal()),
|
||||
ioblock_size(ioblock_size) {
|
||||
this->root = Directory::Create<Directory>();
|
||||
// clear defaults, write
|
||||
@ -223,15 +226,6 @@ 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);
|
||||
@ -370,6 +364,8 @@ bool Partition::IndexInode(inode_ptr node) {
|
||||
|
||||
node->st.st_ino = node_fileno;
|
||||
node->st.st_dev = block_id;
|
||||
node->st.st_blksize = ioblock_size;
|
||||
node->st.st_blocks = Common::AlignUp(static_cast<u64>(node->st.st_size), ioblock_size) / 512;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -936,7 +936,7 @@ s32 QFS::OperationImpl::FChmod(const s32 fd, u16 mode) {
|
||||
return vio_status;
|
||||
}
|
||||
|
||||
s64 QFS::OperationImpl::GetDents(s32 fd, void* buf, u32 nbytes, s64* basep) {
|
||||
s64 QFS::OperationImpl::GetDents(const s32 fd, void* buf, u64 count, s64* basep) {
|
||||
if (fd < 0)
|
||||
return -QUASI_EBADF;
|
||||
|
||||
@ -948,7 +948,7 @@ s64 QFS::OperationImpl::GetDents(s32 fd, void* buf, u32 nbytes, s64* basep) {
|
||||
return -QUASI_EBADF;
|
||||
|
||||
qfs.vio_driver.SetCtx(nullptr, false, handle);
|
||||
int vio_status = qfs.vio_driver.GetDents(fd, buf, nbytes, basep);
|
||||
int vio_status = qfs.vio_driver.GetDents(fd, buf, count, basep);
|
||||
qfs.vio_driver.ClearCtx();
|
||||
|
||||
return vio_status;
|
||||
|
||||
@ -14,12 +14,15 @@
|
||||
#include "core/libraries/system/systemservice.h"
|
||||
|
||||
#include "core/file_sys/quasifs/quasifs.h"
|
||||
#include "core/file_sys/quasifs/quasifs_inode_quasi_directory_pfs.h"
|
||||
#include "core/file_sys/quasifs/quasifs_partition.h"
|
||||
|
||||
static QuasiFS::QFS* g_qfs = Common::Singleton<QuasiFS::QFS>::Instance();
|
||||
namespace qfs = QuasiFS;
|
||||
|
||||
namespace Libraries::AppContent {
|
||||
|
||||
static qfs::QFS* g_qfs = Common::Singleton<qfs::QFS>::Instance();
|
||||
|
||||
struct AddContInfo {
|
||||
char entitlement_label[ORBIS_NP_UNIFIED_ENTITLEMENT_LABEL_SIZE];
|
||||
OrbisAppContentAddcontDownloadStatus status;
|
||||
@ -109,11 +112,12 @@ int PS4_SYSV_ABI sceAppContentAddcontMount(u32 service_label,
|
||||
// We've located the correct folder.
|
||||
|
||||
g_qfs->Operation.MKDir(mount_point->data, 0555 /* I think it's like /app0*/);
|
||||
QuasiFS::partition_ptr partition_dlc = QuasiFS::Partition::Create(entry.path(), 0555);
|
||||
g_qfs->Mount(mount_point->data, partition_dlc, QuasiFS::MountOptions::MOUNT_RW);
|
||||
qfs::partition_ptr partition_dlc = qfs::Partition::Create(
|
||||
qfs::Directory::Create<qfs::DirectoryPFS>(), entry.path(), 0555);
|
||||
g_qfs->Mount(mount_point->data, partition_dlc, qfs::MountOptions::MOUNT_RW);
|
||||
g_qfs->SyncHost(mount_point->data);
|
||||
g_qfs->Mount(mount_point->data, partition_dlc,
|
||||
QuasiFS::MountOptions::MOUNT_REMOUNT | QuasiFS::MountOptions::MOUNT_NOOPT);
|
||||
qfs::MountOptions::MOUNT_REMOUNT | qfs::MountOptions::MOUNT_NOOPT);
|
||||
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
@ -40,10 +40,11 @@
|
||||
#endif
|
||||
|
||||
namespace qfs = QuasiFS;
|
||||
static QuasiFS::QFS* g_qfs = Common::Singleton<QuasiFS::QFS>::Instance();
|
||||
|
||||
namespace Libraries::Kernel {
|
||||
|
||||
static QuasiFS::QFS* g_qfs = Common::Singleton<QuasiFS::QFS>::Instance();
|
||||
|
||||
s32 PS4_SYSV_ABI open(const char* raw_path, s32 flags, u16 mode) {
|
||||
LOG_INFO(Kernel_Fs, "path = {} flags = {:#x} mode = {:#o}", raw_path, flags, mode);
|
||||
|
||||
@ -537,7 +538,7 @@ static s64 GetDents(s32 fd, char* buf, u64 nbytes, s64* basep) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return ORBIS_OK;
|
||||
return result;
|
||||
}
|
||||
|
||||
s64 PS4_SYSV_ABI posix_getdents(s32 fd, char* buf, u64 nbytes) {
|
||||
|
||||
@ -19,10 +19,8 @@ constexpr auto OrbisSaveDataBlocksMin2 = 96; // 3MiB
|
||||
constexpr auto OrbisSaveDataBlocksMax = 32768; // 1 GiB
|
||||
constexpr std::string_view sce_sys = "sce_sys"; // system folder inside save
|
||||
|
||||
namespace qfs = QuasiFS;
|
||||
static qfs::QFS* g_qfs = Common::Singleton<qfs::QFS>::Instance();
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
namespace qfs = QuasiFS;
|
||||
|
||||
// clang-format off
|
||||
static const std::unordered_map<int, std::string> default_title = {
|
||||
@ -49,6 +47,8 @@ static const std::unordered_map<int, std::string> default_title = {
|
||||
|
||||
namespace Libraries::SaveData {
|
||||
|
||||
static qfs::QFS* g_qfs = Common::Singleton<qfs::QFS>::Instance();
|
||||
|
||||
fs::path SaveInstance::MakeTitleSavePath(OrbisUserServiceUserId user_id,
|
||||
std::string_view game_serial) {
|
||||
return Config::GetSaveDataPath() / std::to_string(user_id) / game_serial;
|
||||
@ -192,7 +192,7 @@ void SaveInstance::SetupAndMount(bool read_only, bool copy_icon, bool ignore_cor
|
||||
max_blocks = static_cast<int>(GetMaxBlockFromSFO(param_sfo));
|
||||
|
||||
g_qfs->Operation.MKDir(mount_point);
|
||||
auto part = qfs::Partition::Create(save_path);
|
||||
auto part = qfs::Partition::Create(qfs::Directory::Create<qfs::Directory>(), save_path);
|
||||
g_qfs->Mount(mount_point, part,
|
||||
read_only ? qfs::MountOptions::MOUNT_NOOPT : qfs::MountOptions::MOUNT_RW);
|
||||
g_qfs->SyncHost(mount_point);
|
||||
|
||||
@ -47,6 +47,7 @@
|
||||
#include "core/file_sys/quasifs/quasi_sys_fcntl.h"
|
||||
#include "core/file_sys/quasifs/quasifs.h"
|
||||
#include "core/file_sys/quasifs/quasifs_inode_quasi_device.h"
|
||||
#include "core/file_sys/quasifs/quasifs_inode_quasi_directory_pfs.h"
|
||||
#include "core/file_sys/quasifs/quasifs_partition.h"
|
||||
|
||||
#include "core/file_sys/devices/console_device.h"
|
||||
@ -93,12 +94,14 @@ Emulator::~Emulator() {}
|
||||
void Emulator::LoadFilesystem(const std::filesystem::path& game_folder) {
|
||||
auto* qfs = Common::Singleton<qfs::QFS>::Instance();
|
||||
|
||||
qfs::partition_ptr partition_app0 = qfs::Partition::Create(game_folder, 0555, 512, 65536);
|
||||
qfs::partition_ptr partition_av_contents = qfs::Partition::Create("", 0775, 512, 16384);
|
||||
qfs::partition_ptr partition_av_contents_photo = qfs::Partition::Create("", 0755, 4096, 32768);
|
||||
qfs::partition_ptr partition_av_contents_thumbs = qfs::Partition::Create("", 0755, 4096, 32768);
|
||||
qfs::partition_ptr partition_av_contents_video = qfs::Partition::Create("", 0755, 4096, 32768);
|
||||
qfs::partition_ptr partition_dev = qfs::Partition::Create("", 0755, 16384, 16384);
|
||||
qfs::partition_ptr partition_app0 = qfs::Partition::Create(game_folder, 0555, 65536);
|
||||
// qfs::partition_ptr partition_app0 = qfs::Partition::Create(
|
||||
// qfs::Directory::Create<qfs::DirectoryPFS>(), game_folder, 0555, 512, 65536);
|
||||
qfs::partition_ptr partition_av_contents = qfs::Partition::Create("", 0775, 16384);
|
||||
qfs::partition_ptr partition_av_contents_photo = qfs::Partition::Create("", 0755, 32768);
|
||||
qfs::partition_ptr partition_av_contents_thumbs = qfs::Partition::Create("", 0755, 32768);
|
||||
qfs::partition_ptr partition_av_contents_video = qfs::Partition::Create("", 0755, 32768);
|
||||
qfs::partition_ptr partition_dev = qfs::Partition::Create("", 0755, 16384);
|
||||
|
||||
qfs->Operation.MKDir("/app0", 0555);
|
||||
qfs->Operation.MKDir("/av_contents", 0775);
|
||||
@ -264,10 +267,9 @@ void Emulator::Run(std::filesystem::path file, std::vector<std::string> args,
|
||||
qfs->Operation.MKDir("/download0", 0777); // not sure about perms here
|
||||
qfs->Operation.MKDir("/temp", 0777);
|
||||
qfs->Operation.MKDir("/temp0", 0777);
|
||||
qfs::partition_ptr partition_data = qfs::Partition::Create(mount_data_dir, 0777, 4096, 32768);
|
||||
qfs::partition_ptr partition_download =
|
||||
qfs::Partition::Create(mount_download_dir, 0777, 512, 65536);
|
||||
qfs::partition_ptr partition_temp = qfs::Partition::Create(mount_temp_dir, 0777, 512, 16384);
|
||||
qfs::partition_ptr partition_data = qfs::Partition::Create(mount_data_dir, 0777, 32768);
|
||||
qfs::partition_ptr partition_download = qfs::Partition::Create(mount_download_dir, 0777, 65536);
|
||||
qfs::partition_ptr partition_temp = qfs::Partition::Create(mount_temp_dir, 0777, 16384);
|
||||
qfs->Mount("/data", partition_data, qfs::MountOptions::MOUNT_RW);
|
||||
qfs->Mount("/download0", partition_download, qfs::MountOptions::MOUNT_RW);
|
||||
qfs->Mount("/temp", partition_temp, qfs::MountOptions::MOUNT_RW);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user