aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/lldb/source/Host/common/File.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/lldb/source/Host/common/File.cpp')
-rw-r--r--contrib/llvm-project/lldb/source/Host/common/File.cpp758
1 files changed, 758 insertions, 0 deletions
diff --git a/contrib/llvm-project/lldb/source/Host/common/File.cpp b/contrib/llvm-project/lldb/source/Host/common/File.cpp
new file mode 100644
index 000000000000..a5b970907e64
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Host/common/File.cpp
@@ -0,0 +1,758 @@
+//===-- File.cpp ----------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Host/File.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+#ifdef _WIN32
+#include "lldb/Host/windows/windows.h"
+#else
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <termios.h>
+#include <unistd.h>
+#endif
+
+#include "llvm/Support/ConvertUTF.h"
+#include "llvm/Support/Errno.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Process.h"
+
+#include "lldb/Host/Config.h"
+#include "lldb/Host/FileSystem.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/FileSpec.h"
+#include "lldb/Utility/Log.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using llvm::Expected;
+
+Expected<const char *>
+File::GetStreamOpenModeFromOptions(File::OpenOptions options) {
+ if (options & File::eOpenOptionAppend) {
+ if (options & File::eOpenOptionRead) {
+ if (options & File::eOpenOptionCanCreateNewOnly)
+ return "a+x";
+ else
+ return "a+";
+ } else if (options & File::eOpenOptionWrite) {
+ if (options & File::eOpenOptionCanCreateNewOnly)
+ return "ax";
+ else
+ return "a";
+ }
+ } else if (options & File::eOpenOptionRead &&
+ options & File::eOpenOptionWrite) {
+ if (options & File::eOpenOptionCanCreate) {
+ if (options & File::eOpenOptionCanCreateNewOnly)
+ return "w+x";
+ else
+ return "w+";
+ } else
+ return "r+";
+ } else if (options & File::eOpenOptionRead) {
+ return "r";
+ } else if (options & File::eOpenOptionWrite) {
+ return "w";
+ }
+ return llvm::createStringError(
+ llvm::inconvertibleErrorCode(),
+ "invalid options, cannot convert to mode string");
+}
+
+Expected<File::OpenOptions> File::GetOptionsFromMode(llvm::StringRef mode) {
+ OpenOptions opts =
+ llvm::StringSwitch<OpenOptions>(mode)
+ .Cases("r", "rb", eOpenOptionRead)
+ .Cases("w", "wb", eOpenOptionWrite)
+ .Cases("a", "ab",
+ eOpenOptionWrite | eOpenOptionAppend | eOpenOptionCanCreate)
+ .Cases("r+", "rb+", "r+b", eOpenOptionRead | eOpenOptionWrite)
+ .Cases("w+", "wb+", "w+b",
+ eOpenOptionRead | eOpenOptionWrite | eOpenOptionCanCreate |
+ eOpenOptionTruncate)
+ .Cases("a+", "ab+", "a+b",
+ eOpenOptionRead | eOpenOptionWrite | eOpenOptionAppend |
+ eOpenOptionCanCreate)
+ .Default(OpenOptions());
+ if (opts)
+ return opts;
+ return llvm::createStringError(
+ llvm::inconvertibleErrorCode(),
+ "invalid mode, cannot convert to File::OpenOptions");
+}
+
+int File::kInvalidDescriptor = -1;
+FILE *File::kInvalidStream = nullptr;
+
+Status File::Read(void *buf, size_t &num_bytes) {
+ return std::error_code(ENOTSUP, std::system_category());
+}
+Status File::Write(const void *buf, size_t &num_bytes) {
+ return std::error_code(ENOTSUP, std::system_category());
+}
+
+bool File::IsValid() const { return false; }
+
+Status File::Close() { return Flush(); }
+
+IOObject::WaitableHandle File::GetWaitableHandle() {
+ return IOObject::kInvalidHandleValue;
+}
+
+Status File::GetFileSpec(FileSpec &file_spec) const {
+ file_spec.Clear();
+ return std::error_code(ENOTSUP, std::system_category());
+}
+
+int File::GetDescriptor() const { return kInvalidDescriptor; }
+
+FILE *File::GetStream() { return nullptr; }
+
+off_t File::SeekFromStart(off_t offset, Status *error_ptr) {
+ if (error_ptr)
+ *error_ptr = std::error_code(ENOTSUP, std::system_category());
+ return -1;
+}
+
+off_t File::SeekFromCurrent(off_t offset, Status *error_ptr) {
+ if (error_ptr)
+ *error_ptr = std::error_code(ENOTSUP, std::system_category());
+ return -1;
+}
+
+off_t File::SeekFromEnd(off_t offset, Status *error_ptr) {
+ if (error_ptr)
+ *error_ptr = std::error_code(ENOTSUP, std::system_category());
+ return -1;
+}
+
+Status File::Read(void *dst, size_t &num_bytes, off_t &offset) {
+ return std::error_code(ENOTSUP, std::system_category());
+}
+
+Status File::Write(const void *src, size_t &num_bytes, off_t &offset) {
+ return std::error_code(ENOTSUP, std::system_category());
+}
+
+Status File::Flush() { return Status(); }
+
+Status File::Sync() { return Flush(); }
+
+void File::CalculateInteractiveAndTerminal() {
+ const int fd = GetDescriptor();
+ if (!DescriptorIsValid(fd)) {
+ m_is_interactive = eLazyBoolNo;
+ m_is_real_terminal = eLazyBoolNo;
+ m_supports_colors = eLazyBoolNo;
+ return;
+ }
+ m_is_interactive = eLazyBoolNo;
+ m_is_real_terminal = eLazyBoolNo;
+#if defined(_WIN32)
+ if (_isatty(fd)) {
+ m_is_interactive = eLazyBoolYes;
+ m_is_real_terminal = eLazyBoolYes;
+#if defined(ENABLE_VIRTUAL_TERMINAL_PROCESSING)
+ m_supports_colors = eLazyBoolYes;
+#endif
+ }
+#else
+ if (isatty(fd)) {
+ m_is_interactive = eLazyBoolYes;
+ struct winsize window_size;
+ if (::ioctl(fd, TIOCGWINSZ, &window_size) == 0) {
+ if (window_size.ws_col > 0) {
+ m_is_real_terminal = eLazyBoolYes;
+ if (llvm::sys::Process::FileDescriptorHasColors(fd))
+ m_supports_colors = eLazyBoolYes;
+ }
+ }
+ }
+#endif
+}
+
+bool File::GetIsInteractive() {
+ if (m_is_interactive == eLazyBoolCalculate)
+ CalculateInteractiveAndTerminal();
+ return m_is_interactive == eLazyBoolYes;
+}
+
+bool File::GetIsRealTerminal() {
+ if (m_is_real_terminal == eLazyBoolCalculate)
+ CalculateInteractiveAndTerminal();
+ return m_is_real_terminal == eLazyBoolYes;
+}
+
+bool File::GetIsTerminalWithColors() {
+ if (m_supports_colors == eLazyBoolCalculate)
+ CalculateInteractiveAndTerminal();
+ return m_supports_colors == eLazyBoolYes;
+}
+
+size_t File::Printf(const char *format, ...) {
+ va_list args;
+ va_start(args, format);
+ size_t result = PrintfVarArg(format, args);
+ va_end(args);
+ return result;
+}
+
+size_t File::PrintfVarArg(const char *format, va_list args) {
+ size_t result = 0;
+ char *s = nullptr;
+ result = vasprintf(&s, format, args);
+ if (s != nullptr) {
+ if (result > 0) {
+ size_t s_len = result;
+ Write(s, s_len);
+ result = s_len;
+ }
+ free(s);
+ }
+ return result;
+}
+
+Expected<File::OpenOptions> File::GetOptions() const {
+ return llvm::createStringError(
+ llvm::inconvertibleErrorCode(),
+ "GetOptions() not implemented for this File class");
+}
+
+uint32_t File::GetPermissions(Status &error) const {
+ int fd = GetDescriptor();
+ if (!DescriptorIsValid(fd)) {
+ error = std::error_code(ENOTSUP, std::system_category());
+ return 0;
+ }
+ struct stat file_stats;
+ if (::fstat(fd, &file_stats) == -1) {
+ error.SetErrorToErrno();
+ return 0;
+ }
+ error.Clear();
+ return file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
+}
+
+Expected<File::OpenOptions> NativeFile::GetOptions() const { return m_options; }
+
+int NativeFile::GetDescriptor() const {
+ if (DescriptorIsValid())
+ return m_descriptor;
+
+ // Don't open the file descriptor if we don't need to, just get it from the
+ // stream if we have one.
+ if (StreamIsValid()) {
+#if defined(_WIN32)
+ return _fileno(m_stream);
+#else
+ return fileno(m_stream);
+#endif
+ }
+
+ // Invalid descriptor and invalid stream, return invalid descriptor.
+ return kInvalidDescriptor;
+}
+
+IOObject::WaitableHandle NativeFile::GetWaitableHandle() {
+ return GetDescriptor();
+}
+
+FILE *NativeFile::GetStream() {
+ if (!StreamIsValid()) {
+ if (DescriptorIsValid()) {
+ auto mode = GetStreamOpenModeFromOptions(m_options);
+ if (!mode)
+ llvm::consumeError(mode.takeError());
+ else {
+ if (!m_own_descriptor) {
+// We must duplicate the file descriptor if we don't own it because when you
+// call fdopen, the stream will own the fd
+#ifdef _WIN32
+ m_descriptor = ::_dup(GetDescriptor());
+#else
+ m_descriptor = dup(GetDescriptor());
+#endif
+ m_own_descriptor = true;
+ }
+
+ m_stream = llvm::sys::RetryAfterSignal(nullptr, ::fdopen, m_descriptor,
+ mode.get());
+
+ // If we got a stream, then we own the stream and should no longer own
+ // the descriptor because fclose() will close it for us
+
+ if (m_stream) {
+ m_own_stream = true;
+ m_own_descriptor = false;
+ }
+ }
+ }
+ }
+ return m_stream;
+}
+
+Status NativeFile::Close() {
+ Status error;
+ if (StreamIsValid()) {
+ if (m_own_stream) {
+ if (::fclose(m_stream) == EOF)
+ error.SetErrorToErrno();
+ } else if (m_options & eOpenOptionWrite) {
+ if (::fflush(m_stream) == EOF)
+ error.SetErrorToErrno();
+ }
+ }
+ if (DescriptorIsValid() && m_own_descriptor) {
+ if (::close(m_descriptor) != 0)
+ error.SetErrorToErrno();
+ }
+ m_descriptor = kInvalidDescriptor;
+ m_stream = kInvalidStream;
+ m_options = OpenOptions(0);
+ m_own_stream = false;
+ m_own_descriptor = false;
+ m_is_interactive = eLazyBoolCalculate;
+ m_is_real_terminal = eLazyBoolCalculate;
+ return error;
+}
+
+Status NativeFile::GetFileSpec(FileSpec &file_spec) const {
+ Status error;
+#ifdef F_GETPATH
+ if (IsValid()) {
+ char path[PATH_MAX];
+ if (::fcntl(GetDescriptor(), F_GETPATH, path) == -1)
+ error.SetErrorToErrno();
+ else
+ file_spec.SetFile(path, FileSpec::Style::native);
+ } else {
+ error.SetErrorString("invalid file handle");
+ }
+#elif defined(__linux__)
+ char proc[64];
+ char path[PATH_MAX];
+ if (::snprintf(proc, sizeof(proc), "/proc/self/fd/%d", GetDescriptor()) < 0)
+ error.SetErrorString("cannot resolve file descriptor");
+ else {
+ ssize_t len;
+ if ((len = ::readlink(proc, path, sizeof(path) - 1)) == -1)
+ error.SetErrorToErrno();
+ else {
+ path[len] = '\0';
+ file_spec.SetFile(path, FileSpec::Style::native);
+ }
+ }
+#else
+ error.SetErrorString(
+ "NativeFile::GetFileSpec is not supported on this platform");
+#endif
+
+ if (error.Fail())
+ file_spec.Clear();
+ return error;
+}
+
+off_t NativeFile::SeekFromStart(off_t offset, Status *error_ptr) {
+ off_t result = 0;
+ if (DescriptorIsValid()) {
+ result = ::lseek(m_descriptor, offset, SEEK_SET);
+
+ if (error_ptr) {
+ if (result == -1)
+ error_ptr->SetErrorToErrno();
+ else
+ error_ptr->Clear();
+ }
+ } else if (StreamIsValid()) {
+ result = ::fseek(m_stream, offset, SEEK_SET);
+
+ if (error_ptr) {
+ if (result == -1)
+ error_ptr->SetErrorToErrno();
+ else
+ error_ptr->Clear();
+ }
+ } else if (error_ptr) {
+ error_ptr->SetErrorString("invalid file handle");
+ }
+ return result;
+}
+
+off_t NativeFile::SeekFromCurrent(off_t offset, Status *error_ptr) {
+ off_t result = -1;
+ if (DescriptorIsValid()) {
+ result = ::lseek(m_descriptor, offset, SEEK_CUR);
+
+ if (error_ptr) {
+ if (result == -1)
+ error_ptr->SetErrorToErrno();
+ else
+ error_ptr->Clear();
+ }
+ } else if (StreamIsValid()) {
+ result = ::fseek(m_stream, offset, SEEK_CUR);
+
+ if (error_ptr) {
+ if (result == -1)
+ error_ptr->SetErrorToErrno();
+ else
+ error_ptr->Clear();
+ }
+ } else if (error_ptr) {
+ error_ptr->SetErrorString("invalid file handle");
+ }
+ return result;
+}
+
+off_t NativeFile::SeekFromEnd(off_t offset, Status *error_ptr) {
+ off_t result = -1;
+ if (DescriptorIsValid()) {
+ result = ::lseek(m_descriptor, offset, SEEK_END);
+
+ if (error_ptr) {
+ if (result == -1)
+ error_ptr->SetErrorToErrno();
+ else
+ error_ptr->Clear();
+ }
+ } else if (StreamIsValid()) {
+ result = ::fseek(m_stream, offset, SEEK_END);
+
+ if (error_ptr) {
+ if (result == -1)
+ error_ptr->SetErrorToErrno();
+ else
+ error_ptr->Clear();
+ }
+ } else if (error_ptr) {
+ error_ptr->SetErrorString("invalid file handle");
+ }
+ return result;
+}
+
+Status NativeFile::Flush() {
+ Status error;
+ if (StreamIsValid()) {
+ if (llvm::sys::RetryAfterSignal(EOF, ::fflush, m_stream) == EOF)
+ error.SetErrorToErrno();
+ } else if (!DescriptorIsValid()) {
+ error.SetErrorString("invalid file handle");
+ }
+ return error;
+}
+
+Status NativeFile::Sync() {
+ Status error;
+ if (DescriptorIsValid()) {
+#ifdef _WIN32
+ int err = FlushFileBuffers((HANDLE)_get_osfhandle(m_descriptor));
+ if (err == 0)
+ error.SetErrorToGenericError();
+#else
+ if (llvm::sys::RetryAfterSignal(-1, ::fsync, m_descriptor) == -1)
+ error.SetErrorToErrno();
+#endif
+ } else {
+ error.SetErrorString("invalid file handle");
+ }
+ return error;
+}
+
+#if defined(__APPLE__)
+// Darwin kernels only can read/write <= INT_MAX bytes
+#define MAX_READ_SIZE INT_MAX
+#define MAX_WRITE_SIZE INT_MAX
+#endif
+
+Status NativeFile::Read(void *buf, size_t &num_bytes) {
+ Status error;
+
+#if defined(MAX_READ_SIZE)
+ if (num_bytes > MAX_READ_SIZE) {
+ uint8_t *p = (uint8_t *)buf;
+ size_t bytes_left = num_bytes;
+ // Init the num_bytes read to zero
+ num_bytes = 0;
+
+ while (bytes_left > 0) {
+ size_t curr_num_bytes;
+ if (bytes_left > MAX_READ_SIZE)
+ curr_num_bytes = MAX_READ_SIZE;
+ else
+ curr_num_bytes = bytes_left;
+
+ error = Read(p + num_bytes, curr_num_bytes);
+
+ // Update how many bytes were read
+ num_bytes += curr_num_bytes;
+ if (bytes_left < curr_num_bytes)
+ bytes_left = 0;
+ else
+ bytes_left -= curr_num_bytes;
+
+ if (error.Fail())
+ break;
+ }
+ return error;
+ }
+#endif
+
+ ssize_t bytes_read = -1;
+ if (DescriptorIsValid()) {
+ bytes_read = llvm::sys::RetryAfterSignal(-1, ::read, m_descriptor, buf, num_bytes);
+ if (bytes_read == -1) {
+ error.SetErrorToErrno();
+ num_bytes = 0;
+ } else
+ num_bytes = bytes_read;
+ } else if (StreamIsValid()) {
+ bytes_read = ::fread(buf, 1, num_bytes, m_stream);
+
+ if (bytes_read == 0) {
+ if (::feof(m_stream))
+ error.SetErrorString("feof");
+ else if (::ferror(m_stream))
+ error.SetErrorString("ferror");
+ num_bytes = 0;
+ } else
+ num_bytes = bytes_read;
+ } else {
+ num_bytes = 0;
+ error.SetErrorString("invalid file handle");
+ }
+ return error;
+}
+
+Status NativeFile::Write(const void *buf, size_t &num_bytes) {
+ Status error;
+
+#if defined(MAX_WRITE_SIZE)
+ if (num_bytes > MAX_WRITE_SIZE) {
+ const uint8_t *p = (const uint8_t *)buf;
+ size_t bytes_left = num_bytes;
+ // Init the num_bytes written to zero
+ num_bytes = 0;
+
+ while (bytes_left > 0) {
+ size_t curr_num_bytes;
+ if (bytes_left > MAX_WRITE_SIZE)
+ curr_num_bytes = MAX_WRITE_SIZE;
+ else
+ curr_num_bytes = bytes_left;
+
+ error = Write(p + num_bytes, curr_num_bytes);
+
+ // Update how many bytes were read
+ num_bytes += curr_num_bytes;
+ if (bytes_left < curr_num_bytes)
+ bytes_left = 0;
+ else
+ bytes_left -= curr_num_bytes;
+
+ if (error.Fail())
+ break;
+ }
+ return error;
+ }
+#endif
+
+ ssize_t bytes_written = -1;
+ if (DescriptorIsValid()) {
+ bytes_written =
+ llvm::sys::RetryAfterSignal(-1, ::write, m_descriptor, buf, num_bytes);
+ if (bytes_written == -1) {
+ error.SetErrorToErrno();
+ num_bytes = 0;
+ } else
+ num_bytes = bytes_written;
+ } else if (StreamIsValid()) {
+ bytes_written = ::fwrite(buf, 1, num_bytes, m_stream);
+
+ if (bytes_written == 0) {
+ if (::feof(m_stream))
+ error.SetErrorString("feof");
+ else if (::ferror(m_stream))
+ error.SetErrorString("ferror");
+ num_bytes = 0;
+ } else
+ num_bytes = bytes_written;
+
+ } else {
+ num_bytes = 0;
+ error.SetErrorString("invalid file handle");
+ }
+
+ return error;
+}
+
+Status NativeFile::Read(void *buf, size_t &num_bytes, off_t &offset) {
+ Status error;
+
+#if defined(MAX_READ_SIZE)
+ if (num_bytes > MAX_READ_SIZE) {
+ uint8_t *p = (uint8_t *)buf;
+ size_t bytes_left = num_bytes;
+ // Init the num_bytes read to zero
+ num_bytes = 0;
+
+ while (bytes_left > 0) {
+ size_t curr_num_bytes;
+ if (bytes_left > MAX_READ_SIZE)
+ curr_num_bytes = MAX_READ_SIZE;
+ else
+ curr_num_bytes = bytes_left;
+
+ error = Read(p + num_bytes, curr_num_bytes, offset);
+
+ // Update how many bytes were read
+ num_bytes += curr_num_bytes;
+ if (bytes_left < curr_num_bytes)
+ bytes_left = 0;
+ else
+ bytes_left -= curr_num_bytes;
+
+ if (error.Fail())
+ break;
+ }
+ return error;
+ }
+#endif
+
+#ifndef _WIN32
+ int fd = GetDescriptor();
+ if (fd != kInvalidDescriptor) {
+ ssize_t bytes_read =
+ llvm::sys::RetryAfterSignal(-1, ::pread, fd, buf, num_bytes, offset);
+ if (bytes_read < 0) {
+ num_bytes = 0;
+ error.SetErrorToErrno();
+ } else {
+ offset += bytes_read;
+ num_bytes = bytes_read;
+ }
+ } else {
+ num_bytes = 0;
+ error.SetErrorString("invalid file handle");
+ }
+#else
+ std::lock_guard<std::mutex> guard(offset_access_mutex);
+ long cur = ::lseek(m_descriptor, 0, SEEK_CUR);
+ SeekFromStart(offset);
+ error = Read(buf, num_bytes);
+ if (!error.Fail())
+ SeekFromStart(cur);
+#endif
+ return error;
+}
+
+Status NativeFile::Write(const void *buf, size_t &num_bytes, off_t &offset) {
+ Status error;
+
+#if defined(MAX_WRITE_SIZE)
+ if (num_bytes > MAX_WRITE_SIZE) {
+ const uint8_t *p = (const uint8_t *)buf;
+ size_t bytes_left = num_bytes;
+ // Init the num_bytes written to zero
+ num_bytes = 0;
+
+ while (bytes_left > 0) {
+ size_t curr_num_bytes;
+ if (bytes_left > MAX_WRITE_SIZE)
+ curr_num_bytes = MAX_WRITE_SIZE;
+ else
+ curr_num_bytes = bytes_left;
+
+ error = Write(p + num_bytes, curr_num_bytes, offset);
+
+ // Update how many bytes were read
+ num_bytes += curr_num_bytes;
+ if (bytes_left < curr_num_bytes)
+ bytes_left = 0;
+ else
+ bytes_left -= curr_num_bytes;
+
+ if (error.Fail())
+ break;
+ }
+ return error;
+ }
+#endif
+
+ int fd = GetDescriptor();
+ if (fd != kInvalidDescriptor) {
+#ifndef _WIN32
+ ssize_t bytes_written =
+ llvm::sys::RetryAfterSignal(-1, ::pwrite, m_descriptor, buf, num_bytes, offset);
+ if (bytes_written < 0) {
+ num_bytes = 0;
+ error.SetErrorToErrno();
+ } else {
+ offset += bytes_written;
+ num_bytes = bytes_written;
+ }
+#else
+ std::lock_guard<std::mutex> guard(offset_access_mutex);
+ long cur = ::lseek(m_descriptor, 0, SEEK_CUR);
+ SeekFromStart(offset);
+ error = Write(buf, num_bytes);
+ long after = ::lseek(m_descriptor, 0, SEEK_CUR);
+
+ if (!error.Fail())
+ SeekFromStart(cur);
+
+ offset = after;
+#endif
+ } else {
+ num_bytes = 0;
+ error.SetErrorString("invalid file handle");
+ }
+ return error;
+}
+
+size_t NativeFile::PrintfVarArg(const char *format, va_list args) {
+ if (StreamIsValid()) {
+ return ::vfprintf(m_stream, format, args);
+ } else {
+ return File::PrintfVarArg(format, args);
+ }
+}
+
+mode_t File::ConvertOpenOptionsForPOSIXOpen(OpenOptions open_options) {
+ mode_t mode = 0;
+ if (open_options & eOpenOptionRead && open_options & eOpenOptionWrite)
+ mode |= O_RDWR;
+ else if (open_options & eOpenOptionWrite)
+ mode |= O_WRONLY;
+
+ if (open_options & eOpenOptionAppend)
+ mode |= O_APPEND;
+
+ if (open_options & eOpenOptionTruncate)
+ mode |= O_TRUNC;
+
+ if (open_options & eOpenOptionNonBlocking)
+ mode |= O_NONBLOCK;
+
+ if (open_options & eOpenOptionCanCreateNewOnly)
+ mode |= O_CREAT | O_EXCL;
+ else if (open_options & eOpenOptionCanCreate)
+ mode |= O_CREAT;
+
+ return mode;
+}
+
+char File::ID = 0;
+char NativeFile::ID = 0;