diff options
Diffstat (limited to 'tools/llvm-objcopy/Buffer.cpp')
-rw-r--r-- | tools/llvm-objcopy/Buffer.cpp | 50 |
1 files changed, 39 insertions, 11 deletions
diff --git a/tools/llvm-objcopy/Buffer.cpp b/tools/llvm-objcopy/Buffer.cpp index 8044b023aaad..06b2a20a762f 100644 --- a/tools/llvm-objcopy/Buffer.cpp +++ b/tools/llvm-objcopy/Buffer.cpp @@ -1,16 +1,16 @@ //===- Buffer.cpp ---------------------------------------------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "Buffer.h" -#include "llvm-objcopy.h" #include "llvm/Support/FileOutputBuffer.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Process.h" #include <memory> namespace llvm { @@ -18,23 +18,51 @@ namespace objcopy { Buffer::~Buffer() {} -void FileBuffer::allocate(size_t Size) { +static Error createEmptyFile(StringRef FileName) { + // Create an empty tempfile and atomically swap it in place with the desired + // output file. + Expected<sys::fs::TempFile> Temp = + sys::fs::TempFile::create(FileName + ".temp-empty-%%%%%%%"); + return Temp ? Temp->keep(FileName) : Temp.takeError(); +} + +Error FileBuffer::allocate(size_t Size) { + // When a 0-sized file is requested, skip allocation but defer file + // creation/truncation until commit() to avoid side effects if something + // happens between allocate() and commit(). + if (Size == 0) { + EmptyFile = true; + return Error::success(); + } + Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr = FileOutputBuffer::create(getName(), Size, FileOutputBuffer::F_executable); - handleAllErrors(BufferOrErr.takeError(), [this](const ErrorInfoBase &E) { - error("failed to open " + getName() + ": " + E.message()); - }); + // FileOutputBuffer::create() returns an Error that is just a wrapper around + // std::error_code. Wrap it in FileError to include the actual filename. + if (!BufferOrErr) + return createFileError(getName(), BufferOrErr.takeError()); Buf = std::move(*BufferOrErr); + return Error::success(); } -Error FileBuffer::commit() { return Buf->commit(); } +Error FileBuffer::commit() { + if (EmptyFile) + return createEmptyFile(getName()); + + assert(Buf && "allocate() not called before commit()!"); + Error Err = Buf->commit(); + // FileOutputBuffer::commit() returns an Error that is just a wrapper around + // std::error_code. Wrap it in FileError to include the actual filename. + return Err ? createFileError(getName(), std::move(Err)) : std::move(Err); +} uint8_t *FileBuffer::getBufferStart() { return reinterpret_cast<uint8_t *>(Buf->getBufferStart()); } -void MemBuffer::allocate(size_t Size) { +Error MemBuffer::allocate(size_t Size) { Buf = WritableMemoryBuffer::getNewMemBuffer(Size, getName()); + return Error::success(); } Error MemBuffer::commit() { return Error::success(); } |