Index: clangd/index/BackgroundIndexStorage.cpp =================================================================== --- clangd/index/BackgroundIndexStorage.cpp +++ clangd/index/BackgroundIndexStorage.cpp @@ -9,6 +9,8 @@ #include "Logger.h" #include "index/Background.h" +#include "llvm/ADT/ScopeExit.h" +#include "llvm/Support/Error.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" @@ -33,6 +35,34 @@ return ShardRootSS.str(); } +llvm::Error +writeAtomically(llvm::StringRef OutPath, + llvm::function_ref 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 { @@ -70,14 +100,9 @@ llvm::Error storeShard(llvm::StringRef ShardIdentifier, IndexFileOut Shard) const override { - auto ShardPath = getShardPathFromFilePath(DiskShardRoot, ShardIdentifier); - std::error_code EC; - llvm::raw_fd_ostream OS(ShardPath, EC); - if (EC) - return llvm::errorCodeToError(EC); - OS << Shard; - OS.close(); - return llvm::errorCodeToError(OS.error()); + return writeAtomically( + getShardPathFromFilePath(DiskShardRoot, ShardIdentifier), + [&Shard](llvm::raw_ostream &OS) { OS << Shard; }); } };