blob: 7af9d912edaef65475a6a84a2c206a2637992345 [file] [log] [blame]
Alexander Shaposhnikov3d4c4ac2018-10-16 05:40:18 +00001//===- Buffer.cpp ---------------------------------------------------------===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
Alexander Shaposhnikov3d4c4ac2018-10-16 05:40:18 +00006//
7//===----------------------------------------------------------------------===//
8
9#include "Buffer.h"
10#include "llvm-objcopy.h"
11#include "llvm/Support/FileOutputBuffer.h"
Jordan Rupprechtb2702d62019-01-28 15:02:40 +000012#include "llvm/Support/FileSystem.h"
Alexander Shaposhnikov3d4c4ac2018-10-16 05:40:18 +000013#include "llvm/Support/MemoryBuffer.h"
Jordan Rupprechtb2702d62019-01-28 15:02:40 +000014#include "llvm/Support/Process.h"
Alexander Shaposhnikov3d4c4ac2018-10-16 05:40:18 +000015#include <memory>
16
17namespace llvm {
18namespace objcopy {
19
20Buffer::~Buffer() {}
21
Jordan Rupprechtb2702d62019-01-28 15:02:40 +000022static Error createEmptyFile(StringRef FileName) {
23 // Create an empty tempfile and atomically swap it in place with the desired
24 // output file.
25 Expected<sys::fs::TempFile> Temp =
26 sys::fs::TempFile::create(FileName + ".temp-empty-%%%%%%%");
27 return Temp ? Temp->keep(FileName) : Temp.takeError();
28}
29
Jordan Rupprecht881cae72019-01-22 23:49:16 +000030Error FileBuffer::allocate(size_t Size) {
Jordan Rupprechtb2702d62019-01-28 15:02:40 +000031 // When a 0-sized file is requested, skip allocation but defer file
32 // creation/truncation until commit() to avoid side effects if something
33 // happens between allocate() and commit().
34 if (Size == 0) {
35 EmptyFile = true;
36 return Error::success();
37 }
38
Alexander Shaposhnikov3d4c4ac2018-10-16 05:40:18 +000039 Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
40 FileOutputBuffer::create(getName(), Size, FileOutputBuffer::F_executable);
Jordan Rupprecht881cae72019-01-22 23:49:16 +000041 // FileOutputBuffer::create() returns an Error that is just a wrapper around
42 // std::error_code. Wrap it in FileError to include the actual filename.
43 if (!BufferOrErr)
44 return createFileError(getName(), BufferOrErr.takeError());
Alexander Shaposhnikov3d4c4ac2018-10-16 05:40:18 +000045 Buf = std::move(*BufferOrErr);
Jordan Rupprecht881cae72019-01-22 23:49:16 +000046 return Error::success();
Alexander Shaposhnikov3d4c4ac2018-10-16 05:40:18 +000047}
48
Jordan Rupprecht881cae72019-01-22 23:49:16 +000049Error FileBuffer::commit() {
Jordan Rupprechtb2702d62019-01-28 15:02:40 +000050 if (EmptyFile)
51 return createEmptyFile(getName());
52
53 assert(Buf && "allocate() not called before commit()!");
Jordan Rupprecht881cae72019-01-22 23:49:16 +000054 Error Err = Buf->commit();
55 // FileOutputBuffer::commit() returns an Error that is just a wrapper around
56 // std::error_code. Wrap it in FileError to include the actual filename.
57 return Err ? createFileError(getName(), std::move(Err)) : std::move(Err);
58}
Alexander Shaposhnikov3d4c4ac2018-10-16 05:40:18 +000059
60uint8_t *FileBuffer::getBufferStart() {
61 return reinterpret_cast<uint8_t *>(Buf->getBufferStart());
62}
63
Jordan Rupprecht881cae72019-01-22 23:49:16 +000064Error MemBuffer::allocate(size_t Size) {
Alexander Shaposhnikov3d4c4ac2018-10-16 05:40:18 +000065 Buf = WritableMemoryBuffer::getNewMemBuffer(Size, getName());
Jordan Rupprecht881cae72019-01-22 23:49:16 +000066 return Error::success();
Alexander Shaposhnikov3d4c4ac2018-10-16 05:40:18 +000067}
68
69Error MemBuffer::commit() { return Error::success(); }
70
71uint8_t *MemBuffer::getBufferStart() {
72 return reinterpret_cast<uint8_t *>(Buf->getBufferStart());
73}
74
75std::unique_ptr<WritableMemoryBuffer> MemBuffer::releaseMemoryBuffer() {
76 return std::move(Buf);
77}
78
79} // end namespace objcopy
80} // end namespace llvm