Another attempt to fix fs::pending_file for hardlinks

This commit is contained in:
Elad 2024-11-02 12:47:42 +02:00
parent d3c0ec5651
commit b053b1e200
2 changed files with 44 additions and 4 deletions

View File

@ -2412,6 +2412,13 @@ fs::file fs::make_gather(std::vector<fs::file> files)
return result;
}
std::string fs::generate_neighboring_path(std::string_view source, [[maybe_unused]] u64 seed)
{
// Seed is currently not used
return fmt::format(u8"%s/%s.%s.tmp", get_parent_dir(source), source.substr(source.find_last_of(fs::delim) + 1), fmt::base57(utils::get_unique_tsc()));
}
bool fs::pending_file::open(std::string_view path)
{
file.close();
@ -2430,7 +2437,7 @@ bool fs::pending_file::open(std::string_view path)
do
{
m_path = fmt::format(u8"%s/%s.%s.tmp", get_parent_dir(path), path.substr(path.find_last_of(fs::delim) + 1), fmt::base57(utils::get_unique_tsc()));
m_path = fs::generate_neighboring_path(path, 0);
if (file.open(m_path, fs::create + fs::write + fs::read + fs::excl))
{
@ -2563,21 +2570,52 @@ bool fs::pending_file::commit(bool overwrite)
file.close();
#ifdef _WIN32
const auto ws2 = to_wchar(m_dest);
const auto wdest = to_wchar(m_dest);
bool ok = false;
if (hardlink_paths.empty())
{
ok = MoveFileExW(ws1.get(), ws2.get(), overwrite ? MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH : MOVEFILE_WRITE_THROUGH);
ok = MoveFileExW(ws1.get(), wdest.get(), overwrite ? MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH : MOVEFILE_WRITE_THROUGH);
}
else
{
ok = ReplaceFileW(ws1.get(), ws2.get(), nullptr, 0, nullptr, nullptr);
ok = ReplaceFileW(ws1.get(), wdest.get(), nullptr, 0, nullptr, nullptr);
}
if (ok)
{
for (const std::wstring& link_name : hardlink_paths)
{
std::unique_ptr<wchar_t[]> write_temp_path;
do
{
write_temp_path = to_wchar(fs::generate_neighboring_path(m_dest, 0));
// Generate a temporary hard linke
if (CreateHardLinkW(wdest.get(), write_temp_path.get(), nullptr))
{
if (MoveFileExW(write_temp_path.get(), link_name.data(), MOVEFILE_REPLACE_EXISTING))
{
// Success
write_temp_path.reset();
break;
}
break;
}
}
while (fs::g_tls_error == fs::error::exist); // Only retry if failed due to existing file
if (write_temp_path)
{
// Failure
g_tls_error = to_error(GetLastError());
return false;
}
}
// Disable the destructor
m_path.clear();
return true;

View File

@ -601,6 +601,8 @@ namespace fs
// Temporary directory
const std::string& get_temp_dir();
std::string generate_neighboring_path(std::string_view source, u64 seed);
// Unique pending file creation destined to be renamed to the destination file
struct pending_file
{