summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Support/FileOutputBuffer.cpp
diff options
context:
space:
mode:
authorZachary Turner <zturner@google.com>2018-06-28 18:49:09 +0000
committerZachary Turner <zturner@google.com>2018-06-28 18:49:09 +0000
commit1adca7c4a5119fb79757a5a9635c9e01ec996ced (patch)
treee1f12ba1e6575501af5af7abccb1e285e08aad3d /llvm/lib/Support/FileOutputBuffer.cpp
parentc09b5e31d778ad6cb96b5cbc8d1153e5b9b23cf8 (diff)
downloadbcm5719-llvm-1adca7c4a5119fb79757a5a9635c9e01ec996ced.tar.gz
bcm5719-llvm-1adca7c4a5119fb79757a5a9635c9e01ec996ced.zip
Add a flag to FileOutputBuffer that allows modification.
FileOutputBuffer creates a temp file and on commit atomically renames the temp file to the destination file. Sometimes we want to modify an existing file in place, but still have the atomicity guarantee. To do this we can initialize the contents of the temp file from the destination file (if it exists), that way the resulting FileOutputBuffer can have only selective bytes modified. Committing will then atomically replace the destination file as desired. llvm-svn: 335902
Diffstat (limited to 'llvm/lib/Support/FileOutputBuffer.cpp')
-rw-r--r--llvm/lib/Support/FileOutputBuffer.cpp37
1 files changed, 26 insertions, 11 deletions
diff --git a/llvm/lib/Support/FileOutputBuffer.cpp b/llvm/lib/Support/FileOutputBuffer.cpp
index de555388866..1214b5a0ba1 100644
--- a/llvm/lib/Support/FileOutputBuffer.cpp
+++ b/llvm/lib/Support/FileOutputBuffer.cpp
@@ -110,24 +110,30 @@ createInMemoryBuffer(StringRef Path, size_t Size, unsigned Mode) {
}
static Expected<std::unique_ptr<OnDiskBuffer>>
-createOnDiskBuffer(StringRef Path, size_t Size, unsigned Mode) {
+createOnDiskBuffer(StringRef Path, size_t Size, bool InitExisting,
+ unsigned Mode) {
Expected<fs::TempFile> FileOrErr =
fs::TempFile::create(Path + ".tmp%%%%%%%", Mode);
if (!FileOrErr)
return FileOrErr.takeError();
fs::TempFile File = std::move(*FileOrErr);
+ if (InitExisting) {
+ if (auto EC = sys::fs::copy_file(Path, File.FD))
+ return errorCodeToError(EC);
+ } else {
#ifndef _WIN32
- // On Windows, CreateFileMapping (the mmap function on Windows)
- // automatically extends the underlying file. We don't need to
- // extend the file beforehand. _chsize (ftruncate on Windows) is
- // pretty slow just like it writes specified amount of bytes,
- // so we should avoid calling that function.
- if (auto EC = fs::resize_file(File.FD, Size)) {
- consumeError(File.discard());
- return errorCodeToError(EC);
- }
+ // On Windows, CreateFileMapping (the mmap function on Windows)
+ // automatically extends the underlying file. We don't need to
+ // extend the file beforehand. _chsize (ftruncate on Windows) is
+ // pretty slow just like it writes specified amount of bytes,
+ // so we should avoid calling that function.
+ if (auto EC = fs::resize_file(File.FD, Size)) {
+ consumeError(File.discard());
+ return errorCodeToError(EC);
+ }
#endif
+ }
// Mmap it.
std::error_code EC;
@@ -151,6 +157,15 @@ FileOutputBuffer::create(StringRef Path, size_t Size, unsigned Flags) {
fs::file_status Stat;
fs::status(Path, Stat);
+ if ((Flags & F_modify) && Size == size_t(-1)) {
+ if (Stat.type() == fs::file_type::regular_file)
+ Size = Stat.getSize();
+ else if (Stat.type() == fs::file_type::file_not_found)
+ return errorCodeToError(errc::no_such_file_or_directory);
+ else
+ return errorCodeToError(errc::invalid_argument);
+ }
+
// Usually, we want to create OnDiskBuffer to create a temporary file in
// the same directory as the destination file and atomically replaces it
// by rename(2).
@@ -165,7 +180,7 @@ FileOutputBuffer::create(StringRef Path, size_t Size, unsigned Flags) {
case fs::file_type::regular_file:
case fs::file_type::file_not_found:
case fs::file_type::status_error:
- return createOnDiskBuffer(Path, Size, Mode);
+ return createOnDiskBuffer(Path, Size, !!(Flags & F_modify), Mode);
default:
return createInMemoryBuffer(Path, Size, Mode);
}
OpenPOWER on IntegriCloud