1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2025-01-31 20:51:52 +01:00

[Support] Add overload writeFileAtomically(std::function Writer)

Differential Revision: https://reviews.llvm.org/D67424

llvm-svn: 371890
This commit is contained in:
Jan Korous 2019-09-13 20:08:27 +00:00
parent bdeb54a918
commit f726c5e75f
3 changed files with 96 additions and 30 deletions

View File

@ -16,6 +16,7 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Errc.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
@ -75,10 +76,40 @@ namespace llvm {
void releaseFile() { DeleteIt = false; }
};
enum class atomic_write_error {
failed_to_create_uniq_file = 0,
output_stream_error,
failed_to_rename_temp_file
};
class AtomicFileWriteError : public llvm::ErrorInfo<AtomicFileWriteError> {
public:
AtomicFileWriteError(atomic_write_error Error) : Error(Error) {}
void log(raw_ostream &OS) const override;
const atomic_write_error Error;
static char ID;
private:
// Users are not expected to use error_code.
std::error_code convertToErrorCode() const override {
return llvm::inconvertibleErrorCode();
}
};
// atomic_write_error + whatever the Writer can return
/// Creates a unique file with name according to the given \p TempPathModel,
/// writes content of \p Buffer to the file and renames it to \p FinalPath.
///
/// \returns \c AtomicFileWriteError in case of error.
llvm::Error writeFileAtomically(StringRef TempPathModel, StringRef FinalPath,
StringRef Buffer);
llvm::Error
writeFileAtomically(StringRef TempPathModel, StringRef FinalPath,
std::function<llvm::Error(llvm::raw_ostream &)> Writer);
} // End llvm namespace
#endif

View File

@ -39,6 +39,7 @@
#include "llvm/Support/CachePruning.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/FileUtilities.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/SHA1.h"
#include "llvm/Support/SmallVectorMemoryBuffer.h"
@ -368,23 +369,26 @@ public:
// Write to a temporary to avoid race condition
SmallString<128> TempFilename;
SmallString<128> CachePath(EntryPath);
int TempFD;
llvm::sys::path::remove_filename(CachePath);
sys::path::append(TempFilename, CachePath, "Thin-%%%%%%.tmp.o");
std::error_code EC =
sys::fs::createUniqueFile(TempFilename, TempFD, TempFilename);
if (EC) {
errs() << "Error: " << EC.message() << "\n";
if (auto Err = handleErrors(
llvm::writeFileAtomically(TempFilename, EntryPath,
OutputBuffer.getBuffer()),
[](const llvm::AtomicFileWriteError &E) {
std::string ErrorMsgBuffer;
llvm::raw_string_ostream S(ErrorMsgBuffer);
E.log(S);
if (E.Error ==
llvm::atomic_write_error::failed_to_create_uniq_file) {
errs() << "Error: " << ErrorMsgBuffer << "\n";
report_fatal_error("ThinLTO: Can't get a temporary file");
}
{
raw_fd_ostream OS(TempFD, /* ShouldClose */ true);
OS << OutputBuffer.getBuffer();
})) {
// FIXME
consumeError(std::move(Err));
}
// Rename temp file to final destination; rename is atomic
EC = sys::fs::rename(TempFilename, EntryPath);
if (EC)
sys::fs::remove(TempFilename);
}
};

View File

@ -12,7 +12,9 @@
//===----------------------------------------------------------------------===//
#include "llvm/Support/FileUtilities.h"
#include "llvm/ADT/ScopeExit.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/ErrorOr.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
@ -266,36 +268,65 @@ int llvm::DiffFilesWithTolerance(StringRef NameA,
return CompareFailed;
}
Error llvm::writeFileAtomically(StringRef TempPathModel, StringRef FinalPath,
StringRef Buffer) {
void llvm::AtomicFileWriteError::log(raw_ostream &OS) const {
OS << "atomic_write_error: ";
switch (Error) {
case atomic_write_error::failed_to_create_uniq_file:
OS << "failed_to_create_uniq_file";
return;
case atomic_write_error::output_stream_error:
OS << "output_stream_error";
return;
case atomic_write_error::failed_to_rename_temp_file:
OS << "failed_to_rename_temp_file";
return;
}
llvm_unreachable("unknown atomic_write_error value in "
"failed_to_rename_temp_file::log()");
}
llvm::Error llvm::writeFileAtomically(StringRef TempPathModel,
StringRef FinalPath, StringRef Buffer) {
return writeFileAtomically(TempPathModel, FinalPath,
[&Buffer](llvm::raw_ostream &OS) {
OS.write(Buffer.data(), Buffer.size());
return llvm::Error::success();
});
}
llvm::Error llvm::writeFileAtomically(
StringRef TempPathModel, StringRef FinalPath,
std::function<llvm::Error(llvm::raw_ostream &)> Writer) {
SmallString<128> GeneratedUniqPath;
int TempFD;
if (const std::error_code Error = sys::fs::createUniqueFile(
TempPathModel.str(), TempFD, GeneratedUniqPath)) {
return createStringError(
Error, "failed to create temporary file with model \"%s\"",
TempPathModel.str().c_str());
if (sys::fs::createUniqueFile(TempPathModel.str(), TempFD,
GeneratedUniqPath)) {
return llvm::make_error<AtomicFileWriteError>(
atomic_write_error::failed_to_create_uniq_file);
}
llvm::FileRemover RemoveTmpFileOnFail(GeneratedUniqPath);
raw_fd_ostream OS(TempFD, /*shouldClose=*/true);
OS.write(Buffer.data(), Buffer.size());
OS.close();
TempFD = -1;
if (llvm::Error Err = Writer(OS)) {
return Err;
}
OS.close();
if (OS.has_error()) {
const std::error_code Error = OS.error();
OS.clear_error();
return createStringError(Error, "failed to write to \"%s\"",
GeneratedUniqPath.c_str());
return llvm::make_error<AtomicFileWriteError>(
atomic_write_error::output_stream_error);
}
if (const std::error_code Error =
sys::fs::rename(/*from=*/GeneratedUniqPath.c_str(),
/*to=*/FinalPath.str().c_str())) {
return createStringError(Error, "failed to rename file \"%s\" to \"%s\"",
GeneratedUniqPath.c_str(),
FinalPath.str().c_str());
return llvm::make_error<AtomicFileWriteError>(
atomic_write_error::failed_to_rename_temp_file);
}
RemoveTmpFileOnFail.releaseFile();
return Error::success();
}
char llvm::AtomicFileWriteError::ID;