xref: /openbsd-src/gnu/llvm/lldb/source/Host/common/File.cpp (revision be691f3bb6417f04a68938fadbcaee2d5795e764)
1dda28197Spatrick //===-- File.cpp ----------------------------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick 
9061da546Spatrick #include "lldb/Host/File.h"
10061da546Spatrick 
11*be691f3bSpatrick #include <cerrno>
12*be691f3bSpatrick #include <climits>
13*be691f3bSpatrick #include <cstdarg>
14*be691f3bSpatrick #include <cstdio>
15061da546Spatrick #include <fcntl.h>
16061da546Spatrick 
17061da546Spatrick #ifdef _WIN32
18061da546Spatrick #include "lldb/Host/windows/windows.h"
19061da546Spatrick #else
20061da546Spatrick #include <sys/ioctl.h>
21061da546Spatrick #include <sys/stat.h>
22061da546Spatrick #include <termios.h>
23061da546Spatrick #include <unistd.h>
24061da546Spatrick #endif
25061da546Spatrick 
26061da546Spatrick #include "llvm/Support/ConvertUTF.h"
27061da546Spatrick #include "llvm/Support/Errno.h"
28061da546Spatrick #include "llvm/Support/FileSystem.h"
29061da546Spatrick #include "llvm/Support/Process.h"
30061da546Spatrick 
31061da546Spatrick #include "lldb/Host/Config.h"
32061da546Spatrick #include "lldb/Host/FileSystem.h"
33061da546Spatrick #include "lldb/Host/Host.h"
34061da546Spatrick #include "lldb/Utility/DataBufferHeap.h"
35061da546Spatrick #include "lldb/Utility/FileSpec.h"
36061da546Spatrick #include "lldb/Utility/Log.h"
37061da546Spatrick 
38061da546Spatrick using namespace lldb;
39061da546Spatrick using namespace lldb_private;
40061da546Spatrick using llvm::Expected;
41061da546Spatrick 
42061da546Spatrick Expected<const char *>
43061da546Spatrick File::GetStreamOpenModeFromOptions(File::OpenOptions options) {
44061da546Spatrick   if (options & File::eOpenOptionAppend) {
45061da546Spatrick     if (options & File::eOpenOptionRead) {
46061da546Spatrick       if (options & File::eOpenOptionCanCreateNewOnly)
47061da546Spatrick         return "a+x";
48061da546Spatrick       else
49061da546Spatrick         return "a+";
50061da546Spatrick     } else if (options & File::eOpenOptionWrite) {
51061da546Spatrick       if (options & File::eOpenOptionCanCreateNewOnly)
52061da546Spatrick         return "ax";
53061da546Spatrick       else
54061da546Spatrick         return "a";
55061da546Spatrick     }
56061da546Spatrick   } else if (options & File::eOpenOptionRead &&
57061da546Spatrick              options & File::eOpenOptionWrite) {
58061da546Spatrick     if (options & File::eOpenOptionCanCreate) {
59061da546Spatrick       if (options & File::eOpenOptionCanCreateNewOnly)
60061da546Spatrick         return "w+x";
61061da546Spatrick       else
62061da546Spatrick         return "w+";
63061da546Spatrick     } else
64061da546Spatrick       return "r+";
65061da546Spatrick   } else if (options & File::eOpenOptionRead) {
66061da546Spatrick     return "r";
67061da546Spatrick   } else if (options & File::eOpenOptionWrite) {
68061da546Spatrick     return "w";
69061da546Spatrick   }
70061da546Spatrick   return llvm::createStringError(
71061da546Spatrick       llvm::inconvertibleErrorCode(),
72061da546Spatrick       "invalid options, cannot convert to mode string");
73061da546Spatrick }
74061da546Spatrick 
75061da546Spatrick Expected<File::OpenOptions> File::GetOptionsFromMode(llvm::StringRef mode) {
76061da546Spatrick   OpenOptions opts =
77061da546Spatrick       llvm::StringSwitch<OpenOptions>(mode)
78061da546Spatrick           .Cases("r", "rb", eOpenOptionRead)
79061da546Spatrick           .Cases("w", "wb", eOpenOptionWrite)
80061da546Spatrick           .Cases("a", "ab",
81061da546Spatrick                  eOpenOptionWrite | eOpenOptionAppend | eOpenOptionCanCreate)
82061da546Spatrick           .Cases("r+", "rb+", "r+b", eOpenOptionRead | eOpenOptionWrite)
83061da546Spatrick           .Cases("w+", "wb+", "w+b",
84061da546Spatrick                  eOpenOptionRead | eOpenOptionWrite | eOpenOptionCanCreate |
85061da546Spatrick                      eOpenOptionTruncate)
86061da546Spatrick           .Cases("a+", "ab+", "a+b",
87061da546Spatrick                  eOpenOptionRead | eOpenOptionWrite | eOpenOptionAppend |
88061da546Spatrick                      eOpenOptionCanCreate)
89061da546Spatrick           .Default(OpenOptions());
90061da546Spatrick   if (opts)
91061da546Spatrick     return opts;
92061da546Spatrick   return llvm::createStringError(
93061da546Spatrick       llvm::inconvertibleErrorCode(),
94061da546Spatrick       "invalid mode, cannot convert to File::OpenOptions");
95061da546Spatrick }
96061da546Spatrick 
97061da546Spatrick int File::kInvalidDescriptor = -1;
98061da546Spatrick FILE *File::kInvalidStream = nullptr;
99061da546Spatrick 
100061da546Spatrick Status File::Read(void *buf, size_t &num_bytes) {
101061da546Spatrick   return std::error_code(ENOTSUP, std::system_category());
102061da546Spatrick }
103061da546Spatrick Status File::Write(const void *buf, size_t &num_bytes) {
104061da546Spatrick   return std::error_code(ENOTSUP, std::system_category());
105061da546Spatrick }
106061da546Spatrick 
107061da546Spatrick bool File::IsValid() const { return false; }
108061da546Spatrick 
109061da546Spatrick Status File::Close() { return Flush(); }
110061da546Spatrick 
111061da546Spatrick IOObject::WaitableHandle File::GetWaitableHandle() {
112061da546Spatrick   return IOObject::kInvalidHandleValue;
113061da546Spatrick }
114061da546Spatrick 
115061da546Spatrick Status File::GetFileSpec(FileSpec &file_spec) const {
116061da546Spatrick   file_spec.Clear();
117061da546Spatrick   return std::error_code(ENOTSUP, std::system_category());
118061da546Spatrick }
119061da546Spatrick 
120061da546Spatrick int File::GetDescriptor() const { return kInvalidDescriptor; }
121061da546Spatrick 
122061da546Spatrick FILE *File::GetStream() { return nullptr; }
123061da546Spatrick 
124061da546Spatrick off_t File::SeekFromStart(off_t offset, Status *error_ptr) {
125061da546Spatrick   if (error_ptr)
126061da546Spatrick     *error_ptr = std::error_code(ENOTSUP, std::system_category());
127061da546Spatrick   return -1;
128061da546Spatrick }
129061da546Spatrick 
130061da546Spatrick off_t File::SeekFromCurrent(off_t offset, Status *error_ptr) {
131061da546Spatrick   if (error_ptr)
132061da546Spatrick     *error_ptr = std::error_code(ENOTSUP, std::system_category());
133061da546Spatrick   return -1;
134061da546Spatrick }
135061da546Spatrick 
136061da546Spatrick off_t File::SeekFromEnd(off_t offset, Status *error_ptr) {
137061da546Spatrick   if (error_ptr)
138061da546Spatrick     *error_ptr = std::error_code(ENOTSUP, std::system_category());
139061da546Spatrick   return -1;
140061da546Spatrick }
141061da546Spatrick 
142061da546Spatrick Status File::Read(void *dst, size_t &num_bytes, off_t &offset) {
143061da546Spatrick   return std::error_code(ENOTSUP, std::system_category());
144061da546Spatrick }
145061da546Spatrick 
146061da546Spatrick Status File::Write(const void *src, size_t &num_bytes, off_t &offset) {
147061da546Spatrick   return std::error_code(ENOTSUP, std::system_category());
148061da546Spatrick }
149061da546Spatrick 
150061da546Spatrick Status File::Flush() { return Status(); }
151061da546Spatrick 
152061da546Spatrick Status File::Sync() { return Flush(); }
153061da546Spatrick 
154061da546Spatrick void File::CalculateInteractiveAndTerminal() {
155061da546Spatrick   const int fd = GetDescriptor();
156061da546Spatrick   if (!DescriptorIsValid(fd)) {
157061da546Spatrick     m_is_interactive = eLazyBoolNo;
158061da546Spatrick     m_is_real_terminal = eLazyBoolNo;
159061da546Spatrick     m_supports_colors = eLazyBoolNo;
160061da546Spatrick     return;
161061da546Spatrick   }
162061da546Spatrick   m_is_interactive = eLazyBoolNo;
163061da546Spatrick   m_is_real_terminal = eLazyBoolNo;
164061da546Spatrick #if defined(_WIN32)
165061da546Spatrick   if (_isatty(fd)) {
166061da546Spatrick     m_is_interactive = eLazyBoolYes;
167061da546Spatrick     m_is_real_terminal = eLazyBoolYes;
168061da546Spatrick #if defined(ENABLE_VIRTUAL_TERMINAL_PROCESSING)
169061da546Spatrick     m_supports_colors = eLazyBoolYes;
170061da546Spatrick #endif
171061da546Spatrick   }
172061da546Spatrick #else
173061da546Spatrick   if (isatty(fd)) {
174061da546Spatrick     m_is_interactive = eLazyBoolYes;
175061da546Spatrick     struct winsize window_size;
176061da546Spatrick     if (::ioctl(fd, TIOCGWINSZ, &window_size) == 0) {
177061da546Spatrick       if (window_size.ws_col > 0) {
178061da546Spatrick         m_is_real_terminal = eLazyBoolYes;
179061da546Spatrick         if (llvm::sys::Process::FileDescriptorHasColors(fd))
180061da546Spatrick           m_supports_colors = eLazyBoolYes;
181061da546Spatrick       }
182061da546Spatrick     }
183061da546Spatrick   }
184061da546Spatrick #endif
185061da546Spatrick }
186061da546Spatrick 
187061da546Spatrick bool File::GetIsInteractive() {
188061da546Spatrick   if (m_is_interactive == eLazyBoolCalculate)
189061da546Spatrick     CalculateInteractiveAndTerminal();
190061da546Spatrick   return m_is_interactive == eLazyBoolYes;
191061da546Spatrick }
192061da546Spatrick 
193061da546Spatrick bool File::GetIsRealTerminal() {
194061da546Spatrick   if (m_is_real_terminal == eLazyBoolCalculate)
195061da546Spatrick     CalculateInteractiveAndTerminal();
196061da546Spatrick   return m_is_real_terminal == eLazyBoolYes;
197061da546Spatrick }
198061da546Spatrick 
199061da546Spatrick bool File::GetIsTerminalWithColors() {
200061da546Spatrick   if (m_supports_colors == eLazyBoolCalculate)
201061da546Spatrick     CalculateInteractiveAndTerminal();
202061da546Spatrick   return m_supports_colors == eLazyBoolYes;
203061da546Spatrick }
204061da546Spatrick 
205061da546Spatrick size_t File::Printf(const char *format, ...) {
206061da546Spatrick   va_list args;
207061da546Spatrick   va_start(args, format);
208061da546Spatrick   size_t result = PrintfVarArg(format, args);
209061da546Spatrick   va_end(args);
210061da546Spatrick   return result;
211061da546Spatrick }
212061da546Spatrick 
213061da546Spatrick size_t File::PrintfVarArg(const char *format, va_list args) {
214061da546Spatrick   size_t result = 0;
215061da546Spatrick   char *s = nullptr;
216061da546Spatrick   result = vasprintf(&s, format, args);
217061da546Spatrick   if (s != nullptr) {
218061da546Spatrick     if (result > 0) {
219061da546Spatrick       size_t s_len = result;
220061da546Spatrick       Write(s, s_len);
221061da546Spatrick       result = s_len;
222061da546Spatrick     }
223061da546Spatrick     free(s);
224061da546Spatrick   }
225061da546Spatrick   return result;
226061da546Spatrick }
227061da546Spatrick 
228061da546Spatrick Expected<File::OpenOptions> File::GetOptions() const {
229061da546Spatrick   return llvm::createStringError(
230061da546Spatrick       llvm::inconvertibleErrorCode(),
231061da546Spatrick       "GetOptions() not implemented for this File class");
232061da546Spatrick }
233061da546Spatrick 
234061da546Spatrick uint32_t File::GetPermissions(Status &error) const {
235061da546Spatrick   int fd = GetDescriptor();
236061da546Spatrick   if (!DescriptorIsValid(fd)) {
237061da546Spatrick     error = std::error_code(ENOTSUP, std::system_category());
238061da546Spatrick     return 0;
239061da546Spatrick   }
240061da546Spatrick   struct stat file_stats;
241061da546Spatrick   if (::fstat(fd, &file_stats) == -1) {
242061da546Spatrick     error.SetErrorToErrno();
243061da546Spatrick     return 0;
244061da546Spatrick   }
245061da546Spatrick   error.Clear();
246061da546Spatrick   return file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
247061da546Spatrick }
248061da546Spatrick 
249061da546Spatrick Expected<File::OpenOptions> NativeFile::GetOptions() const { return m_options; }
250061da546Spatrick 
251061da546Spatrick int NativeFile::GetDescriptor() const {
252061da546Spatrick   if (DescriptorIsValid())
253061da546Spatrick     return m_descriptor;
254061da546Spatrick 
255061da546Spatrick   // Don't open the file descriptor if we don't need to, just get it from the
256061da546Spatrick   // stream if we have one.
257061da546Spatrick   if (StreamIsValid()) {
258061da546Spatrick #if defined(_WIN32)
259061da546Spatrick     return _fileno(m_stream);
260061da546Spatrick #else
261061da546Spatrick     return fileno(m_stream);
262061da546Spatrick #endif
263061da546Spatrick   }
264061da546Spatrick 
265061da546Spatrick   // Invalid descriptor and invalid stream, return invalid descriptor.
266061da546Spatrick   return kInvalidDescriptor;
267061da546Spatrick }
268061da546Spatrick 
269061da546Spatrick IOObject::WaitableHandle NativeFile::GetWaitableHandle() {
270061da546Spatrick   return GetDescriptor();
271061da546Spatrick }
272061da546Spatrick 
273061da546Spatrick FILE *NativeFile::GetStream() {
274061da546Spatrick   if (!StreamIsValid()) {
275061da546Spatrick     if (DescriptorIsValid()) {
276061da546Spatrick       auto mode = GetStreamOpenModeFromOptions(m_options);
277061da546Spatrick       if (!mode)
278061da546Spatrick         llvm::consumeError(mode.takeError());
279061da546Spatrick       else {
280061da546Spatrick         if (!m_own_descriptor) {
281061da546Spatrick // We must duplicate the file descriptor if we don't own it because when you
282061da546Spatrick // call fdopen, the stream will own the fd
283061da546Spatrick #ifdef _WIN32
284061da546Spatrick           m_descriptor = ::_dup(GetDescriptor());
285061da546Spatrick #else
286061da546Spatrick           m_descriptor = dup(GetDescriptor());
287061da546Spatrick #endif
288061da546Spatrick           m_own_descriptor = true;
289061da546Spatrick         }
290061da546Spatrick 
291061da546Spatrick         m_stream = llvm::sys::RetryAfterSignal(nullptr, ::fdopen, m_descriptor,
292061da546Spatrick                                                mode.get());
293061da546Spatrick 
294061da546Spatrick         // If we got a stream, then we own the stream and should no longer own
295061da546Spatrick         // the descriptor because fclose() will close it for us
296061da546Spatrick 
297061da546Spatrick         if (m_stream) {
298061da546Spatrick           m_own_stream = true;
299061da546Spatrick           m_own_descriptor = false;
300061da546Spatrick         }
301061da546Spatrick       }
302061da546Spatrick     }
303061da546Spatrick   }
304061da546Spatrick   return m_stream;
305061da546Spatrick }
306061da546Spatrick 
307061da546Spatrick Status NativeFile::Close() {
308061da546Spatrick   Status error;
309061da546Spatrick   if (StreamIsValid()) {
310061da546Spatrick     if (m_own_stream) {
311061da546Spatrick       if (::fclose(m_stream) == EOF)
312061da546Spatrick         error.SetErrorToErrno();
313061da546Spatrick     } else if (m_options & eOpenOptionWrite) {
314061da546Spatrick       if (::fflush(m_stream) == EOF)
315061da546Spatrick         error.SetErrorToErrno();
316061da546Spatrick     }
317061da546Spatrick   }
318061da546Spatrick   if (DescriptorIsValid() && m_own_descriptor) {
319061da546Spatrick     if (::close(m_descriptor) != 0)
320061da546Spatrick       error.SetErrorToErrno();
321061da546Spatrick   }
322061da546Spatrick   m_descriptor = kInvalidDescriptor;
323061da546Spatrick   m_stream = kInvalidStream;
324061da546Spatrick   m_options = OpenOptions(0);
325061da546Spatrick   m_own_stream = false;
326061da546Spatrick   m_own_descriptor = false;
327061da546Spatrick   m_is_interactive = eLazyBoolCalculate;
328061da546Spatrick   m_is_real_terminal = eLazyBoolCalculate;
329061da546Spatrick   return error;
330061da546Spatrick }
331061da546Spatrick 
332061da546Spatrick Status NativeFile::GetFileSpec(FileSpec &file_spec) const {
333061da546Spatrick   Status error;
334061da546Spatrick #ifdef F_GETPATH
335061da546Spatrick   if (IsValid()) {
336061da546Spatrick     char path[PATH_MAX];
337061da546Spatrick     if (::fcntl(GetDescriptor(), F_GETPATH, path) == -1)
338061da546Spatrick       error.SetErrorToErrno();
339061da546Spatrick     else
340061da546Spatrick       file_spec.SetFile(path, FileSpec::Style::native);
341061da546Spatrick   } else {
342061da546Spatrick     error.SetErrorString("invalid file handle");
343061da546Spatrick   }
344061da546Spatrick #elif defined(__linux__)
345061da546Spatrick   char proc[64];
346061da546Spatrick   char path[PATH_MAX];
347061da546Spatrick   if (::snprintf(proc, sizeof(proc), "/proc/self/fd/%d", GetDescriptor()) < 0)
348061da546Spatrick     error.SetErrorString("cannot resolve file descriptor");
349061da546Spatrick   else {
350061da546Spatrick     ssize_t len;
351061da546Spatrick     if ((len = ::readlink(proc, path, sizeof(path) - 1)) == -1)
352061da546Spatrick       error.SetErrorToErrno();
353061da546Spatrick     else {
354061da546Spatrick       path[len] = '\0';
355061da546Spatrick       file_spec.SetFile(path, FileSpec::Style::native);
356061da546Spatrick     }
357061da546Spatrick   }
358061da546Spatrick #else
359061da546Spatrick   error.SetErrorString(
360061da546Spatrick       "NativeFile::GetFileSpec is not supported on this platform");
361061da546Spatrick #endif
362061da546Spatrick 
363061da546Spatrick   if (error.Fail())
364061da546Spatrick     file_spec.Clear();
365061da546Spatrick   return error;
366061da546Spatrick }
367061da546Spatrick 
368061da546Spatrick off_t NativeFile::SeekFromStart(off_t offset, Status *error_ptr) {
369061da546Spatrick   off_t result = 0;
370061da546Spatrick   if (DescriptorIsValid()) {
371061da546Spatrick     result = ::lseek(m_descriptor, offset, SEEK_SET);
372061da546Spatrick 
373061da546Spatrick     if (error_ptr) {
374061da546Spatrick       if (result == -1)
375061da546Spatrick         error_ptr->SetErrorToErrno();
376061da546Spatrick       else
377061da546Spatrick         error_ptr->Clear();
378061da546Spatrick     }
379061da546Spatrick   } else if (StreamIsValid()) {
380061da546Spatrick     result = ::fseek(m_stream, offset, SEEK_SET);
381061da546Spatrick 
382061da546Spatrick     if (error_ptr) {
383061da546Spatrick       if (result == -1)
384061da546Spatrick         error_ptr->SetErrorToErrno();
385061da546Spatrick       else
386061da546Spatrick         error_ptr->Clear();
387061da546Spatrick     }
388061da546Spatrick   } else if (error_ptr) {
389061da546Spatrick     error_ptr->SetErrorString("invalid file handle");
390061da546Spatrick   }
391061da546Spatrick   return result;
392061da546Spatrick }
393061da546Spatrick 
394061da546Spatrick off_t NativeFile::SeekFromCurrent(off_t offset, Status *error_ptr) {
395061da546Spatrick   off_t result = -1;
396061da546Spatrick   if (DescriptorIsValid()) {
397061da546Spatrick     result = ::lseek(m_descriptor, offset, SEEK_CUR);
398061da546Spatrick 
399061da546Spatrick     if (error_ptr) {
400061da546Spatrick       if (result == -1)
401061da546Spatrick         error_ptr->SetErrorToErrno();
402061da546Spatrick       else
403061da546Spatrick         error_ptr->Clear();
404061da546Spatrick     }
405061da546Spatrick   } else if (StreamIsValid()) {
406061da546Spatrick     result = ::fseek(m_stream, offset, SEEK_CUR);
407061da546Spatrick 
408061da546Spatrick     if (error_ptr) {
409061da546Spatrick       if (result == -1)
410061da546Spatrick         error_ptr->SetErrorToErrno();
411061da546Spatrick       else
412061da546Spatrick         error_ptr->Clear();
413061da546Spatrick     }
414061da546Spatrick   } else if (error_ptr) {
415061da546Spatrick     error_ptr->SetErrorString("invalid file handle");
416061da546Spatrick   }
417061da546Spatrick   return result;
418061da546Spatrick }
419061da546Spatrick 
420061da546Spatrick off_t NativeFile::SeekFromEnd(off_t offset, Status *error_ptr) {
421061da546Spatrick   off_t result = -1;
422061da546Spatrick   if (DescriptorIsValid()) {
423061da546Spatrick     result = ::lseek(m_descriptor, offset, SEEK_END);
424061da546Spatrick 
425061da546Spatrick     if (error_ptr) {
426061da546Spatrick       if (result == -1)
427061da546Spatrick         error_ptr->SetErrorToErrno();
428061da546Spatrick       else
429061da546Spatrick         error_ptr->Clear();
430061da546Spatrick     }
431061da546Spatrick   } else if (StreamIsValid()) {
432061da546Spatrick     result = ::fseek(m_stream, offset, SEEK_END);
433061da546Spatrick 
434061da546Spatrick     if (error_ptr) {
435061da546Spatrick       if (result == -1)
436061da546Spatrick         error_ptr->SetErrorToErrno();
437061da546Spatrick       else
438061da546Spatrick         error_ptr->Clear();
439061da546Spatrick     }
440061da546Spatrick   } else if (error_ptr) {
441061da546Spatrick     error_ptr->SetErrorString("invalid file handle");
442061da546Spatrick   }
443061da546Spatrick   return result;
444061da546Spatrick }
445061da546Spatrick 
446061da546Spatrick Status NativeFile::Flush() {
447061da546Spatrick   Status error;
448061da546Spatrick   if (StreamIsValid()) {
449061da546Spatrick     if (llvm::sys::RetryAfterSignal(EOF, ::fflush, m_stream) == EOF)
450061da546Spatrick       error.SetErrorToErrno();
451061da546Spatrick   } else if (!DescriptorIsValid()) {
452061da546Spatrick     error.SetErrorString("invalid file handle");
453061da546Spatrick   }
454061da546Spatrick   return error;
455061da546Spatrick }
456061da546Spatrick 
457061da546Spatrick Status NativeFile::Sync() {
458061da546Spatrick   Status error;
459061da546Spatrick   if (DescriptorIsValid()) {
460061da546Spatrick #ifdef _WIN32
461061da546Spatrick     int err = FlushFileBuffers((HANDLE)_get_osfhandle(m_descriptor));
462061da546Spatrick     if (err == 0)
463061da546Spatrick       error.SetErrorToGenericError();
464061da546Spatrick #else
465061da546Spatrick     if (llvm::sys::RetryAfterSignal(-1, ::fsync, m_descriptor) == -1)
466061da546Spatrick       error.SetErrorToErrno();
467061da546Spatrick #endif
468061da546Spatrick   } else {
469061da546Spatrick     error.SetErrorString("invalid file handle");
470061da546Spatrick   }
471061da546Spatrick   return error;
472061da546Spatrick }
473061da546Spatrick 
474061da546Spatrick #if defined(__APPLE__)
475061da546Spatrick // Darwin kernels only can read/write <= INT_MAX bytes
476061da546Spatrick #define MAX_READ_SIZE INT_MAX
477061da546Spatrick #define MAX_WRITE_SIZE INT_MAX
478061da546Spatrick #endif
479061da546Spatrick 
480061da546Spatrick Status NativeFile::Read(void *buf, size_t &num_bytes) {
481061da546Spatrick   Status error;
482061da546Spatrick 
483061da546Spatrick #if defined(MAX_READ_SIZE)
484061da546Spatrick   if (num_bytes > MAX_READ_SIZE) {
485061da546Spatrick     uint8_t *p = (uint8_t *)buf;
486061da546Spatrick     size_t bytes_left = num_bytes;
487061da546Spatrick     // Init the num_bytes read to zero
488061da546Spatrick     num_bytes = 0;
489061da546Spatrick 
490061da546Spatrick     while (bytes_left > 0) {
491061da546Spatrick       size_t curr_num_bytes;
492061da546Spatrick       if (bytes_left > MAX_READ_SIZE)
493061da546Spatrick         curr_num_bytes = MAX_READ_SIZE;
494061da546Spatrick       else
495061da546Spatrick         curr_num_bytes = bytes_left;
496061da546Spatrick 
497061da546Spatrick       error = Read(p + num_bytes, curr_num_bytes);
498061da546Spatrick 
499061da546Spatrick       // Update how many bytes were read
500061da546Spatrick       num_bytes += curr_num_bytes;
501061da546Spatrick       if (bytes_left < curr_num_bytes)
502061da546Spatrick         bytes_left = 0;
503061da546Spatrick       else
504061da546Spatrick         bytes_left -= curr_num_bytes;
505061da546Spatrick 
506061da546Spatrick       if (error.Fail())
507061da546Spatrick         break;
508061da546Spatrick     }
509061da546Spatrick     return error;
510061da546Spatrick   }
511061da546Spatrick #endif
512061da546Spatrick 
513061da546Spatrick   ssize_t bytes_read = -1;
514061da546Spatrick   if (DescriptorIsValid()) {
515061da546Spatrick     bytes_read = llvm::sys::RetryAfterSignal(-1, ::read, m_descriptor, buf, num_bytes);
516061da546Spatrick     if (bytes_read == -1) {
517061da546Spatrick       error.SetErrorToErrno();
518061da546Spatrick       num_bytes = 0;
519061da546Spatrick     } else
520061da546Spatrick       num_bytes = bytes_read;
521061da546Spatrick   } else if (StreamIsValid()) {
522061da546Spatrick     bytes_read = ::fread(buf, 1, num_bytes, m_stream);
523061da546Spatrick 
524061da546Spatrick     if (bytes_read == 0) {
525061da546Spatrick       if (::feof(m_stream))
526061da546Spatrick         error.SetErrorString("feof");
527061da546Spatrick       else if (::ferror(m_stream))
528061da546Spatrick         error.SetErrorString("ferror");
529061da546Spatrick       num_bytes = 0;
530061da546Spatrick     } else
531061da546Spatrick       num_bytes = bytes_read;
532061da546Spatrick   } else {
533061da546Spatrick     num_bytes = 0;
534061da546Spatrick     error.SetErrorString("invalid file handle");
535061da546Spatrick   }
536061da546Spatrick   return error;
537061da546Spatrick }
538061da546Spatrick 
539061da546Spatrick Status NativeFile::Write(const void *buf, size_t &num_bytes) {
540061da546Spatrick   Status error;
541061da546Spatrick 
542061da546Spatrick #if defined(MAX_WRITE_SIZE)
543061da546Spatrick   if (num_bytes > MAX_WRITE_SIZE) {
544061da546Spatrick     const uint8_t *p = (const uint8_t *)buf;
545061da546Spatrick     size_t bytes_left = num_bytes;
546061da546Spatrick     // Init the num_bytes written to zero
547061da546Spatrick     num_bytes = 0;
548061da546Spatrick 
549061da546Spatrick     while (bytes_left > 0) {
550061da546Spatrick       size_t curr_num_bytes;
551061da546Spatrick       if (bytes_left > MAX_WRITE_SIZE)
552061da546Spatrick         curr_num_bytes = MAX_WRITE_SIZE;
553061da546Spatrick       else
554061da546Spatrick         curr_num_bytes = bytes_left;
555061da546Spatrick 
556061da546Spatrick       error = Write(p + num_bytes, curr_num_bytes);
557061da546Spatrick 
558061da546Spatrick       // Update how many bytes were read
559061da546Spatrick       num_bytes += curr_num_bytes;
560061da546Spatrick       if (bytes_left < curr_num_bytes)
561061da546Spatrick         bytes_left = 0;
562061da546Spatrick       else
563061da546Spatrick         bytes_left -= curr_num_bytes;
564061da546Spatrick 
565061da546Spatrick       if (error.Fail())
566061da546Spatrick         break;
567061da546Spatrick     }
568061da546Spatrick     return error;
569061da546Spatrick   }
570061da546Spatrick #endif
571061da546Spatrick 
572061da546Spatrick   ssize_t bytes_written = -1;
573061da546Spatrick   if (DescriptorIsValid()) {
574061da546Spatrick     bytes_written =
575061da546Spatrick         llvm::sys::RetryAfterSignal(-1, ::write, m_descriptor, buf, num_bytes);
576061da546Spatrick     if (bytes_written == -1) {
577061da546Spatrick       error.SetErrorToErrno();
578061da546Spatrick       num_bytes = 0;
579061da546Spatrick     } else
580061da546Spatrick       num_bytes = bytes_written;
581061da546Spatrick   } else if (StreamIsValid()) {
582061da546Spatrick     bytes_written = ::fwrite(buf, 1, num_bytes, m_stream);
583061da546Spatrick 
584061da546Spatrick     if (bytes_written == 0) {
585061da546Spatrick       if (::feof(m_stream))
586061da546Spatrick         error.SetErrorString("feof");
587061da546Spatrick       else if (::ferror(m_stream))
588061da546Spatrick         error.SetErrorString("ferror");
589061da546Spatrick       num_bytes = 0;
590061da546Spatrick     } else
591061da546Spatrick       num_bytes = bytes_written;
592061da546Spatrick 
593061da546Spatrick   } else {
594061da546Spatrick     num_bytes = 0;
595061da546Spatrick     error.SetErrorString("invalid file handle");
596061da546Spatrick   }
597061da546Spatrick 
598061da546Spatrick   return error;
599061da546Spatrick }
600061da546Spatrick 
601061da546Spatrick Status NativeFile::Read(void *buf, size_t &num_bytes, off_t &offset) {
602061da546Spatrick   Status error;
603061da546Spatrick 
604061da546Spatrick #if defined(MAX_READ_SIZE)
605061da546Spatrick   if (num_bytes > MAX_READ_SIZE) {
606061da546Spatrick     uint8_t *p = (uint8_t *)buf;
607061da546Spatrick     size_t bytes_left = num_bytes;
608061da546Spatrick     // Init the num_bytes read to zero
609061da546Spatrick     num_bytes = 0;
610061da546Spatrick 
611061da546Spatrick     while (bytes_left > 0) {
612061da546Spatrick       size_t curr_num_bytes;
613061da546Spatrick       if (bytes_left > MAX_READ_SIZE)
614061da546Spatrick         curr_num_bytes = MAX_READ_SIZE;
615061da546Spatrick       else
616061da546Spatrick         curr_num_bytes = bytes_left;
617061da546Spatrick 
618061da546Spatrick       error = Read(p + num_bytes, curr_num_bytes, offset);
619061da546Spatrick 
620061da546Spatrick       // Update how many bytes were read
621061da546Spatrick       num_bytes += curr_num_bytes;
622061da546Spatrick       if (bytes_left < curr_num_bytes)
623061da546Spatrick         bytes_left = 0;
624061da546Spatrick       else
625061da546Spatrick         bytes_left -= curr_num_bytes;
626061da546Spatrick 
627061da546Spatrick       if (error.Fail())
628061da546Spatrick         break;
629061da546Spatrick     }
630061da546Spatrick     return error;
631061da546Spatrick   }
632061da546Spatrick #endif
633061da546Spatrick 
634061da546Spatrick #ifndef _WIN32
635061da546Spatrick   int fd = GetDescriptor();
636061da546Spatrick   if (fd != kInvalidDescriptor) {
637061da546Spatrick     ssize_t bytes_read =
638061da546Spatrick         llvm::sys::RetryAfterSignal(-1, ::pread, fd, buf, num_bytes, offset);
639061da546Spatrick     if (bytes_read < 0) {
640061da546Spatrick       num_bytes = 0;
641061da546Spatrick       error.SetErrorToErrno();
642061da546Spatrick     } else {
643061da546Spatrick       offset += bytes_read;
644061da546Spatrick       num_bytes = bytes_read;
645061da546Spatrick     }
646061da546Spatrick   } else {
647061da546Spatrick     num_bytes = 0;
648061da546Spatrick     error.SetErrorString("invalid file handle");
649061da546Spatrick   }
650061da546Spatrick #else
651061da546Spatrick   std::lock_guard<std::mutex> guard(offset_access_mutex);
652061da546Spatrick   long cur = ::lseek(m_descriptor, 0, SEEK_CUR);
653061da546Spatrick   SeekFromStart(offset);
654061da546Spatrick   error = Read(buf, num_bytes);
655061da546Spatrick   if (!error.Fail())
656061da546Spatrick     SeekFromStart(cur);
657061da546Spatrick #endif
658061da546Spatrick   return error;
659061da546Spatrick }
660061da546Spatrick 
661061da546Spatrick Status NativeFile::Write(const void *buf, size_t &num_bytes, off_t &offset) {
662061da546Spatrick   Status error;
663061da546Spatrick 
664061da546Spatrick #if defined(MAX_WRITE_SIZE)
665061da546Spatrick   if (num_bytes > MAX_WRITE_SIZE) {
666061da546Spatrick     const uint8_t *p = (const uint8_t *)buf;
667061da546Spatrick     size_t bytes_left = num_bytes;
668061da546Spatrick     // Init the num_bytes written to zero
669061da546Spatrick     num_bytes = 0;
670061da546Spatrick 
671061da546Spatrick     while (bytes_left > 0) {
672061da546Spatrick       size_t curr_num_bytes;
673061da546Spatrick       if (bytes_left > MAX_WRITE_SIZE)
674061da546Spatrick         curr_num_bytes = MAX_WRITE_SIZE;
675061da546Spatrick       else
676061da546Spatrick         curr_num_bytes = bytes_left;
677061da546Spatrick 
678061da546Spatrick       error = Write(p + num_bytes, curr_num_bytes, offset);
679061da546Spatrick 
680061da546Spatrick       // Update how many bytes were read
681061da546Spatrick       num_bytes += curr_num_bytes;
682061da546Spatrick       if (bytes_left < curr_num_bytes)
683061da546Spatrick         bytes_left = 0;
684061da546Spatrick       else
685061da546Spatrick         bytes_left -= curr_num_bytes;
686061da546Spatrick 
687061da546Spatrick       if (error.Fail())
688061da546Spatrick         break;
689061da546Spatrick     }
690061da546Spatrick     return error;
691061da546Spatrick   }
692061da546Spatrick #endif
693061da546Spatrick 
694061da546Spatrick   int fd = GetDescriptor();
695061da546Spatrick   if (fd != kInvalidDescriptor) {
696061da546Spatrick #ifndef _WIN32
697061da546Spatrick     ssize_t bytes_written =
698061da546Spatrick         llvm::sys::RetryAfterSignal(-1, ::pwrite, m_descriptor, buf, num_bytes, offset);
699061da546Spatrick     if (bytes_written < 0) {
700061da546Spatrick       num_bytes = 0;
701061da546Spatrick       error.SetErrorToErrno();
702061da546Spatrick     } else {
703061da546Spatrick       offset += bytes_written;
704061da546Spatrick       num_bytes = bytes_written;
705061da546Spatrick     }
706061da546Spatrick #else
707061da546Spatrick     std::lock_guard<std::mutex> guard(offset_access_mutex);
708061da546Spatrick     long cur = ::lseek(m_descriptor, 0, SEEK_CUR);
709061da546Spatrick     SeekFromStart(offset);
710061da546Spatrick     error = Write(buf, num_bytes);
711061da546Spatrick     long after = ::lseek(m_descriptor, 0, SEEK_CUR);
712061da546Spatrick 
713061da546Spatrick     if (!error.Fail())
714061da546Spatrick       SeekFromStart(cur);
715061da546Spatrick 
716061da546Spatrick     offset = after;
717061da546Spatrick #endif
718061da546Spatrick   } else {
719061da546Spatrick     num_bytes = 0;
720061da546Spatrick     error.SetErrorString("invalid file handle");
721061da546Spatrick   }
722061da546Spatrick   return error;
723061da546Spatrick }
724061da546Spatrick 
725061da546Spatrick size_t NativeFile::PrintfVarArg(const char *format, va_list args) {
726061da546Spatrick   if (StreamIsValid()) {
727061da546Spatrick     return ::vfprintf(m_stream, format, args);
728061da546Spatrick   } else {
729061da546Spatrick     return File::PrintfVarArg(format, args);
730061da546Spatrick   }
731061da546Spatrick }
732061da546Spatrick 
733061da546Spatrick mode_t File::ConvertOpenOptionsForPOSIXOpen(OpenOptions open_options) {
734061da546Spatrick   mode_t mode = 0;
735061da546Spatrick   if (open_options & eOpenOptionRead && open_options & eOpenOptionWrite)
736061da546Spatrick     mode |= O_RDWR;
737061da546Spatrick   else if (open_options & eOpenOptionWrite)
738061da546Spatrick     mode |= O_WRONLY;
739061da546Spatrick 
740061da546Spatrick   if (open_options & eOpenOptionAppend)
741061da546Spatrick     mode |= O_APPEND;
742061da546Spatrick 
743061da546Spatrick   if (open_options & eOpenOptionTruncate)
744061da546Spatrick     mode |= O_TRUNC;
745061da546Spatrick 
746061da546Spatrick   if (open_options & eOpenOptionNonBlocking)
747061da546Spatrick     mode |= O_NONBLOCK;
748061da546Spatrick 
749061da546Spatrick   if (open_options & eOpenOptionCanCreateNewOnly)
750061da546Spatrick     mode |= O_CREAT | O_EXCL;
751061da546Spatrick   else if (open_options & eOpenOptionCanCreate)
752061da546Spatrick     mode |= O_CREAT;
753061da546Spatrick 
754061da546Spatrick   return mode;
755061da546Spatrick }
756061da546Spatrick 
757061da546Spatrick char File::ID = 0;
758061da546Spatrick char NativeFile::ID = 0;
759