1258884Semaste//===-- File.cpp ------------------------------------------------*- C++ -*-===//
2254721Semaste//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6254721Semaste//
7254721Semaste//===----------------------------------------------------------------------===//
8254721Semaste
9254721Semaste#include "lldb/Host/File.h"
10254721Semaste
11254721Semaste#include <errno.h>
12254721Semaste#include <fcntl.h>
13254721Semaste#include <limits.h>
14254721Semaste#include <stdarg.h>
15262528Semaste#include <stdio.h>
16254721Semaste
17258054Semaste#ifdef _WIN32
18258054Semaste#include "lldb/Host/windows/windows.h"
19262528Semaste#else
20262528Semaste#include <sys/ioctl.h>
21321369Sdim#include <sys/stat.h>
22321369Sdim#include <termios.h>
23321369Sdim#include <unistd.h>
24258054Semaste#endif
25258054Semaste
26309124Sdim#include "llvm/Support/ConvertUTF.h"
27321369Sdim#include "llvm/Support/Errno.h"
28321369Sdim#include "llvm/Support/FileSystem.h"
29344779Sdim#include "llvm/Support/Process.h"
30296417Sdim
31254721Semaste#include "lldb/Host/Config.h"
32344779Sdim#include "lldb/Host/FileSystem.h"
33321369Sdim#include "lldb/Host/Host.h"
34321369Sdim#include "lldb/Utility/DataBufferHeap.h"
35321369Sdim#include "lldb/Utility/FileSpec.h"
36321369Sdim#include "lldb/Utility/Log.h"
37254721Semaste
38254721Semasteusing namespace lldb;
39254721Semasteusing namespace lldb_private;
40360784Sdimusing llvm::Expected;
41254721Semaste
42360784SdimExpected<const char *>
43360784SdimFile::GetStreamOpenModeFromOptions(File::OpenOptions options) {
44314564Sdim  if (options & File::eOpenOptionAppend) {
45314564Sdim    if (options & File::eOpenOptionRead) {
46314564Sdim      if (options & File::eOpenOptionCanCreateNewOnly)
47314564Sdim        return "a+x";
48314564Sdim      else
49314564Sdim        return "a+";
50314564Sdim    } else if (options & File::eOpenOptionWrite) {
51314564Sdim      if (options & File::eOpenOptionCanCreateNewOnly)
52314564Sdim        return "ax";
53314564Sdim      else
54314564Sdim        return "a";
55254721Semaste    }
56314564Sdim  } else if (options & File::eOpenOptionRead &&
57314564Sdim             options & File::eOpenOptionWrite) {
58314564Sdim    if (options & File::eOpenOptionCanCreate) {
59314564Sdim      if (options & File::eOpenOptionCanCreateNewOnly)
60314564Sdim        return "w+x";
61314564Sdim      else
62314564Sdim        return "w+";
63314564Sdim    } else
64314564Sdim      return "r+";
65314564Sdim  } else if (options & File::eOpenOptionRead) {
66314564Sdim    return "r";
67314564Sdim  } else if (options & File::eOpenOptionWrite) {
68314564Sdim    return "w";
69314564Sdim  }
70360784Sdim  return llvm::createStringError(
71360784Sdim      llvm::inconvertibleErrorCode(),
72360784Sdim      "invalid options, cannot convert to mode string");
73254721Semaste}
74254721Semaste
75360784SdimExpected<File::OpenOptions> File::GetOptionsFromMode(llvm::StringRef mode) {
76360784Sdim  OpenOptions opts =
77360784Sdim      llvm::StringSwitch<OpenOptions>(mode)
78360784Sdim          .Cases("r", "rb", eOpenOptionRead)
79360784Sdim          .Cases("w", "wb", eOpenOptionWrite)
80360784Sdim          .Cases("a", "ab",
81360784Sdim                 eOpenOptionWrite | eOpenOptionAppend | eOpenOptionCanCreate)
82360784Sdim          .Cases("r+", "rb+", "r+b", eOpenOptionRead | eOpenOptionWrite)
83360784Sdim          .Cases("w+", "wb+", "w+b",
84360784Sdim                 eOpenOptionRead | eOpenOptionWrite | eOpenOptionCanCreate |
85360784Sdim                     eOpenOptionTruncate)
86360784Sdim          .Cases("a+", "ab+", "a+b",
87360784Sdim                 eOpenOptionRead | eOpenOptionWrite | eOpenOptionAppend |
88360784Sdim                     eOpenOptionCanCreate)
89360784Sdim          .Default(OpenOptions());
90360784Sdim  if (opts)
91360784Sdim    return opts;
92360784Sdim  return llvm::createStringError(
93360784Sdim      llvm::inconvertibleErrorCode(),
94360784Sdim      "invalid mode, cannot convert to File::OpenOptions");
95360784Sdim}
96360784Sdim
97254721Semasteint File::kInvalidDescriptor = -1;
98353358SdimFILE *File::kInvalidStream = nullptr;
99254721Semaste
100360784SdimStatus File::Read(void *buf, size_t &num_bytes) {
101360784Sdim  return std::error_code(ENOTSUP, std::system_category());
102360784Sdim}
103360784SdimStatus File::Write(const void *buf, size_t &num_bytes) {
104360784Sdim  return std::error_code(ENOTSUP, std::system_category());
105360784Sdim}
106254721Semaste
107360784Sdimbool File::IsValid() const { return false; }
108360784Sdim
109360784SdimStatus File::Close() { return Flush(); }
110360784Sdim
111360784SdimIOObject::WaitableHandle File::GetWaitableHandle() {
112360784Sdim  return IOObject::kInvalidHandleValue;
113360784Sdim}
114360784Sdim
115360784SdimStatus File::GetFileSpec(FileSpec &file_spec) const {
116360784Sdim  file_spec.Clear();
117360784Sdim  return std::error_code(ENOTSUP, std::system_category());
118360784Sdim}
119360784Sdim
120360784Sdimint File::GetDescriptor() const { return kInvalidDescriptor; }
121360784Sdim
122360784SdimFILE *File::GetStream() { return nullptr; }
123360784Sdim
124360784Sdimoff_t File::SeekFromStart(off_t offset, Status *error_ptr) {
125360784Sdim  if (error_ptr)
126360784Sdim    *error_ptr = std::error_code(ENOTSUP, std::system_category());
127360784Sdim  return -1;
128360784Sdim}
129360784Sdim
130360784Sdimoff_t File::SeekFromCurrent(off_t offset, Status *error_ptr) {
131360784Sdim  if (error_ptr)
132360784Sdim    *error_ptr = std::error_code(ENOTSUP, std::system_category());
133360784Sdim  return -1;
134360784Sdim}
135360784Sdim
136360784Sdimoff_t File::SeekFromEnd(off_t offset, Status *error_ptr) {
137360784Sdim  if (error_ptr)
138360784Sdim    *error_ptr = std::error_code(ENOTSUP, std::system_category());
139360784Sdim  return -1;
140360784Sdim}
141360784Sdim
142360784SdimStatus File::Read(void *dst, size_t &num_bytes, off_t &offset) {
143360784Sdim  return std::error_code(ENOTSUP, std::system_category());
144360784Sdim}
145360784Sdim
146360784SdimStatus File::Write(const void *src, size_t &num_bytes, off_t &offset) {
147360784Sdim  return std::error_code(ENOTSUP, std::system_category());
148360784Sdim}
149360784Sdim
150360784SdimStatus File::Flush() { return Status(); }
151360784Sdim
152360784SdimStatus File::Sync() { return Flush(); }
153360784Sdim
154360784Sdimvoid File::CalculateInteractiveAndTerminal() {
155360784Sdim  const int fd = GetDescriptor();
156360784Sdim  if (!DescriptorIsValid(fd)) {
157360784Sdim    m_is_interactive = eLazyBoolNo;
158360784Sdim    m_is_real_terminal = eLazyBoolNo;
159360784Sdim    m_supports_colors = eLazyBoolNo;
160360784Sdim    return;
161360784Sdim  }
162360784Sdim  m_is_interactive = eLazyBoolNo;
163360784Sdim  m_is_real_terminal = eLazyBoolNo;
164360784Sdim#if defined(_WIN32)
165360784Sdim  if (_isatty(fd)) {
166360784Sdim    m_is_interactive = eLazyBoolYes;
167360784Sdim    m_is_real_terminal = eLazyBoolYes;
168360784Sdim#if defined(ENABLE_VIRTUAL_TERMINAL_PROCESSING)
169360784Sdim    m_supports_colors = eLazyBoolYes;
170360784Sdim#endif
171360784Sdim  }
172360784Sdim#else
173360784Sdim  if (isatty(fd)) {
174360784Sdim    m_is_interactive = eLazyBoolYes;
175360784Sdim    struct winsize window_size;
176360784Sdim    if (::ioctl(fd, TIOCGWINSZ, &window_size) == 0) {
177360784Sdim      if (window_size.ws_col > 0) {
178360784Sdim        m_is_real_terminal = eLazyBoolYes;
179360784Sdim        if (llvm::sys::Process::FileDescriptorHasColors(fd))
180360784Sdim          m_supports_colors = eLazyBoolYes;
181360784Sdim      }
182360784Sdim    }
183360784Sdim  }
184360784Sdim#endif
185360784Sdim}
186360784Sdim
187360784Sdimbool File::GetIsInteractive() {
188360784Sdim  if (m_is_interactive == eLazyBoolCalculate)
189360784Sdim    CalculateInteractiveAndTerminal();
190360784Sdim  return m_is_interactive == eLazyBoolYes;
191360784Sdim}
192360784Sdim
193360784Sdimbool File::GetIsRealTerminal() {
194360784Sdim  if (m_is_real_terminal == eLazyBoolCalculate)
195360784Sdim    CalculateInteractiveAndTerminal();
196360784Sdim  return m_is_real_terminal == eLazyBoolYes;
197360784Sdim}
198360784Sdim
199360784Sdimbool File::GetIsTerminalWithColors() {
200360784Sdim  if (m_supports_colors == eLazyBoolCalculate)
201360784Sdim    CalculateInteractiveAndTerminal();
202360784Sdim  return m_supports_colors == eLazyBoolYes;
203360784Sdim}
204360784Sdim
205360784Sdimsize_t File::Printf(const char *format, ...) {
206360784Sdim  va_list args;
207360784Sdim  va_start(args, format);
208360784Sdim  size_t result = PrintfVarArg(format, args);
209360784Sdim  va_end(args);
210360784Sdim  return result;
211360784Sdim}
212360784Sdim
213360784Sdimsize_t File::PrintfVarArg(const char *format, va_list args) {
214360784Sdim  size_t result = 0;
215360784Sdim  char *s = nullptr;
216360784Sdim  result = vasprintf(&s, format, args);
217360784Sdim  if (s != nullptr) {
218360784Sdim    if (result > 0) {
219360784Sdim      size_t s_len = result;
220360784Sdim      Write(s, s_len);
221360784Sdim      result = s_len;
222360784Sdim    }
223360784Sdim    free(s);
224360784Sdim  }
225360784Sdim  return result;
226360784Sdim}
227360784Sdim
228360784SdimExpected<File::OpenOptions> File::GetOptions() const {
229360784Sdim  return llvm::createStringError(
230360784Sdim      llvm::inconvertibleErrorCode(),
231360784Sdim      "GetOptions() not implemented for this File class");
232360784Sdim}
233360784Sdim
234360784Sdimuint32_t File::GetPermissions(Status &error) const {
235360784Sdim  int fd = GetDescriptor();
236360784Sdim  if (!DescriptorIsValid(fd)) {
237360784Sdim    error = std::error_code(ENOTSUP, std::system_category());
238360784Sdim    return 0;
239360784Sdim  }
240360784Sdim  struct stat file_stats;
241360784Sdim  if (::fstat(fd, &file_stats) == -1) {
242360784Sdim    error.SetErrorToErrno();
243360784Sdim    return 0;
244360784Sdim  }
245360784Sdim  error.Clear();
246360784Sdim  return file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
247360784Sdim}
248360784Sdim
249360784SdimExpected<File::OpenOptions> NativeFile::GetOptions() const { return m_options; }
250360784Sdim
251360784Sdimint NativeFile::GetDescriptor() const {
252314564Sdim  if (DescriptorIsValid())
253314564Sdim    return m_descriptor;
254254721Semaste
255314564Sdim  // Don't open the file descriptor if we don't need to, just get it from the
256314564Sdim  // stream if we have one.
257314564Sdim  if (StreamIsValid()) {
258341825Sdim#if defined(_WIN32)
259314564Sdim    return _fileno(m_stream);
260296417Sdim#else
261314564Sdim    return fileno(m_stream);
262296417Sdim#endif
263314564Sdim  }
264254721Semaste
265314564Sdim  // Invalid descriptor and invalid stream, return invalid descriptor.
266314564Sdim  return kInvalidDescriptor;
267254721Semaste}
268254721Semaste
269360784SdimIOObject::WaitableHandle NativeFile::GetWaitableHandle() {
270360784Sdim  return GetDescriptor();
271254721Semaste}
272254721Semaste
273360784SdimFILE *NativeFile::GetStream() {
274314564Sdim  if (!StreamIsValid()) {
275314564Sdim    if (DescriptorIsValid()) {
276360784Sdim      auto mode = GetStreamOpenModeFromOptions(m_options);
277360784Sdim      if (!mode)
278360784Sdim        llvm::consumeError(mode.takeError());
279360784Sdim      else {
280360784Sdim        if (!m_own_descriptor) {
281341825Sdim// We must duplicate the file descriptor if we don't own it because when you
282341825Sdim// call fdopen, the stream will own the fd
283262528Semaste#ifdef _WIN32
284314564Sdim          m_descriptor = ::_dup(GetDescriptor());
285262528Semaste#else
286314564Sdim          m_descriptor = dup(GetDescriptor());
287262528Semaste#endif
288360784Sdim          m_own_descriptor = true;
289314564Sdim        }
290262528Semaste
291360784Sdim        m_stream = llvm::sys::RetryAfterSignal(nullptr, ::fdopen, m_descriptor,
292360784Sdim                                               mode.get());
293262528Semaste
294341825Sdim        // If we got a stream, then we own the stream and should no longer own
295341825Sdim        // the descriptor because fclose() will close it for us
296262528Semaste
297314564Sdim        if (m_stream) {
298314564Sdim          m_own_stream = true;
299360784Sdim          m_own_descriptor = false;
300254721Semaste        }
301314564Sdim      }
302254721Semaste    }
303314564Sdim  }
304314564Sdim  return m_stream;
305254721Semaste}
306254721Semaste
307360784SdimStatus NativeFile::Close() {
308360784Sdim  Status error;
309360784Sdim  if (StreamIsValid()) {
310360784Sdim    if (m_own_stream) {
311360784Sdim      if (::fclose(m_stream) == EOF)
312360784Sdim        error.SetErrorToErrno();
313360784Sdim    } else if (m_options & eOpenOptionWrite) {
314360784Sdim      if (::fflush(m_stream) == EOF)
315360784Sdim        error.SetErrorToErrno();
316258054Semaste    }
317314564Sdim  }
318360784Sdim  if (DescriptorIsValid() && m_own_descriptor) {
319314564Sdim    if (::close(m_descriptor) != 0)
320314564Sdim      error.SetErrorToErrno();
321314564Sdim  }
322314564Sdim  m_descriptor = kInvalidDescriptor;
323314564Sdim  m_stream = kInvalidStream;
324360784Sdim  m_options = OpenOptions(0);
325314564Sdim  m_own_stream = false;
326360784Sdim  m_own_descriptor = false;
327314564Sdim  m_is_interactive = eLazyBoolCalculate;
328314564Sdim  m_is_real_terminal = eLazyBoolCalculate;
329314564Sdim  return error;
330254721Semaste}
331254721Semaste
332360784SdimStatus NativeFile::GetFileSpec(FileSpec &file_spec) const {
333321369Sdim  Status error;
334321369Sdim#ifdef F_GETPATH
335314564Sdim  if (IsValid()) {
336254721Semaste    char path[PATH_MAX];
337314564Sdim    if (::fcntl(GetDescriptor(), F_GETPATH, path) == -1)
338314564Sdim      error.SetErrorToErrno();
339254721Semaste    else
340344779Sdim      file_spec.SetFile(path, FileSpec::Style::native);
341314564Sdim  } else {
342314564Sdim    error.SetErrorString("invalid file handle");
343314564Sdim  }
344314564Sdim#elif defined(__linux__)
345314564Sdim  char proc[64];
346314564Sdim  char path[PATH_MAX];
347314564Sdim  if (::snprintf(proc, sizeof(proc), "/proc/self/fd/%d", GetDescriptor()) < 0)
348314564Sdim    error.SetErrorString("cannot resolve file descriptor");
349314564Sdim  else {
350314564Sdim    ssize_t len;
351314564Sdim    if ((len = ::readlink(proc, path, sizeof(path) - 1)) == -1)
352314564Sdim      error.SetErrorToErrno();
353314564Sdim    else {
354314564Sdim      path[len] = '\0';
355344779Sdim      file_spec.SetFile(path, FileSpec::Style::native);
356254721Semaste    }
357314564Sdim  }
358254721Semaste#else
359360784Sdim  error.SetErrorString(
360360784Sdim      "NativeFile::GetFileSpec is not supported on this platform");
361254721Semaste#endif
362254721Semaste
363314564Sdim  if (error.Fail())
364314564Sdim    file_spec.Clear();
365314564Sdim  return error;
366254721Semaste}
367254721Semaste
368360784Sdimoff_t NativeFile::SeekFromStart(off_t offset, Status *error_ptr) {
369314564Sdim  off_t result = 0;
370314564Sdim  if (DescriptorIsValid()) {
371314564Sdim    result = ::lseek(m_descriptor, offset, SEEK_SET);
372254721Semaste
373314564Sdim    if (error_ptr) {
374314564Sdim      if (result == -1)
375314564Sdim        error_ptr->SetErrorToErrno();
376314564Sdim      else
377314564Sdim        error_ptr->Clear();
378254721Semaste    }
379314564Sdim  } else if (StreamIsValid()) {
380314564Sdim    result = ::fseek(m_stream, offset, SEEK_SET);
381314564Sdim
382314564Sdim    if (error_ptr) {
383314564Sdim      if (result == -1)
384314564Sdim        error_ptr->SetErrorToErrno();
385314564Sdim      else
386314564Sdim        error_ptr->Clear();
387254721Semaste    }
388314564Sdim  } else if (error_ptr) {
389314564Sdim    error_ptr->SetErrorString("invalid file handle");
390314564Sdim  }
391314564Sdim  return result;
392254721Semaste}
393254721Semaste
394360784Sdimoff_t NativeFile::SeekFromCurrent(off_t offset, Status *error_ptr) {
395314564Sdim  off_t result = -1;
396314564Sdim  if (DescriptorIsValid()) {
397314564Sdim    result = ::lseek(m_descriptor, offset, SEEK_CUR);
398314564Sdim
399314564Sdim    if (error_ptr) {
400314564Sdim      if (result == -1)
401314564Sdim        error_ptr->SetErrorToErrno();
402314564Sdim      else
403314564Sdim        error_ptr->Clear();
404254721Semaste    }
405314564Sdim  } else if (StreamIsValid()) {
406314564Sdim    result = ::fseek(m_stream, offset, SEEK_CUR);
407314564Sdim
408314564Sdim    if (error_ptr) {
409314564Sdim      if (result == -1)
410314564Sdim        error_ptr->SetErrorToErrno();
411314564Sdim      else
412314564Sdim        error_ptr->Clear();
413254721Semaste    }
414314564Sdim  } else if (error_ptr) {
415314564Sdim    error_ptr->SetErrorString("invalid file handle");
416314564Sdim  }
417314564Sdim  return result;
418254721Semaste}
419254721Semaste
420360784Sdimoff_t NativeFile::SeekFromEnd(off_t offset, Status *error_ptr) {
421314564Sdim  off_t result = -1;
422314564Sdim  if (DescriptorIsValid()) {
423314564Sdim    result = ::lseek(m_descriptor, offset, SEEK_END);
424314564Sdim
425314564Sdim    if (error_ptr) {
426314564Sdim      if (result == -1)
427314564Sdim        error_ptr->SetErrorToErrno();
428314564Sdim      else
429314564Sdim        error_ptr->Clear();
430254721Semaste    }
431314564Sdim  } else if (StreamIsValid()) {
432314564Sdim    result = ::fseek(m_stream, offset, SEEK_END);
433314564Sdim
434314564Sdim    if (error_ptr) {
435314564Sdim      if (result == -1)
436314564Sdim        error_ptr->SetErrorToErrno();
437314564Sdim      else
438314564Sdim        error_ptr->Clear();
439254721Semaste    }
440314564Sdim  } else if (error_ptr) {
441314564Sdim    error_ptr->SetErrorString("invalid file handle");
442314564Sdim  }
443314564Sdim  return result;
444254721Semaste}
445254721Semaste
446360784SdimStatus NativeFile::Flush() {
447321369Sdim  Status error;
448314564Sdim  if (StreamIsValid()) {
449321369Sdim    if (llvm::sys::RetryAfterSignal(EOF, ::fflush, m_stream) == EOF)
450314564Sdim      error.SetErrorToErrno();
451314564Sdim  } else if (!DescriptorIsValid()) {
452314564Sdim    error.SetErrorString("invalid file handle");
453314564Sdim  }
454314564Sdim  return error;
455254721Semaste}
456254721Semaste
457360784SdimStatus NativeFile::Sync() {
458321369Sdim  Status error;
459314564Sdim  if (DescriptorIsValid()) {
460258054Semaste#ifdef _WIN32
461314564Sdim    int err = FlushFileBuffers((HANDLE)_get_osfhandle(m_descriptor));
462314564Sdim    if (err == 0)
463314564Sdim      error.SetErrorToGenericError();
464258054Semaste#else
465321369Sdim    if (llvm::sys::RetryAfterSignal(-1, ::fsync, m_descriptor) == -1)
466314564Sdim      error.SetErrorToErrno();
467258054Semaste#endif
468314564Sdim  } else {
469314564Sdim    error.SetErrorString("invalid file handle");
470314564Sdim  }
471314564Sdim  return error;
472254721Semaste}
473254721Semaste
474314564Sdim#if defined(__APPLE__)
475288943Sdim// Darwin kernels only can read/write <= INT_MAX bytes
476288943Sdim#define MAX_READ_SIZE INT_MAX
477288943Sdim#define MAX_WRITE_SIZE INT_MAX
478288943Sdim#endif
479288943Sdim
480360784SdimStatus NativeFile::Read(void *buf, size_t &num_bytes) {
481321369Sdim  Status error;
482288943Sdim
483314564Sdim#if defined(MAX_READ_SIZE)
484314564Sdim  if (num_bytes > MAX_READ_SIZE) {
485314564Sdim    uint8_t *p = (uint8_t *)buf;
486314564Sdim    size_t bytes_left = num_bytes;
487314564Sdim    // Init the num_bytes read to zero
488314564Sdim    num_bytes = 0;
489288943Sdim
490314564Sdim    while (bytes_left > 0) {
491314564Sdim      size_t curr_num_bytes;
492314564Sdim      if (bytes_left > MAX_READ_SIZE)
493314564Sdim        curr_num_bytes = MAX_READ_SIZE;
494314564Sdim      else
495314564Sdim        curr_num_bytes = bytes_left;
496288943Sdim
497314564Sdim      error = Read(p + num_bytes, curr_num_bytes);
498288943Sdim
499314564Sdim      // Update how many bytes were read
500314564Sdim      num_bytes += curr_num_bytes;
501314564Sdim      if (bytes_left < curr_num_bytes)
502314564Sdim        bytes_left = 0;
503314564Sdim      else
504314564Sdim        bytes_left -= curr_num_bytes;
505288943Sdim
506314564Sdim      if (error.Fail())
507314564Sdim        break;
508288943Sdim    }
509314564Sdim    return error;
510314564Sdim  }
511288943Sdim#endif
512288943Sdim
513314564Sdim  ssize_t bytes_read = -1;
514314564Sdim  if (DescriptorIsValid()) {
515321369Sdim    bytes_read = llvm::sys::RetryAfterSignal(-1, ::read, m_descriptor, buf, num_bytes);
516314564Sdim    if (bytes_read == -1) {
517314564Sdim      error.SetErrorToErrno();
518314564Sdim      num_bytes = 0;
519314564Sdim    } else
520314564Sdim      num_bytes = bytes_read;
521314564Sdim  } else if (StreamIsValid()) {
522314564Sdim    bytes_read = ::fread(buf, 1, num_bytes, m_stream);
523254721Semaste
524314564Sdim    if (bytes_read == 0) {
525314564Sdim      if (::feof(m_stream))
526314564Sdim        error.SetErrorString("feof");
527314564Sdim      else if (::ferror(m_stream))
528314564Sdim        error.SetErrorString("ferror");
529314564Sdim      num_bytes = 0;
530314564Sdim    } else
531314564Sdim      num_bytes = bytes_read;
532314564Sdim  } else {
533314564Sdim    num_bytes = 0;
534314564Sdim    error.SetErrorString("invalid file handle");
535314564Sdim  }
536314564Sdim  return error;
537254721Semaste}
538288943Sdim
539360784SdimStatus NativeFile::Write(const void *buf, size_t &num_bytes) {
540321369Sdim  Status error;
541288943Sdim
542314564Sdim#if defined(MAX_WRITE_SIZE)
543314564Sdim  if (num_bytes > MAX_WRITE_SIZE) {
544314564Sdim    const uint8_t *p = (const uint8_t *)buf;
545314564Sdim    size_t bytes_left = num_bytes;
546314564Sdim    // Init the num_bytes written to zero
547314564Sdim    num_bytes = 0;
548288943Sdim
549314564Sdim    while (bytes_left > 0) {
550314564Sdim      size_t curr_num_bytes;
551314564Sdim      if (bytes_left > MAX_WRITE_SIZE)
552314564Sdim        curr_num_bytes = MAX_WRITE_SIZE;
553314564Sdim      else
554314564Sdim        curr_num_bytes = bytes_left;
555288943Sdim
556314564Sdim      error = Write(p + num_bytes, curr_num_bytes);
557288943Sdim
558314564Sdim      // Update how many bytes were read
559314564Sdim      num_bytes += curr_num_bytes;
560314564Sdim      if (bytes_left < curr_num_bytes)
561314564Sdim        bytes_left = 0;
562314564Sdim      else
563314564Sdim        bytes_left -= curr_num_bytes;
564314564Sdim
565314564Sdim      if (error.Fail())
566314564Sdim        break;
567288943Sdim    }
568314564Sdim    return error;
569314564Sdim  }
570288943Sdim#endif
571288943Sdim
572314564Sdim  ssize_t bytes_written = -1;
573314564Sdim  if (DescriptorIsValid()) {
574321369Sdim    bytes_written =
575321369Sdim        llvm::sys::RetryAfterSignal(-1, ::write, m_descriptor, buf, num_bytes);
576314564Sdim    if (bytes_written == -1) {
577314564Sdim      error.SetErrorToErrno();
578314564Sdim      num_bytes = 0;
579314564Sdim    } else
580314564Sdim      num_bytes = bytes_written;
581314564Sdim  } else if (StreamIsValid()) {
582314564Sdim    bytes_written = ::fwrite(buf, 1, num_bytes, m_stream);
583254721Semaste
584314564Sdim    if (bytes_written == 0) {
585314564Sdim      if (::feof(m_stream))
586314564Sdim        error.SetErrorString("feof");
587314564Sdim      else if (::ferror(m_stream))
588314564Sdim        error.SetErrorString("ferror");
589314564Sdim      num_bytes = 0;
590314564Sdim    } else
591314564Sdim      num_bytes = bytes_written;
592276479Sdim
593314564Sdim  } else {
594314564Sdim    num_bytes = 0;
595314564Sdim    error.SetErrorString("invalid file handle");
596314564Sdim  }
597314564Sdim
598314564Sdim  return error;
599254721Semaste}
600254721Semaste
601360784SdimStatus NativeFile::Read(void *buf, size_t &num_bytes, off_t &offset) {
602321369Sdim  Status error;
603254721Semaste
604314564Sdim#if defined(MAX_READ_SIZE)
605314564Sdim  if (num_bytes > MAX_READ_SIZE) {
606314564Sdim    uint8_t *p = (uint8_t *)buf;
607314564Sdim    size_t bytes_left = num_bytes;
608314564Sdim    // Init the num_bytes read to zero
609314564Sdim    num_bytes = 0;
610288943Sdim
611314564Sdim    while (bytes_left > 0) {
612314564Sdim      size_t curr_num_bytes;
613314564Sdim      if (bytes_left > MAX_READ_SIZE)
614314564Sdim        curr_num_bytes = MAX_READ_SIZE;
615314564Sdim      else
616314564Sdim        curr_num_bytes = bytes_left;
617288943Sdim
618314564Sdim      error = Read(p + num_bytes, curr_num_bytes, offset);
619288943Sdim
620314564Sdim      // Update how many bytes were read
621314564Sdim      num_bytes += curr_num_bytes;
622314564Sdim      if (bytes_left < curr_num_bytes)
623314564Sdim        bytes_left = 0;
624314564Sdim      else
625314564Sdim        bytes_left -= curr_num_bytes;
626288943Sdim
627314564Sdim      if (error.Fail())
628314564Sdim        break;
629288943Sdim    }
630314564Sdim    return error;
631314564Sdim  }
632288943Sdim#endif
633288943Sdim
634258054Semaste#ifndef _WIN32
635314564Sdim  int fd = GetDescriptor();
636314564Sdim  if (fd != kInvalidDescriptor) {
637321369Sdim    ssize_t bytes_read =
638321369Sdim        llvm::sys::RetryAfterSignal(-1, ::pread, fd, buf, num_bytes, offset);
639314564Sdim    if (bytes_read < 0) {
640314564Sdim      num_bytes = 0;
641314564Sdim      error.SetErrorToErrno();
642314564Sdim    } else {
643314564Sdim      offset += bytes_read;
644314564Sdim      num_bytes = bytes_read;
645254721Semaste    }
646314564Sdim  } else {
647314564Sdim    num_bytes = 0;
648314564Sdim    error.SetErrorString("invalid file handle");
649314564Sdim  }
650258054Semaste#else
651353358Sdim  std::lock_guard<std::mutex> guard(offset_access_mutex);
652314564Sdim  long cur = ::lseek(m_descriptor, 0, SEEK_CUR);
653314564Sdim  SeekFromStart(offset);
654314564Sdim  error = Read(buf, num_bytes);
655314564Sdim  if (!error.Fail())
656314564Sdim    SeekFromStart(cur);
657288943Sdim#endif
658314564Sdim  return error;
659254721Semaste}
660254721Semaste
661360784SdimStatus NativeFile::Write(const void *buf, size_t &num_bytes, off_t &offset) {
662321369Sdim  Status error;
663314564Sdim
664314564Sdim#if defined(MAX_WRITE_SIZE)
665314564Sdim  if (num_bytes > MAX_WRITE_SIZE) {
666314564Sdim    const uint8_t *p = (const uint8_t *)buf;
667314564Sdim    size_t bytes_left = num_bytes;
668314564Sdim    // Init the num_bytes written to zero
669314564Sdim    num_bytes = 0;
670288943Sdim
671314564Sdim    while (bytes_left > 0) {
672314564Sdim      size_t curr_num_bytes;
673314564Sdim      if (bytes_left > MAX_WRITE_SIZE)
674314564Sdim        curr_num_bytes = MAX_WRITE_SIZE;
675314564Sdim      else
676314564Sdim        curr_num_bytes = bytes_left;
677288943Sdim
678314564Sdim      error = Write(p + num_bytes, curr_num_bytes, offset);
679288943Sdim
680314564Sdim      // Update how many bytes were read
681314564Sdim      num_bytes += curr_num_bytes;
682314564Sdim      if (bytes_left < curr_num_bytes)
683314564Sdim        bytes_left = 0;
684314564Sdim      else
685314564Sdim        bytes_left -= curr_num_bytes;
686288943Sdim
687314564Sdim      if (error.Fail())
688314564Sdim        break;
689288943Sdim    }
690314564Sdim    return error;
691314564Sdim  }
692288943Sdim#endif
693288943Sdim
694314564Sdim  int fd = GetDescriptor();
695314564Sdim  if (fd != kInvalidDescriptor) {
696258054Semaste#ifndef _WIN32
697321369Sdim    ssize_t bytes_written =
698321369Sdim        llvm::sys::RetryAfterSignal(-1, ::pwrite, m_descriptor, buf, num_bytes, offset);
699314564Sdim    if (bytes_written < 0) {
700314564Sdim      num_bytes = 0;
701314564Sdim      error.SetErrorToErrno();
702314564Sdim    } else {
703314564Sdim      offset += bytes_written;
704314564Sdim      num_bytes = bytes_written;
705314564Sdim    }
706258054Semaste#else
707353358Sdim    std::lock_guard<std::mutex> guard(offset_access_mutex);
708314564Sdim    long cur = ::lseek(m_descriptor, 0, SEEK_CUR);
709353358Sdim    SeekFromStart(offset);
710314564Sdim    error = Write(buf, num_bytes);
711314564Sdim    long after = ::lseek(m_descriptor, 0, SEEK_CUR);
712258054Semaste
713314564Sdim    if (!error.Fail())
714314564Sdim      SeekFromStart(cur);
715258054Semaste
716314564Sdim    offset = after;
717258054Semaste#endif
718314564Sdim  } else {
719314564Sdim    num_bytes = 0;
720314564Sdim    error.SetErrorString("invalid file handle");
721314564Sdim  }
722314564Sdim  return error;
723254721Semaste}
724254721Semaste
725360784Sdimsize_t NativeFile::PrintfVarArg(const char *format, va_list args) {
726360784Sdim  if (StreamIsValid()) {
727360784Sdim    return ::vfprintf(m_stream, format, args);
728360784Sdim  } else {
729360784Sdim    return File::PrintfVarArg(format, args);
730314564Sdim  }
731254721Semaste}
732258054Semaste
733360784Sdimmode_t File::ConvertOpenOptionsForPOSIXOpen(OpenOptions open_options) {
734314564Sdim  mode_t mode = 0;
735314564Sdim  if (open_options & eOpenOptionRead && open_options & eOpenOptionWrite)
736314564Sdim    mode |= O_RDWR;
737314564Sdim  else if (open_options & eOpenOptionWrite)
738314564Sdim    mode |= O_WRONLY;
739258054Semaste
740314564Sdim  if (open_options & eOpenOptionAppend)
741314564Sdim    mode |= O_APPEND;
742258054Semaste
743314564Sdim  if (open_options & eOpenOptionTruncate)
744314564Sdim    mode |= O_TRUNC;
745258054Semaste
746314564Sdim  if (open_options & eOpenOptionNonBlocking)
747314564Sdim    mode |= O_NONBLOCK;
748258054Semaste
749314564Sdim  if (open_options & eOpenOptionCanCreateNewOnly)
750314564Sdim    mode |= O_CREAT | O_EXCL;
751314564Sdim  else if (open_options & eOpenOptionCanCreate)
752314564Sdim    mode |= O_CREAT;
753314564Sdim
754314564Sdim  return mode;
755258054Semaste}
756262528Semaste
757360784Sdimchar File::ID = 0;
758360784Sdimchar NativeFile::ID = 0;
759