fs path was changed to 255 in the past because that is the real path size that fs can handle. however, this restriction does not apply to nfs, samba, http - and it is very easy to exceed this 255 path length. to fix this, i have increased the path len to 1024. this allows fs to continue to work as the buffer is big enough, but also gives network mounts enough space to work with.
572 lines
20 KiB
C++
572 lines
20 KiB
C++
#pragma once
|
|
|
|
#include <switch.h>
|
|
#include <dirent.h>
|
|
#include <cstring>
|
|
#include <vector>
|
|
#include <string>
|
|
#include <string_view>
|
|
#include <sys/syslimits.h>
|
|
#include "defines.hpp"
|
|
|
|
namespace fs {
|
|
|
|
struct FsPath {
|
|
FsPath() = default;
|
|
|
|
constexpr FsPath(const FsPath& p) { From(p); }
|
|
constexpr FsPath(const char* str) { From(str); }
|
|
constexpr FsPath(const std::string& str) { From(str); }
|
|
constexpr FsPath(const std::string_view& str) { From(str); }
|
|
|
|
constexpr void From(const FsPath& p) {
|
|
From(p.s);
|
|
}
|
|
|
|
constexpr void From(const char* str) {
|
|
if consteval {
|
|
for (u32 i = 0; str[i] != '\0'; i++) {
|
|
s[i] = str[i];
|
|
}
|
|
} else {
|
|
std::strcpy(s, str);
|
|
}
|
|
}
|
|
|
|
constexpr void From(const std::string& str) {
|
|
std::copy(str.cbegin(), str.cend(), std::begin(s));
|
|
}
|
|
|
|
constexpr void From(const std::string_view& str) {
|
|
std::copy(str.cbegin(), str.cend(), std::begin(s));
|
|
}
|
|
|
|
constexpr auto toString() const -> std::string {
|
|
return s;
|
|
}
|
|
|
|
constexpr auto empty() const {
|
|
return s[0] == '\0';
|
|
}
|
|
|
|
constexpr auto size() const {
|
|
return std::strlen(s);
|
|
}
|
|
|
|
constexpr auto length() const {
|
|
return std::strlen(s);
|
|
}
|
|
|
|
constexpr void clear() {
|
|
s[0] = '\0';
|
|
}
|
|
|
|
constexpr auto starts_with(std::string_view str) const -> bool {
|
|
return !strncasecmp(s, str.data(), str.length());
|
|
}
|
|
|
|
constexpr auto ends_with(std::string_view str) const -> bool {
|
|
const auto len = length();
|
|
if (len < str.length()) {
|
|
return false;
|
|
}
|
|
|
|
return !strncasecmp(s + len - str.length(), str.data(), str.length());
|
|
}
|
|
|
|
constexpr operator const char*() const { return s; }
|
|
constexpr operator char*() { return s; }
|
|
constexpr operator std::string() { return s; }
|
|
constexpr operator std::string_view() { return s; }
|
|
constexpr operator std::string() const { return s; }
|
|
constexpr operator std::string_view() const { return s; }
|
|
constexpr char& operator[](std::size_t idx) { return s[idx]; }
|
|
constexpr const char& operator[](std::size_t idx) const { return s[idx]; }
|
|
|
|
constexpr FsPath& operator=(const FsPath& p) noexcept {
|
|
From(p.s);
|
|
return *this;
|
|
}
|
|
|
|
constexpr FsPath operator+(const FsPath& v) const noexcept {
|
|
FsPath r{*this};
|
|
return r += v;
|
|
}
|
|
|
|
constexpr FsPath operator+(const char* v) const noexcept {
|
|
FsPath r{*this};
|
|
return r += v;
|
|
}
|
|
|
|
constexpr FsPath operator+(const std::string& v) const noexcept {
|
|
FsPath r{*this};
|
|
return r += v;
|
|
}
|
|
|
|
constexpr FsPath operator+(const std::string_view v) const noexcept {
|
|
FsPath r{*this};
|
|
return r += v;
|
|
}
|
|
|
|
constexpr const char* operator+(std::size_t v) const noexcept {
|
|
return this->s + v;
|
|
}
|
|
|
|
constexpr FsPath& operator+=(const FsPath& v) noexcept {
|
|
std::strcat(*this, v);
|
|
return *this;
|
|
}
|
|
|
|
constexpr FsPath& operator+=(const char* v) noexcept {
|
|
std::strcat(*this, v);
|
|
return *this;
|
|
}
|
|
|
|
constexpr FsPath& operator+=(const std::string& v) noexcept {
|
|
std::strncat(*this, v.data(), v.length());
|
|
return *this;
|
|
}
|
|
|
|
constexpr FsPath& operator+=(const std::string_view& v) noexcept {
|
|
std::strncat(*this, v.data(), v.length());
|
|
return *this;
|
|
}
|
|
|
|
constexpr FsPath& operator+=(char v) noexcept {
|
|
const auto sz = size();
|
|
s[sz + 0] = v;
|
|
s[sz + 1] = '\0';
|
|
return *this;
|
|
}
|
|
|
|
static constexpr bool path_equal(std::string_view a, std::string_view b) {
|
|
return a.length() == b.length() && !strncasecmp(a.data(), b.data(), a.length());
|
|
}
|
|
|
|
constexpr bool operator==(const FsPath& v) const noexcept {
|
|
return path_equal(*this, v);
|
|
}
|
|
|
|
constexpr bool operator==(const char* v) const noexcept {
|
|
return path_equal(*this, v);
|
|
}
|
|
|
|
constexpr bool operator==(const std::string& v) const noexcept {
|
|
return path_equal(*this, v);
|
|
}
|
|
|
|
constexpr bool operator==(const std::string_view v) const noexcept {
|
|
return path_equal(*this, v);
|
|
}
|
|
|
|
static consteval bool Test(const auto& str) {
|
|
FsPath path{str};
|
|
return path[0] == str[0];
|
|
}
|
|
static consteval bool TestFrom(const auto& str) {
|
|
FsPath path;
|
|
path.From(str);
|
|
return path[0] == str[0];
|
|
}
|
|
|
|
char s[PATH_MAX]{};
|
|
};
|
|
|
|
inline FsPath operator+(const char* v, const FsPath& fp) {
|
|
FsPath r{v};
|
|
return r += fp;
|
|
}
|
|
|
|
inline FsPath operator+(const std::string& v, const FsPath& fp) {
|
|
FsPath r{v};
|
|
return r += fp;
|
|
}
|
|
|
|
inline FsPath operator+(const std::string_view& v, const FsPath& fp) {
|
|
FsPath r{v};
|
|
return r += fp;
|
|
}
|
|
|
|
// Fs seems to be limted to file paths of 255 characters.
|
|
// i've disabled this as network mounts will often have very long paths
|
|
// that do not have this limit.
|
|
// a proper fix would be to return an error if the path is too long and the path
|
|
// is native.
|
|
struct FsPathReal {
|
|
static constexpr inline size_t FS_REAL_MAX_LENGTH = PATH_MAX;
|
|
|
|
constexpr FsPathReal(const FsPath& str) : FsPathReal{str.s} { }
|
|
explicit constexpr FsPathReal(const char* str) {
|
|
size_t real = 0;
|
|
for (size_t i = 0; str[i]; i++) {
|
|
// skip multiple slashes.
|
|
if (i && str[i] == '/' && str[i - 1] == '/') {
|
|
continue;
|
|
}
|
|
|
|
// save single char.
|
|
s[real++] = str[i];
|
|
|
|
// check if we have exceeded the path.
|
|
if (real >= FS_REAL_MAX_LENGTH) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
// null the end.
|
|
s[real] = '\0';
|
|
}
|
|
|
|
constexpr operator const char*() const { return s; }
|
|
constexpr operator std::string_view() const { return s; }
|
|
|
|
char s[PATH_MAX];
|
|
};
|
|
|
|
// fwd
|
|
struct Fs;
|
|
|
|
struct File {
|
|
~File();
|
|
|
|
Result Read(s64 off, void* buf, u64 read_size, u32 option, u64* bytes_read);
|
|
Result Write(s64 off, const void* buf, u64 write_size, u32 option);
|
|
Result SetSize(s64 sz);
|
|
Result GetSize(s64* out);
|
|
void Close();
|
|
|
|
fs::Fs* m_fs{};
|
|
FsFile m_native{};
|
|
std::FILE* m_stdio{};
|
|
u32 m_mode{};
|
|
};
|
|
|
|
struct Dir {
|
|
~Dir();
|
|
|
|
Result GetEntryCount(s64* out);
|
|
Result Read(s64 *total_entries, size_t max_entries, FsDirectoryEntry *buf);
|
|
Result ReadAll(std::vector<FsDirectoryEntry>& buf);
|
|
void Close();
|
|
|
|
fs::Fs* m_fs{};
|
|
FsDir m_native{};
|
|
DIR* m_stdio{};
|
|
u32 m_mode{};
|
|
};
|
|
|
|
FsPath AppendPath(const fs::FsPath& root_path, const fs::FsPath& file_path);
|
|
|
|
Result CreateFile(FsFileSystem* fs, const FsPathReal& path, u64 size = 0, u32 option = 0, bool ignore_read_only = true);
|
|
Result CreateDirectory(FsFileSystem* fs, const FsPathReal& path, bool ignore_read_only = true);
|
|
Result CreateDirectoryRecursively(FsFileSystem* fs, const FsPath& path, bool ignore_read_only = true);
|
|
Result CreateDirectoryRecursivelyWithPath(FsFileSystem* fs, const FsPath& path, bool ignore_read_only = true);
|
|
Result DeleteFile(FsFileSystem* fs, const FsPathReal& path, bool ignore_read_only = true);
|
|
Result DeleteDirectory(FsFileSystem* fs, const FsPathReal& path, bool ignore_read_only = true);
|
|
Result DeleteDirectoryRecursively(FsFileSystem* fs, const FsPathReal& path, bool ignore_read_only = true);
|
|
Result RenameFile(FsFileSystem* fs, const FsPathReal& src, const FsPathReal& dst, bool ignore_read_only = true);
|
|
Result RenameDirectory(FsFileSystem* fs, const FsPathReal& src, const FsPathReal& dst, bool ignore_read_only = true);
|
|
Result GetEntryType(FsFileSystem* fs, const FsPathReal& path, FsDirEntryType* out);
|
|
Result GetFileTimeStampRaw(FsFileSystem* fs, const FsPathReal& path, FsTimeStampRaw *out);
|
|
Result SetTimestamp(FsFileSystem* fs, const FsPathReal& path, const FsTimeStampRaw* ts);
|
|
bool FileExists(FsFileSystem* fs, const FsPath& path);
|
|
bool DirExists(FsFileSystem* fs, const FsPath& path);
|
|
|
|
Result CreateFile(const FsPathReal& path, u64 size = 0, u32 option = 0, bool ignore_read_only = true);
|
|
Result CreateDirectory(const FsPathReal& path, bool ignore_read_only = true);
|
|
Result CreateDirectoryRecursively(const FsPath& path, bool ignore_read_only = true);
|
|
Result CreateDirectoryRecursivelyWithPath(const FsPath& path, bool ignore_read_only = true);
|
|
Result DeleteFile(const FsPathReal& path, bool ignore_read_only = true);
|
|
Result DeleteDirectory(const FsPathReal& path, bool ignore_read_only = true);
|
|
Result DeleteDirectoryRecursively(const FsPath& path, bool ignore_read_only = true);
|
|
Result RenameFile(const FsPathReal& src, const FsPathReal& dst, bool ignore_read_only = true);
|
|
Result RenameDirectory(const FsPathReal& src, const FsPathReal& dst, bool ignore_read_only = true);
|
|
Result GetEntryType(const FsPathReal& path, FsDirEntryType* out);
|
|
Result GetFileTimeStampRaw(const FsPathReal& path, FsTimeStampRaw *out);
|
|
Result SetTimestamp(const FsPathReal& path, const FsTimeStampRaw* ts);
|
|
bool FileExists(const FsPath& path);
|
|
bool DirExists(const FsPath& path);
|
|
|
|
Result OpenFile(fs::Fs* fs, const FsPathReal& path, u32 mode, File* f);
|
|
Result OpenDirectory(fs::Fs* fs, const FsPathReal& path, u32 mode, Dir* d);
|
|
|
|
// opens dir, fetches count for all entries.
|
|
// NOTE: this function will be slow on non-native fs, due to multiple
|
|
// readdir() functions being needed!
|
|
Result DirGetEntryCount(fs::Fs* fs, const fs::FsPath& path, s64* count, u32 mode);
|
|
// same as the above, but fetches file and folder count in a single pass
|
|
// this is faster when using native, and *much* faster for stdio.
|
|
Result DirGetEntryCount(fs::Fs* fs, const fs::FsPath& path, s64* file_count, s64* dir_count, u32 mode = FsDirOpenMode_ReadDirs|FsDirOpenMode_ReadFiles);
|
|
|
|
// optimised for stdio calls as stat returns size and timestamp in a single call.
|
|
// whereas for native, this is 2 function calls.
|
|
// however if you need both, you will need 2 calls for native anyway,
|
|
// but can avoid the second (expensive) stat call.
|
|
Result FileGetSizeAndTimestamp(fs::Fs* fs, const FsPath& path, FsTimeStampRaw* ts, s64* size);
|
|
Result IsDirEmpty(fs::Fs* m_fs, const fs::FsPath& path, bool* out);
|
|
|
|
// helpers.
|
|
Result read_entire_file(Fs* fs, const FsPath& path, std::vector<u8>& out);
|
|
Result write_entire_file(Fs* fs, const FsPath& path, const std::vector<u8>& in, bool ignore_read_only = true);
|
|
Result copy_entire_file(Fs* fs, const FsPath& dst, const FsPath& src, bool ignore_read_only = true);
|
|
|
|
struct Fs {
|
|
Fs(bool ignore_read_only = true) : m_ignore_read_only{ignore_read_only} {}
|
|
virtual ~Fs() = default;
|
|
|
|
virtual Result CreateFile(const FsPath& path, u64 size = 0, u32 option = 0) = 0;
|
|
virtual Result CreateDirectory(const FsPath& path) = 0;
|
|
virtual Result CreateDirectoryRecursively(const FsPath& path) = 0;
|
|
virtual Result CreateDirectoryRecursivelyWithPath(const FsPath& path) = 0;
|
|
virtual Result DeleteFile(const FsPath& path) = 0;
|
|
virtual Result DeleteDirectory(const FsPath& path) = 0;
|
|
virtual Result DeleteDirectoryRecursively(const FsPath& path) = 0;
|
|
virtual Result RenameFile(const FsPath& src, const FsPath& dst) = 0;
|
|
virtual Result RenameDirectory(const FsPath& src, const FsPath& dst) = 0;
|
|
virtual Result GetEntryType(const FsPath& path, FsDirEntryType* out) = 0;
|
|
virtual Result GetFileTimeStampRaw(const FsPath& path, FsTimeStampRaw *out) = 0;
|
|
virtual Result SetTimestamp(const FsPath& path, const FsTimeStampRaw* ts) = 0;
|
|
virtual Result Commit() = 0;
|
|
virtual bool FileExists(const FsPath& path) = 0;
|
|
virtual bool DirExists(const FsPath& path) = 0;
|
|
virtual bool IsNative() const = 0;
|
|
virtual bool IsSd() const { return false; }
|
|
virtual FsPath Root() const { return "/"; }
|
|
|
|
Result OpenFile(const fs::FsPath& path, u32 mode, File* f) {
|
|
return fs::OpenFile(this, path, mode, f);
|
|
}
|
|
Result OpenDirectory(const fs::FsPath& path, u32 mode, Dir* d) {
|
|
return fs::OpenDirectory(this, path, mode, d);
|
|
}
|
|
Result DirGetEntryCount(const fs::FsPath& path, s64* count, u32 mode) {
|
|
return fs::DirGetEntryCount(this, path, count, mode);
|
|
}
|
|
Result DirGetEntryCount(const fs::FsPath& path, s64* file_count, s64* dir_count, u32 mode = FsDirOpenMode_ReadDirs|FsDirOpenMode_ReadFiles) {
|
|
return fs::DirGetEntryCount(this, path, file_count, dir_count, mode);
|
|
}
|
|
Result FileGetSizeAndTimestamp(const FsPath& path, FsTimeStampRaw* ts, s64* size) {
|
|
return fs::FileGetSizeAndTimestamp(this, path, ts, size);
|
|
}
|
|
Result IsDirEmpty(const fs::FsPath& path, bool* out) {
|
|
return fs::IsDirEmpty(this, path, out);
|
|
}
|
|
Result read_entire_file(const FsPath& path, std::vector<u8>& out) {
|
|
return fs::read_entire_file(this, path, out);
|
|
}
|
|
Result write_entire_file(const FsPath& path, const std::vector<u8>& in) {
|
|
return fs::write_entire_file(this, path, in, m_ignore_read_only);
|
|
}
|
|
Result copy_entire_file(const FsPath& dst, const FsPath& src) {
|
|
return fs::copy_entire_file(this, dst, src, m_ignore_read_only);
|
|
}
|
|
|
|
void SetIgnoreReadOnly(bool enable) {
|
|
m_ignore_read_only = enable;
|
|
}
|
|
|
|
protected:
|
|
bool m_ignore_read_only;
|
|
};
|
|
|
|
struct FsStdio : Fs {
|
|
FsStdio(bool ignore_read_only = true, const FsPath& root = "/") : Fs{ignore_read_only}, m_root{root} {}
|
|
virtual ~FsStdio() = default;
|
|
|
|
Result CreateFile(const FsPath& path, u64 size = 0, u32 option = 0) override {
|
|
return fs::CreateFile(path, size, option, m_ignore_read_only);
|
|
}
|
|
Result CreateDirectory(const FsPath& path) override {
|
|
return fs::CreateDirectory(path, m_ignore_read_only);
|
|
}
|
|
Result CreateDirectoryRecursively(const FsPath& path) override {
|
|
return fs::CreateDirectoryRecursively(path, m_ignore_read_only);
|
|
}
|
|
Result CreateDirectoryRecursivelyWithPath(const FsPath& path) override {
|
|
return fs::CreateDirectoryRecursivelyWithPath(path, m_ignore_read_only);
|
|
}
|
|
Result DeleteFile(const FsPath& path) override {
|
|
return fs::DeleteFile(path, m_ignore_read_only);
|
|
}
|
|
Result DeleteDirectory(const FsPath& path) override {
|
|
return fs::DeleteDirectory(path, m_ignore_read_only);
|
|
}
|
|
Result DeleteDirectoryRecursively(const FsPath& path) override {
|
|
return fs::DeleteDirectoryRecursively(path, m_ignore_read_only);
|
|
}
|
|
Result RenameFile(const FsPath& src, const FsPath& dst) override {
|
|
return fs::RenameFile(src, dst, m_ignore_read_only);
|
|
}
|
|
Result RenameDirectory(const FsPath& src, const FsPath& dst) override {
|
|
return fs::RenameDirectory(src, dst, m_ignore_read_only);
|
|
}
|
|
Result GetEntryType(const FsPath& path, FsDirEntryType* out) override {
|
|
return fs::GetEntryType(path, out);
|
|
}
|
|
Result GetFileTimeStampRaw(const FsPath& path, FsTimeStampRaw *out) override {
|
|
return fs::GetFileTimeStampRaw(path, out);
|
|
}
|
|
Result SetTimestamp(const FsPath& path, const FsTimeStampRaw *ts) override {
|
|
return fs::SetTimestamp(path, ts);
|
|
}
|
|
Result Commit() override {
|
|
R_SUCCEED();
|
|
}
|
|
bool FileExists(const FsPath& path) override {
|
|
return fs::FileExists(path);
|
|
}
|
|
bool DirExists(const FsPath& path) override {
|
|
return fs::DirExists(path);
|
|
}
|
|
bool IsNative() const override {
|
|
return false;
|
|
}
|
|
FsPath Root() const override {
|
|
return m_root;
|
|
}
|
|
|
|
const FsPath m_root;
|
|
};
|
|
|
|
struct FsNative : Fs {
|
|
explicit FsNative(bool ignore_read_only = true) : Fs{ignore_read_only} {}
|
|
explicit FsNative(FsFileSystem* fs, bool own, bool ignore_read_only = true) : Fs{ignore_read_only}, m_fs{*fs}, m_own{own} {}
|
|
|
|
virtual ~FsNative() {
|
|
if (m_own) {
|
|
fsFsClose(&m_fs);
|
|
}
|
|
}
|
|
|
|
Result GetFreeSpace(const FsPath& path, s64* out) {
|
|
return fsFsGetFreeSpace(&m_fs, path, out);
|
|
}
|
|
|
|
Result GetTotalSpace(const FsPath& path, s64* out) {
|
|
return fsFsGetTotalSpace(&m_fs, path, out);
|
|
}
|
|
|
|
virtual bool IsFsActive() {
|
|
return serviceIsActive(&m_fs.s);
|
|
}
|
|
|
|
virtual Result GetFsOpenResult() const {
|
|
return m_open_result;
|
|
}
|
|
|
|
Result CreateFile(const FsPath& path, u64 size = 0, u32 option = 0) override {
|
|
return fs::CreateFile(&m_fs, path, size, option, m_ignore_read_only);
|
|
}
|
|
Result CreateDirectory(const FsPath& path) override {
|
|
return fs::CreateDirectory(&m_fs, path, m_ignore_read_only);
|
|
}
|
|
Result CreateDirectoryRecursively(const FsPath& path) override {
|
|
return fs::CreateDirectoryRecursively(&m_fs, path, m_ignore_read_only);
|
|
}
|
|
Result CreateDirectoryRecursivelyWithPath(const FsPath& path) override {
|
|
return fs::CreateDirectoryRecursivelyWithPath(&m_fs, path, m_ignore_read_only);
|
|
}
|
|
Result DeleteFile(const FsPath& path) override {
|
|
return fs::DeleteFile(&m_fs, path, m_ignore_read_only);
|
|
}
|
|
Result DeleteDirectory(const FsPath& path) override {
|
|
return fs::DeleteDirectory(&m_fs, path, m_ignore_read_only);
|
|
}
|
|
Result DeleteDirectoryRecursively(const FsPath& path) override {
|
|
return fs::DeleteDirectoryRecursively(&m_fs, path, m_ignore_read_only);
|
|
}
|
|
Result RenameFile(const FsPath& src, const FsPath& dst) override {
|
|
return fs::RenameFile(&m_fs, src, dst, m_ignore_read_only);
|
|
}
|
|
Result RenameDirectory(const FsPath& src, const FsPath& dst) override {
|
|
return fs::RenameDirectory(&m_fs, src, dst, m_ignore_read_only);
|
|
}
|
|
Result GetEntryType(const FsPath& path, FsDirEntryType* out) override {
|
|
return fs::GetEntryType(&m_fs, path, out);
|
|
}
|
|
Result GetFileTimeStampRaw(const FsPath& path, FsTimeStampRaw *out) override {
|
|
return fs::GetFileTimeStampRaw(&m_fs, path, out);
|
|
}
|
|
Result SetTimestamp(const FsPath& path, const FsTimeStampRaw *ts) override {
|
|
return fs::SetTimestamp(&m_fs, path, ts);
|
|
}
|
|
Result Commit() override {
|
|
return fsFsCommit(&m_fs);
|
|
}
|
|
bool FileExists(const FsPath& path) override {
|
|
return fs::FileExists(&m_fs, path);
|
|
}
|
|
bool DirExists(const FsPath& path) override {
|
|
return fs::DirExists(&m_fs, path);
|
|
}
|
|
bool IsNative() const override {
|
|
return true;
|
|
}
|
|
|
|
FsFileSystem m_fs{};
|
|
Result m_open_result{};
|
|
const bool m_own{true};
|
|
};
|
|
|
|
#if 0
|
|
struct FsNativeSd final : FsNative {
|
|
FsNativeSd() {
|
|
m_open_result = fsOpenSdCardFileSystem(&m_fs);
|
|
}
|
|
};
|
|
#else
|
|
struct FsNativeSd final : FsNative {
|
|
FsNativeSd(bool ignore_read_only = true) : FsNative{fsdevGetDeviceFileSystem("sdmc:"), false, ignore_read_only} {
|
|
m_open_result = 0;
|
|
}
|
|
|
|
bool IsSd() const override { return true; }
|
|
};
|
|
#endif
|
|
|
|
struct FsNativeBis final : FsNative {
|
|
FsNativeBis(FsBisPartitionId id, const FsPath& string) {
|
|
m_open_result = fsOpenBisFileSystem(&m_fs, id, string);
|
|
}
|
|
};
|
|
|
|
struct FsNativeImage final : FsNative {
|
|
FsNativeImage(FsImageDirectoryId id) {
|
|
m_open_result = fsOpenImageDirectoryFileSystem(&m_fs, id);
|
|
}
|
|
};
|
|
|
|
struct FsNativeContentStorage final : FsNative {
|
|
FsNativeContentStorage(FsContentStorageId id) {
|
|
m_open_result = fsOpenContentStorageFileSystem(&m_fs, id);
|
|
}
|
|
};
|
|
|
|
struct FsNativeGameCard final : FsNative {
|
|
FsNativeGameCard(const FsGameCardHandle* handle, FsGameCardPartition partition) {
|
|
m_open_result = fsOpenGameCardFileSystem(&m_fs, handle, partition);
|
|
}
|
|
};
|
|
|
|
struct FsNativeSave final : FsNative {
|
|
FsNativeSave(FsSaveDataType data_type, FsSaveDataSpaceId save_data_space_id, const FsSaveDataAttribute *attr, bool read_only) {
|
|
if (data_type == FsSaveDataType_System || data_type == FsSaveDataType_SystemBcat) {
|
|
m_open_result = fsOpenSaveDataFileSystemBySystemSaveDataId(&m_fs, FsSaveDataSpaceId_System, attr);
|
|
} else {
|
|
if (read_only) {
|
|
m_open_result = fsOpenReadOnlySaveDataFileSystem(&m_fs, save_data_space_id, attr);
|
|
} else {
|
|
m_open_result = fsOpenSaveDataFileSystem(&m_fs, save_data_space_id, attr);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
struct FsNativeId final : FsNative {
|
|
FsNativeId(u64 program_id, FsFileSystemType type, const FsPath& path, FsContentAttributes attr = FsContentAttributes_All) {
|
|
m_open_result = fsOpenFileSystemWithId(&m_fs, program_id, type, path, attr);
|
|
}
|
|
};
|
|
|
|
} // namespace fs
|