forked from OSchip/llvm-project
[Support] Add overload writeFileAtomically(std::function Writer)
Differential Revision: https://reviews.llvm.org/D67424 llvm-svn: 371890
This commit is contained in:
parent
c6ffefd2d1
commit
f69c91780f
|
@ -18,6 +18,7 @@
|
|||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include "llvm/Support/FileSystem.h"
|
||||
#include "llvm/Support/FileUtilities.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
#include <functional>
|
||||
|
@ -35,34 +36,6 @@ std::string getShardPathFromFilePath(llvm::StringRef ShardRoot,
|
|||
return ShardRootSS.str();
|
||||
}
|
||||
|
||||
llvm::Error
|
||||
writeAtomically(llvm::StringRef OutPath,
|
||||
llvm::function_ref<void(llvm::raw_ostream &)> Writer) {
|
||||
// Write to a temporary file first.
|
||||
llvm::SmallString<128> TempPath;
|
||||
int FD;
|
||||
auto EC =
|
||||
llvm::sys::fs::createUniqueFile(OutPath + ".tmp.%%%%%%%%", FD, TempPath);
|
||||
if (EC)
|
||||
return llvm::errorCodeToError(EC);
|
||||
// Make sure temp file is destroyed on failure.
|
||||
auto RemoveOnFail =
|
||||
llvm::make_scope_exit([TempPath] { llvm::sys::fs::remove(TempPath); });
|
||||
llvm::raw_fd_ostream OS(FD, /*shouldClose=*/true);
|
||||
Writer(OS);
|
||||
OS.close();
|
||||
if (OS.has_error())
|
||||
return llvm::errorCodeToError(OS.error());
|
||||
// Then move to real location.
|
||||
EC = llvm::sys::fs::rename(TempPath, OutPath);
|
||||
if (EC)
|
||||
return llvm::errorCodeToError(EC);
|
||||
// If everything went well, we already moved the file to another name. So
|
||||
// don't delete the file, as the name might be taken by another file.
|
||||
RemoveOnFail.release();
|
||||
return llvm::ErrorSuccess();
|
||||
}
|
||||
|
||||
// Uses disk as a storage for index shards. Creates a directory called
|
||||
// ".clangd/index/" under the path provided during construction.
|
||||
class DiskBackedIndexStorage : public BackgroundIndexStorage {
|
||||
|
@ -100,9 +73,12 @@ public:
|
|||
|
||||
llvm::Error storeShard(llvm::StringRef ShardIdentifier,
|
||||
IndexFileOut Shard) const override {
|
||||
return writeAtomically(
|
||||
getShardPathFromFilePath(DiskShardRoot, ShardIdentifier),
|
||||
[&Shard](llvm::raw_ostream &OS) { OS << Shard; });
|
||||
auto ShardPath = getShardPathFromFilePath(DiskShardRoot, ShardIdentifier);
|
||||
return llvm::writeFileAtomically(ShardPath + ".tmp.%%%%%%%%", ShardPath,
|
||||
[&Shard](llvm::raw_ostream &OS) {
|
||||
OS << Shard;
|
||||
return llvm::Error::success();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -84,6 +84,7 @@
|
|||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/ErrorOr.h"
|
||||
#include "llvm/Support/FileSystem.h"
|
||||
#include "llvm/Support/FileUtilities.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "llvm/Support/Timer.h"
|
||||
#include "llvm/Support/VirtualFileSystem.h"
|
||||
|
@ -2301,26 +2302,19 @@ bool ASTUnit::Save(StringRef File) {
|
|||
SmallString<128> TempPath;
|
||||
TempPath = File;
|
||||
TempPath += "-%%%%%%%%";
|
||||
int fd;
|
||||
if (llvm::sys::fs::createUniqueFile(TempPath, fd, TempPath))
|
||||
return true;
|
||||
|
||||
// FIXME: Can we somehow regenerate the stat cache here, or do we need to
|
||||
// unconditionally create a stat cache when we parse the file?
|
||||
llvm::raw_fd_ostream Out(fd, /*shouldClose=*/true);
|
||||
|
||||
serialize(Out);
|
||||
Out.close();
|
||||
if (Out.has_error()) {
|
||||
Out.clear_error();
|
||||
if (llvm::Error Err = llvm::writeFileAtomically(
|
||||
TempPath, File, [this](llvm::raw_ostream &Out) {
|
||||
return serialize(Out) ? llvm::make_error<llvm::StringError>(
|
||||
"ASTUnit serialization failed",
|
||||
llvm::inconvertibleErrorCode())
|
||||
: llvm::Error::success();
|
||||
})) {
|
||||
consumeError(std::move(Err));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (llvm::sys::fs::rename(TempPath, File)) {
|
||||
llvm::sys::fs::remove(TempPath);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
|
||||
#include "ASTReaderInternals.h"
|
||||
#include "clang/Basic/FileManager.h"
|
||||
#include "clang/Lex/HeaderSearch.h"
|
||||
|
@ -21,10 +20,12 @@
|
|||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/MapVector.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Bitstream/BitstreamReader.h"
|
||||
#include "llvm/Bitstream/BitstreamWriter.h"
|
||||
#include "llvm/Support/DJB.h"
|
||||
#include "llvm/Support/FileSystem.h"
|
||||
#include "llvm/Support/FileUtilities.h"
|
||||
#include "llvm/Support/LockFileManager.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "llvm/Support/OnDiskHashTable.h"
|
||||
|
@ -912,37 +913,9 @@ GlobalModuleIndex::writeIndex(FileManager &FileMgr,
|
|||
"failed writing index");
|
||||
}
|
||||
|
||||
// Write the global index file to a temporary file.
|
||||
llvm::SmallString<128> IndexTmpPath;
|
||||
int TmpFD;
|
||||
if (llvm::sys::fs::createUniqueFile(IndexPath + "-%%%%%%%%", TmpFD,
|
||||
IndexTmpPath))
|
||||
return llvm::createStringError(std::errc::io_error,
|
||||
"failed creating unique file");
|
||||
|
||||
// Open the temporary global index file for output.
|
||||
llvm::raw_fd_ostream Out(TmpFD, true);
|
||||
if (Out.has_error())
|
||||
return llvm::createStringError(Out.error(), "failed outputting to stream");
|
||||
|
||||
// Write the index.
|
||||
Out.write(OutputBuffer.data(), OutputBuffer.size());
|
||||
Out.close();
|
||||
if (Out.has_error())
|
||||
return llvm::createStringError(Out.error(), "failed writing to stream");
|
||||
|
||||
// Remove the old index file. It isn't relevant any more.
|
||||
llvm::sys::fs::remove(IndexPath);
|
||||
|
||||
// Rename the newly-written index file to the proper name.
|
||||
if (std::error_code Err = llvm::sys::fs::rename(IndexTmpPath, IndexPath)) {
|
||||
// Remove the file on failure, don't check whether removal succeeded.
|
||||
llvm::sys::fs::remove(IndexTmpPath);
|
||||
return llvm::createStringError(Err, "failed renaming file \"%s\" to \"%s\"",
|
||||
IndexTmpPath.c_str(), IndexPath.c_str());
|
||||
}
|
||||
|
||||
return llvm::Error::success();
|
||||
return llvm::writeFileAtomically(
|
||||
(IndexPath + "-%%%%%%%%").str(), IndexPath,
|
||||
llvm::StringRef(OutputBuffer.data(), OutputBuffer.size()));
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
#include "llvm/Support/FileSystem.h"
|
||||
#include "llvm/Support/FileUtilities.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
#include "Acceptor.h"
|
||||
#include "LLDBServerUtilities.h"
|
||||
|
@ -103,29 +104,34 @@ static Status save_socket_id_to_file(const std::string &socket_id,
|
|||
|
||||
llvm::SmallString<64> temp_file_path;
|
||||
temp_file_spec.AppendPathComponent("port-file.%%%%%%");
|
||||
int FD;
|
||||
auto err_code = llvm::sys::fs::createUniqueFile(temp_file_spec.GetPath(), FD,
|
||||
temp_file_path);
|
||||
if (err_code)
|
||||
return Status("Failed to create temp file: %s", err_code.message().c_str());
|
||||
|
||||
llvm::FileRemover tmp_file_remover(temp_file_path);
|
||||
Status status;
|
||||
if (auto Err =
|
||||
handleErrors(llvm::writeFileAtomically(
|
||||
temp_file_path, temp_file_spec.GetPath(), socket_id),
|
||||
[&status, &temp_file_path,
|
||||
&file_spec](const AtomicFileWriteError &E) {
|
||||
std::string ErrorMsgBuffer;
|
||||
llvm::raw_string_ostream S(ErrorMsgBuffer);
|
||||
E.log(S);
|
||||
|
||||
{
|
||||
llvm::raw_fd_ostream temp_file(FD, true);
|
||||
temp_file << socket_id;
|
||||
temp_file.close();
|
||||
if (temp_file.has_error())
|
||||
return Status("Failed to write to port file.");
|
||||
switch (E.Error) {
|
||||
case atomic_write_error::failed_to_create_uniq_file:
|
||||
status = Status("Failed to create temp file: %s",
|
||||
ErrorMsgBuffer.c_str());
|
||||
case atomic_write_error::output_stream_error:
|
||||
status = Status("Failed to write to port file.");
|
||||
case atomic_write_error::failed_to_rename_temp_file:
|
||||
status = Status("Failed to rename file %s to %s: %s",
|
||||
ErrorMsgBuffer.c_str(),
|
||||
file_spec.GetPath().c_str(),
|
||||
ErrorMsgBuffer.c_str());
|
||||
}
|
||||
})) {
|
||||
return Status("Failed to atomically write file %s",
|
||||
file_spec.GetPath().c_str());
|
||||
}
|
||||
|
||||
err_code = llvm::sys::fs::rename(temp_file_path, file_spec.GetPath());
|
||||
if (err_code)
|
||||
return Status("Failed to rename file %s to %s: %s", temp_file_path.c_str(),
|
||||
file_spec.GetPath().c_str(), err_code.message().c_str());
|
||||
|
||||
tmp_file_remover.releaseFile();
|
||||
return Status();
|
||||
return status;
|
||||
}
|
||||
|
||||
// main
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
|
||||
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));
|
||||
}
|
||||
{
|
||||
raw_fd_ostream OS(TempFD, /* ShouldClose */ true);
|
||||
OS << OutputBuffer.getBuffer();
|
||||
}
|
||||
// Rename temp file to final destination; rename is atomic
|
||||
EC = sys::fs::rename(TempFilename, EntryPath);
|
||||
if (EC)
|
||||
sys::fs::remove(TempFilename);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue