diff options
author | Zachary Turner <zturner@google.com> | 2018-03-08 20:34:47 +0000 |
---|---|---|
committer | Zachary Turner <zturner@google.com> | 2018-03-08 20:34:47 +0000 |
commit | adad33011f3f5511e5959362fc33003e1e378eb6 (patch) | |
tree | e27f8cb286ddea20f07e6d589f2a8e55c72f0eec /llvm/lib/Support/MemoryBuffer.cpp | |
parent | 373c38a2db3787b60a5d2588922e8b8eac389d17 (diff) | |
download | bcm5719-llvm-adad33011f3f5511e5959362fc33003e1e378eb6.tar.gz bcm5719-llvm-adad33011f3f5511e5959362fc33003e1e378eb6.zip |
[Support] Add WriteThroughMemoryBuffer.
This is like MemoryBuffer (read-only) and WritableMemoryBuffer
(writable private), but where the underlying file can be modified
after writing. This is useful when you want to open a file, make
some targeted edits, and then write it back out.
Differential Revision: https://reviews.llvm.org/D44230
llvm-svn: 327057
Diffstat (limited to 'llvm/lib/Support/MemoryBuffer.cpp')
-rw-r--r-- | llvm/lib/Support/MemoryBuffer.cpp | 59 |
1 files changed, 55 insertions, 4 deletions
diff --git a/llvm/lib/Support/MemoryBuffer.cpp b/llvm/lib/Support/MemoryBuffer.cpp index 9cea9a28107..9f9987b8e6e 100644 --- a/llvm/lib/Support/MemoryBuffer.cpp +++ b/llvm/lib/Support/MemoryBuffer.cpp @@ -184,10 +184,8 @@ class MemoryBufferMMapFile : public MB { public: MemoryBufferMMapFile(bool RequiresNullTerminator, int FD, uint64_t Len, uint64_t Offset, std::error_code &EC) - : MFR(FD, - MB::Writable ? sys::fs::mapped_file_region::priv - : sys::fs::mapped_file_region::readonly, - getLegalMapSize(Len, Offset), getLegalMapOffset(Offset), EC) { + : MFR(FD, MB::Mapmode, getLegalMapSize(Len, Offset), + getLegalMapOffset(Offset), EC) { if (!EC) { const char *Start = getStart(Len, Offset); MemoryBuffer::init(Start, Start + Len, RequiresNullTerminator); @@ -361,6 +359,59 @@ static bool shouldUseMmap(int FD, return true; } +static ErrorOr<std::unique_ptr<WriteThroughMemoryBuffer>> +getReadWriteFile(const Twine &Filename, int64_t FileSize, uint64_t MapSize, + uint64_t Offset) { + int FD; + std::error_code EC = sys::fs::openFileForWrite( + Filename, FD, sys::fs::F_RW | sys::fs::F_NoTrunc); + + if (EC) + return EC; + + // Default is to map the full file. + if (MapSize == uint64_t(-1)) { + // If we don't know the file size, use fstat to find out. fstat on an open + // file descriptor is cheaper than stat on a random path. + if (FileSize == uint64_t(-1)) { + sys::fs::file_status Status; + std::error_code EC = sys::fs::status(FD, Status); + if (EC) + return EC; + + // If this not a file or a block device (e.g. it's a named pipe + // or character device), we can't mmap it, so error out. + sys::fs::file_type Type = Status.type(); + if (Type != sys::fs::file_type::regular_file && + Type != sys::fs::file_type::block_file) + return make_error_code(errc::invalid_argument); + + FileSize = Status.getSize(); + } + MapSize = FileSize; + } + + std::unique_ptr<WriteThroughMemoryBuffer> Result( + new (NamedBufferAlloc(Filename)) + MemoryBufferMMapFile<WriteThroughMemoryBuffer>(false, FD, MapSize, + Offset, EC)); + if (EC) + return EC; + return std::move(Result); +} + +ErrorOr<std::unique_ptr<WriteThroughMemoryBuffer>> +WriteThroughMemoryBuffer::getFile(const Twine &Filename, int64_t FileSize) { + return getReadWriteFile(Filename, FileSize, FileSize, 0); +} + +/// Map a subrange of the specified file as a WritableMemoryBuffer. +ErrorOr<std::unique_ptr<WriteThroughMemoryBuffer>> +WriteThroughMemoryBuffer::getFileSlice(const Twine &Filename, uint64_t MapSize, + uint64_t Offset) { + return getReadWriteFile(Filename, -1, MapSize, Offset); +} + template <typename MB> static ErrorOr<std::unique_ptr<MB>> getOpenFileImpl(int FD, const Twine &Filename, uint64_t FileSize, |