Skip to content

Commit

Permalink
UICommon: When importing userdir, verify that the zip actually contai…
Browse files Browse the repository at this point in the history
…ns a userdir backup before deleting the old one. Also give more detailed error messages on failure.
  • Loading branch information
AdmiralCurtiss committed May 31, 2022
1 parent 6a52c9c commit 18a2db0
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 17 deletions.
43 changes: 33 additions & 10 deletions Source/Core/DolphinQt/MenuBar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1078,26 +1078,49 @@ void MenuBar::ImportUserDirBackup()
progress.GetRaw()->setWindowTitle(tr("Importing"));
progress.GetRaw()->setWindowModality(Qt::WindowModal);

auto future = std::async(std::launch::async, [&]() -> bool {
bool result = UICommon::ImportUserDir(path.toStdString());
auto future = std::async(std::launch::async, [&]() -> UICommon::ImportUserDirResult {
auto result = UICommon::ImportUserDir(path.toStdString());
progress.Reset();
return result;
});

progress.GetRaw()->exec();

bool success = future.get();
if (success)
auto result = future.get();
switch (result)
{
case UICommon::ImportUserDirResult::Success:
ModalMessageBox::information(this, tr("Success"),
tr("Successfully imported Global User Directory."));
}
else
{
break;
case UICommon::ImportUserDirResult::ArchiveFileError:
ModalMessageBox::critical(this, tr("Failure"),
tr("Importing Global User Directory failed. The directory may now be "
"in an inconsistent state. It is recommended to close Dolphin and "
"manually delete the directory before continuing."));
tr("Importing Global User Directory failed: The selected archive "
"could not be opened or is corrupt."));
break;
case UICommon::ImportUserDirResult::ArchiveDoesNotContainUserdir:
ModalMessageBox::critical(this, tr("Failure"),
tr("Importing Global User Directory failed: The selected archive "
"does not appear to contain a Global User Directory backup."));
break;
case UICommon::ImportUserDirResult::OldUserdirDeleteError:
ModalMessageBox::critical(
this, tr("Failure"),
tr("Importing Global User Directory failed: Unable to delete the existing Global User "
"Directory. The directory may now be in an inconsistent state. It is recommended to "
"close Dolphin and manually delete the directory before continuing."));
break;
case UICommon::ImportUserDirResult::ExtractError:
ModalMessageBox::critical(
this, tr("Failure"),
tr("Importing Global User Directory failed: Failed to extract archive. The archive may be "
"corrupt or there may not be enough disk space available. The directory may now be in "
"an inconsistent state. It is recommended to close Dolphin and manually delete the "
"directory before continuing."));
break;
default:
ModalMessageBox::critical(this, tr("Failure"), tr("Importing Global User Directory failed."));
break;
}
}

Expand Down
42 changes: 36 additions & 6 deletions Source/Core/UICommon/ImportExportUserdir.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,40 @@

namespace UICommon
{
bool ImportUserDir(const std::string& archive_path)
ImportUserDirResult ImportUserDir(const std::string& archive_path)
{
const auto& directory_path = File::GetUserPath(D_USER_IDX);

void* reader = nullptr;
mz_zip_reader_create(&reader);
if (!reader)
return ImportUserDirResult::UnknownError;

Common::ScopeGuard delete_reader_guard([&reader] { mz_zip_reader_delete(&reader); });

mz_zip_reader_set_encoding(reader, MZ_ENCODING_UTF8);

if (mz_zip_reader_open_file(reader, archive_path.c_str()) != MZ_OK)
return ImportUserDirResult::ArchiveFileError;

Common::ScopeGuard close_reader_guard([&reader] { mz_zip_reader_close(reader); });

void* zip_handle = nullptr;
if (mz_zip_reader_get_zip_handle(reader, &zip_handle) != MZ_OK || !zip_handle)
return ImportUserDirResult::UnknownError;
if (mz_zip_entry_is_open(zip_handle) == MZ_OK)
mz_zip_reader_entry_close(reader);

const auto go_to_first_entry_result = mz_zip_locate_first_entry(
zip_handle, nullptr, [](void* handle, void* userdata, mz_zip_file* file_info) -> int32_t {
const bool is_dolphin_ini =
Common::CaseInsensitiveEquals(file_info->filename, "Config/Dolphin.ini") ||
Common::CaseInsensitiveEquals(file_info->filename, "Config\\Dolphin.ini");
return is_dolphin_ini ? 0 : -1;
});
if (go_to_first_entry_result != MZ_OK)
return ImportUserDirResult::ArchiveDoesNotContainUserdir;

const auto root = File::ScanDirectoryTree(directory_path, false);
for (const auto& file : root.children)
{
Expand All @@ -32,21 +62,21 @@ bool ImportUserDir(const std::string& archive_path)
if (file.isDirectory)
{
if (!File::DeleteDirRecursively(file.physicalName))
return false;
return ImportUserDirResult::OldUserdirDeleteError;
}
else
{
if (!File::Delete(file.physicalName))
return false;
return ImportUserDirResult::OldUserdirDeleteError;
}
}

if (!Common::UnpackZipToDirectory(archive_path, directory_path))
return false;
if (mz_zip_reader_save_all(reader, directory_path.c_str()) != MZ_OK)
return ImportUserDirResult::ExtractError;

// Need to reload the configuration now
Config::Reload();
return true;
return ImportUserDirResult::Success;
}

static bool ExportUserDirRecursive(void** writer, const File::FSTEntry& file,
Expand Down
12 changes: 11 additions & 1 deletion Source/Core/UICommon/ImportExportUserdir.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,16 @@

namespace UICommon
{
bool ImportUserDir(const std::string& archive_path);
enum class ImportUserDirResult
{
Success,
UnknownError,
ArchiveFileError,
ArchiveDoesNotContainUserdir,
OldUserdirDeleteError,
ExtractError,
};

ImportUserDirResult ImportUserDir(const std::string& archive_path);
bool ExportUserDir(const std::string& archive_path, Common::Flag* cancel_requested_flag);
} // namespace UICommon

0 comments on commit 18a2db0

Please sign in to comment.