-MemoryBuffer *MemoryBuffer::getFile(const char *Filename, std::string *ErrStr,
- int64_t FileSize) {
- int OpenFlags = O_RDONLY;
-#ifdef O_BINARY
- OpenFlags |= O_BINARY; // Open input file in binary mode on win32.
-#endif
- int FD = ::open(Filename, OpenFlags);
- if (FD == -1) {
- if (ErrStr) *ErrStr = sys::StrError();
- return 0;
- }
- FileCloser FC(FD); // Close FD on return.
-
+static ErrorOr<std::unique_ptr<MemoryBuffer>>
+getFileAux(const char *Filename, int64_t FileSize, bool RequiresNullTerminator,
+ bool IsVolatileSize);
+
+ErrorOr<std::unique_ptr<MemoryBuffer>>
+MemoryBuffer::getFile(Twine Filename, 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(), FileSize, RequiresNullTerminator,
+ IsVolatileSize);
+}
+
+static ErrorOr<std::unique_ptr<MemoryBuffer>>
+getOpenFileImpl(int FD, const char *Filename, uint64_t FileSize,
+ uint64_t MapSize, int64_t Offset, bool RequiresNullTerminator,
+ bool IsVolatileSize);
+
+static ErrorOr<std::unique_ptr<MemoryBuffer>>
+getFileAux(const char *Filename, int64_t FileSize, bool RequiresNullTerminator,
+ bool IsVolatileSize) {
+ int FD;
+ std::error_code EC = sys::fs::openFileForRead(Filename, FD);
+ if (EC)
+ return EC;
+
+ ErrorOr<std::unique_ptr<MemoryBuffer>> Ret =
+ getOpenFileImpl(FD, Filename, 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)
+ return true;
+
+