|
|
|
@ -1176,23 +1176,49 @@ void FileSystem::AtomicRenamedFileDeleter::operator()(std::FILE* fp)
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
Error error;
|
|
|
|
Error error;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// final filename empty => discarded.
|
|
|
|
|
|
|
|
if (!m_final_filename.empty())
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if (!commit(fp, &error))
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
ERROR_LOG("Failed to commit temporary file '{}', discarding. Error was {}.", Path::GetFileName(m_temp_filename),
|
|
|
|
|
|
|
|
error.GetDescription());
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// we're discarding the file, don't care if it fails.
|
|
|
|
|
|
|
|
std::fclose(fp);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!DeleteFile(m_temp_filename.c_str(), &error))
|
|
|
|
|
|
|
|
ERROR_LOG("Failed to delete temporary file '{}': {}", Path::GetFileName(m_temp_filename), error.GetDescription());
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool FileSystem::AtomicRenamedFileDeleter::commit(std::FILE* fp, Error* error)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if (!fp) [[unlikely]]
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
Error::SetStringView(error, "File pointer is null.");
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (std::fclose(fp) != 0)
|
|
|
|
if (std::fclose(fp) != 0)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
error.SetErrno(errno);
|
|
|
|
Error::SetErrno(error, "fclose() failed: ", errno);
|
|
|
|
ERROR_LOG("Failed to close temporary file '{}', discarding.", Path::GetFileName(m_temp_filename));
|
|
|
|
|
|
|
|
m_final_filename.clear();
|
|
|
|
m_final_filename.clear();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// final filename empty => discarded.
|
|
|
|
// Should not have been discarded.
|
|
|
|
if (m_final_filename.empty())
|
|
|
|
if (!m_final_filename.empty())
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (!DeleteFile(m_temp_filename.c_str(), &error))
|
|
|
|
return RenamePath(m_temp_filename.c_str(), m_final_filename.c_str(), error);
|
|
|
|
ERROR_LOG("Failed to delete temporary file '{}': {}", Path::GetFileName(m_temp_filename), error.GetDescription());
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
else
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (!RenamePath(m_temp_filename.c_str(), m_final_filename.c_str(), &error))
|
|
|
|
Error::SetStringView(error, "File has already been discarded.");
|
|
|
|
ERROR_LOG("Failed to rename temporary file '{}': {}", Path::GetFileName(m_temp_filename), error.GetDescription());
|
|
|
|
return DeleteFile(m_temp_filename.c_str(), error);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@ -1201,8 +1227,7 @@ void FileSystem::AtomicRenamedFileDeleter::discard()
|
|
|
|
m_final_filename = {};
|
|
|
|
m_final_filename = {};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
FileSystem::AtomicRenamedFile FileSystem::CreateAtomicRenamedFile(std::string filename, const char* mode,
|
|
|
|
FileSystem::AtomicRenamedFile FileSystem::CreateAtomicRenamedFile(std::string filename, Error* error /*= nullptr*/)
|
|
|
|
Error* error /*= nullptr*/)
|
|
|
|
|
|
|
|
{
|
|
|
|
{
|
|
|
|
std::string temp_filename;
|
|
|
|
std::string temp_filename;
|
|
|
|
std::FILE* fp = nullptr;
|
|
|
|
std::FILE* fp = nullptr;
|
|
|
|
@ -1216,14 +1241,29 @@ FileSystem::AtomicRenamedFile FileSystem::CreateAtomicRenamedFile(std::string fi
|
|
|
|
StringUtil::Strlcpy(name_buf.get() + filename_length, ".XXXXXX", name_buf_size);
|
|
|
|
StringUtil::Strlcpy(name_buf.get() + filename_length, ".XXXXXX", name_buf_size);
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
#ifdef _WIN32
|
|
|
|
_mktemp_s(name_buf.get(), name_buf_size);
|
|
|
|
const errno_t err = _mktemp_s(name_buf.get(), name_buf_size);
|
|
|
|
#elif defined(__linux__) || defined(__ANDROID__) || defined(__APPLE__)
|
|
|
|
if (err == 0)
|
|
|
|
mkstemp(name_buf.get());
|
|
|
|
fp = OpenCFile(name_buf.get(), "w+b", error);
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
Error::SetErrno(error, "_mktemp_s() failed: ", err);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#elif defined(__linux__) || defined(__ANDROID__) || defined(__APPLE__) || defined(__FreeBSD__)
|
|
|
|
|
|
|
|
const int fd = mkstemp(name_buf.get());
|
|
|
|
|
|
|
|
if (fd >= 0)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
fp = fdopen(fd, "w+b");
|
|
|
|
|
|
|
|
if (!fp)
|
|
|
|
|
|
|
|
Error::SetErrno(error, "fdopen() failed: ", errno);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
Error::SetErrno(error, "mkstemp() failed: ", errno);
|
|
|
|
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
#else
|
|
|
|
mktemp(name_buf.get());
|
|
|
|
mktemp(name_buf.get());
|
|
|
|
|
|
|
|
fp = OpenCFile(name_buf.get(), "w+b", error);
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
fp = OpenCFile(name_buf.get(), mode, error);
|
|
|
|
|
|
|
|
if (fp)
|
|
|
|
if (fp)
|
|
|
|
temp_filename.assign(name_buf.get(), name_buf_size - 1);
|
|
|
|
temp_filename.assign(name_buf.get(), name_buf_size - 1);
|
|
|
|
else
|
|
|
|
else
|
|
|
|
@ -1236,7 +1276,7 @@ FileSystem::AtomicRenamedFile FileSystem::CreateAtomicRenamedFile(std::string fi
|
|
|
|
bool FileSystem::WriteAtomicRenamedFile(std::string filename, const void* data, size_t data_length,
|
|
|
|
bool FileSystem::WriteAtomicRenamedFile(std::string filename, const void* data, size_t data_length,
|
|
|
|
Error* error /*= nullptr*/)
|
|
|
|
Error* error /*= nullptr*/)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
AtomicRenamedFile fp = CreateAtomicRenamedFile(std::move(filename), "wb", error);
|
|
|
|
AtomicRenamedFile fp = CreateAtomicRenamedFile(std::move(filename), error);
|
|
|
|
if (!fp)
|
|
|
|
if (!fp)
|
|
|
|
return false;
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
|
|
@ -1255,6 +1295,15 @@ void FileSystem::DiscardAtomicRenamedFile(AtomicRenamedFile& file)
|
|
|
|
file.get_deleter().discard();
|
|
|
|
file.get_deleter().discard();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool FileSystem::CommitAtomicRenamedFile(AtomicRenamedFile& file, Error* error)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if (file.get_deleter().commit(file.release(), error))
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Error::AddPrefix(error, "Failed to commit file: ");
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
FileSystem::ManagedCFilePtr FileSystem::OpenManagedCFile(const char* filename, const char* mode, Error* error)
|
|
|
|
FileSystem::ManagedCFilePtr FileSystem::OpenManagedCFile(const char* filename, const char* mode, Error* error)
|
|
|
|
|