mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-11-22 18:53:28 +01:00
Qt: more package install fixes
- Clean directories if fill_path fails - Fix check_target_app_version when installing multiple packages (compromise: no more optimized singular file installs for now)
This commit is contained in:
parent
fc85ed8730
commit
12fa7c41f6
@ -689,20 +689,16 @@ package_error package_reader::check_target_app_version() const
|
|||||||
return package_error::app_version;
|
return package_error::app_version;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool package_reader::fill_data(std::map<std::string, install_entry*>& all_install_entries)
|
bool package_reader::set_install_path()
|
||||||
{
|
{
|
||||||
if (!m_is_valid)
|
if (!m_is_valid)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_install_entries.clear();
|
|
||||||
m_install_path.clear();
|
m_install_path.clear();
|
||||||
m_bootable_file_path.clear();
|
|
||||||
m_entry_indexer = 0;
|
|
||||||
m_written_bytes = 0;
|
|
||||||
|
|
||||||
// Get full path and create the directory
|
// Get full path
|
||||||
std::string dir = rpcs3::utils::get_hdd0_dir();
|
std::string dir = rpcs3::utils::get_hdd0_dir();
|
||||||
|
|
||||||
// Based on https://www.psdevwiki.com/ps3/PKG_files#ContentType
|
// Based on https://www.psdevwiki.com/ps3/PKG_files#ContentType
|
||||||
@ -739,13 +735,27 @@ bool package_reader::fill_data(std::map<std::string, install_entry*>& all_instal
|
|||||||
// If false, an existing directory is being overwritten: cannot cancel the operation
|
// If false, an existing directory is being overwritten: cannot cancel the operation
|
||||||
m_was_null = !fs::is_dir(dir);
|
m_was_null = !fs::is_dir(dir);
|
||||||
|
|
||||||
if (!fs::create_path(dir))
|
m_install_path = dir;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool package_reader::fill_data(std::map<std::string, install_entry*>& all_install_entries)
|
||||||
|
{
|
||||||
|
if (!m_is_valid)
|
||||||
{
|
{
|
||||||
pkg_log.error("Could not create the installation directory %s", dir);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_install_path = dir;
|
if (!fs::create_path(m_install_path))
|
||||||
|
{
|
||||||
|
pkg_log.error("Could not create the installation directory %s (error=%s)", m_install_path, fs::g_tls_error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_install_entries.clear();
|
||||||
|
m_bootable_file_path.clear();
|
||||||
|
m_entry_indexer = 0;
|
||||||
|
m_written_bytes = 0;
|
||||||
|
|
||||||
if (!decrypt_data())
|
if (!decrypt_data())
|
||||||
{
|
{
|
||||||
@ -772,7 +782,7 @@ bool package_reader::fill_data(std::map<std::string, install_entry*>& all_instal
|
|||||||
decrypt(entry.name_offset, entry.name_size, is_psp ? PKG_AES_KEY2 : m_dec_key.data());
|
decrypt(entry.name_offset, entry.name_size, is_psp ? PKG_AES_KEY2 : m_dec_key.data());
|
||||||
|
|
||||||
const std::string name{reinterpret_cast<char*>(m_bufs.back().get()), entry.name_size};
|
const std::string name{reinterpret_cast<char*>(m_bufs.back().get()), entry.name_size};
|
||||||
std::string path = dir + vfs::escape(name);
|
std::string path = m_install_path + vfs::escape(name);
|
||||||
|
|
||||||
const bool log_error = entry.pad || (entry.type & ~PKG_FILE_ENTRY_KNOWN_BITS);
|
const bool log_error = entry.pad || (entry.type & ~PKG_FILE_ENTRY_KNOWN_BITS);
|
||||||
|
|
||||||
@ -831,7 +841,7 @@ bool package_reader::fill_data(std::map<std::string, install_entry*>& all_instal
|
|||||||
|
|
||||||
if (num_failures != 0)
|
if (num_failures != 0)
|
||||||
{
|
{
|
||||||
pkg_log.error("Package installation failed: %s", dir);
|
pkg_log.error("Package installation failed: %s", m_install_path);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -988,29 +998,53 @@ void package_reader::extract_worker(thread_key thread_data_key)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool package_reader::extract_data(std::deque<package_reader>& readers, std::deque<std::string>& bootable_paths)
|
package_error package_reader::extract_data(std::deque<package_reader>& readers, std::deque<std::string>& bootable_paths)
|
||||||
{
|
{
|
||||||
std::map<std::string, install_entry*> all_install_entries;
|
package_error error = package_error::no_error;
|
||||||
|
usz num_failures = 0;
|
||||||
|
|
||||||
|
// Set paths first in order to know if the install dir was empty before starting any installations.
|
||||||
|
// This will also allow us to remove all the new packages in one path at once if any of them fail.
|
||||||
for (package_reader& reader : readers)
|
for (package_reader& reader : readers)
|
||||||
{
|
{
|
||||||
if (!reader.fill_data(all_install_entries))
|
reader.m_result = result::not_started;
|
||||||
|
|
||||||
|
if (!reader.set_install_path())
|
||||||
{
|
{
|
||||||
return false;
|
error = package_error::other;
|
||||||
|
reader.m_result = result::error;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
usz num_failures = 0;
|
|
||||||
|
|
||||||
for (package_reader& reader : readers)
|
for (package_reader& reader : readers)
|
||||||
{
|
{
|
||||||
|
// Use a seperate map for each reader. We need to check if the target app version exists for each package in sequence.
|
||||||
|
std::map<std::string, install_entry*> all_install_entries;
|
||||||
|
|
||||||
|
if (error == package_error::no_error)
|
||||||
|
{
|
||||||
|
// Check if this package is allowed to be installed on top of the existing data
|
||||||
|
error = reader.check_target_app_version();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error == package_error::no_error)
|
||||||
|
{
|
||||||
|
reader.m_result = result::started;
|
||||||
|
|
||||||
|
// Parse the files to be installed and create all paths.
|
||||||
|
if (!reader.fill_data(all_install_entries))
|
||||||
|
{
|
||||||
|
error = package_error::other;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
reader.m_bufs.resize(std::min<usz>(utils::get_thread_count(), reader.m_install_entries.size()));
|
reader.m_bufs.resize(std::min<usz>(utils::get_thread_count(), reader.m_install_entries.size()));
|
||||||
reader.m_num_failures = 0;
|
reader.m_num_failures = error == package_error::no_error ? 0 : 1;
|
||||||
reader.m_result = result::not_started;
|
|
||||||
|
|
||||||
atomic_t<usz> thread_indexer = 0;
|
atomic_t<usz> thread_indexer = 0;
|
||||||
|
|
||||||
named_thread_group workers("PKG Installer "sv, std::max<usz>(reader.m_bufs.size(), 1) - 1, [&]()
|
named_thread_group workers("PKG Installer "sv, std::max<u32>(::narrow<u32>(reader.m_bufs.size()), 1) - 1, [&]()
|
||||||
{
|
{
|
||||||
reader.extract_worker(thread_key{thread_indexer++});
|
reader.extract_worker(thread_key{thread_indexer++});
|
||||||
});
|
});
|
||||||
@ -1067,7 +1101,12 @@ bool package_reader::extract_data(std::deque<package_reader>& readers, std::dequ
|
|||||||
bootable_paths.emplace_back(std::move(reader.m_bootable_file_path));
|
bootable_paths.emplace_back(std::move(reader.m_bootable_file_path));
|
||||||
}
|
}
|
||||||
|
|
||||||
return num_failures == 0;
|
if (num_failures > 0)
|
||||||
|
{
|
||||||
|
error = package_error::other;
|
||||||
|
}
|
||||||
|
|
||||||
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
void package_reader::archive_seek(const s64 new_offset, const fs::seek_mode damode)
|
void package_reader::archive_seek(const s64 new_offset, const fs::seek_mode damode)
|
||||||
|
@ -335,6 +335,7 @@ public:
|
|||||||
enum result
|
enum result
|
||||||
{
|
{
|
||||||
not_started,
|
not_started,
|
||||||
|
started,
|
||||||
success,
|
success,
|
||||||
aborted,
|
aborted,
|
||||||
aborted_cleaned,
|
aborted_cleaned,
|
||||||
@ -344,7 +345,7 @@ public:
|
|||||||
|
|
||||||
bool is_valid() const { return m_is_valid; }
|
bool is_valid() const { return m_is_valid; }
|
||||||
package_error check_target_app_version() const;
|
package_error check_target_app_version() const;
|
||||||
static bool extract_data(std::deque<package_reader>& readers, std::deque<std::string>& bootable_paths);
|
static package_error extract_data(std::deque<package_reader>& readers, std::deque<std::string>& bootable_paths);
|
||||||
psf::registry get_psf() const { return m_psf; }
|
psf::registry get_psf() const { return m_psf; }
|
||||||
result get_result() const { return m_result; };
|
result get_result() const { return m_result; };
|
||||||
|
|
||||||
@ -359,6 +360,7 @@ private:
|
|||||||
bool decrypt_data();
|
bool decrypt_data();
|
||||||
void archive_seek(s64 new_offset, const fs::seek_mode damode = fs::seek_set);
|
void archive_seek(s64 new_offset, const fs::seek_mode damode = fs::seek_set);
|
||||||
u64 archive_read(void* data_ptr, u64 num_bytes);
|
u64 archive_read(void* data_ptr, u64 num_bytes);
|
||||||
|
bool set_install_path();
|
||||||
bool fill_data(std::map<std::string, install_entry*>& all_install_entries);
|
bool fill_data(std::map<std::string, install_entry*>& all_install_entries);
|
||||||
std::span<const char> archive_read_block(u64 offset, void* data_ptr, u64 num_bytes);
|
std::span<const char> archive_read_block(u64 offset, void* data_ptr, u64 num_bytes);
|
||||||
std::span<const char> decrypt(u64 offset, u64 size, const uchar* key, thread_key thread_data_key = {0});
|
std::span<const char> decrypt(u64 offset, u64 size, const uchar* key, thread_key thread_data_key = {0});
|
||||||
|
@ -92,8 +92,8 @@ namespace rpcs3::utils
|
|||||||
named_thread worker("PKG Installer", [&]
|
named_thread worker("PKG Installer", [&]
|
||||||
{
|
{
|
||||||
std::deque<std::string> bootables;
|
std::deque<std::string> bootables;
|
||||||
|
const package_error error = package_reader::extract_data(reader, bootables);
|
||||||
return package_reader::extract_data(reader, bootables);
|
return error == package_error::no_error;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Wait for the completion
|
// Wait for the completion
|
||||||
|
@ -944,10 +944,9 @@ void main_window::HandlePackageInstallation(QStringList file_paths)
|
|||||||
|
|
||||||
std::deque<package_reader> readers;
|
std::deque<package_reader> readers;
|
||||||
|
|
||||||
for (usz i = 0; error == package_error::no_error && i < packages.size(); i++)
|
for (const compat::package_info& info : packages)
|
||||||
{
|
{
|
||||||
readers.emplace_back(sstr(packages[i].path));
|
readers.emplace_back(sstr(info.path));
|
||||||
error = readers.back().check_target_app_version();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::deque<std::string> bootable_paths;
|
std::deque<std::string> bootable_paths;
|
||||||
@ -955,15 +954,8 @@ void main_window::HandlePackageInstallation(QStringList file_paths)
|
|||||||
// Run PKG unpacking asynchronously
|
// Run PKG unpacking asynchronously
|
||||||
named_thread worker("PKG Installer", [&readers, &error, &bootable_paths]
|
named_thread worker("PKG Installer", [&readers, &error, &bootable_paths]
|
||||||
{
|
{
|
||||||
if (error == package_error::no_error)
|
error = package_reader::extract_data(readers, bootable_paths);
|
||||||
{
|
return error == package_error::no_error;
|
||||||
if (package_reader::extract_data(readers, bootable_paths))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
pdlg.show();
|
pdlg.show();
|
||||||
@ -1021,6 +1013,7 @@ void main_window::HandlePackageInstallation(QStringList file_paths)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case package_reader::result::not_started:
|
case package_reader::result::not_started:
|
||||||
|
case package_reader::result::started:
|
||||||
case package_reader::result::aborted_cleaned:
|
case package_reader::result::aborted_cleaned:
|
||||||
{
|
{
|
||||||
gui_log.notice("Aborted installation of %s (title_id=%s, title=%s, version=%s).", sstr(package.path), sstr(package.title_id), sstr(package.title), sstr(package.version));
|
gui_log.notice("Aborted installation of %s (title_id=%s, title=%s, version=%s).", sstr(package.path), sstr(package.title_id), sstr(package.title), sstr(package.version));
|
||||||
@ -1146,6 +1139,7 @@ void main_window::HandlePackageInstallation(QStringList file_paths)
|
|||||||
{
|
{
|
||||||
case package_reader::result::success:
|
case package_reader::result::success:
|
||||||
case package_reader::result::not_started:
|
case package_reader::result::not_started:
|
||||||
|
case package_reader::result::started:
|
||||||
case package_reader::result::aborted:
|
case package_reader::result::aborted:
|
||||||
case package_reader::result::aborted_cleaned:
|
case package_reader::result::aborted_cleaned:
|
||||||
break;
|
break;
|
||||||
|
Loading…
Reference in New Issue
Block a user