mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-07-05 22:41:25 +12:00
Improve vfs::host::rename
This commit is contained in:
parent
ce3d7f90fd
commit
c3f1d39563
3 changed files with 62 additions and 22 deletions
|
@ -926,13 +926,47 @@ error_code cellGameContentPermit(ppu_thread& ppu, vm::ptr<char[CELL_GAME_PATH_MA
|
||||||
|
|
||||||
if (!perm.temp.empty())
|
if (!perm.temp.empty())
|
||||||
{
|
{
|
||||||
|
std::vector<std::shared_ptr<lv2_file>> lv2_files;
|
||||||
|
|
||||||
|
const std::string real_dir = vfs::get(dir) + "/";
|
||||||
|
|
||||||
|
std::lock_guard lock(g_mp_sys_dev_hdd0.mutex);
|
||||||
|
|
||||||
// Create PARAM.SFO
|
// Create PARAM.SFO
|
||||||
fs::pending_file temp(perm.temp + "/PARAM.SFO");
|
fs::pending_file temp(perm.temp + "/PARAM.SFO");
|
||||||
temp.file.write(psf::save_object(perm.sfo));
|
temp.file.write(psf::save_object(perm.sfo));
|
||||||
ensure(temp.commit());
|
ensure(temp.commit());
|
||||||
|
|
||||||
|
idm::select<lv2_fs_object, lv2_file>([&](u32 id, lv2_file& file)
|
||||||
|
{
|
||||||
|
if (file.mp != &g_mp_sys_dev_hdd0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (real_dir.starts_with(file.real_path))
|
||||||
|
{
|
||||||
|
if (!file.file)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file.flags & CELL_FS_O_ACCMODE)
|
||||||
|
{
|
||||||
|
// Synchronize outside IDM lock scope
|
||||||
|
lv2_files.emplace_back(ensure(idm::get_unlocked<lv2_fs_object, lv2_file>(id)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
for (auto& file : lv2_files)
|
||||||
|
{
|
||||||
|
// For atomicity
|
||||||
|
file->file.sync();
|
||||||
|
}
|
||||||
|
|
||||||
// Make temporary directory persistent (atomically)
|
// Make temporary directory persistent (atomically)
|
||||||
if (vfs::host::rename(perm.temp, vfs::get(dir), &g_mp_sys_dev_hdd0, false))
|
if (vfs::host::rename(perm.temp, real_dir, &g_mp_sys_dev_hdd0, false, false))
|
||||||
{
|
{
|
||||||
cellGame.success("cellGameContentPermit(): directory '%s' has been created", dir);
|
cellGame.success("cellGameContentPermit(): directory '%s' has been created", dir);
|
||||||
|
|
||||||
|
|
|
@ -289,7 +289,7 @@ struct lv2_file final : lv2_fs_object
|
||||||
// Stream lock
|
// Stream lock
|
||||||
atomic_t<u32> lock{0};
|
atomic_t<u32> lock{0};
|
||||||
|
|
||||||
// Some variables for convinience of data restoration
|
// Some variables for convenience of data restoration
|
||||||
struct save_restore_t
|
struct save_restore_t
|
||||||
{
|
{
|
||||||
u64 seek_pos;
|
u64 seek_pos;
|
||||||
|
|
|
@ -931,7 +931,8 @@ bool vfs::host::rename(const std::string& from, const std::string& to, const lv2
|
||||||
{
|
{
|
||||||
// Lock mount point, close file descriptors, retry
|
// Lock mount point, close file descriptors, retry
|
||||||
const auto from0 = std::string_view(from).substr(0, from.find_last_not_of(fs::delim) + 1);
|
const auto from0 = std::string_view(from).substr(0, from.find_last_not_of(fs::delim) + 1);
|
||||||
const auto escaped_from = Emu.GetCallbacks().resolve_path(from);
|
|
||||||
|
std::vector<std::pair<std::shared_ptr<lv2_file>, std::string>> escaped_real;
|
||||||
|
|
||||||
std::unique_lock mp_lock(mp->mutex, std::defer_lock);
|
std::unique_lock mp_lock(mp->mutex, std::defer_lock);
|
||||||
|
|
||||||
|
@ -940,33 +941,43 @@ bool vfs::host::rename(const std::string& from, const std::string& to, const lv2
|
||||||
mp_lock.lock();
|
mp_lock.lock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (fs::rename(from, to, overwrite))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fs::g_tls_error != fs::error::acces)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto escaped_from = Emu.GetCallbacks().resolve_path(from);
|
||||||
|
|
||||||
auto check_path = [&](std::string_view path)
|
auto check_path = [&](std::string_view path)
|
||||||
{
|
{
|
||||||
return path.starts_with(from) && (path.size() == from.size() || path[from.size()] == fs::delim[0] || path[from.size()] == fs::delim[1]);
|
return path.starts_with(from) && (path.size() == from.size() || path[from.size()] == fs::delim[0] || path[from.size()] == fs::delim[1]);
|
||||||
};
|
};
|
||||||
|
|
||||||
std::map<u32, std::string> escaped_real;
|
|
||||||
idm::select<lv2_fs_object, lv2_file>([&](u32 id, lv2_file& file)
|
idm::select<lv2_fs_object, lv2_file>([&](u32 id, lv2_file& file)
|
||||||
{
|
{
|
||||||
escaped_real[id] = Emu.GetCallbacks().resolve_path(file.real_path);
|
if (file.mp != mp)
|
||||||
if (check_path(escaped_real[id]))
|
|
||||||
{
|
{
|
||||||
ensure(file.mp == mp);
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string escaped = Emu.GetCallbacks().resolve_path(file.real_path);
|
||||||
|
|
||||||
|
if (check_path(escaped))
|
||||||
|
{
|
||||||
if (!file.file)
|
if (!file.file)
|
||||||
{
|
{
|
||||||
file.restore_data.seek_pos = -1;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
file.restore_data.seek_pos = file.file.pos();
|
file.restore_data.seek_pos = file.file.pos();
|
||||||
|
|
||||||
if (!(file.mp.read_only && file.mp->flags & lv2_mp_flag::cache) && file.flags & CELL_FS_O_ACCMODE)
|
|
||||||
{
|
|
||||||
file.file.sync(); // For cellGameContentPermit atomicity
|
|
||||||
}
|
|
||||||
|
|
||||||
file.file.close(); // Actually close it!
|
file.file.close(); // Actually close it!
|
||||||
|
escaped_real.emplace_back(ensure(idm::get_unlocked<lv2_file>(id)), std::move(escaped));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -989,19 +1000,14 @@ bool vfs::host::rename(const std::string& from, const std::string& to, const lv2
|
||||||
|
|
||||||
const auto fs_error = fs::g_tls_error;
|
const auto fs_error = fs::g_tls_error;
|
||||||
|
|
||||||
idm::select<lv2_fs_object, lv2_file>([&](u32 id, lv2_file& file)
|
for (const auto& [file_ptr, real_path] : escaped_real)
|
||||||
{
|
{
|
||||||
if (check_path(escaped_real[id]))
|
lv2_file& file = *file_ptr;
|
||||||
{
|
{
|
||||||
if (file.restore_data.seek_pos == umax)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update internal path
|
// Update internal path
|
||||||
if (res)
|
if (res)
|
||||||
{
|
{
|
||||||
file.real_path = to + (escaped_real[id] != escaped_from ? '/' + file.real_path.substr(from0.size()) : ""s);
|
file.real_path = to + (real_path != escaped_from ? '/' + file.real_path.substr(from0.size()) : ""s);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reopen with ignored TRUNC, APPEND, CREATE and EXCL flags
|
// Reopen with ignored TRUNC, APPEND, CREATE and EXCL flags
|
||||||
|
@ -1010,7 +1016,7 @@ bool vfs::host::rename(const std::string& from, const std::string& to, const lv2
|
||||||
ensure(file.file.operator bool());
|
ensure(file.file.operator bool());
|
||||||
file.file.seek(file.restore_data.seek_pos);
|
file.file.seek(file.restore_data.seek_pos);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
fs::g_tls_error = fs_error;
|
fs::g_tls_error = fs_error;
|
||||||
return res;
|
return res;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue