From a9931a975db0852e30069823d99c2a6ee1af02b3 Mon Sep 17 00:00:00 2001 From: ITotalJustice <47043333+ITotalJustice@users.noreply.github.com> Date: Mon, 26 May 2025 17:06:04 +0100 Subject: [PATCH] many more optimisations. cleaned up fs code. bug fixes etc (see below). - fix usb using the wrong year when polling the timestamp. - fs file/dir has been re-written to allow for simplified calling and remove the need of manually closing. - add SetSize for stdio by using ftruncate. - don't truncate the file when opened in stdio. - add getcount api for stdio. - display file/dir count in filebrowser for non-native fs. - allow hash to be used on non-native fs. - slightly optimise nro parsing by manually calculating nro size rather than doing an os call. - slightly optimise nro parsing by keeping the fs struct alive between calls, rather than creating a new one on the stack. - fix filebrowser peeking into zip files that are stored on non-sd fs. - set the timestamp of a file moved to a stdio location (cut/paste). - slightly optimise daybreak update folder detection by skipping opening/polling the dir size. - set the fullpath of the file thats being hashed in progress box. --- sphaira/CMakeLists.txt | 2 +- sphaira/include/fs.hpp | 134 +++++----- sphaira/include/ui/menus/file_viewer.hpp | 3 +- sphaira/include/yati/source/file.hpp | 7 +- sphaira/include/yati/source/stream_file.hpp | 7 +- sphaira/include/yati/yati.hpp | 3 +- sphaira/source/download.cpp | 18 +- sphaira/source/dumper.cpp | 3 +- sphaira/source/fs.cpp | 268 ++++++++++++++------ sphaira/source/hasher.cpp | 8 +- sphaira/source/nro.cpp | 89 +++---- sphaira/source/nxlink.cpp | 7 +- sphaira/source/ui/menus/appstore.cpp | 8 +- sphaira/source/ui/menus/file_viewer.cpp | 8 +- sphaira/source/ui/menus/filebrowser.cpp | 108 ++++---- sphaira/source/ui/menus/gc_menu.cpp | 24 +- sphaira/source/ui/menus/ghdl.cpp | 8 +- sphaira/source/ui/menus/main_menu.cpp | 8 +- sphaira/source/ui/menus/themezer.cpp | 8 +- sphaira/source/ui/progress_box.cpp | 10 +- sphaira/source/yati/source/file.cpp | 20 +- sphaira/source/yati/source/stream_file.cpp | 20 +- sphaira/source/yati/yati.cpp | 6 +- 23 files changed, 390 insertions(+), 387 deletions(-) diff --git a/sphaira/CMakeLists.txt b/sphaira/CMakeLists.txt index c629e27..4f3a29d 100644 --- a/sphaira/CMakeLists.txt +++ b/sphaira/CMakeLists.txt @@ -197,7 +197,7 @@ FetchContent_Declare(zstd FetchContent_Declare(libusbhsfs GIT_REPOSITORY https://github.com/ITotalJustice/libusbhsfs.git - GIT_TAG d2395e9 + GIT_TAG b963156 ) set(USE_NEW_ZSTD ON) diff --git a/sphaira/include/fs.hpp b/sphaira/include/fs.hpp index 987a47f..ec79e9e 100644 --- a/sphaira/include/fs.hpp +++ b/sphaira/include/fs.hpp @@ -174,20 +174,34 @@ static_assert(FsPath::TestFrom(FsPath{"abc"})); struct Fs; struct File { - fs::Fs* m_fs; - FsFile m_native; - std::FILE* m_stdio; - s64 m_stdio_off; + ~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{}; + s64 m_stdio_off{}; // sadly, fatfs doesn't support fstat, so we have to manually // stat the file to get it's size. - FsPath m_path; + FsPath m_path{}; }; struct Dir { - fs::Fs* m_fs; - FsDir m_native; - DIR* m_stdio; - u32 m_mode; + ~Dir(); + + Result GetEntryCount(s64* out); + Result ReadAll(std::vector& 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); @@ -203,6 +217,7 @@ Result RenameFile(FsFileSystem* fs, const FsPath& src, const FsPath& dst, bool i Result RenameDirectory(FsFileSystem* fs, const FsPath& src, const FsPath& dst, bool ignore_read_only = true); Result GetEntryType(FsFileSystem* fs, const FsPath& path, FsDirEntryType* out); Result GetFileTimeStampRaw(FsFileSystem* fs, const FsPath& path, FsTimeStampRaw *out); +Result SetTimestamp(FsFileSystem* fs, const FsPath& path, const FsTimeStampRaw* ts); bool FileExists(FsFileSystem* fs, const FsPath& path); bool DirExists(FsFileSystem* fs, const FsPath& path); Result read_entire_file(FsFileSystem* fs, const FsPath& path, std::vector& out); @@ -220,6 +235,7 @@ Result RenameFile(const FsPath& src, const FsPath& dst, bool ignore_read_only = Result RenameDirectory(const FsPath& src, const FsPath& dst, bool ignore_read_only = true); Result GetEntryType(const FsPath& path, FsDirEntryType* out); Result GetFileTimeStampRaw(const FsPath& path, FsTimeStampRaw *out); +Result SetTimestamp(const FsPath& path, const FsTimeStampRaw* ts); bool FileExists(const FsPath& path); bool DirExists(const FsPath& path); Result read_entire_file(const FsPath& path, std::vector& out); @@ -227,15 +243,15 @@ Result write_entire_file(const FsPath& path, const std::vector& in, bool ign Result copy_entire_file(const FsPath& dst, const FsPath& src, bool ignore_read_only = true); Result OpenFile(fs::Fs* fs, const fs::FsPath& path, u32 mode, File* f); -Result FileRead(File* f, s64 off, void* buf, u64 read_size, u32 option, u64* bytes_read); -Result FileWrite(File* f, s64 off, const void* buf, u64 write_size, u32 option); -Result FileSetSize(File* f, s64 sz); -Result FileGetSize(File* f, s64* out); -void FileClose(File* f); - Result OpenDirectory(fs::Fs* fs, const fs::FsPath& path, u32 mode, Dir* d); -Result DirReadAll(Dir* d, std::vector& buf); -void DirClose(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. @@ -275,6 +291,7 @@ struct Fs { 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 bool FileExists(const FsPath& path) = 0; virtual bool DirExists(const FsPath& path) = 0; virtual bool IsNative() const = 0; @@ -286,32 +303,15 @@ struct Fs { Result OpenFile(const fs::FsPath& path, u32 mode, File* f) { return fs::OpenFile(this, path, mode, f); } - Result FileRead(File* f, s64 off, void* buf, u64 read_size, u32 option, u64* bytes_read) { - return fs::FileRead(f, off, buf, read_size, option, bytes_read); - } - Result FileWrite(File* f, s64 off, const void* buf, u64 write_size, u32 option) { - return fs::FileWrite(f, off, buf, write_size, option); - } - Result FileSetSize(File* f, s64 sz) { - return fs::FileSetSize(f, sz); - } - Result FileGetSize(File* f, s64* out) { - return fs::FileGetSize(f, out); - } - void FileClose(File* f) { - fs::FileClose(f); - } - Result OpenDirectory(const fs::FsPath& path, u32 mode, Dir* d) { return fs::OpenDirectory(this, path, mode, d); } - Result DirReadAll(Dir* d, std::vector& buf) { - return fs::DirReadAll(d, buf); + Result DirGetEntryCount(const fs::FsPath& path, s64* count, u32 mode) { + return fs::DirGetEntryCount(this, path, count, mode); } - void DirClose(Dir* d) { - fs::DirClose(d); + 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); } @@ -364,6 +364,9 @@ struct FsStdio : Fs { 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); + } bool FileExists(const FsPath& path) override { return fs::FileExists(path); } @@ -411,39 +414,35 @@ struct FsNative : Fs { return fsFsGetTotalSpace(&m_fs, path, out); } - Result OpenFile(const FsPath& path, u32 mode, FsFile *out) { - return fsFsOpenFile(&m_fs, path, mode, out); - } + // Result OpenDirectory(const FsPath& path, u32 mode, FsDir *out) { + // return fsFsOpenDirectory(&m_fs, path, mode, out); + // } - Result OpenDirectory(const FsPath& path, u32 mode, FsDir *out) { - return fsFsOpenDirectory(&m_fs, path, mode, out); - } + // void DirClose(FsDir *d) { + // fsDirClose(d); + // } - void DirClose(FsDir *d) { - fsDirClose(d); - } + // Result DirGetEntryCount(FsDir *d, s64* out) { + // return fsDirGetEntryCount(d, out); + // } - Result DirGetEntryCount(FsDir *d, s64* out) { - return fsDirGetEntryCount(d, out); - } + // Result DirGetEntryCount(const FsPath& path, u32 mode, s64* out) { + // FsDir d; + // R_TRY(OpenDirectory(path, mode, &d)); + // ON_SCOPE_EXIT(DirClose(&d)); + // return DirGetEntryCount(&d, out); + // } - Result DirGetEntryCount(const FsPath& path, u32 mode, s64* out) { - FsDir d; - R_TRY(OpenDirectory(path, mode, &d)); - ON_SCOPE_EXIT(DirClose(&d)); - return DirGetEntryCount(&d, out); - } + // Result DirRead(FsDir *d, s64 *total_entries, size_t max_entries, FsDirectoryEntry *buf) { + // return fsDirRead(d, total_entries, max_entries, buf); + // } - Result DirRead(FsDir *d, s64 *total_entries, size_t max_entries, FsDirectoryEntry *buf) { - return fsDirRead(d, total_entries, max_entries, buf); - } - - Result DirRead(const FsPath& path, u32 mode, s64 *total_entries, size_t max_entries, FsDirectoryEntry *buf) { - FsDir d; - R_TRY(OpenDirectory(path, mode, &d)); - ON_SCOPE_EXIT(DirClose(&d)); - return DirRead(&d, total_entries, max_entries, buf); - } + // Result DirRead(const FsPath& path, u32 mode, s64 *total_entries, size_t max_entries, FsDirectoryEntry *buf) { + // FsDir d; + // R_TRY(OpenDirectory(path, mode, &d)); + // ON_SCOPE_EXIT(DirClose(&d)); + // return DirRead(&d, total_entries, max_entries, buf); + // } virtual bool IsFsActive() { return serviceIsActive(&m_fs.s); @@ -486,6 +485,9 @@ struct FsNative : Fs { 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); + } bool FileExists(const FsPath& path) override { return fs::FileExists(&m_fs, path); } diff --git a/sphaira/include/ui/menus/file_viewer.hpp b/sphaira/include/ui/menus/file_viewer.hpp index c48c641..5cd9974 100644 --- a/sphaira/include/ui/menus/file_viewer.hpp +++ b/sphaira/include/ui/menus/file_viewer.hpp @@ -8,7 +8,6 @@ namespace sphaira::ui::menu::fileview { struct Menu final : MenuBase { Menu(const fs::FsPath& path); - ~Menu(); auto GetShortTitle() const -> const char* override { return "File"; }; void Update(Controller* controller, TouchInfo* touch) override; @@ -18,7 +17,7 @@ struct Menu final : MenuBase { private: const fs::FsPath m_path; fs::FsNativeSd m_fs{}; - FsFile m_file{}; + fs::File m_file{}; s64 m_file_size{}; s64 m_file_offset{}; diff --git a/sphaira/include/yati/source/file.hpp b/sphaira/include/yati/source/file.hpp index bc1f395..bfdd875 100644 --- a/sphaira/include/yati/source/file.hpp +++ b/sphaira/include/yati/source/file.hpp @@ -8,14 +8,11 @@ namespace sphaira::yati::source { struct File final : Base { - File(FsFileSystem* fs, const fs::FsPath& path); - File(const fs::FsPath& path); - ~File(); - + File(fs::Fs* fs, const fs::FsPath& path); Result Read(void* buf, s64 off, s64 size, u64* bytes_read) override; private: - std::unique_ptr m_fs{}; + fs::Fs* m_fs{}; fs::File m_file{}; }; diff --git a/sphaira/include/yati/source/stream_file.hpp b/sphaira/include/yati/source/stream_file.hpp index 0ba6c25..4590c3e 100644 --- a/sphaira/include/yati/source/stream_file.hpp +++ b/sphaira/include/yati/source/stream_file.hpp @@ -10,14 +10,11 @@ namespace sphaira::yati::source { struct StreamFile final : Stream { - StreamFile(FsFileSystem* fs, const fs::FsPath& path); - StreamFile(const fs::FsPath& path); - ~StreamFile(); - + StreamFile(fs::Fs* fs, const fs::FsPath& path); Result ReadChunk(void* buf, s64 size, u64* bytes_read) override; private: - std::unique_ptr m_fs{}; + fs::Fs* m_fs{}; fs::File m_file{}; s64 m_offset{}; }; diff --git a/sphaira/include/yati/yati.hpp b/sphaira/include/yati/yati.hpp index 27f41bb..58d1d21 100644 --- a/sphaira/include/yati/yati.hpp +++ b/sphaira/include/yati/yati.hpp @@ -125,8 +125,7 @@ struct ConfigOverride { std::optional lower_system_version{}; }; -Result InstallFromFile(ui::ProgressBox* pbox, FsFileSystem* fs, const fs::FsPath& path, const ConfigOverride& override = {}); -Result InstallFromFile(ui::ProgressBox* pbox, const fs::FsPath& path, const ConfigOverride& override = {}); +Result InstallFromFile(ui::ProgressBox* pbox, fs::Fs* fs, const fs::FsPath& path, const ConfigOverride& override = {}); Result InstallFromSource(ui::ProgressBox* pbox, std::shared_ptr source, const fs::FsPath& path, const ConfigOverride& override = {}); Result InstallFromContainer(ui::ProgressBox* pbox, std::shared_ptr container, const ConfigOverride& override = {}); Result InstallFromCollections(ui::ProgressBox* pbox, std::shared_ptr source, const container::Collections& collections, const ConfigOverride& override = {}); diff --git a/sphaira/source/download.cpp b/sphaira/source/download.cpp index 577f435..9fe0883 100644 --- a/sphaira/source/download.cpp +++ b/sphaira/source/download.cpp @@ -46,13 +46,13 @@ struct UploadStruct { std::span data; s64 offset{}; s64 size{}; - FsFile f{}; + fs::File f{}; }; struct DataStruct { std::vector data; s64 offset{}; - FsFile f{}; + fs::File f{}; s64 file_offset{}; }; @@ -439,7 +439,7 @@ auto ReadFileCallback(char *ptr, size_t size, size_t nmemb, void *userp) -> size const auto realsize = size * nmemb; u64 bytes_read; - if (R_FAILED(fsFileRead(&data_struct->f, data_struct->offset, ptr, realsize, FsReadOption_None, &bytes_read))) { + if (R_FAILED(data_struct->f.Read(data_struct->offset, ptr, realsize, FsReadOption_None, &bytes_read))) { log_write("reading file error\n"); return 0; } @@ -509,7 +509,7 @@ auto WriteFileCallback(void *contents, size_t size, size_t num_files, void *user // flush data if incomming data would overflow the buffer if (data_struct->offset && data_struct->data.size() < data_struct->offset + realsize) { - if (R_FAILED(fsFileWrite(&data_struct->f, data_struct->file_offset, data_struct->data.data(), data_struct->offset, FsWriteOption_None))) { + if (R_FAILED(data_struct->f.Write(data_struct->file_offset, data_struct->data.data(), data_struct->offset, FsWriteOption_None))) { return 0; } @@ -519,7 +519,7 @@ auto WriteFileCallback(void *contents, size_t size, size_t num_files, void *user // we have a huge chunk! write it directly to file if (data_struct->data.size() < realsize) { - if (R_FAILED(fsFileWrite(&data_struct->f, data_struct->file_offset, contents, realsize, FsWriteOption_None))) { + if (R_FAILED(data_struct->f.Write(data_struct->file_offset, contents, realsize, FsWriteOption_None))) { return 0; } @@ -762,10 +762,10 @@ auto DownloadInternal(CURL* curl, const Api& e) -> ApiResult { if (has_file) { ON_SCOPE_EXIT( fs.DeleteFile(tmp_buf) ); if (res == CURLE_OK && chunk.offset) { - fsFileWrite(&chunk.f, chunk.file_offset, chunk.data.data(), chunk.offset, FsWriteOption_None); + chunk.f.Write(chunk.file_offset, chunk.data.data(), chunk.offset, FsWriteOption_None); } - fsFileClose(&chunk.f); + chunk.f.Close(); if (res == CURLE_OK) { if (http_code == 304) { @@ -835,7 +835,7 @@ auto UploadInternal(CURL* curl, const Api& e) -> ApiResult { return {}; } - fsFileGetSize(&chunk.f, &chunk.size); + chunk.f.GetSize(&chunk.size); log_write("got chunk size: %zd\n", chunk.size); } else { if (info.m_callback) { @@ -929,7 +929,7 @@ auto UploadInternal(CURL* curl, const Api& e) -> ApiResult { curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code); if (has_file) { - fsFileClose(&chunk.f); + chunk.f.Close(); } log_write("Uploaded %s code: %ld %s\n", url.c_str(), http_code, curl_easy_strerror(res)); diff --git a/sphaira/source/dumper.cpp b/sphaira/source/dumper.cpp index 61308ed..9727acc 100644 --- a/sphaira/source/dumper.cpp +++ b/sphaira/source/dumper.cpp @@ -124,14 +124,13 @@ Result DumpToFile(ui::ProgressBox* pbox, fs::Fs* fs, const fs::FsPath& root, Bas { fs::File file; R_TRY(fs->OpenFile(temp_path, FsOpenMode_Write, &file)); - ON_SCOPE_EXIT(fs->FileClose(&file)); R_TRY(thread::Transfer(pbox, file_size, [&](void* data, s64 off, s64 size, u64* bytes_read) -> Result { return source->Read(path, data, off, size, bytes_read); }, [&](const void* data, s64 off, s64 size) -> Result { - return fs->FileWrite(&file, off, data, size, FsWriteOption_None); + return file.Write(off, data, size, FsWriteOption_None); } )); } diff --git a/sphaira/source/fs.cpp b/sphaira/source/fs.cpp index 3c30178..aea518d 100644 --- a/sphaira/source/fs.cpp +++ b/sphaira/source/fs.cpp @@ -221,6 +221,11 @@ Result GetFileTimeStampRaw(FsFileSystem* fs, const FsPath& path, FsTimeStampRaw return fsFsGetFileTimeStampRaw(fs, path, out); } +Result SetTimestamp(FsFileSystem* fs, const FsPath& path, const FsTimeStampRaw* ts) { + // unsuported. + R_SUCCEED(); +} + bool FileExists(FsFileSystem* fs, const FsPath& path) { FsDirEntryType type; R_TRY_RESULT(GetEntryType(fs, path, &type), false); @@ -237,16 +242,16 @@ Result read_entire_file(FsFileSystem* _fs, const FsPath& path, std::vector& FsNative fs{_fs, false}; R_TRY(fs.GetFsOpenResult()); - FsFile f; + File f; R_TRY(fs.OpenFile(path, FsOpenMode_Read, &f)); - ON_SCOPE_EXIT(fsFileClose(&f)); + ON_SCOPE_EXIT(f.Close()); s64 size; - R_TRY(fsFileGetSize(&f, &size)); + R_TRY(f.GetSize(&size)); out.resize(size); u64 bytes_read; - R_TRY(fsFileRead(&f, 0, out.data(), out.size(), FsReadOption_None, &bytes_read)); + R_TRY(f.Read(0, out.data(), out.size(), FsReadOption_None, &bytes_read)); R_UNLESS(bytes_read == out.size(), 1); R_SUCCEED(); @@ -262,12 +267,12 @@ Result write_entire_file(FsFileSystem* _fs, const FsPath& path, const std::vecto return rc; } - FsFile f; + File f; R_TRY(fs.OpenFile(path, FsOpenMode_Write, &f)); - ON_SCOPE_EXIT(fsFileClose(&f)); + ON_SCOPE_EXIT(f.Close()); - R_TRY(fsFileSetSize(&f, in.size())); - R_TRY(fsFileWrite(&f, 0, in.data(), in.size(), FsWriteOption_None)); + R_TRY(f.SetSize(in.size())); + R_TRY(f.Write(0, in.data(), in.size(), FsWriteOption_None)); R_SUCCEED(); } @@ -292,7 +297,12 @@ Result CreateFile(const FsPath& path, u64 size, u32 option, bool ignore_read_onl R_TRY(fsdevGetLastResult()); return Fs::ResultUnknownStdioError; } - close(fd); + ON_SCOPE_EXIT(close(fd)); + + if (size) { + R_UNLESS(!ftruncate(fd, size), Fs::ResultUnknownStdioError); + } + R_SUCCEED(); } @@ -405,6 +415,20 @@ Result GetFileTimeStampRaw(const FsPath& path, FsTimeStampRaw *out) { R_SUCCEED(); } +Result SetTimestamp(const FsPath& path, const FsTimeStampRaw* ts) { + if (ts->is_valid) { + timeval val[2]{}; + val[0].tv_sec = ts->accessed; + val[1].tv_sec = ts->modified; + + if (utimes(path, val)) { + log_write("utimes() failed: %d %s\n", errno, strerror(errno)); + } + } + + R_SUCCEED(); +} + bool FileExists(const FsPath& path) { FsDirEntryType type; R_TRY_RESULT(GetEntryType(path, &type), false); @@ -458,92 +482,95 @@ Result copy_entire_file(const FsPath& dst, const FsPath& src, bool ignore_read_o } Result OpenFile(fs::Fs* fs, const fs::FsPath& path, u32 mode, File* f) { - *f = {}; f->m_fs = fs; if (f->m_fs->IsNative()) { auto fs = (fs::FsNative*)f->m_fs; - R_TRY(fs->OpenFile(path, mode, &f->m_native)); + R_TRY(fsFsOpenFile(&fs->m_fs, path, mode, &f->m_native)); } else { if ((mode & FsOpenMode_Read) && (mode & FsOpenMode_Write)) { - // todo: - R_THROW(0x1); + f->m_stdio = std::fopen(path, "rb+"); } else if (mode & FsOpenMode_Read) { f->m_stdio = std::fopen(path, "rb"); } else if (mode & FsOpenMode_Write) { - f->m_stdio = std::fopen(path, "wb"); + // not possible to open file with just write and not append + // or create or truncate. So rw it is! + f->m_stdio = std::fopen(path, "rb+"); } - R_UNLESS(f->m_stdio, 0x1); + R_UNLESS(f->m_stdio, Fs::ResultUnknownStdioError); + std::strcpy(f->m_path, path); } - std::strcpy(f->m_path, path); R_SUCCEED(); } -Result FileRead(File* f, s64 off, void* buf, u64 read_size, u32 option, u64* bytes_read) { - if (f->m_fs->IsNative()) { - R_TRY(fsFileRead(&f->m_native, off, buf, read_size, option, bytes_read)); +File::~File() { + Close(); +} + +Result File::Read( s64 off, void* buf, u64 read_size, u32 option, u64* bytes_read) { + if (m_fs->IsNative()) { + R_TRY(fsFileRead(&m_native, off, buf, read_size, option, bytes_read)); } else { - if (f->m_stdio_off != off) { - f->m_stdio_off = off; - std::fseek(f->m_stdio, off, SEEK_SET); + if (m_stdio_off != off) { + m_stdio_off = off; + std::fseek(m_stdio, off, SEEK_SET); } - *bytes_read = std::fread(buf, 1, read_size, f->m_stdio); + *bytes_read = std::fread(buf, 1, read_size, m_stdio); // if we read less bytes than expected, check if there was an error (ignoring eof). if (*bytes_read < read_size) { - if (!std::feof(f->m_stdio) && std::ferror(f->m_stdio)) { - R_THROW(0x1); + if (!std::feof(m_stdio) && std::ferror(m_stdio)) { + R_THROW(Fs::ResultUnknownStdioError); } } - f->m_stdio_off += *bytes_read; + m_stdio_off += *bytes_read; } R_SUCCEED(); } -Result FileWrite(File* f, s64 off, const void* buf, u64 write_size, u32 option) { - if (f->m_fs->IsNative()) { - R_TRY(fsFileWrite(&f->m_native, off, buf, write_size, option)); +Result File::Write(s64 off, const void* buf, u64 write_size, u32 option) { + if (m_fs->IsNative()) { + R_TRY(fsFileWrite(&m_native, off, buf, write_size, option)); } else { - if (f->m_stdio_off != off) { + if (m_stdio_off != off) { log_write("[FS] diff seek\n"); - f->m_stdio_off = off; - std::fseek(f->m_stdio, off, SEEK_SET); + m_stdio_off = off; + std::fseek(m_stdio, off, SEEK_SET); } - const auto result = std::fwrite(buf, 1, write_size, f->m_stdio); + const auto result = std::fwrite(buf, 1, write_size, m_stdio); // log_write("[FS] fwrite res: %zu vs %zu\n", result, write_size); - R_UNLESS(result == write_size, 0x1); + R_UNLESS(result == write_size, Fs::ResultUnknownStdioError); - f->m_stdio_off += write_size; + m_stdio_off += write_size; } R_SUCCEED(); } -Result FileSetSize(File* f, s64 sz) { - if (f->m_fs->IsNative()) { - R_TRY(fsFileSetSize(&f->m_native, sz)); +Result File::SetSize(s64 sz) { + if (m_fs->IsNative()) { + R_TRY(fsFileSetSize(&m_native, sz)); } else { - R_SUCCEED(); - // const auto fd = fileno(f->m_stdio); - // R_UNLESS(fd > 0, 0x1); - // R_UNLESS(!ftruncate(fd, sz), 0x1); + const auto fd = fileno(m_stdio); + R_UNLESS(fd > 0, Fs::ResultUnknownStdioError); + R_UNLESS(!ftruncate(fd, sz), Fs::ResultUnknownStdioError); } R_SUCCEED(); } -Result FileGetSize(File* f, s64* out) { - if (f->m_fs->IsNative()) { - R_TRY(fsFileGetSize(&f->m_native, out)); +Result File::GetSize(s64* out) { + if (m_fs->IsNative()) { + R_TRY(fsFileGetSize(&m_native, out)); } else { struct stat st; - const auto fd = fileno(f->m_stdio); + const auto fd = fileno(m_stdio); bool did_stat{}; if (fd && !fstat(fd, &st)) { @@ -551,7 +578,7 @@ Result FileGetSize(File* f, s64* out) { } if (!did_stat) { - R_UNLESS(!lstat(f->m_path, &st), 0x1); + R_UNLESS(!lstat(m_path, &st), Fs::ResultUnknownStdioError); } *out = st.st_size; @@ -560,68 +587,142 @@ Result FileGetSize(File* f, s64* out) { R_SUCCEED(); } -void FileClose(File* f) { - if (f->m_fs->IsNative()) { - fsFileClose(&f->m_native); +void File::Close() { + if (m_fs->IsNative()) { + if (serviceIsActive(&m_native.s)) { + fsFileClose(&m_native); + m_native = {}; + } } else { - std::fclose(f->m_stdio); + if (m_stdio) { + std::fclose(m_stdio); + m_stdio = {}; + } } - - *f = {}; } Result OpenDirectory(fs::Fs* fs, const fs::FsPath& path, u32 mode, Dir* d) { - *d = {}; d->m_fs = fs; d->m_mode = mode; if (d->m_fs->IsNative()) { auto fs = (fs::FsNative*)d->m_fs; - R_TRY(fs->OpenDirectory(path, mode, &d->m_native)); + R_TRY(fsFsOpenDirectory(&fs->m_fs, path, mode, &d->m_native)); } else { d->m_stdio = opendir(path); - R_UNLESS(d->m_stdio, 0x1); + R_UNLESS(d->m_stdio, Fs::ResultUnknownStdioError); } R_SUCCEED(); } -Result DirReadAll(Dir* d, std::vector& buf) { +Result DirGetEntryCount(fs::Fs* m_fs, const fs::FsPath& path, s64* count, u32 mode) { + s64 file_count, dir_count; + R_TRY(DirGetEntryCount(m_fs, path, &file_count, &dir_count, mode)); + *count = file_count + dir_count; + R_SUCCEED(); +} + +Result DirGetEntryCount(fs::Fs* m_fs, const fs::FsPath& path, s64* file_count, s64* dir_count, u32 mode) { + *file_count = *dir_count = 0; + + if (m_fs->IsNative()) { + if (mode & FsDirOpenMode_ReadDirs){ + fs::Dir dir; + R_TRY(m_fs->OpenDirectory(path, FsDirOpenMode_ReadDirs|FsDirOpenMode_NoFileSize, &dir)); + R_TRY(dir.GetEntryCount(file_count)); + } + if (mode & FsDirOpenMode_ReadFiles){ + fs::Dir dir; + R_TRY(m_fs->OpenDirectory(path, FsDirOpenMode_ReadFiles|FsDirOpenMode_NoFileSize, &dir)); + R_TRY(dir.GetEntryCount(file_count)); + } + } else { + fs::Dir dir; + R_TRY(m_fs->OpenDirectory(path, mode, &dir)); + + while (auto d = readdir(dir.m_stdio)) { + if (!std::strcmp(d->d_name, ".") || !std::strcmp(d->d_name, "..")) { + continue; + } + + if (d->d_type == DT_DIR) { + if (!(mode & FsDirOpenMode_ReadDirs)) { + continue; + } + (*dir_count)++; + } else if (d->d_type == DT_REG) { + if (!(mode & FsDirOpenMode_ReadFiles)) { + continue; + } + (*file_count)++; + } + } + } + + R_SUCCEED(); +} + +Dir::~Dir() { + Close(); +} + +Result Dir::GetEntryCount(s64* out) { + *out = 0; + + if (m_fs->IsNative()) { + R_TRY(fsDirGetEntryCount(&m_native, out)); + } else { + while (auto d = readdir(m_stdio)) { + if (!std::strcmp(d->d_name, ".") || !std::strcmp(d->d_name, "..")) { + continue; + } + (*out)++; + } + + // NOTE: this will *not* work for native mounted folders!!! + rewinddir(m_stdio); + } + + R_SUCCEED(); +} + +Result Dir::ReadAll(std::vector& buf) { buf.clear(); - if (d->m_fs->IsNative()) { - auto fs = (fs::FsNative*)d->m_fs; - + if (m_fs->IsNative()) { s64 count; - R_TRY(fs->DirGetEntryCount(&d->m_native, &count)); + R_TRY(GetEntryCount(&count)); buf.resize(count); - R_TRY(fs->DirRead(&d->m_native, &count, buf.size(), buf.data())); + R_TRY(fsDirRead(&m_native, &count, buf.size(), buf.data())); buf.resize(count); } else { buf.reserve(1000); - struct dirent* dirent; - while ((dirent = readdir(d->m_stdio))) { - if (!std::strcmp(dirent->d_name, ".") || !std::strcmp(dirent->d_name, "..")) { + while (auto d = readdir(m_stdio)) { + if (!std::strcmp(d->d_name, ".") || !std::strcmp(d->d_name, "..")) { continue; } FsDirectoryEntry entry{}; - if (dirent->d_type == DT_DIR) { - if (!(d->m_mode & FsDirOpenMode_ReadDirs)) { + if (d->d_type == DT_DIR) { + if (!(m_mode & FsDirOpenMode_ReadDirs)) { continue; } entry.type = FsDirEntryType_Dir; - } else if (dirent->d_type == DT_REG) { - if (!(d->m_mode & FsDirOpenMode_ReadFiles)) { + } else if (d->d_type == DT_REG) { + if (!(m_mode & FsDirOpenMode_ReadFiles)) { continue; } entry.type = FsDirEntryType_File; + } else { + log_write("[FS] WARNING: unknown type when reading dir: %u\n", d->d_type); + continue; } - std::strcpy(entry.name, dirent->d_name); + std::strcpy(entry.name, d->d_name); buf.emplace_back(entry); } } @@ -629,14 +730,18 @@ Result DirReadAll(Dir* d, std::vector& buf) { R_SUCCEED(); } -void DirClose(Dir* d) { - if (d->m_fs->IsNative()) { - fsDirClose(&d->m_native); +void Dir::Close() { + if (m_fs->IsNative()) { + if (serviceIsActive(&m_native.s)) { + fsDirClose(&m_native); + m_native = {}; + } } else { - closedir(d->m_stdio); + if (m_stdio) { + closedir(m_stdio); + m_stdio = {}; + } } - - *d = {}; } Result FileGetSizeAndTimestamp(fs::Fs* m_fs, const FsPath& path, FsTimeStampRaw* ts, s64* size) { @@ -649,9 +754,9 @@ Result FileGetSizeAndTimestamp(fs::Fs* m_fs, const FsPath& path, FsTimeStampRaw* File f; R_TRY(m_fs->OpenFile(path, FsOpenMode_Read, &f)); - ON_SCOPE_EXIT(fs->FileClose(&f)); + ON_SCOPE_EXIT(f.Close()); - R_TRY(m_fs->FileGetSize(&f, size)); + R_TRY(f.GetSize(size)); } else { struct stat st; R_UNLESS(!lstat(path, &st), 0x1); @@ -673,16 +778,15 @@ Result IsDirEmpty(fs::Fs* m_fs, const fs::FsPath& path, bool* out) { auto fs = (fs::FsNative*)m_fs; s64 count; - R_TRY(fs->DirGetEntryCount(path, FsDirOpenMode_ReadDirs | FsDirOpenMode_ReadFiles | FsDirOpenMode_NoFileSize, &count)); + R_TRY(fs->DirGetEntryCount(path, &count, FsDirOpenMode_ReadDirs | FsDirOpenMode_ReadFiles)); *out = !count; } else { auto dir = opendir(path); R_UNLESS(dir, 0x1); ON_SCOPE_EXIT(closedir(dir)); - struct dirent* dirent; - while ((dirent = readdir(dir))) { - if (!std::strcmp(dirent->d_name, ".") || !std::strcmp(dirent->d_name, "..")) { + while (auto d = readdir(dir)) { + if (!std::strcmp(d->d_name, ".") || !std::strcmp(d->d_name, "..")) { continue; } diff --git a/sphaira/source/hasher.cpp b/sphaira/source/hasher.cpp index 9ac1d66..8e2d015 100644 --- a/sphaira/source/hasher.cpp +++ b/sphaira/source/hasher.cpp @@ -13,16 +13,12 @@ struct FileSource final : BaseSource { m_open_result = m_fs->OpenFile(path, FsOpenMode_Read, std::addressof(m_file)); } - ~FileSource() { - m_fs->FileClose(std::addressof(m_file)); - } - Result Size(s64* out) { - return m_fs->FileGetSize(std::addressof(m_file), out); + return m_file.GetSize(out); } Result Read(void* buf, s64 off, s64 size, u64* bytes_read) { - return m_fs->FileRead(std::addressof(m_file), off, buf, size, 0, bytes_read); + return m_file.Read(off, buf, size, 0, bytes_read); } private: diff --git a/sphaira/source/nro.cpp b/sphaira/source/nro.cpp index 6abde12..263a784 100644 --- a/sphaira/source/nro.cpp +++ b/sphaira/source/nro.cpp @@ -27,34 +27,35 @@ struct NroData { NroHeader header; }; -auto nro_parse_internal(fs::FsNative& fs, const fs::FsPath& path, NroEntry& entry) -> Result { +auto nro_parse_internal(fs::Fs* fs, const fs::FsPath& path, NroEntry& entry) -> Result { entry.path = path; // todo: special sorting for fw 2.0.0 to make it not look like shit if (hosversionAtLeast(3,0,0)) { // it doesn't matter if we fail entry.timestamp.is_valid = false; - fs.GetFileTimeStampRaw(entry.path, &entry.timestamp); + fs->GetFileTimeStampRaw(entry.path, &entry.timestamp); // if (R_FAILED(fsFsGetFileTimeStampRaw(fs, entry.path, &entry.timestamp))) { // // log_write("failed to get timestamp for: %s\n", path); // } } - FsFile f; - R_TRY(fs.OpenFile(entry.path, FsOpenMode_Read, &f)); - ON_SCOPE_EXIT(fsFileClose(&f)); - - R_TRY(fsFileGetSize(&f, &entry.size)); + fs::File f; + R_TRY(fs->OpenFile(entry.path, FsOpenMode_Read, &f)); + // todo: buffer reads to 16k to avoid 2 fs read calls per entry. NroData data; u64 bytes_read; - R_TRY(fsFileRead(&f, 0, &data, sizeof(data), FsReadOption_None, &bytes_read)); + R_TRY(f.Read(0, &data, sizeof(data), FsReadOption_None, &bytes_read)); R_UNLESS(data.header.magic == NROHEADER_MAGIC, NroError_BadMagic); NroAssetHeader asset; - R_TRY(fsFileRead(&f, data.header.size, &asset, sizeof(asset), FsReadOption_None, &bytes_read)); + R_TRY(f.Read(data.header.size, &asset, sizeof(asset), FsReadOption_None, &bytes_read)); // R_UNLESS(asset.magic == NROASSETHEADER_MAGIC, NroError_BadMagic); + // we can avoid a GetSize() call by calculating the size manually. + entry.size = data.header.size; + // some .nro (vgedit) have bad nacp, fake the nacp auto& nacp = entry.nacp; if (asset.magic != NROASSETHEADER_MAGIC || asset.nacp.offset == 0 || asset.nacp.size != sizeof(NacpStruct)) { @@ -69,8 +70,9 @@ auto nro_parse_internal(fs::FsNative& fs, const fs::FsPath& path, NroEntry& entr std::strcpy(nacp.display_version, "Unknown"); entry.is_nacp_valid = false; } else { - R_TRY(fsFileRead(&f, data.header.size + asset.nacp.offset, &nacp.lang, sizeof(nacp.lang), FsReadOption_None, &bytes_read)); - R_TRY(fsFileRead(&f, data.header.size + asset.nacp.offset + offsetof(NacpStruct, display_version), nacp.display_version, sizeof(nacp.display_version), FsReadOption_None, &bytes_read)); + entry.size += sizeof(asset) + asset.icon.size + asset.nacp.size + asset.romfs.size; + R_TRY(f.Read(data.header.size + asset.nacp.offset, &nacp.lang, sizeof(nacp.lang), FsReadOption_None, &bytes_read)); + R_TRY(f.Read(data.header.size + asset.nacp.offset + offsetof(NacpStruct, display_version), nacp.display_version, sizeof(nacp.display_version), FsReadOption_None, &bytes_read)); entry.is_nacp_valid = true; } @@ -84,32 +86,19 @@ auto nro_parse_internal(fs::FsNative& fs, const fs::FsPath& path, NroEntry& entr // this function is recursive by 1 level deep // if the nro is in switch/folder/folder2/app.nro it will NOT be found // switch/folder/app.nro for example will work fine. -auto nro_scan_internal(const fs::FsPath& path, std::vector& nros, bool hide_sphaira, bool nested, bool scan_all_dir, bool root) -> Result { - fs::FsNativeSd fs; - R_TRY(fs.GetFsOpenResult()); - +auto nro_scan_internal(fs::Fs* fs, const fs::FsPath& path, std::vector& nros, bool hide_sphaira, bool nested, bool scan_all_dir, bool root) -> Result { // we don't need to scan for folders if we are not root u32 dir_open_type = FsDirOpenMode_ReadFiles | FsDirOpenMode_NoFileSize; if (root) { dir_open_type |= FsDirOpenMode_ReadDirs; } - FsDir d; - R_TRY(fs.OpenDirectory(path, dir_open_type, &d)); - ON_SCOPE_EXIT(fs.DirClose(&d)); - - s64 count; - R_TRY(fs.DirGetEntryCount(&d, &count)); - // return early if empty - R_UNLESS(count > 0, 0x0); + fs::Dir d; + R_TRY(fs->OpenDirectory(path, dir_open_type, &d)); // we won't run out of memory here - std::vector entries(count); - - R_TRY(fs.DirRead(&d, &count, entries.size(), entries.data())); - - // size may of changed - entries.resize(count); + std::vector entries; + R_TRY(d.ReadAll(entries)); for (const auto& e : entries) { // skip hidden files / folders @@ -135,7 +124,7 @@ auto nro_scan_internal(const fs::FsPath& path, std::vector& nros, bool } else { // slow path... std::snprintf(fullpath, sizeof(fullpath), "%s/%s", path.s, e.name); - nro_scan_internal(fullpath, nros, hide_sphaira, nested, scan_all_dir, false); + nro_scan_internal(fs, fullpath, nros, hide_sphaira, nested, scan_all_dir, false); } } else if (e.type == FsDirEntryType_File && std::string_view{e.name}.ends_with(".nro")) { fs::FsPath fullpath; @@ -157,7 +146,12 @@ auto nro_scan_internal(const fs::FsPath& path, std::vector& nros, bool R_SUCCEED(); } -auto nro_get_icon_internal(FsFile* f, u64 size, u64 offset) -> std::vector { +auto nro_scan_internal(const fs::FsPath& path, std::vector& nros, bool hide_sphaira, bool nested, bool scan_all_dir, bool root) -> Result { + fs::FsNativeSd fs; + return nro_scan_internal(&fs, path, nros, hide_sphaira, nested, scan_all_dir, root); +} + +auto nro_get_icon_internal(fs::File* f, u64 size, u64 offset) -> std::vector { // protect again really messed up sizes. if (size > 1024 * 1024) { return {}; @@ -167,7 +161,7 @@ auto nro_get_icon_internal(FsFile* f, u64 size, u64 offset) -> std::vector { u64 bytes_read{}; icon.resize(size); - R_TRY_RESULT(fsFileRead(f, offset, icon.data(), icon.size(), FsReadOption_None, &bytes_read), {}); + R_TRY_RESULT(f->Read(offset, icon.data(), icon.size(), FsReadOption_None, &bytes_read), {}); R_UNLESS(bytes_read == icon.size(), {}); return icon; @@ -208,9 +202,7 @@ auto nro_verify(std::span data) -> Result { auto nro_parse(const fs::FsPath& path, NroEntry& entry) -> Result { fs::FsNativeSd fs; - R_TRY(fs.GetFsOpenResult()); - - return nro_parse_internal(fs, path, entry); + return nro_parse_internal(&fs, path, entry); } auto nro_scan(const fs::FsPath& path, std::vector& nros, bool hide_sphaira, bool nested, bool scan_all_dir) -> Result { @@ -219,31 +211,23 @@ auto nro_scan(const fs::FsPath& path, std::vector& nros, bool hide_sph auto nro_get_icon(const fs::FsPath& path, u64 size, u64 offset) -> std::vector { fs::FsNativeSd fs; - FsFile f; - - R_TRY_RESULT(fs.GetFsOpenResult(), {}); - + fs::File f; R_TRY_RESULT(fs.OpenFile(path, FsOpenMode_Read, &f), {}); - ON_SCOPE_EXIT(fsFileClose(&f)); - return nro_get_icon_internal(&f, size, offset); } auto nro_get_icon(const fs::FsPath& path) -> std::vector { fs::FsNativeSd fs; - FsFile f; NroData data; NroAssetHeader asset; u64 bytes_read; - R_TRY_RESULT(fs.GetFsOpenResult(), {}); - + fs::File f; R_TRY_RESULT(fs.OpenFile(path, FsOpenMode_Read, &f), {}); - ON_SCOPE_EXIT(fsFileClose(&f)); - R_TRY_RESULT(fsFileRead(&f, 0, &data, sizeof(data), FsReadOption_None, &bytes_read), {}); + R_TRY_RESULT(f.Read(0, &data, sizeof(data), FsReadOption_None, &bytes_read), {}); R_UNLESS(data.header.magic == NROHEADER_MAGIC, {}); - R_TRY_RESULT(fsFileRead(&f, data.header.size, &asset, sizeof(asset), FsReadOption_None, &bytes_read), {}); + R_TRY_RESULT(f.Read(data.header.size, &asset, sizeof(asset), FsReadOption_None, &bytes_read), {}); R_UNLESS(asset.magic == NROASSETHEADER_MAGIC, {}); return nro_get_icon_internal(&f, asset.icon.size, data.header.size + asset.icon.offset); @@ -251,21 +235,18 @@ auto nro_get_icon(const fs::FsPath& path) -> std::vector { auto nro_get_nacp(const fs::FsPath& path, NacpStruct& nacp) -> Result { fs::FsNativeSd fs; - FsFile f; NroData data; NroAssetHeader asset; u64 bytes_read; - R_TRY_RESULT(fs.GetFsOpenResult(), {}); - + fs::File f; R_TRY(fs.OpenFile(path, FsOpenMode_Read, &f)); - ON_SCOPE_EXIT(fsFileClose(&f)); - R_TRY(fsFileRead(&f, 0, &data, sizeof(data), FsReadOption_None, &bytes_read)); + R_TRY(f.Read(0, &data, sizeof(data), FsReadOption_None, &bytes_read)); R_UNLESS(data.header.magic == NROHEADER_MAGIC, NroError_BadMagic); - R_TRY(fsFileRead(&f, data.header.size, &asset, sizeof(asset), FsReadOption_None, &bytes_read)); + R_TRY(f.Read(data.header.size, &asset, sizeof(asset), FsReadOption_None, &bytes_read)); R_UNLESS(asset.magic == NROASSETHEADER_MAGIC, NroError_BadMagic); - R_TRY(fsFileRead(&f, data.header.size + asset.nacp.offset, &nacp, sizeof(nacp), FsReadOption_None, &bytes_read)); + R_TRY(f.Read(data.header.size + asset.nacp.offset, &nacp, sizeof(nacp), FsReadOption_None, &bytes_read)); R_SUCCEED(); } diff --git a/sphaira/source/nxlink.cpp b/sphaira/source/nxlink.cpp index c692d17..cff63ef 100644 --- a/sphaira/source/nxlink.cpp +++ b/sphaira/source/nxlink.cpp @@ -357,15 +357,14 @@ void loop(void* args) { ON_SCOPE_EXIT(fs.DeleteFile(temp_path)); { - FsFile f; + fs::File f; if (R_FAILED(rc = fs.OpenFile(temp_path, FsOpenMode_Write, &f))) { sendall(connfd, &ERR_FILE, sizeof(ERR_FILE)); log_write("failed to open file %X\n", rc); continue; } - ON_SCOPE_EXIT(fsFileClose(&f)); - if (R_FAILED(rc = fsFileSetSize(&f, file_data.size()))) { + if (R_FAILED(rc = f.SetSize(file_data.size()))) { sendall(connfd, &ERR_FILE, sizeof(ERR_FILE)); log_write("failed to set file size: 0x%X\n", socketGetLastResult()); continue; @@ -379,7 +378,7 @@ void loop(void* args) { if (offset + chunk_size > file_data.size()) { chunk_size = file_data.size() - offset; } - if (R_FAILED(rc = fsFileWrite(&f, offset, file_data.data() + offset, chunk_size, FsWriteOption_None))) { + if (R_FAILED(rc = f.Write(offset, file_data.data() + offset, chunk_size, FsWriteOption_None))) { break; } offset += chunk_size; diff --git a/sphaira/source/ui/menus/appstore.cpp b/sphaira/source/ui/menus/appstore.cpp index 70a8e6d..ca018a7 100644 --- a/sphaira/source/ui/menus/appstore.cpp +++ b/sphaira/source/ui/menus/appstore.cpp @@ -448,11 +448,9 @@ auto InstallApp(ProgressBox* pbox, const Entry& entry) -> Result { R_THROW(rc); } - FsFile f; + fs::File f; R_TRY(fs.OpenFile(output, FsOpenMode_Write, &f)); - ON_SCOPE_EXIT(fsFileClose(&f)); - - R_TRY(fsFileSetSize(&f, info.uncompressed_size)); + R_TRY(f.SetSize(info.uncompressed_size)); u64 offset{}; while (offset < info.uncompressed_size) { @@ -464,7 +462,7 @@ auto InstallApp(ProgressBox* pbox, const Entry& entry) -> Result { R_THROW(0x1); } - R_TRY(fsFileWrite(&f, offset, buf.data(), bytes_read, FsWriteOption_None)); + R_TRY(f.Write(offset, buf.data(), bytes_read, FsWriteOption_None)); pbox->UpdateTransfer(offset, info.uncompressed_size); offset += bytes_read; diff --git a/sphaira/source/ui/menus/file_viewer.cpp b/sphaira/source/ui/menus/file_viewer.cpp index 6885f6b..d0b3eb9 100644 --- a/sphaira/source/ui/menus/file_viewer.cpp +++ b/sphaira/source/ui/menus/file_viewer.cpp @@ -13,21 +13,17 @@ Menu::Menu(const fs::FsPath& path) : MenuBase{path}, m_path{path} { std::string buf; if (R_SUCCEEDED(m_fs.OpenFile(m_path, FsOpenMode_Read, &m_file))) { - fsFileGetSize(&m_file, &m_file_size); + m_file.GetSize(&m_file_size); buf.resize(m_file_size + 1); u64 read_bytes; - fsFileRead(&m_file, m_file_offset, buf.data(), buf.size(), 0, &read_bytes); + m_file.Read(m_file_offset, buf.data(), buf.size(), 0, &read_bytes); buf[m_file_size] = '\0'; } m_scroll_text = std::make_unique(buf, 0, 120, 500, 1150-110, 18); } -Menu::~Menu() { - fsFileClose(&m_file); -} - void Menu::Update(Controller* controller, TouchInfo* touch) { MenuBase::Update(controller, touch); diff --git a/sphaira/source/ui/menus/filebrowser.cpp b/sphaira/source/ui/menus/filebrowser.cpp index 5b3cbed..efdef2c 100644 --- a/sphaira/source/ui/menus/filebrowser.cpp +++ b/sphaira/source/ui/menus/filebrowser.cpp @@ -675,7 +675,7 @@ FsView::FsView(Menu* menu, const fs::FsPath& path, const FsEntry& entry, ViewSid })); } - if (IsSd() && m_entries_current.size() && !m_selected_count && GetEntry().IsFile()) { + if (m_entries_current.size() && !m_selected_count && GetEntry().IsFile()) { options->Add(std::make_shared("Hash"_i18n, [this](){ auto options = std::make_shared("Hash Options"_i18n, Sidebar::Side::RIGHT); ON_SCOPE_EXIT(App::Push(options)); @@ -751,10 +751,10 @@ void FsView::Draw(NVGcontext* vg, Theme* theme) { auto& e = GetEntry(i); if (e.IsDir()) { - if (m_fs->IsNative() && e.file_count == -1 && e.dir_count == -1) { - const auto full_path = GetNewPath(e); - GetNative()->DirGetEntryCount(full_path, FsDirOpenMode_ReadFiles | FsDirOpenMode_NoFileSize, &e.file_count); - GetNative()->DirGetEntryCount(full_path, FsDirOpenMode_ReadDirs | FsDirOpenMode_NoFileSize, &e.dir_count); + // NOTE: make this native only if hdd dir scan is too slow. + // if (m_fs->IsNative() && e.file_count == -1 && e.dir_count == -1) { + if (e.file_count == -1 && e.dir_count == -1) { + m_fs->DirGetEntryCount(GetNewPath(e), &e.file_count, &e.dir_count); } } else if (!e.checked_extension) { e.checked_extension = true; @@ -803,7 +803,8 @@ void FsView::Draw(NVGcontext* vg, Theme* theme) { m_scroll_name.Draw(vg, selected, x + text_xoffset+65, y + (h / 2.f), w-(75+text_xoffset+65+50), 20, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE, theme->GetColour(text_id), e.name); - if (m_fs->IsNative() && e.IsDir()) { + // NOTE: make this native only if i disable dir scan from above. + if (e.IsDir()) { gfx::drawTextArgs(vg, x + w - text_xoffset, y + (h / 2.f) - 3, 16.f, NVG_ALIGN_RIGHT | NVG_ALIGN_BOTTOM, theme->GetColour(text_id), "%zd files"_i18n.c_str(), e.file_count); gfx::drawTextArgs(vg, x + w - text_xoffset, y + (h / 2.f) + 3, 16.f, NVG_ALIGN_RIGHT | NVG_ALIGN_TOP, theme->GetColour(text_id), "%zd dirs"_i18n.c_str(), e.dir_count); } else if (e.IsFile()) { @@ -881,23 +882,21 @@ void FsView::SetIndex(s64 index) { m_list->SetYoff(); } - if (!m_entries_current.empty() && !GetEntry().checked_internal_extension && GetEntry().extension == "zip") { + if (IsSd() && !m_entries_current.empty() && !GetEntry().checked_internal_extension && GetEntry().extension == "zip") { GetEntry().checked_internal_extension = true; if (auto zfile = unzOpen64(GetNewPathCurrent())) { ON_SCOPE_EXIT(unzClose(zfile)); - unz_global_info gi{}; + // only check first entry (i think RA does the same) - if (UNZ_OK == unzGetGlobalInfo(zfile, &gi) && gi.number_entry >= 1) { - fs::FsPath filename_inzip{}; - unz_file_info64 file_info{}; - if (UNZ_OK == unzOpenCurrentFile(zfile)) { - ON_SCOPE_EXIT(unzCloseCurrentFile(zfile)); - if (UNZ_OK == unzGetCurrentFileInfo64(zfile, &file_info, filename_inzip, sizeof(filename_inzip), NULL, 0, NULL, 0)) { - if (auto ext = std::strrchr(filename_inzip, '.')) { - GetEntry().internal_name = filename_inzip.toString(); - GetEntry().internal_extension = ext+1; - } + fs::FsPath filename_inzip{}; + unz_file_info64 file_info{}; + if (UNZ_OK == unzOpenCurrentFile(zfile)) { + ON_SCOPE_EXIT(unzCloseCurrentFile(zfile)); + if (UNZ_OK == unzGetCurrentFileInfo64(zfile, &file_info, filename_inzip, sizeof(filename_inzip), NULL, 0, NULL, 0)) { + if (auto ext = std::strrchr(filename_inzip, '.')) { + GetEntry().internal_name = filename_inzip.toString(); + GetEntry().internal_extension = ext+1; } } } @@ -980,11 +979,7 @@ void FsView::InstallFiles() { App::Push(std::make_shared(0, "Installing "_i18n, "", [this, targets](auto pbox) -> Result { for (auto& e : targets) { - if (m_fs->IsNative()) { - R_TRY(yati::InstallFromFile(pbox, &GetNative()->m_fs, GetNewPath(e))); - } else { - R_TRY(yati::InstallFromFile(pbox, GetNewPath(e))); - } + R_TRY(yati::InstallFromFile(pbox, m_fs.get(), GetNewPath(e))); App::Notify("Installed "_i18n + e.GetName()); } @@ -1053,9 +1048,7 @@ void FsView::UnzipFiles(fs::FsPath dir_path) { fs::File f; R_TRY(m_fs->OpenFile(file_path, FsOpenMode_Write, &f)); - ON_SCOPE_EXIT(m_fs->FileClose(&f)); - - R_TRY(m_fs->FileSetSize(&f, info.uncompressed_size)); + R_TRY(f.SetSize(info.uncompressed_size)); std::vector buf(chunk_size); s64 offset{}; @@ -1068,7 +1061,7 @@ void FsView::UnzipFiles(fs::FsPath dir_path) { R_THROW(0x1); } - R_TRY(m_fs->FileWrite(&f, offset, buf.data(), bytes_read, FsWriteOption_None)); + R_TRY(f.Write(offset, buf.data(), bytes_read, FsWriteOption_None)); pbox->UpdateTransfer(offset, info.uncompressed_size); offset += bytes_read; @@ -1165,10 +1158,9 @@ void FsView::ZipFiles(fs::FsPath zip_out) { fs::File f; R_TRY(m_fs->OpenFile(file_path, FsOpenMode_Read, &f)); - ON_SCOPE_EXIT(m_fs->FileClose(&f)); s64 file_size; - R_TRY(m_fs->FileGetSize(&f, &file_size)); + R_TRY(f.GetSize(&file_size)); std::vector buf(chunk_size); s64 offset{}; @@ -1176,7 +1168,7 @@ void FsView::ZipFiles(fs::FsPath zip_out) { R_TRY(pbox->ShouldExitResult()); u64 bytes_read; - R_TRY(m_fs->FileRead(&f, offset, buf.data(), buf.size(), FsReadOption_None, &bytes_read)); + R_TRY(f.Read(offset, buf.data(), buf.size(), FsReadOption_None, &bytes_read)); if (ZIP_OK != zipWriteInFileInZip(zfile, buf.data(), bytes_read)) { log_write("failed to write zip file: %s\n", file_path.s); @@ -1253,11 +1245,10 @@ void FsView::UploadFiles() { fs::File f; R_TRY(m_fs->OpenFile(file_path, FsOpenMode_Read, &f)); - ON_SCOPE_EXIT(m_fs->FileClose(&f)); return thread::TransferPull(pbox, file_size, [&](void* data, s64 off, s64 size, u64* bytes_read) -> Result { - return m_fs->FileRead(&f, off, data, size, FsReadOption_None, bytes_read); + return f.Read(off, data, size, FsReadOption_None, bytes_read); }, [&](thread::PullCallback pull) -> Result { s64 offset{}; @@ -1340,21 +1331,14 @@ auto FsView::Scan(const fs::FsPath& new_path, bool is_walk_up) -> Result { m_index = 0; m_list->SetYoff(0); m_menu->SetTitleSubHeading(m_path); - - // todo: verify this works as expected. m_selected_count = 0; - // if (m_selected_type == SelectedType::None) { - // ResetSelection(); - // } fs::Dir d; R_TRY(m_fs->OpenDirectory(new_path, FsDirOpenMode_ReadDirs | FsDirOpenMode_ReadFiles, &d)); - ON_SCOPE_EXIT(m_fs->DirClose(&d)); // we won't run out of memory here (tm) std::vector dir_entries; - - R_TRY(m_fs->DirReadAll(&d, dir_entries)); + R_TRY(d.ReadAll(dir_entries)); const auto count = dir_entries.size(); m_entries.reserve(count); @@ -1585,6 +1569,23 @@ void FsView::OnPasteCallback() { } else { FsDirCollections collections; + const auto on_paste_file = [&](auto& src_path, auto& dst_path) -> Result { + if (selected.m_type == SelectedType::Cut) { + // update timestamp if possible. + if (!m_fs->IsNative()) { + FsTimeStampRaw ts; + if (R_SUCCEEDED(src_fs->GetFileTimeStampRaw(src_path, &ts))) { + m_fs->SetTimestamp(dst_path, &ts); + } + } + + // delete src file. folders are removed after. + R_TRY(src_fs->DeleteFile(src_path)); + } + + R_SUCCEED(); + }; + // build list of dirs / files for (const auto&p : selected.m_files) { pbox->Yield(); @@ -1612,11 +1613,7 @@ void FsView::OnPasteCallback() { pbox->SetTitle(p.name); pbox->NewTransfer("Copying "_i18n + src_path); R_TRY(pbox->CopyFile(src_fs, m_fs.get(), src_path, dst_path)); - - // delete src file. folders are removed after. - if (selected.m_type == SelectedType::Cut) { - R_TRY(src_fs->DeleteFile(src_path)); - } + R_TRY(on_paste_file(src_path, dst_path)); } } @@ -1646,11 +1643,7 @@ void FsView::OnPasteCallback() { pbox->SetTitle(p.name); pbox->NewTransfer("Copying "_i18n + src_path); R_TRY(pbox->CopyFile(src_fs, m_fs.get(), src_path, dst_path)); - - // delete src file. folders are removed after. - if (selected.m_type == SelectedType::Cut) { - R_TRY(src_fs->DeleteFile(src_path)); - } + R_TRY(on_paste_file(src_path, dst_path)); } } @@ -1704,17 +1697,15 @@ auto FsView::CheckIfUpdateFolder() -> Result { log_write("found daybreak in: %s\n", m_daybreak_path.value().s); } - s64 count; - R_TRY(GetNative()->DirGetEntryCount(m_path, FsDirOpenMode_ReadDirs, &count)); - - // check that we are at the bottom level - R_UNLESS(count == 0, 0x1); // check that we have enough ncas and not too many R_UNLESS(m_entries.size() > 150 && m_entries.size() < 300, 0x1); // check that all entries end in .nca const auto nca_ext = std::string_view{".nca"}; for (auto& e : m_entries) { + // check that we are at the bottom level + R_UNLESS(e.type == FsDirEntryType_File, 0x1); + const auto ext = std::strrchr(e.name, '.'); R_UNLESS(ext && ext == nca_ext, 0x1); } @@ -1729,8 +1720,7 @@ auto FsView::get_collection(fs::Fs* fs, const fs::FsPath& path, const fs::FsPath const auto fetch = [fs, &path](std::vector& out, u32 flags) -> Result { fs::Dir d; R_TRY(fs->OpenDirectory(path, flags, &d)); - ON_SCOPE_EXIT(fs->DirClose(&d)); - return fs->DirReadAll(&d, out); + return d.ReadAll(out); }; if (inc_file) { @@ -1870,7 +1860,9 @@ void FsView::DisplayHash(hash::Type type) { hash_out.clear(); App::Push(std::make_shared(0, "Hashing"_i18n, GetEntry().name, [this, type](auto pbox) -> Result { - R_TRY(hash::Hash(pbox, type, m_fs.get(), GetNewPathCurrent(), hash_out)); + const auto full_path = GetNewPathCurrent(); + pbox->NewTransfer(full_path); + R_TRY(hash::Hash(pbox, type, m_fs.get(), full_path, hash_out)); R_SUCCEED(); }, [this, type](Result rc){ diff --git a/sphaira/source/ui/menus/gc_menu.cpp b/sphaira/source/ui/menus/gc_menu.cpp index 6bb4609..3fb6136 100644 --- a/sphaira/source/ui/menus/gc_menu.cpp +++ b/sphaira/source/ui/menus/gc_menu.cpp @@ -278,13 +278,12 @@ Result fsOpenGameCardDetectionEventNotifier(FsEventNotifier* out) { struct GcSource final : yati::source::Base { GcSource(const ApplicationEntry& entry, fs::FsNativeGameCard* fs); - ~GcSource(); Result Read(void* buf, s64 off, s64 size, u64* bytes_read); yati::container::Collections m_collections{}; yati::ConfigOverride m_config{}; fs::FsNativeGameCard* m_fs{}; - FsFile m_file{}; + fs::File m_file{}; s64 m_offset{}; s64 m_size{}; @@ -342,15 +341,10 @@ GcSource::GcSource(const ApplicationEntry& entry, fs::FsNativeGameCard* fs) m_config.skip_rsa_npdm_fixed_key_verify = true; } -GcSource::~GcSource() { - fsFileClose(&m_file); -} - Result GcSource::Read(void* buf, s64 off, s64 size, u64* bytes_read) { // check is we need to open a new file. if (!InRange(off, m_offset, m_size)) { - fsFileClose(&m_file); - m_file = {}; + m_file.Close(); // find new file based on the offset. bool found = false; @@ -368,7 +362,7 @@ Result GcSource::Read(void* buf, s64 off, s64 size, u64* bytes_read) { R_UNLESS(found, 0x1); } - return fsFileRead(&m_file, off - m_offset, buf, size, 0, bytes_read); + return m_file.Read(off - m_offset, buf, size, 0, bytes_read); } } // namespace @@ -526,17 +520,11 @@ Result Menu::GcMount() { R_TRY(m_fs->GetFsOpenResult()); - FsDir dir; + fs::Dir dir; R_TRY(m_fs->OpenDirectory("/", FsDirOpenMode_ReadFiles, std::addressof(dir))); - ON_SCOPE_EXIT(fsDirClose(std::addressof(dir))); - s64 count; - R_TRY(m_fs->DirGetEntryCount(std::addressof(dir), std::addressof(count))); - - std::vector buf(count); - s64 total_entries; - R_TRY(m_fs->DirRead(std::addressof(dir), std::addressof(total_entries), buf.size(), buf.data())); - R_UNLESS(buf.size() == total_entries, 0x1); + std::vector buf; + R_TRY(dir.ReadAll(buf)); yati::container::Collections ticket_collections; for (const auto& e : buf) { diff --git a/sphaira/source/ui/menus/ghdl.cpp b/sphaira/source/ui/menus/ghdl.cpp index 134738e..aa78a54 100644 --- a/sphaira/source/ui/menus/ghdl.cpp +++ b/sphaira/source/ui/menus/ghdl.cpp @@ -162,11 +162,9 @@ auto DownloadApp(ProgressBox* pbox, const GhApiAsset& gh_asset, const AssetEntry R_THROW(rc); } - FsFile f; + fs::File f; R_TRY(fs.OpenFile(file_path, FsOpenMode_Write, &f)); - ON_SCOPE_EXIT(fsFileClose(&f)); - - R_TRY(fsFileSetSize(&f, info.uncompressed_size)); + R_TRY(f.SetSize(info.uncompressed_size)); std::vector buf(chunk_size); s64 offset{}; @@ -179,7 +177,7 @@ auto DownloadApp(ProgressBox* pbox, const GhApiAsset& gh_asset, const AssetEntry R_THROW(0x1); } - R_TRY(fsFileWrite(&f, offset, buf.data(), bytes_read, FsWriteOption_None)); + R_TRY(f.Write(offset, buf.data(), bytes_read, FsWriteOption_None)); pbox->UpdateTransfer(offset, info.uncompressed_size); offset += bytes_read; diff --git a/sphaira/source/ui/menus/main_menu.cpp b/sphaira/source/ui/menus/main_menu.cpp index 826e1c0..7532fa9 100644 --- a/sphaira/source/ui/menus/main_menu.cpp +++ b/sphaira/source/ui/menus/main_menu.cpp @@ -123,11 +123,9 @@ auto InstallUpdate(ProgressBox* pbox, const std::string url, const std::string v R_THROW(rc); } - FsFile f; + fs::File f; R_TRY(fs.OpenFile(file_path, FsOpenMode_Write, &f)); - ON_SCOPE_EXIT(fsFileClose(&f)); - - R_TRY(fsFileSetSize(&f, info.uncompressed_size)); + R_TRY(f.SetSize(info.uncompressed_size)); std::vector buf(chunk_size); s64 offset{}; @@ -138,7 +136,7 @@ auto InstallUpdate(ProgressBox* pbox, const std::string url, const std::string v R_THROW(0x1); } - R_TRY(fsFileWrite(&f, offset, buf.data(), bytes_read, FsWriteOption_None)); + R_TRY(f.Write(offset, buf.data(), bytes_read, FsWriteOption_None)); pbox->UpdateTransfer(offset, info.uncompressed_size); offset += bytes_read; diff --git a/sphaira/source/ui/menus/themezer.cpp b/sphaira/source/ui/menus/themezer.cpp index 20f4e59..12f7d33 100644 --- a/sphaira/source/ui/menus/themezer.cpp +++ b/sphaira/source/ui/menus/themezer.cpp @@ -311,11 +311,9 @@ auto InstallTheme(ProgressBox* pbox, const PackListEntry& entry) -> Result { R_THROW(rc); } - FsFile f; + fs::File f; R_TRY(fs.OpenFile(file_path, FsOpenMode_Write, &f)); - ON_SCOPE_EXIT(fsFileClose(&f)); - - R_TRY(fsFileSetSize(&f, info.uncompressed_size)); + R_TRY(f.SetSize(info.uncompressed_size)); std::vector buf(chunk_size); s64 offset{}; @@ -328,7 +326,7 @@ auto InstallTheme(ProgressBox* pbox, const PackListEntry& entry) -> Result { R_THROW(0x1); } - R_TRY(fsFileWrite(&f, offset, buf.data(), bytes_read, FsWriteOption_None)); + R_TRY(f.Write(offset, buf.data(), bytes_read, FsWriteOption_None)); pbox->UpdateTransfer(offset, info.uncompressed_size); offset += bytes_read; diff --git a/sphaira/source/ui/progress_box.cpp b/sphaira/source/ui/progress_box.cpp index 71ff1eb..c7cbe53 100644 --- a/sphaira/source/ui/progress_box.cpp +++ b/sphaira/source/ui/progress_box.cpp @@ -256,10 +256,9 @@ auto ProgressBox::ShouldExitResult() -> Result { auto ProgressBox::CopyFile(fs::Fs* fs_src, fs::Fs* fs_dst, const fs::FsPath& src_path, const fs::FsPath& dst_path) -> Result { fs::File src_file; R_TRY(fs_src->OpenFile(src_path, FsOpenMode_Read, &src_file)); - ON_SCOPE_EXIT(fs_src->FileClose(&src_file)); s64 src_size; - R_TRY(fs_src->FileGetSize(&src_file, &src_size)); + R_TRY(src_file.GetSize(&src_size)); // this can fail if it already exists so we ignore the result. // if the file actually failed to be created, the result is implicitly @@ -268,9 +267,8 @@ auto ProgressBox::CopyFile(fs::Fs* fs_src, fs::Fs* fs_dst, const fs::FsPath& src fs::File dst_file; R_TRY(fs_dst->OpenFile(dst_path, FsOpenMode_Write, &dst_file)); - ON_SCOPE_EXIT(fs_dst->FileClose(&dst_file)); - R_TRY(fs_dst->FileSetSize(&dst_file, src_size)); + R_TRY(dst_file.SetSize(src_size)); s64 offset{}; std::vector buf(1024*1024*4); // 4MiB @@ -279,10 +277,10 @@ auto ProgressBox::CopyFile(fs::Fs* fs_src, fs::Fs* fs_dst, const fs::FsPath& src R_TRY(ShouldExitResult()); u64 bytes_read; - R_TRY(fs_src->FileRead(&src_file, offset, buf.data(), buf.size(), 0, &bytes_read)); + R_TRY(src_file.Read(offset, buf.data(), buf.size(), 0, &bytes_read)); Yield(); - R_TRY(fs_dst->FileWrite(&dst_file, offset, buf.data(), bytes_read, FsWriteOption_None)); + R_TRY(dst_file.Write(offset, buf.data(), bytes_read, FsWriteOption_None)); Yield(); UpdateTransfer(offset, src_size); diff --git a/sphaira/source/yati/source/file.cpp b/sphaira/source/yati/source/file.cpp index 2133d01..a5e5e29 100644 --- a/sphaira/source/yati/source/file.cpp +++ b/sphaira/source/yati/source/file.cpp @@ -2,29 +2,13 @@ namespace sphaira::yati::source { -File::File(FsFileSystem* fs, const fs::FsPath& path) { - if (fs) { - m_fs = std::make_unique(fs, false); - } else { - m_fs = std::make_unique(); - } - +File::File(fs::Fs* fs, const fs::FsPath& path) : m_fs{fs} { m_open_result = m_fs->OpenFile(path, FsOpenMode_Read, std::addressof(m_file)); } -File::File(const fs::FsPath& path) : File{nullptr, path} { - -} - -File::~File() { - if (R_SUCCEEDED(GetOpenResult())) { - m_fs->FileClose(std::addressof(m_file)); - } -} - Result File::Read(void* buf, s64 off, s64 size, u64* bytes_read) { R_TRY(GetOpenResult()); - return m_fs->FileRead(std::addressof(m_file), off, buf, size, 0, bytes_read); + return m_file.Read(off, buf, size, 0, bytes_read); } } // namespace sphaira::yati::source diff --git a/sphaira/source/yati/source/stream_file.cpp b/sphaira/source/yati/source/stream_file.cpp index 68066f0..3b114d2 100644 --- a/sphaira/source/yati/source/stream_file.cpp +++ b/sphaira/source/yati/source/stream_file.cpp @@ -3,29 +3,13 @@ namespace sphaira::yati::source { -StreamFile::StreamFile(FsFileSystem* fs, const fs::FsPath& path) { - if (fs) { - m_fs = std::make_unique(fs, false); - } else { - m_fs = std::make_unique(); - } - +StreamFile::StreamFile(fs::Fs* fs, const fs::FsPath& path) : m_fs{fs} { m_open_result = m_fs->OpenFile(path, FsOpenMode_Read, std::addressof(m_file)); } -StreamFile::StreamFile(const fs::FsPath& path) : StreamFile{nullptr, path} { - -} - -StreamFile::~StreamFile() { - if (R_SUCCEEDED(GetOpenResult())) { - m_fs->FileClose(std::addressof(m_file)); - } -} - Result StreamFile::ReadChunk(void* buf, s64 size, u64* bytes_read) { R_TRY(GetOpenResult()); - const auto rc = m_fs->FileRead(std::addressof(m_file), m_offset, buf, size, 0, bytes_read); + const auto rc = m_file.Read(m_offset, buf, size, 0, bytes_read); m_offset += *bytes_read; return rc; } diff --git a/sphaira/source/yati/yati.cpp b/sphaira/source/yati/yati.cpp index 02d0175..0076b36 100644 --- a/sphaira/source/yati/yati.cpp +++ b/sphaira/source/yati/yati.cpp @@ -1378,15 +1378,11 @@ Result InstallInternalStream(ui::ProgressBox* pbox, std::shared_ptr(fs, path), path, override); // return InstallFromSource(pbox, std::make_shared(fs, path), path, override); } -Result InstallFromFile(ui::ProgressBox* pbox, const fs::FsPath& path, const ConfigOverride& override) { - return InstallFromFile(pbox, nullptr, path, override); -} - Result InstallFromSource(ui::ProgressBox* pbox, std::shared_ptr source, const fs::FsPath& path, const ConfigOverride& override) { const auto ext = std::strrchr(path.s, '.'); R_UNLESS(ext, Result_ContainerNotFound);