delete save file before restoring. always commit fs after every write + close, delete, rename, create.
This commit is contained in:
@@ -199,6 +199,7 @@ struct File {
|
||||
FsFile m_native{};
|
||||
std::FILE* m_stdio{};
|
||||
s64 m_stdio_off{};
|
||||
u32 m_mode{};
|
||||
};
|
||||
|
||||
struct Dir {
|
||||
@@ -287,6 +288,7 @@ struct Fs {
|
||||
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;
|
||||
@@ -362,6 +364,9 @@ struct FsStdio : Fs {
|
||||
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);
|
||||
}
|
||||
@@ -397,10 +402,6 @@ struct FsNative : Fs {
|
||||
}
|
||||
}
|
||||
|
||||
Result Commit() {
|
||||
return fsFsCommit(&m_fs);
|
||||
}
|
||||
|
||||
Result GetFreeSpace(const FsPath& path, s64* out) {
|
||||
return fsFsGetFreeSpace(&m_fs, path, out);
|
||||
}
|
||||
@@ -453,6 +454,9 @@ struct FsNative : Fs {
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "ui/menus/menu_base.hpp"
|
||||
#include "ui/scrolling_text.hpp"
|
||||
#include "ui/progress_box.hpp"
|
||||
#include "ui/list.hpp"
|
||||
#include "fs.hpp"
|
||||
#include "option.hpp"
|
||||
@@ -183,6 +184,7 @@ struct FsView final : Widget {
|
||||
|
||||
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_collections(fs::Fs* fs, const fs::FsPath& path, const fs::FsPath& parent_name, FsDirCollections& out, bool inc_size = false) -> Result;
|
||||
|
||||
|
||||
@@ -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) {
|
||||
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) {
|
||||
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) {
|
||||
@@ -180,38 +184,50 @@ Result CreateDirectoryRecursivelyWithPath(FsFileSystem* fs, const FsPath& _path,
|
||||
|
||||
FsPath new_path{};
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
R_UNLESS(ignore_read_only || !is_read_only(src), 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) {
|
||||
R_UNLESS(ignore_read_only || !is_read_only(src), 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) {
|
||||
@@ -263,6 +279,7 @@ Result write_entire_file(FsFileSystem* _fs, const FsPath& path, const std::vecto
|
||||
|
||||
FsNative fs{_fs, false, ignore_read_only};
|
||||
R_TRY(fs.GetFsOpenResult());
|
||||
ON_SCOPE_EXIT(fs.Commit());
|
||||
|
||||
if (auto rc = fs.CreateFile(path, in.size(), 0); R_FAILED(rc) && rc != FsError_PathAlreadyExists) {
|
||||
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) {
|
||||
f->m_fs = fs;
|
||||
f->m_mode = mode;
|
||||
|
||||
if (f->m_fs->IsNative()) {
|
||||
auto fs = (fs::FsNative*)f->m_fs;
|
||||
@@ -594,6 +612,9 @@ void File::Close() {
|
||||
if (m_fs->IsNative()) {
|
||||
if (serviceIsActive(&m_native.s)) {
|
||||
fsFileClose(&m_native);
|
||||
if (m_mode & FsOpenMode_Write) {
|
||||
m_fs->Commit();
|
||||
}
|
||||
m_native = {};
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -1185,7 +1185,7 @@ void FsView::OnDeleteCallback() {
|
||||
}
|
||||
}
|
||||
|
||||
return DeleteAllCollections(pbox, src_fs, selected, collections);
|
||||
return DeleteAllCollectionsWithSelected(pbox, src_fs, selected, collections);
|
||||
}, [this](Result rc){
|
||||
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
|
||||
// reverse order so that the folder can be deleted (it must be empty).
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
for (const auto& c : std::views::reverse(collections)) {
|
||||
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_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) {
|
||||
pbox->Yield();
|
||||
R_TRY(pbox->ShouldExitResult());
|
||||
|
||||
@@ -1197,8 +1197,7 @@ Result Menu::RestoreSaveInternal(ProgressBox* pbox, const Entry& e, const fs::Fs
|
||||
ON_SCOPE_EXIT(unzClose(zfile));
|
||||
log_write("opened zip\n");
|
||||
|
||||
bool has_meta{};
|
||||
NXSaveMeta meta{};
|
||||
std::optional<NXSaveMeta> meta{};
|
||||
|
||||
// get manifest
|
||||
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");
|
||||
ON_SCOPE_EXIT(unzCloseCurrentFile(zfile));
|
||||
|
||||
const auto len = unzReadCurrentFile(zfile, &meta, sizeof(meta));
|
||||
if (len == sizeof(meta) && meta.magic == NX_SAVE_META_MAGIC && meta.version == NX_SAVE_META_VERSION) {
|
||||
has_meta = true;
|
||||
NXSaveMeta temp_meta;
|
||||
const auto len = unzReadCurrentFile(zfile, &temp_meta, sizeof(temp_meta));
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (has_meta) {
|
||||
if (meta.has_value()) {
|
||||
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");
|
||||
} else {
|
||||
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};
|
||||
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");
|
||||
// restore save data from zip.
|
||||
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.
|
||||
log_write("restoring: %s\n", path.s);
|
||||
|
||||
// commit after every save otherwise FsError_MappingTableFull is thrown.
|
||||
R_TRY(save_fs.Commit());
|
||||
return true;
|
||||
}));
|
||||
|
||||
log_write("finished, doing commit\n");
|
||||
R_TRY(save_fs.Commit());
|
||||
log_write("finished save backup\n");
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user