From: Jan Korous Date: Fri, 13 Sep 2019 20:08:27 +0000 (+0000) Subject: [Support] Add overload writeFileAtomically(std::function Writer) X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=b64af0b5e20e3646b3b304724878fa2489b8a931;p=llvm [Support] Add overload writeFileAtomically(std::function Writer) Differential Revision: https://reviews.llvm.org/D67424 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@371890 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/llvm/Support/FileUtilities.h b/include/llvm/Support/FileUtilities.h index 715ed80d537..04efdced32a 100644 --- a/include/llvm/Support/FileUtilities.h +++ b/include/llvm/Support/FileUtilities.h @@ -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 { + 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 Writer); } // End llvm namespace #endif diff --git a/lib/LTO/ThinLTOCodeGenerator.cpp b/lib/LTO/ThinLTOCodeGenerator.cpp index 02c0d41d132..db3ca90d905 100644 --- a/lib/LTO/ThinLTOCodeGenerator.cpp +++ b/lib/LTO/ThinLTOCodeGenerator.cpp @@ -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"; - report_fatal_error("ThinLTO: Can't get a temporary file"); - } - { - raw_fd_ostream OS(TempFD, /* ShouldClose */ true); - OS << OutputBuffer.getBuffer(); + + 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"); + } + })) { + // 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); } }; diff --git a/lib/Support/FileUtilities.cpp b/lib/Support/FileUtilities.cpp index b933692d92e..d11fbb54dc0 100644 --- a/lib/Support/FileUtilities.cpp +++ b/lib/Support/FileUtilities.cpp @@ -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 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( + 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( + 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( + atomic_write_error::failed_to_rename_temp_file); } + RemoveTmpFileOnFail.releaseFile(); return Error::success(); } + +char llvm::AtomicFileWriteError::ID;