1 | //===--- MemoryBuffer.cpp - Memory Buffer implementation ------------------===// |
2 | // |
3 | // 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 |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // This file implements the MemoryBuffer interface. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include "llvm/Support/MemoryBuffer.h" |
14 | #include "llvm/ADT/STLExtras.h" |
15 | #include "llvm/ADT/SmallString.h" |
16 | #include "llvm/Config/config.h" |
17 | #include "llvm/Support/Alignment.h" |
18 | #include "llvm/Support/Errc.h" |
19 | #include "llvm/Support/Error.h" |
20 | #include "llvm/Support/ErrorHandling.h" |
21 | #include "llvm/Support/FileSystem.h" |
22 | #include "llvm/Support/MathExtras.h" |
23 | #include "llvm/Support/Process.h" |
24 | #include "llvm/Support/Program.h" |
25 | #include "llvm/Support/SmallVectorMemoryBuffer.h" |
26 | #include <algorithm> |
27 | #include <cassert> |
28 | #include <cstring> |
29 | #include <new> |
30 | #include <sys/types.h> |
31 | #include <system_error> |
32 | #if !defined(_MSC_VER) && !defined(__MINGW32__) |
33 | #include <unistd.h> |
34 | #else |
35 | #include <io.h> |
36 | #endif |
37 | |
38 | #ifdef __MVS__ |
39 | #include "llvm/Support/AutoConvert.h" |
40 | #endif |
41 | using namespace llvm; |
42 | |
43 | //===----------------------------------------------------------------------===// |
44 | // MemoryBuffer implementation itself. |
45 | //===----------------------------------------------------------------------===// |
46 | |
47 | MemoryBuffer::~MemoryBuffer() = default; |
48 | |
49 | /// init - Initialize this MemoryBuffer as a reference to externally allocated |
50 | /// memory, memory that we know is already null terminated. |
51 | void MemoryBuffer::init(const char *BufStart, const char *BufEnd, |
52 | bool RequiresNullTerminator) { |
53 | assert((!RequiresNullTerminator || BufEnd[0] == 0) && |
54 | "Buffer is not null terminated!" ); |
55 | BufferStart = BufStart; |
56 | BufferEnd = BufEnd; |
57 | } |
58 | |
59 | //===----------------------------------------------------------------------===// |
60 | // MemoryBufferMem implementation. |
61 | //===----------------------------------------------------------------------===// |
62 | |
63 | /// CopyStringRef - Copies contents of a StringRef into a block of memory and |
64 | /// null-terminates it. |
65 | static void CopyStringRef(char *Memory, StringRef Data) { |
66 | if (!Data.empty()) |
67 | memcpy(dest: Memory, src: Data.data(), n: Data.size()); |
68 | Memory[Data.size()] = 0; // Null terminate string. |
69 | } |
70 | |
71 | namespace { |
72 | struct NamedBufferAlloc { |
73 | const Twine &Name; |
74 | NamedBufferAlloc(const Twine &Name) : Name(Name) {} |
75 | }; |
76 | } // namespace |
77 | |
78 | void *operator new(size_t N, const NamedBufferAlloc &Alloc) { |
79 | SmallString<256> NameBuf; |
80 | StringRef NameRef = Alloc.Name.toStringRef(Out&: NameBuf); |
81 | |
82 | char *Mem = static_cast<char *>(operator new(N + sizeof(size_t) + |
83 | NameRef.size() + 1)); |
84 | *reinterpret_cast<size_t *>(Mem + N) = NameRef.size(); |
85 | CopyStringRef(Memory: Mem + N + sizeof(size_t), Data: NameRef); |
86 | return Mem; |
87 | } |
88 | |
89 | namespace { |
90 | /// MemoryBufferMem - Named MemoryBuffer pointing to a block of memory. |
91 | template<typename MB> |
92 | class MemoryBufferMem : public MB { |
93 | public: |
94 | MemoryBufferMem(StringRef InputData, bool RequiresNullTerminator) { |
95 | MemoryBuffer::init(BufStart: InputData.begin(), BufEnd: InputData.end(), |
96 | RequiresNullTerminator); |
97 | } |
98 | |
99 | /// Disable sized deallocation for MemoryBufferMem, because it has |
100 | /// tail-allocated data. |
101 | void operator delete(void *p) { ::operator delete(p); } |
102 | |
103 | StringRef getBufferIdentifier() const override { |
104 | // The name is stored after the class itself. |
105 | return StringRef(reinterpret_cast<const char *>(this + 1) + sizeof(size_t), |
106 | *reinterpret_cast<const size_t *>(this + 1)); |
107 | } |
108 | |
109 | MemoryBuffer::BufferKind getBufferKind() const override { |
110 | return MemoryBuffer::MemoryBuffer_Malloc; |
111 | } |
112 | }; |
113 | } // namespace |
114 | |
115 | template <typename MB> |
116 | static ErrorOr<std::unique_ptr<MB>> |
117 | getFileAux(const Twine &Filename, uint64_t MapSize, uint64_t Offset, |
118 | bool IsText, bool RequiresNullTerminator, bool IsVolatile, |
119 | std::optional<Align> Alignment); |
120 | |
121 | std::unique_ptr<MemoryBuffer> |
122 | MemoryBuffer::getMemBuffer(StringRef InputData, StringRef BufferName, |
123 | bool RequiresNullTerminator) { |
124 | auto *Ret = new (NamedBufferAlloc(BufferName)) |
125 | MemoryBufferMem<MemoryBuffer>(InputData, RequiresNullTerminator); |
126 | return std::unique_ptr<MemoryBuffer>(Ret); |
127 | } |
128 | |
129 | std::unique_ptr<MemoryBuffer> |
130 | MemoryBuffer::getMemBuffer(MemoryBufferRef Ref, bool RequiresNullTerminator) { |
131 | return std::unique_ptr<MemoryBuffer>(getMemBuffer( |
132 | InputData: Ref.getBuffer(), BufferName: Ref.getBufferIdentifier(), RequiresNullTerminator)); |
133 | } |
134 | |
135 | static ErrorOr<std::unique_ptr<WritableMemoryBuffer>> |
136 | getMemBufferCopyImpl(StringRef InputData, const Twine &BufferName) { |
137 | auto Buf = |
138 | WritableMemoryBuffer::getNewUninitMemBuffer(Size: InputData.size(), BufferName); |
139 | if (!Buf) |
140 | return make_error_code(E: errc::not_enough_memory); |
141 | // Calling memcpy with null src/dst is UB, and an empty StringRef is |
142 | // represented with {nullptr, 0}. |
143 | llvm::copy(Range&: InputData, Out: Buf->getBufferStart()); |
144 | return std::move(Buf); |
145 | } |
146 | |
147 | std::unique_ptr<MemoryBuffer> |
148 | MemoryBuffer::getMemBufferCopy(StringRef InputData, const Twine &BufferName) { |
149 | auto Buf = getMemBufferCopyImpl(InputData, BufferName); |
150 | if (Buf) |
151 | return std::move(*Buf); |
152 | return nullptr; |
153 | } |
154 | |
155 | ErrorOr<std::unique_ptr<MemoryBuffer>> |
156 | MemoryBuffer::getFileOrSTDIN(const Twine &Filename, bool IsText, |
157 | bool RequiresNullTerminator, |
158 | std::optional<Align> Alignment) { |
159 | SmallString<256> NameBuf; |
160 | StringRef NameRef = Filename.toStringRef(Out&: NameBuf); |
161 | |
162 | if (NameRef == "-" ) |
163 | return getSTDIN(); |
164 | return getFile(Filename, IsText, RequiresNullTerminator, |
165 | /*IsVolatile=*/false, Alignment); |
166 | } |
167 | |
168 | ErrorOr<std::unique_ptr<MemoryBuffer>> |
169 | MemoryBuffer::getFileSlice(const Twine &FilePath, uint64_t MapSize, |
170 | uint64_t Offset, bool IsVolatile, |
171 | std::optional<Align> Alignment) { |
172 | return getFileAux<MemoryBuffer>(Filename: FilePath, MapSize, Offset, /*IsText=*/false, |
173 | /*RequiresNullTerminator=*/false, IsVolatile, |
174 | Alignment); |
175 | } |
176 | |
177 | //===----------------------------------------------------------------------===// |
178 | // MemoryBuffer::getFile implementation. |
179 | //===----------------------------------------------------------------------===// |
180 | |
181 | namespace { |
182 | |
183 | template <typename MB> |
184 | constexpr sys::fs::mapped_file_region::mapmode Mapmode = |
185 | sys::fs::mapped_file_region::readonly; |
186 | template <> |
187 | constexpr sys::fs::mapped_file_region::mapmode Mapmode<MemoryBuffer> = |
188 | sys::fs::mapped_file_region::readonly; |
189 | template <> |
190 | constexpr sys::fs::mapped_file_region::mapmode Mapmode<WritableMemoryBuffer> = |
191 | sys::fs::mapped_file_region::priv; |
192 | template <> |
193 | constexpr sys::fs::mapped_file_region::mapmode |
194 | Mapmode<WriteThroughMemoryBuffer> = sys::fs::mapped_file_region::readwrite; |
195 | |
196 | /// Memory maps a file descriptor using sys::fs::mapped_file_region. |
197 | /// |
198 | /// This handles converting the offset into a legal offset on the platform. |
199 | template<typename MB> |
200 | class MemoryBufferMMapFile : public MB { |
201 | sys::fs::mapped_file_region MFR; |
202 | |
203 | static uint64_t getLegalMapOffset(uint64_t Offset) { |
204 | return Offset & ~(sys::fs::mapped_file_region::alignment() - 1); |
205 | } |
206 | |
207 | static uint64_t getLegalMapSize(uint64_t Len, uint64_t Offset) { |
208 | return Len + (Offset - getLegalMapOffset(Offset)); |
209 | } |
210 | |
211 | const char *getStart(uint64_t Len, uint64_t Offset) { |
212 | return MFR.const_data() + (Offset - getLegalMapOffset(Offset)); |
213 | } |
214 | |
215 | public: |
216 | MemoryBufferMMapFile(bool RequiresNullTerminator, sys::fs::file_t FD, uint64_t Len, |
217 | uint64_t Offset, std::error_code &EC) |
218 | : MFR(FD, Mapmode<MB>, getLegalMapSize(Len, Offset), |
219 | getLegalMapOffset(Offset), EC) { |
220 | if (!EC) { |
221 | const char *Start = getStart(Len, Offset); |
222 | MemoryBuffer::init(BufStart: Start, BufEnd: Start + Len, RequiresNullTerminator); |
223 | } |
224 | } |
225 | |
226 | /// Disable sized deallocation for MemoryBufferMMapFile, because it has |
227 | /// tail-allocated data. |
228 | void operator delete(void *p) { ::operator delete(p); } |
229 | |
230 | StringRef getBufferIdentifier() const override { |
231 | // The name is stored after the class itself. |
232 | return StringRef(reinterpret_cast<const char *>(this + 1) + sizeof(size_t), |
233 | *reinterpret_cast<const size_t *>(this + 1)); |
234 | } |
235 | |
236 | MemoryBuffer::BufferKind getBufferKind() const override { |
237 | return MemoryBuffer::MemoryBuffer_MMap; |
238 | } |
239 | |
240 | void dontNeedIfMmap() override { MFR.dontNeed(); } |
241 | }; |
242 | } // namespace |
243 | |
244 | static ErrorOr<std::unique_ptr<WritableMemoryBuffer>> |
245 | getMemoryBufferForStream(sys::fs::file_t FD, const Twine &BufferName) { |
246 | SmallString<sys::fs::DefaultReadChunkSize> Buffer; |
247 | if (Error E = sys::fs::readNativeFileToEOF(FileHandle: FD, Buffer)) |
248 | return errorToErrorCode(Err: std::move(E)); |
249 | return getMemBufferCopyImpl(InputData: Buffer, BufferName); |
250 | } |
251 | |
252 | ErrorOr<std::unique_ptr<MemoryBuffer>> |
253 | MemoryBuffer::getFile(const Twine &Filename, bool IsText, |
254 | bool RequiresNullTerminator, bool IsVolatile, |
255 | std::optional<Align> Alignment) { |
256 | return getFileAux<MemoryBuffer>(Filename, /*MapSize=*/-1, /*Offset=*/0, |
257 | IsText, RequiresNullTerminator, IsVolatile, |
258 | Alignment); |
259 | } |
260 | |
261 | template <typename MB> |
262 | static ErrorOr<std::unique_ptr<MB>> |
263 | getOpenFileImpl(sys::fs::file_t FD, const Twine &Filename, uint64_t FileSize, |
264 | uint64_t MapSize, int64_t Offset, bool RequiresNullTerminator, |
265 | bool IsVolatile, std::optional<Align> Alignment); |
266 | |
267 | template <typename MB> |
268 | static ErrorOr<std::unique_ptr<MB>> |
269 | getFileAux(const Twine &Filename, uint64_t MapSize, uint64_t Offset, |
270 | bool IsText, bool RequiresNullTerminator, bool IsVolatile, |
271 | std::optional<Align> Alignment) { |
272 | Expected<sys::fs::file_t> FDOrErr = sys::fs::openNativeFileForRead( |
273 | Name: Filename, Flags: IsText ? sys::fs::OF_TextWithCRLF : sys::fs::OF_None); |
274 | if (!FDOrErr) |
275 | return errorToErrorCode(Err: FDOrErr.takeError()); |
276 | sys::fs::file_t FD = *FDOrErr; |
277 | auto Ret = getOpenFileImpl<MB>(FD, Filename, /*FileSize=*/-1, MapSize, Offset, |
278 | RequiresNullTerminator, IsVolatile, Alignment); |
279 | sys::fs::closeFile(F&: FD); |
280 | return Ret; |
281 | } |
282 | |
283 | ErrorOr<std::unique_ptr<WritableMemoryBuffer>> |
284 | WritableMemoryBuffer::getFile(const Twine &Filename, bool IsVolatile, |
285 | std::optional<Align> Alignment) { |
286 | return getFileAux<WritableMemoryBuffer>( |
287 | Filename, /*MapSize=*/-1, /*Offset=*/0, /*IsText=*/false, |
288 | /*RequiresNullTerminator=*/false, IsVolatile, Alignment); |
289 | } |
290 | |
291 | ErrorOr<std::unique_ptr<WritableMemoryBuffer>> |
292 | WritableMemoryBuffer::getFileSlice(const Twine &Filename, uint64_t MapSize, |
293 | uint64_t Offset, bool IsVolatile, |
294 | std::optional<Align> Alignment) { |
295 | return getFileAux<WritableMemoryBuffer>( |
296 | Filename, MapSize, Offset, /*IsText=*/false, |
297 | /*RequiresNullTerminator=*/false, IsVolatile, Alignment); |
298 | } |
299 | |
300 | std::unique_ptr<WritableMemoryBuffer> |
301 | WritableMemoryBuffer::getNewUninitMemBuffer(size_t Size, |
302 | const Twine &BufferName, |
303 | std::optional<Align> Alignment) { |
304 | using MemBuffer = MemoryBufferMem<WritableMemoryBuffer>; |
305 | |
306 | // Use 16-byte alignment if no alignment is specified. |
307 | Align BufAlign = Alignment.value_or(u: Align(16)); |
308 | |
309 | // Allocate space for the MemoryBuffer, the data and the name. It is important |
310 | // that MemoryBuffer and data are aligned so PointerIntPair works with them. |
311 | SmallString<256> NameBuf; |
312 | StringRef NameRef = BufferName.toStringRef(Out&: NameBuf); |
313 | |
314 | size_t StringLen = sizeof(MemBuffer) + sizeof(size_t) + NameRef.size() + 1; |
315 | size_t RealLen = StringLen + Size + 1 + BufAlign.value(); |
316 | if (RealLen <= Size) // Check for rollover. |
317 | return nullptr; |
318 | char *Mem = static_cast<char*>(operator new(RealLen, std::nothrow)); |
319 | if (!Mem) |
320 | return nullptr; |
321 | |
322 | // The name is stored after the class itself. |
323 | *reinterpret_cast<size_t *>(Mem + sizeof(MemBuffer)) = NameRef.size(); |
324 | CopyStringRef(Memory: Mem + sizeof(MemBuffer) + sizeof(size_t), Data: NameRef); |
325 | |
326 | // The buffer begins after the name and must be aligned. |
327 | char *Buf = (char *)alignAddr(Addr: Mem + StringLen, Alignment: BufAlign); |
328 | Buf[Size] = 0; // Null terminate buffer. |
329 | |
330 | auto *Ret = new (Mem) MemBuffer(StringRef(Buf, Size), true); |
331 | return std::unique_ptr<WritableMemoryBuffer>(Ret); |
332 | } |
333 | |
334 | std::unique_ptr<WritableMemoryBuffer> |
335 | WritableMemoryBuffer::getNewMemBuffer(size_t Size, const Twine &BufferName) { |
336 | auto SB = WritableMemoryBuffer::getNewUninitMemBuffer(Size, BufferName); |
337 | if (!SB) |
338 | return nullptr; |
339 | memset(s: SB->getBufferStart(), c: 0, n: Size); |
340 | return SB; |
341 | } |
342 | |
343 | static bool shouldUseMmap(sys::fs::file_t FD, |
344 | size_t FileSize, |
345 | size_t MapSize, |
346 | off_t Offset, |
347 | bool RequiresNullTerminator, |
348 | int PageSize, |
349 | bool IsVolatile) { |
350 | // mmap may leave the buffer without null terminator if the file size changed |
351 | // by the time the last page is mapped in, so avoid it if the file size is |
352 | // likely to change. |
353 | if (IsVolatile && RequiresNullTerminator) |
354 | return false; |
355 | |
356 | // We don't use mmap for small files because this can severely fragment our |
357 | // address space. |
358 | if (MapSize < 4 * 4096 || MapSize < (unsigned)PageSize) |
359 | return false; |
360 | |
361 | if (!RequiresNullTerminator) |
362 | return true; |
363 | |
364 | // If we don't know the file size, use fstat to find out. fstat on an open |
365 | // file descriptor is cheaper than stat on a random path. |
366 | // FIXME: this chunk of code is duplicated, but it avoids a fstat when |
367 | // RequiresNullTerminator = false and MapSize != -1. |
368 | if (FileSize == size_t(-1)) { |
369 | sys::fs::file_status Status; |
370 | if (sys::fs::status(FD, Result&: Status)) |
371 | return false; |
372 | FileSize = Status.getSize(); |
373 | } |
374 | |
375 | // If we need a null terminator and the end of the map is inside the file, |
376 | // we cannot use mmap. |
377 | size_t End = Offset + MapSize; |
378 | assert(End <= FileSize); |
379 | if (End != FileSize) |
380 | return false; |
381 | |
382 | // Don't try to map files that are exactly a multiple of the system page size |
383 | // if we need a null terminator. |
384 | if ((FileSize & (PageSize -1)) == 0) |
385 | return false; |
386 | |
387 | #if defined(__CYGWIN__) |
388 | // Don't try to map files that are exactly a multiple of the physical page size |
389 | // if we need a null terminator. |
390 | // FIXME: We should reorganize again getPageSize() on Win32. |
391 | if ((FileSize & (4096 - 1)) == 0) |
392 | return false; |
393 | #endif |
394 | |
395 | return true; |
396 | } |
397 | |
398 | static ErrorOr<std::unique_ptr<WriteThroughMemoryBuffer>> |
399 | getReadWriteFile(const Twine &Filename, uint64_t FileSize, uint64_t MapSize, |
400 | uint64_t Offset) { |
401 | Expected<sys::fs::file_t> FDOrErr = sys::fs::openNativeFileForReadWrite( |
402 | Name: Filename, Disp: sys::fs::CD_OpenExisting, Flags: sys::fs::OF_None); |
403 | if (!FDOrErr) |
404 | return errorToErrorCode(Err: FDOrErr.takeError()); |
405 | sys::fs::file_t FD = *FDOrErr; |
406 | |
407 | // Default is to map the full file. |
408 | if (MapSize == uint64_t(-1)) { |
409 | // If we don't know the file size, use fstat to find out. fstat on an open |
410 | // file descriptor is cheaper than stat on a random path. |
411 | if (FileSize == uint64_t(-1)) { |
412 | sys::fs::file_status Status; |
413 | std::error_code EC = sys::fs::status(FD, Result&: Status); |
414 | if (EC) |
415 | return EC; |
416 | |
417 | // If this not a file or a block device (e.g. it's a named pipe |
418 | // or character device), we can't mmap it, so error out. |
419 | sys::fs::file_type Type = Status.type(); |
420 | if (Type != sys::fs::file_type::regular_file && |
421 | Type != sys::fs::file_type::block_file) |
422 | return make_error_code(E: errc::invalid_argument); |
423 | |
424 | FileSize = Status.getSize(); |
425 | } |
426 | MapSize = FileSize; |
427 | } |
428 | |
429 | std::error_code EC; |
430 | std::unique_ptr<WriteThroughMemoryBuffer> Result( |
431 | new (NamedBufferAlloc(Filename)) |
432 | MemoryBufferMMapFile<WriteThroughMemoryBuffer>(false, FD, MapSize, |
433 | Offset, EC)); |
434 | if (EC) |
435 | return EC; |
436 | return std::move(Result); |
437 | } |
438 | |
439 | ErrorOr<std::unique_ptr<WriteThroughMemoryBuffer>> |
440 | WriteThroughMemoryBuffer::getFile(const Twine &Filename, int64_t FileSize) { |
441 | return getReadWriteFile(Filename, FileSize, MapSize: FileSize, Offset: 0); |
442 | } |
443 | |
444 | /// Map a subrange of the specified file as a WritableMemoryBuffer. |
445 | ErrorOr<std::unique_ptr<WriteThroughMemoryBuffer>> |
446 | WriteThroughMemoryBuffer::getFileSlice(const Twine &Filename, uint64_t MapSize, |
447 | uint64_t Offset) { |
448 | return getReadWriteFile(Filename, FileSize: -1, MapSize, Offset); |
449 | } |
450 | |
451 | template <typename MB> |
452 | static ErrorOr<std::unique_ptr<MB>> |
453 | getOpenFileImpl(sys::fs::file_t FD, const Twine &Filename, uint64_t FileSize, |
454 | uint64_t MapSize, int64_t Offset, bool RequiresNullTerminator, |
455 | bool IsVolatile, std::optional<Align> Alignment) { |
456 | static int PageSize = sys::Process::getPageSizeEstimate(); |
457 | |
458 | // Default is to map the full file. |
459 | if (MapSize == uint64_t(-1)) { |
460 | // If we don't know the file size, use fstat to find out. fstat on an open |
461 | // file descriptor is cheaper than stat on a random path. |
462 | if (FileSize == uint64_t(-1)) { |
463 | sys::fs::file_status Status; |
464 | std::error_code EC = sys::fs::status(FD, Result&: Status); |
465 | if (EC) |
466 | return EC; |
467 | |
468 | // If this not a file or a block device (e.g. it's a named pipe |
469 | // or character device), we can't trust the size. Create the memory |
470 | // buffer by copying off the stream. |
471 | sys::fs::file_type Type = Status.type(); |
472 | if (Type != sys::fs::file_type::regular_file && |
473 | Type != sys::fs::file_type::block_file) |
474 | return getMemoryBufferForStream(FD, BufferName: Filename); |
475 | |
476 | FileSize = Status.getSize(); |
477 | } |
478 | MapSize = FileSize; |
479 | } |
480 | |
481 | if (shouldUseMmap(FD, FileSize, MapSize, Offset, RequiresNullTerminator, |
482 | PageSize, IsVolatile)) { |
483 | std::error_code EC; |
484 | std::unique_ptr<MB> Result( |
485 | new (NamedBufferAlloc(Filename)) MemoryBufferMMapFile<MB>( |
486 | RequiresNullTerminator, FD, MapSize, Offset, EC)); |
487 | if (!EC) |
488 | return std::move(Result); |
489 | } |
490 | |
491 | #ifdef __MVS__ |
492 | // Set codepage auto-conversion for z/OS. |
493 | if (auto EC = llvm::enableAutoConversion(FD)) |
494 | return EC; |
495 | #endif |
496 | |
497 | auto Buf = |
498 | WritableMemoryBuffer::getNewUninitMemBuffer(Size: MapSize, BufferName: Filename, Alignment); |
499 | if (!Buf) { |
500 | // Failed to create a buffer. The only way it can fail is if |
501 | // new(std::nothrow) returns 0. |
502 | return make_error_code(E: errc::not_enough_memory); |
503 | } |
504 | |
505 | // Read until EOF, zero-initialize the rest. |
506 | MutableArrayRef<char> ToRead = Buf->getBuffer(); |
507 | while (!ToRead.empty()) { |
508 | Expected<size_t> ReadBytes = |
509 | sys::fs::readNativeFileSlice(FileHandle: FD, Buf: ToRead, Offset); |
510 | if (!ReadBytes) |
511 | return errorToErrorCode(Err: ReadBytes.takeError()); |
512 | if (*ReadBytes == 0) { |
513 | std::memset(s: ToRead.data(), c: 0, n: ToRead.size()); |
514 | break; |
515 | } |
516 | ToRead = ToRead.drop_front(N: *ReadBytes); |
517 | Offset += *ReadBytes; |
518 | } |
519 | |
520 | return std::move(Buf); |
521 | } |
522 | |
523 | ErrorOr<std::unique_ptr<MemoryBuffer>> |
524 | MemoryBuffer::getOpenFile(sys::fs::file_t FD, const Twine &Filename, |
525 | uint64_t FileSize, bool RequiresNullTerminator, |
526 | bool IsVolatile, std::optional<Align> Alignment) { |
527 | return getOpenFileImpl<MemoryBuffer>(FD, Filename, FileSize, MapSize: FileSize, Offset: 0, |
528 | RequiresNullTerminator, IsVolatile, |
529 | Alignment); |
530 | } |
531 | |
532 | ErrorOr<std::unique_ptr<MemoryBuffer>> MemoryBuffer::getOpenFileSlice( |
533 | sys::fs::file_t FD, const Twine &Filename, uint64_t MapSize, int64_t Offset, |
534 | bool IsVolatile, std::optional<Align> Alignment) { |
535 | assert(MapSize != uint64_t(-1)); |
536 | return getOpenFileImpl<MemoryBuffer>(FD, Filename, FileSize: -1, MapSize, Offset, RequiresNullTerminator: false, |
537 | IsVolatile, Alignment); |
538 | } |
539 | |
540 | ErrorOr<std::unique_ptr<MemoryBuffer>> MemoryBuffer::getSTDIN() { |
541 | // Read in all of the data from stdin, we cannot mmap stdin. |
542 | // |
543 | // FIXME: That isn't necessarily true, we should try to mmap stdin and |
544 | // fallback if it fails. |
545 | sys::ChangeStdinMode(Flags: sys::fs::OF_Text); |
546 | |
547 | return getMemoryBufferForStream(FD: sys::fs::getStdinHandle(), BufferName: "<stdin>" ); |
548 | } |
549 | |
550 | ErrorOr<std::unique_ptr<MemoryBuffer>> |
551 | MemoryBuffer::getFileAsStream(const Twine &Filename) { |
552 | Expected<sys::fs::file_t> FDOrErr = |
553 | sys::fs::openNativeFileForRead(Name: Filename, Flags: sys::fs::OF_None); |
554 | if (!FDOrErr) |
555 | return errorToErrorCode(Err: FDOrErr.takeError()); |
556 | sys::fs::file_t FD = *FDOrErr; |
557 | ErrorOr<std::unique_ptr<MemoryBuffer>> Ret = |
558 | getMemoryBufferForStream(FD, BufferName: Filename); |
559 | sys::fs::closeFile(F&: FD); |
560 | return Ret; |
561 | } |
562 | |
563 | MemoryBufferRef MemoryBuffer::getMemBufferRef() const { |
564 | StringRef Data = getBuffer(); |
565 | StringRef Identifier = getBufferIdentifier(); |
566 | return MemoryBufferRef(Data, Identifier); |
567 | } |
568 | |
569 | SmallVectorMemoryBuffer::~SmallVectorMemoryBuffer() = default; |
570 | |