+static error_code getMemoryBufferForStream(int FD,
+ StringRef BufferName,
+ std::unique_ptr<MemoryBuffer> &Result) {
+ const ssize_t ChunkSize = 4096*4;
+ SmallString<ChunkSize> Buffer;
+ ssize_t ReadBytes;
+ // Read into Buffer until we hit EOF.
+ do {
+ Buffer.reserve(Buffer.size() + ChunkSize);
+ ReadBytes = read(FD, Buffer.end(), ChunkSize);
+ if (ReadBytes == -1) {
+ if (errno == EINTR) continue;
+ return error_code(errno, std::generic_category());
+ }
+ Buffer.set_size(Buffer.size() + ReadBytes);
+ } while (ReadBytes != 0);
+
+ Result.reset(MemoryBuffer::getMemBufferCopy(Buffer, BufferName));
+ return error_code();
+}
+
+static error_code getFileAux(const char *Filename,
+ std::unique_ptr<MemoryBuffer> &Result,
+ int64_t FileSize,
+ bool RequiresNullTerminator,
+ bool IsVolatileSize);
+
+error_code MemoryBuffer::getFile(Twine Filename,
+ std::unique_ptr<MemoryBuffer> &Result,
+ int64_t FileSize,
+ bool RequiresNullTerminator,
+ bool IsVolatileSize) {
+ // Ensure the path is null terminated.
+ SmallString<256> PathBuf;
+ StringRef NullTerminatedName = Filename.toNullTerminatedStringRef(PathBuf);
+ return getFileAux(NullTerminatedName.data(), Result, FileSize,
+ RequiresNullTerminator, IsVolatileSize);
+}
+
+static error_code getOpenFileImpl(int FD, const char *Filename,
+ std::unique_ptr<MemoryBuffer> &Result,
+ uint64_t FileSize, uint64_t MapSize,
+ int64_t Offset, bool RequiresNullTerminator,
+ bool IsVolatileSize);
+
+static error_code getFileAux(const char *Filename,
+ std::unique_ptr<MemoryBuffer> &Result, int64_t FileSize,
+ bool RequiresNullTerminator,
+ bool IsVolatileSize) {
+ int FD;
+ error_code EC = sys::fs::openFileForRead(Filename, FD);
+ if (EC)
+ return EC;
+
+ error_code ret = getOpenFileImpl(FD, Filename, Result, FileSize, FileSize, 0,
+ RequiresNullTerminator, IsVolatileSize);
+ close(FD);
+ return ret;
+}
+
+static bool shouldUseMmap(int FD,
+ size_t FileSize,
+ size_t MapSize,
+ off_t Offset,
+ bool RequiresNullTerminator,
+ int PageSize,
+ bool IsVolatileSize) {
+ // mmap may leave the buffer without null terminator if the file size changed
+ // by the time the last page is mapped in, so avoid it if the file size is
+ // likely to change.
+ if (IsVolatileSize)
+ return false;
+
+ // We don't use mmap for small files because this can severely fragment our
+ // address space.
+ if (MapSize < 4 * 4096 || MapSize < (unsigned)PageSize)
+ return false;
+
+ if (!RequiresNullTerminator)