delete save file before restoring. always commit fs after every write + close, delete, rename, create.

This commit is contained in:
ITotalJustice
2025-06-17 01:57:42 +01:00
parent b405a816c9
commit 0789a69975
5 changed files with 61 additions and 27 deletions

View File

@@ -199,6 +199,7 @@ struct File {
FsFile m_native{}; FsFile m_native{};
std::FILE* m_stdio{}; std::FILE* m_stdio{};
s64 m_stdio_off{}; s64 m_stdio_off{};
u32 m_mode{};
}; };
struct Dir { struct Dir {
@@ -287,6 +288,7 @@ struct Fs {
virtual Result GetEntryType(const FsPath& path, FsDirEntryType* out) = 0; virtual Result GetEntryType(const FsPath& path, FsDirEntryType* out) = 0;
virtual Result GetFileTimeStampRaw(const FsPath& path, FsTimeStampRaw *out) = 0; virtual Result GetFileTimeStampRaw(const FsPath& path, FsTimeStampRaw *out) = 0;
virtual Result SetTimestamp(const FsPath& path, const FsTimeStampRaw* ts) = 0; virtual Result SetTimestamp(const FsPath& path, const FsTimeStampRaw* ts) = 0;
virtual Result Commit() = 0;
virtual bool FileExists(const FsPath& path) = 0; virtual bool FileExists(const FsPath& path) = 0;
virtual bool DirExists(const FsPath& path) = 0; virtual bool DirExists(const FsPath& path) = 0;
virtual bool IsNative() const = 0; virtual bool IsNative() const = 0;
@@ -362,6 +364,9 @@ struct FsStdio : Fs {
Result SetTimestamp(const FsPath& path, const FsTimeStampRaw *ts) override { Result SetTimestamp(const FsPath& path, const FsTimeStampRaw *ts) override {
return fs::SetTimestamp(path, ts); return fs::SetTimestamp(path, ts);
} }
Result Commit() override {
R_SUCCEED();
}
bool FileExists(const FsPath& path) override { bool FileExists(const FsPath& path) override {
return fs::FileExists(path); return fs::FileExists(path);
} }
@@ -397,10 +402,6 @@ struct FsNative : Fs {
} }
} }
Result Commit() {
return fsFsCommit(&m_fs);
}
Result GetFreeSpace(const FsPath& path, s64* out) { Result GetFreeSpace(const FsPath& path, s64* out) {
return fsFsGetFreeSpace(&m_fs, path, out); return fsFsGetFreeSpace(&m_fs, path, out);
} }
@@ -453,6 +454,9 @@ struct FsNative : Fs {
Result SetTimestamp(const FsPath& path, const FsTimeStampRaw *ts) override { Result SetTimestamp(const FsPath& path, const FsTimeStampRaw *ts) override {
return fs::SetTimestamp(&m_fs, path, ts); return fs::SetTimestamp(&m_fs, path, ts);
} }
Result Commit() override {
return fsFsCommit(&m_fs);
}
bool FileExists(const FsPath& path) override { bool FileExists(const FsPath& path) override {
return fs::FileExists(&m_fs, path); return fs::FileExists(&m_fs, path);
} }

View File

@@ -2,6 +2,7 @@
#include "ui/menus/menu_base.hpp" #include "ui/menus/menu_base.hpp"
#include "ui/scrolling_text.hpp" #include "ui/scrolling_text.hpp"
#include "ui/progress_box.hpp"
#include "ui/list.hpp" #include "ui/list.hpp"
#include "fs.hpp" #include "fs.hpp"
#include "option.hpp" #include "option.hpp"
@@ -183,6 +184,7 @@ struct FsView final : Widget {
void SetSide(ViewSide side); void SetSide(ViewSide side);
static Result DeleteAllCollections(ProgressBox* pbox, fs::Fs* fs, const FsDirCollections& collections, u32 mode = FsDirOpenMode_ReadDirs|FsDirOpenMode_ReadFiles);
static auto get_collection(fs::Fs* fs, const fs::FsPath& path, const fs::FsPath& parent_name, FsDirCollection& out, bool inc_file, bool inc_dir, bool inc_size) -> Result; static auto get_collection(fs::Fs* fs, const fs::FsPath& path, const fs::FsPath& parent_name, FsDirCollection& out, bool inc_file, bool inc_dir, bool inc_size) -> Result;
static auto get_collections(fs::Fs* fs, const fs::FsPath& path, const fs::FsPath& parent_name, FsDirCollections& out, bool inc_size = false) -> Result; static auto get_collections(fs::Fs* fs, const fs::FsPath& path, const fs::FsPath& parent_name, FsDirCollections& out, bool inc_size = false) -> Result;

View File

@@ -112,13 +112,17 @@ FsPath AppendPath(const FsPath& root_path, const FsPath& _file_path) {
Result CreateFile(FsFileSystem* fs, const FsPath& path, u64 size, u32 option, bool ignore_read_only) { Result CreateFile(FsFileSystem* fs, const FsPath& path, u64 size, u32 option, bool ignore_read_only) {
R_UNLESS(ignore_read_only || !is_read_only_root(path), Result_FsReadOnly); R_UNLESS(ignore_read_only || !is_read_only_root(path), Result_FsReadOnly);
return fsFsCreateFile(fs, path, size, option); R_TRY(fsFsCreateFile(fs, path, size, option));
fsFsCommit(fs);
R_SUCCEED();
} }
Result CreateDirectory(FsFileSystem* fs, const FsPath& path, bool ignore_read_only) { Result CreateDirectory(FsFileSystem* fs, const FsPath& path, bool ignore_read_only) {
R_UNLESS(ignore_read_only || !is_read_only_root(path), Result_FsReadOnly); R_UNLESS(ignore_read_only || !is_read_only_root(path), Result_FsReadOnly);
return fsFsCreateDirectory(fs, path); R_TRY(fsFsCreateDirectory(fs, path));
fsFsCommit(fs);
R_SUCCEED();
} }
Result CreateDirectoryRecursively(FsFileSystem* fs, const FsPath& _path, bool ignore_read_only) { Result CreateDirectoryRecursively(FsFileSystem* fs, const FsPath& _path, bool ignore_read_only) {
@@ -180,38 +184,50 @@ Result CreateDirectoryRecursivelyWithPath(FsFileSystem* fs, const FsPath& _path,
FsPath new_path{}; FsPath new_path{};
std::snprintf(new_path, sizeof(new_path), "%.*s", (int)(last_slash - _path.s), _path.s); std::snprintf(new_path, sizeof(new_path), "%.*s", (int)(last_slash - _path.s), _path.s);
return CreateDirectoryRecursively(fs, new_path, ignore_read_only); R_TRY(CreateDirectoryRecursively(fs, new_path, ignore_read_only));
fsFsCommit(fs);
R_SUCCEED();
} }
Result DeleteFile(FsFileSystem* fs, const FsPath& path, bool ignore_read_only) { Result DeleteFile(FsFileSystem* fs, const FsPath& path, bool ignore_read_only) {
R_UNLESS(ignore_read_only || !is_read_only(path), Result_FsReadOnly); R_UNLESS(ignore_read_only || !is_read_only(path), Result_FsReadOnly);
return fsFsDeleteFile(fs, path); R_TRY(fsFsDeleteFile(fs, path));
fsFsCommit(fs);
R_SUCCEED();
} }
Result DeleteDirectory(FsFileSystem* fs, const FsPath& path, bool ignore_read_only) { Result DeleteDirectory(FsFileSystem* fs, const FsPath& path, bool ignore_read_only) {
R_UNLESS(ignore_read_only || !is_read_only(path), Result_FsReadOnly); R_UNLESS(ignore_read_only || !is_read_only(path), Result_FsReadOnly);
return fsFsDeleteDirectory(fs, path); R_TRY(fsFsDeleteDirectory(fs, path));
fsFsCommit(fs);
R_SUCCEED();
} }
Result DeleteDirectoryRecursively(FsFileSystem* fs, const FsPath& path, bool ignore_read_only) { Result DeleteDirectoryRecursively(FsFileSystem* fs, const FsPath& path, bool ignore_read_only) {
R_UNLESS(ignore_read_only || !is_read_only(path), Result_FsReadOnly); R_UNLESS(ignore_read_only || !is_read_only(path), Result_FsReadOnly);
return fsFsDeleteDirectoryRecursively(fs, path); R_TRY(fsFsDeleteDirectoryRecursively(fs, path));
fsFsCommit(fs);
R_SUCCEED();
} }
Result RenameFile(FsFileSystem* fs, const FsPath& src, const FsPath& dst, bool ignore_read_only) { Result RenameFile(FsFileSystem* fs, const FsPath& src, const FsPath& dst, bool ignore_read_only) {
R_UNLESS(ignore_read_only || !is_read_only(src), Result_FsReadOnly); R_UNLESS(ignore_read_only || !is_read_only(src), Result_FsReadOnly);
R_UNLESS(ignore_read_only || !is_read_only(dst), Result_FsReadOnly); R_UNLESS(ignore_read_only || !is_read_only(dst), Result_FsReadOnly);
return fsFsRenameFile(fs, src, dst); R_TRY(fsFsRenameFile(fs, src, dst));
fsFsCommit(fs);
R_SUCCEED();
} }
Result RenameDirectory(FsFileSystem* fs, const FsPath& src, const FsPath& dst, bool ignore_read_only) { Result RenameDirectory(FsFileSystem* fs, const FsPath& src, const FsPath& dst, bool ignore_read_only) {
R_UNLESS(ignore_read_only || !is_read_only(src), Result_FsReadOnly); R_UNLESS(ignore_read_only || !is_read_only(src), Result_FsReadOnly);
R_UNLESS(ignore_read_only || !is_read_only(dst), Result_FsReadOnly); R_UNLESS(ignore_read_only || !is_read_only(dst), Result_FsReadOnly);
return fsFsRenameDirectory(fs, src, dst); R_TRY(fsFsRenameDirectory(fs, src, dst));
fsFsCommit(fs);
R_SUCCEED();
} }
Result GetEntryType(FsFileSystem* fs, const FsPath& path, FsDirEntryType* out) { Result GetEntryType(FsFileSystem* fs, const FsPath& path, FsDirEntryType* out) {
@@ -263,6 +279,7 @@ Result write_entire_file(FsFileSystem* _fs, const FsPath& path, const std::vecto
FsNative fs{_fs, false, ignore_read_only}; FsNative fs{_fs, false, ignore_read_only};
R_TRY(fs.GetFsOpenResult()); R_TRY(fs.GetFsOpenResult());
ON_SCOPE_EXIT(fs.Commit());
if (auto rc = fs.CreateFile(path, in.size(), 0); R_FAILED(rc) && rc != FsError_PathAlreadyExists) { if (auto rc = fs.CreateFile(path, in.size(), 0); R_FAILED(rc) && rc != FsError_PathAlreadyExists) {
return rc; return rc;
@@ -484,6 +501,7 @@ 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) { Result OpenFile(fs::Fs* fs, const fs::FsPath& path, u32 mode, File* f) {
f->m_fs = fs; f->m_fs = fs;
f->m_mode = mode;
if (f->m_fs->IsNative()) { if (f->m_fs->IsNative()) {
auto fs = (fs::FsNative*)f->m_fs; auto fs = (fs::FsNative*)f->m_fs;
@@ -594,6 +612,9 @@ void File::Close() {
if (m_fs->IsNative()) { if (m_fs->IsNative()) {
if (serviceIsActive(&m_native.s)) { if (serviceIsActive(&m_native.s)) {
fsFileClose(&m_native); fsFileClose(&m_native);
if (m_mode & FsOpenMode_Write) {
m_fs->Commit();
}
m_native = {}; m_native = {};
} }
} else { } else {

View File

@@ -1185,7 +1185,7 @@ void FsView::OnDeleteCallback() {
} }
} }
return DeleteAllCollections(pbox, src_fs, selected, collections); return DeleteAllCollectionsWithSelected(pbox, src_fs, selected, collections);
}, [this](Result rc){ }, [this](Result rc){
App::PushErrorBox(rc, "Failed to, TODO: add message here"_i18n); App::PushErrorBox(rc, "Failed to, TODO: add message here"_i18n);
@@ -1319,7 +1319,7 @@ void FsView::OnPasteCallback() {
// the folders cannot be deleted until the end as they have to be removed in // the folders cannot be deleted until the end as they have to be removed in
// reverse order so that the folder can be deleted (it must be empty). // reverse order so that the folder can be deleted (it must be empty).
if (selected.m_type == SelectedType::Cut) { if (selected.m_type == SelectedType::Cut) {
R_TRY(DeleteAllCollections(pbox, src_fs, selected, collections, FsDirOpenMode_ReadDirs)); R_TRY(DeleteAllCollectionsWithSelected(pbox, src_fs, selected, collections, FsDirOpenMode_ReadDirs));
} }
} }
@@ -1430,7 +1430,7 @@ auto FsView::get_collections(const fs::FsPath& path, const fs::FsPath& parent_na
return get_collections(m_fs.get(), path, parent_name, out, inc_size); return get_collections(m_fs.get(), path, parent_name, out, inc_size);
} }
static Result DeleteAllCollections(ProgressBox* pbox, fs::Fs* fs, const SelectedStash& selected, const FsDirCollections& collections, u32 mode = FsDirOpenMode_ReadDirs|FsDirOpenMode_ReadFiles) { Result FsView::DeleteAllCollections(ProgressBox* pbox, fs::Fs* fs, const FsDirCollections& collections, u32 mode) {
// delete everything in collections, reversed // delete everything in collections, reversed
for (const auto& c : std::views::reverse(collections)) { for (const auto& c : std::views::reverse(collections)) {
const auto delete_func = [&](auto& array) -> Result { const auto delete_func = [&](auto& array) -> Result {
@@ -1459,6 +1459,12 @@ static Result DeleteAllCollections(ProgressBox* pbox, fs::Fs* fs, const Selected
R_TRY(delete_func(c.dirs)); R_TRY(delete_func(c.dirs));
} }
R_SUCCEED();
}
static Result DeleteAllCollectionsWithSelected(ProgressBox* pbox, fs::Fs* fs, const SelectedStash& selected, const FsDirCollections& collections, u32 mode = FsDirOpenMode_ReadDirs|FsDirOpenMode_ReadFiles) {
R_TRY(FsView::DeleteAllCollections(pbox, fs, collections, mode));
for (const auto& p : selected.m_files) { for (const auto& p : selected.m_files) {
pbox->Yield(); pbox->Yield();
R_TRY(pbox->ShouldExitResult()); R_TRY(pbox->ShouldExitResult());

View File

@@ -1197,8 +1197,7 @@ Result Menu::RestoreSaveInternal(ProgressBox* pbox, const Entry& e, const fs::Fs
ON_SCOPE_EXIT(unzClose(zfile)); ON_SCOPE_EXIT(unzClose(zfile));
log_write("opened zip\n"); log_write("opened zip\n");
bool has_meta{}; std::optional<NXSaveMeta> meta{};
NXSaveMeta meta{};
// get manifest // get manifest
if (UNZ_END_OF_LIST_OF_FILE != unzLocateFile(zfile, NX_SAVE_META_NAME, 0)) { if (UNZ_END_OF_LIST_OF_FILE != unzLocateFile(zfile, NX_SAVE_META_NAME, 0)) {
@@ -1207,17 +1206,18 @@ Result Menu::RestoreSaveInternal(ProgressBox* pbox, const Entry& e, const fs::Fs
log_write("opened meta file\n"); log_write("opened meta file\n");
ON_SCOPE_EXIT(unzCloseCurrentFile(zfile)); ON_SCOPE_EXIT(unzCloseCurrentFile(zfile));
const auto len = unzReadCurrentFile(zfile, &meta, sizeof(meta)); NXSaveMeta temp_meta;
if (len == sizeof(meta) && meta.magic == NX_SAVE_META_MAGIC && meta.version == NX_SAVE_META_VERSION) { const auto len = unzReadCurrentFile(zfile, &temp_meta, sizeof(temp_meta));
has_meta = true; if (len == sizeof(temp_meta) && temp_meta.magic == NX_SAVE_META_MAGIC && temp_meta.version == NX_SAVE_META_VERSION) {
meta = temp_meta;
log_write("loaded meta!\n"); log_write("loaded meta!\n");
} }
} }
} }
if (has_meta) { if (meta.has_value()) {
log_write("extending save file\n"); log_write("extending save file\n");
R_TRY(fsExtendSaveDataFileSystem(save_data_space_id, e.save_data_id, meta.data_size, meta.journal_size)); R_TRY(fsExtendSaveDataFileSystem(save_data_space_id, e.save_data_id, meta->data_size, meta->journal_size));
log_write("extended save file\n"); log_write("extended save file\n");
} else { } else {
log_write("doing manual meta parse\n"); log_write("doing manual meta parse\n");
@@ -1267,6 +1267,11 @@ Result Menu::RestoreSaveInternal(ProgressBox* pbox, const Entry& e, const fs::Fs
fs::FsNativeSave save_fs{(FsSaveDataType)e.save_data_type, save_data_space_id, &attr, false}; fs::FsNativeSave save_fs{(FsSaveDataType)e.save_data_type, save_data_space_id, &attr, false};
R_TRY(save_fs.GetFsOpenResult()); R_TRY(save_fs.GetFsOpenResult());
// delete all files in save.
filebrowser::FsDirCollections collections;
R_TRY(filebrowser::FsView::get_collections(&save_fs, "/", "", collections));
R_TRY(filebrowser::FsView::DeleteAllCollections(pbox, &save_fs, collections));
log_write("opened save file\n"); log_write("opened save file\n");
// restore save data from zip. // restore save data from zip.
R_TRY(thread::TransferUnzipAll(pbox, zfile, &save_fs, "/", [&](const fs::FsPath& name, fs::FsPath& path) -> bool { R_TRY(thread::TransferUnzipAll(pbox, zfile, &save_fs, "/", [&](const fs::FsPath& name, fs::FsPath& path) -> bool {
@@ -1278,14 +1283,10 @@ Result Menu::RestoreSaveInternal(ProgressBox* pbox, const Entry& e, const fs::Fs
// restore everything else. // restore everything else.
log_write("restoring: %s\n", path.s); log_write("restoring: %s\n", path.s);
// commit after every save otherwise FsError_MappingTableFull is thrown.
R_TRY(save_fs.Commit());
return true; return true;
})); }));
log_write("finished, doing commit\n"); log_write("finished save backup\n");
R_TRY(save_fs.Commit());
R_SUCCEED(); R_SUCCEED();
} }