180814287SRaphael Isemann //===-- File.cpp ----------------------------------------------------------===//
2504f89a7SGreg Clayton //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6504f89a7SGreg Clayton //
7504f89a7SGreg Clayton //===----------------------------------------------------------------------===//
8504f89a7SGreg Clayton
9504f89a7SGreg Clayton #include "lldb/Host/File.h"
10504f89a7SGreg Clayton
1176e47d48SRaphael Isemann #include <cerrno>
1276e47d48SRaphael Isemann #include <climits>
1376e47d48SRaphael Isemann #include <cstdarg>
1476e47d48SRaphael Isemann #include <cstdio>
15504f89a7SGreg Clayton #include <fcntl.h>
16504f89a7SGreg Clayton
17b2f1fb29SVirgile Bello #ifdef _WIN32
18b2f1fb29SVirgile Bello #include "lldb/Host/windows/windows.h"
1994667bcfSDeepak Panickal #else
2094667bcfSDeepak Panickal #include <sys/ioctl.h>
215821a3bfSZachary Turner #include <sys/stat.h>
22b8ad0155SPavel Labath #include <termios.h>
23b6dbe9a9SPavel Labath #include <unistd.h>
24b2f1fb29SVirgile Bello #endif
25b2f1fb29SVirgile Bello
26925137cfSGreg Clayton #include "lldb/Host/Config.h"
27d7c2b798SJonas Devlieghere #include "lldb/Host/FileSystem.h"
28c1a6b128SPavel Labath #include "lldb/Host/Host.h"
29666cc0b2SZachary Turner #include "lldb/Utility/DataBufferHeap.h"
305713a05bSZachary Turner #include "lldb/Utility/FileSpec.h"
316f9e6901SZachary Turner #include "lldb/Utility/Log.h"
321410a486SPavel Labath #include "lldb/Utility/VASPrintf.h"
331410a486SPavel Labath #include "llvm/Support/ConvertUTF.h"
341410a486SPavel Labath #include "llvm/Support/Errno.h"
351410a486SPavel Labath #include "llvm/Support/FileSystem.h"
361410a486SPavel Labath #include "llvm/Support/Process.h"
37504f89a7SGreg Clayton
38504f89a7SGreg Clayton using namespace lldb;
39504f89a7SGreg Clayton using namespace lldb_private;
4062c9fe42SLawrence D'Anna using llvm::Expected;
41504f89a7SGreg Clayton
42d9b553ecSLawrence D'Anna Expected<const char *>
GetStreamOpenModeFromOptions(File::OpenOptions options)43d9b553ecSLawrence D'Anna File::GetStreamOpenModeFromOptions(File::OpenOptions options) {
4414735cabSMichał Górny File::OpenOptions rw =
4514735cabSMichał Górny options & (File::eOpenOptionReadOnly | File::eOpenOptionWriteOnly |
4614735cabSMichał Górny File::eOpenOptionReadWrite);
4714735cabSMichał Górny
48b9c1b51eSKate Stone if (options & File::eOpenOptionAppend) {
4914735cabSMichał Górny if (rw == File::eOpenOptionReadWrite) {
5051b1e2d2SGreg Clayton if (options & File::eOpenOptionCanCreateNewOnly)
5151b1e2d2SGreg Clayton return "a+x";
5251b1e2d2SGreg Clayton else
5351b1e2d2SGreg Clayton return "a+";
5414735cabSMichał Górny } else if (rw == File::eOpenOptionWriteOnly) {
5551b1e2d2SGreg Clayton if (options & File::eOpenOptionCanCreateNewOnly)
5651b1e2d2SGreg Clayton return "ax";
5751b1e2d2SGreg Clayton else
5851b1e2d2SGreg Clayton return "a";
5951b1e2d2SGreg Clayton }
6014735cabSMichał Górny } else if (rw == File::eOpenOptionReadWrite) {
61b9c1b51eSKate Stone if (options & File::eOpenOptionCanCreate) {
6251b1e2d2SGreg Clayton if (options & File::eOpenOptionCanCreateNewOnly)
6351b1e2d2SGreg Clayton return "w+x";
6451b1e2d2SGreg Clayton else
6551b1e2d2SGreg Clayton return "w+";
66b9c1b51eSKate Stone } else
6751b1e2d2SGreg Clayton return "r+";
6814735cabSMichał Górny } else if (rw == File::eOpenOptionWriteOnly) {
6951b1e2d2SGreg Clayton return "w";
7014735cabSMichał Górny } else if (rw == File::eOpenOptionReadOnly) {
7114735cabSMichał Górny return "r";
7251b1e2d2SGreg Clayton }
7362c9fe42SLawrence D'Anna return llvm::createStringError(
7462c9fe42SLawrence D'Anna llvm::inconvertibleErrorCode(),
7562c9fe42SLawrence D'Anna "invalid options, cannot convert to mode string");
7651b1e2d2SGreg Clayton }
7751b1e2d2SGreg Clayton
GetOptionsFromMode(llvm::StringRef mode)7862c9fe42SLawrence D'Anna Expected<File::OpenOptions> File::GetOptionsFromMode(llvm::StringRef mode) {
7962c9fe42SLawrence D'Anna OpenOptions opts =
8062c9fe42SLawrence D'Anna llvm::StringSwitch<OpenOptions>(mode)
8114735cabSMichał Górny .Cases("r", "rb", eOpenOptionReadOnly)
8214735cabSMichał Górny .Cases("w", "wb", eOpenOptionWriteOnly)
83342b1b2eSPavel Labath .Cases("a", "ab",
8414735cabSMichał Górny eOpenOptionWriteOnly | eOpenOptionAppend |
8514735cabSMichał Górny eOpenOptionCanCreate)
8614735cabSMichał Górny .Cases("r+", "rb+", "r+b", eOpenOptionReadWrite)
87342b1b2eSPavel Labath .Cases("w+", "wb+", "w+b",
8814735cabSMichał Górny eOpenOptionReadWrite | eOpenOptionCanCreate |
89342b1b2eSPavel Labath eOpenOptionTruncate)
90342b1b2eSPavel Labath .Cases("a+", "ab+", "a+b",
9114735cabSMichał Górny eOpenOptionReadWrite | eOpenOptionAppend |
92342b1b2eSPavel Labath eOpenOptionCanCreate)
938bbef4f9SMichał Górny .Default(eOpenOptionInvalid);
948bbef4f9SMichał Górny if (opts != eOpenOptionInvalid)
9562c9fe42SLawrence D'Anna return opts;
9662c9fe42SLawrence D'Anna return llvm::createStringError(
9762c9fe42SLawrence D'Anna llvm::inconvertibleErrorCode(),
9862c9fe42SLawrence D'Anna "invalid mode, cannot convert to File::OpenOptions");
9957504530SLawrence D'Anna }
10057504530SLawrence D'Anna
10151b1e2d2SGreg Clayton int File::kInvalidDescriptor = -1;
102248a1305SKonrad Kleine FILE *File::kInvalidStream = nullptr;
10351b1e2d2SGreg Clayton
Read(void * buf,size_t & num_bytes)104f913fd6eSLawrence D'Anna Status File::Read(void *buf, size_t &num_bytes) {
105f913fd6eSLawrence D'Anna return std::error_code(ENOTSUP, std::system_category());
106f913fd6eSLawrence D'Anna }
Write(const void * buf,size_t & num_bytes)107f913fd6eSLawrence D'Anna Status File::Write(const void *buf, size_t &num_bytes) {
108f913fd6eSLawrence D'Anna return std::error_code(ENOTSUP, std::system_category());
109f913fd6eSLawrence D'Anna }
110504f89a7SGreg Clayton
IsValid() const111f913fd6eSLawrence D'Anna bool File::IsValid() const { return false; }
112f913fd6eSLawrence D'Anna
Close()113f913fd6eSLawrence D'Anna Status File::Close() { return Flush(); }
114f913fd6eSLawrence D'Anna
GetWaitableHandle()115f913fd6eSLawrence D'Anna IOObject::WaitableHandle File::GetWaitableHandle() {
116f913fd6eSLawrence D'Anna return IOObject::kInvalidHandleValue;
117f913fd6eSLawrence D'Anna }
118f913fd6eSLawrence D'Anna
GetFileSpec(FileSpec & file_spec) const119f913fd6eSLawrence D'Anna Status File::GetFileSpec(FileSpec &file_spec) const {
120f913fd6eSLawrence D'Anna file_spec.Clear();
121f913fd6eSLawrence D'Anna return std::error_code(ENOTSUP, std::system_category());
122f913fd6eSLawrence D'Anna }
123f913fd6eSLawrence D'Anna
GetDescriptor() const124f913fd6eSLawrence D'Anna int File::GetDescriptor() const { return kInvalidDescriptor; }
125f913fd6eSLawrence D'Anna
GetStream()126f913fd6eSLawrence D'Anna FILE *File::GetStream() { return nullptr; }
127f913fd6eSLawrence D'Anna
SeekFromStart(off_t offset,Status * error_ptr)128f913fd6eSLawrence D'Anna off_t File::SeekFromStart(off_t offset, Status *error_ptr) {
129f913fd6eSLawrence D'Anna if (error_ptr)
130f913fd6eSLawrence D'Anna *error_ptr = std::error_code(ENOTSUP, std::system_category());
131f913fd6eSLawrence D'Anna return -1;
132f913fd6eSLawrence D'Anna }
133f913fd6eSLawrence D'Anna
SeekFromCurrent(off_t offset,Status * error_ptr)134f913fd6eSLawrence D'Anna off_t File::SeekFromCurrent(off_t offset, Status *error_ptr) {
135f913fd6eSLawrence D'Anna if (error_ptr)
136f913fd6eSLawrence D'Anna *error_ptr = std::error_code(ENOTSUP, std::system_category());
137f913fd6eSLawrence D'Anna return -1;
138f913fd6eSLawrence D'Anna }
139f913fd6eSLawrence D'Anna
SeekFromEnd(off_t offset,Status * error_ptr)140f913fd6eSLawrence D'Anna off_t File::SeekFromEnd(off_t offset, Status *error_ptr) {
141f913fd6eSLawrence D'Anna if (error_ptr)
142f913fd6eSLawrence D'Anna *error_ptr = std::error_code(ENOTSUP, std::system_category());
143f913fd6eSLawrence D'Anna return -1;
144f913fd6eSLawrence D'Anna }
145f913fd6eSLawrence D'Anna
Read(void * dst,size_t & num_bytes,off_t & offset)146f913fd6eSLawrence D'Anna Status File::Read(void *dst, size_t &num_bytes, off_t &offset) {
147f913fd6eSLawrence D'Anna return std::error_code(ENOTSUP, std::system_category());
148f913fd6eSLawrence D'Anna }
149f913fd6eSLawrence D'Anna
Write(const void * src,size_t & num_bytes,off_t & offset)150f913fd6eSLawrence D'Anna Status File::Write(const void *src, size_t &num_bytes, off_t &offset) {
151f913fd6eSLawrence D'Anna return std::error_code(ENOTSUP, std::system_category());
152f913fd6eSLawrence D'Anna }
153f913fd6eSLawrence D'Anna
Flush()154f913fd6eSLawrence D'Anna Status File::Flush() { return Status(); }
155f913fd6eSLawrence D'Anna
Sync()156f913fd6eSLawrence D'Anna Status File::Sync() { return Flush(); }
157f913fd6eSLawrence D'Anna
CalculateInteractiveAndTerminal()158f913fd6eSLawrence D'Anna void File::CalculateInteractiveAndTerminal() {
159f913fd6eSLawrence D'Anna const int fd = GetDescriptor();
160f913fd6eSLawrence D'Anna if (!DescriptorIsValid(fd)) {
161f913fd6eSLawrence D'Anna m_is_interactive = eLazyBoolNo;
162f913fd6eSLawrence D'Anna m_is_real_terminal = eLazyBoolNo;
163f913fd6eSLawrence D'Anna m_supports_colors = eLazyBoolNo;
164f913fd6eSLawrence D'Anna return;
165f913fd6eSLawrence D'Anna }
166f913fd6eSLawrence D'Anna m_is_interactive = eLazyBoolNo;
167f913fd6eSLawrence D'Anna m_is_real_terminal = eLazyBoolNo;
168f913fd6eSLawrence D'Anna #if defined(_WIN32)
169f913fd6eSLawrence D'Anna if (_isatty(fd)) {
170f913fd6eSLawrence D'Anna m_is_interactive = eLazyBoolYes;
171f913fd6eSLawrence D'Anna m_is_real_terminal = eLazyBoolYes;
172f913fd6eSLawrence D'Anna #if defined(ENABLE_VIRTUAL_TERMINAL_PROCESSING)
173f913fd6eSLawrence D'Anna m_supports_colors = eLazyBoolYes;
174f913fd6eSLawrence D'Anna #endif
175f913fd6eSLawrence D'Anna }
176f913fd6eSLawrence D'Anna #else
177f913fd6eSLawrence D'Anna if (isatty(fd)) {
178f913fd6eSLawrence D'Anna m_is_interactive = eLazyBoolYes;
179f913fd6eSLawrence D'Anna struct winsize window_size;
180f913fd6eSLawrence D'Anna if (::ioctl(fd, TIOCGWINSZ, &window_size) == 0) {
181f913fd6eSLawrence D'Anna if (window_size.ws_col > 0) {
182f913fd6eSLawrence D'Anna m_is_real_terminal = eLazyBoolYes;
183f913fd6eSLawrence D'Anna if (llvm::sys::Process::FileDescriptorHasColors(fd))
184f913fd6eSLawrence D'Anna m_supports_colors = eLazyBoolYes;
185f913fd6eSLawrence D'Anna }
186f913fd6eSLawrence D'Anna }
187f913fd6eSLawrence D'Anna }
188f913fd6eSLawrence D'Anna #endif
189f913fd6eSLawrence D'Anna }
190f913fd6eSLawrence D'Anna
GetIsInteractive()191f913fd6eSLawrence D'Anna bool File::GetIsInteractive() {
192f913fd6eSLawrence D'Anna if (m_is_interactive == eLazyBoolCalculate)
193f913fd6eSLawrence D'Anna CalculateInteractiveAndTerminal();
194f913fd6eSLawrence D'Anna return m_is_interactive == eLazyBoolYes;
195f913fd6eSLawrence D'Anna }
196f913fd6eSLawrence D'Anna
GetIsRealTerminal()197f913fd6eSLawrence D'Anna bool File::GetIsRealTerminal() {
198f913fd6eSLawrence D'Anna if (m_is_real_terminal == eLazyBoolCalculate)
199f913fd6eSLawrence D'Anna CalculateInteractiveAndTerminal();
200f913fd6eSLawrence D'Anna return m_is_real_terminal == eLazyBoolYes;
201f913fd6eSLawrence D'Anna }
202f913fd6eSLawrence D'Anna
GetIsTerminalWithColors()203f913fd6eSLawrence D'Anna bool File::GetIsTerminalWithColors() {
204f913fd6eSLawrence D'Anna if (m_supports_colors == eLazyBoolCalculate)
205f913fd6eSLawrence D'Anna CalculateInteractiveAndTerminal();
206f913fd6eSLawrence D'Anna return m_supports_colors == eLazyBoolYes;
207f913fd6eSLawrence D'Anna }
208f913fd6eSLawrence D'Anna
Printf(const char * format,...)209f913fd6eSLawrence D'Anna size_t File::Printf(const char *format, ...) {
210f913fd6eSLawrence D'Anna va_list args;
211f913fd6eSLawrence D'Anna va_start(args, format);
212f913fd6eSLawrence D'Anna size_t result = PrintfVarArg(format, args);
213f913fd6eSLawrence D'Anna va_end(args);
214f913fd6eSLawrence D'Anna return result;
215f913fd6eSLawrence D'Anna }
216f913fd6eSLawrence D'Anna
PrintfVarArg(const char * format,va_list args)217f913fd6eSLawrence D'Anna size_t File::PrintfVarArg(const char *format, va_list args) {
2181410a486SPavel Labath llvm::SmallString<0> s;
2191410a486SPavel Labath if (VASprintf(s, format, args)) {
2201410a486SPavel Labath size_t written = s.size();;
2211410a486SPavel Labath Write(s.data(), written);
2221410a486SPavel Labath return written;
223f913fd6eSLawrence D'Anna }
2241410a486SPavel Labath return 0;
225f913fd6eSLawrence D'Anna }
226f913fd6eSLawrence D'Anna
GetOptions() const227d9b553ecSLawrence D'Anna Expected<File::OpenOptions> File::GetOptions() const {
228d9b553ecSLawrence D'Anna return llvm::createStringError(
229d9b553ecSLawrence D'Anna llvm::inconvertibleErrorCode(),
230d9b553ecSLawrence D'Anna "GetOptions() not implemented for this File class");
231d9b553ecSLawrence D'Anna }
232d9b553ecSLawrence D'Anna
GetPermissions(Status & error) const233f913fd6eSLawrence D'Anna uint32_t File::GetPermissions(Status &error) const {
234f913fd6eSLawrence D'Anna int fd = GetDescriptor();
235f913fd6eSLawrence D'Anna if (!DescriptorIsValid(fd)) {
236f913fd6eSLawrence D'Anna error = std::error_code(ENOTSUP, std::system_category());
237f913fd6eSLawrence D'Anna return 0;
238f913fd6eSLawrence D'Anna }
239f913fd6eSLawrence D'Anna struct stat file_stats;
240f913fd6eSLawrence D'Anna if (::fstat(fd, &file_stats) == -1) {
241f913fd6eSLawrence D'Anna error.SetErrorToErrno();
242f913fd6eSLawrence D'Anna return 0;
243f913fd6eSLawrence D'Anna }
244f913fd6eSLawrence D'Anna error.Clear();
245f913fd6eSLawrence D'Anna return file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
246f913fd6eSLawrence D'Anna }
247f913fd6eSLawrence D'Anna
GetOptions() const248d9b553ecSLawrence D'Anna Expected<File::OpenOptions> NativeFile::GetOptions() const { return m_options; }
249d9b553ecSLawrence D'Anna
GetDescriptor() const250f913fd6eSLawrence D'Anna int NativeFile::GetDescriptor() const {
25151b1e2d2SGreg Clayton if (DescriptorIsValid())
25251b1e2d2SGreg Clayton return m_descriptor;
25351b1e2d2SGreg Clayton
25451b1e2d2SGreg Clayton // Don't open the file descriptor if we don't need to, just get it from the
25551b1e2d2SGreg Clayton // stream if we have one.
256b9c1b51eSKate Stone if (StreamIsValid()) {
257b1cb0b79SNico Weber #if defined(_WIN32)
2589c40264fSZachary Turner return _fileno(m_stream);
2599c40264fSZachary Turner #else
26051b1e2d2SGreg Clayton return fileno(m_stream);
2619c40264fSZachary Turner #endif
2629c40264fSZachary Turner }
26351b1e2d2SGreg Clayton
26451b1e2d2SGreg Clayton // Invalid descriptor and invalid stream, return invalid descriptor.
26551b1e2d2SGreg Clayton return kInvalidDescriptor;
26651b1e2d2SGreg Clayton }
26751b1e2d2SGreg Clayton
GetWaitableHandle()268f913fd6eSLawrence D'Anna IOObject::WaitableHandle NativeFile::GetWaitableHandle() {
269f913fd6eSLawrence D'Anna return GetDescriptor();
270f913fd6eSLawrence D'Anna }
27198688922SZachary Turner
GetStream()272f913fd6eSLawrence D'Anna FILE *NativeFile::GetStream() {
273b9c1b51eSKate Stone if (!StreamIsValid()) {
274b9c1b51eSKate Stone if (DescriptorIsValid()) {
27562c9fe42SLawrence D'Anna auto mode = GetStreamOpenModeFromOptions(m_options);
27662c9fe42SLawrence D'Anna if (!mode)
27762c9fe42SLawrence D'Anna llvm::consumeError(mode.takeError());
27862c9fe42SLawrence D'Anna else {
27911751271SLawrence D'Anna if (!m_own_descriptor) {
28005097246SAdrian Prantl // We must duplicate the file descriptor if we don't own it because when you
28105097246SAdrian Prantl // call fdopen, the stream will own the fd
28244d93782SGreg Clayton #ifdef _WIN32
28344d93782SGreg Clayton m_descriptor = ::_dup(GetDescriptor());
28444d93782SGreg Clayton #else
28535e06390SEnrico Granata m_descriptor = dup(GetDescriptor());
28644d93782SGreg Clayton #endif
28711751271SLawrence D'Anna m_own_descriptor = true;
28844d93782SGreg Clayton }
28944d93782SGreg Clayton
29062c9fe42SLawrence D'Anna m_stream = llvm::sys::RetryAfterSignal(nullptr, ::fdopen, m_descriptor,
29162c9fe42SLawrence D'Anna mode.get());
29244d93782SGreg Clayton
29305097246SAdrian Prantl // If we got a stream, then we own the stream and should no longer own
29405097246SAdrian Prantl // the descriptor because fclose() will close it for us
29544d93782SGreg Clayton
296b9c1b51eSKate Stone if (m_stream) {
29744d93782SGreg Clayton m_own_stream = true;
29811751271SLawrence D'Anna m_own_descriptor = false;
29944d93782SGreg Clayton }
30096c09687SGreg Clayton }
30151b1e2d2SGreg Clayton }
30251b1e2d2SGreg Clayton }
30351b1e2d2SGreg Clayton return m_stream;
30451b1e2d2SGreg Clayton }
30551b1e2d2SGreg Clayton
Close()306f913fd6eSLawrence D'Anna Status NativeFile::Close() {
30797206d57SZachary Turner Status error;
30857504530SLawrence D'Anna if (StreamIsValid()) {
30957504530SLawrence D'Anna if (m_own_stream) {
31051b1e2d2SGreg Clayton if (::fclose(m_stream) == EOF)
311504f89a7SGreg Clayton error.SetErrorToErrno();
31214735cabSMichał Górny } else {
31314735cabSMichał Górny File::OpenOptions rw =
31414735cabSMichał Górny m_options & (File::eOpenOptionReadOnly | File::eOpenOptionWriteOnly |
31514735cabSMichał Górny File::eOpenOptionReadWrite);
31614735cabSMichał Górny
31714735cabSMichał Górny if (rw == eOpenOptionWriteOnly || rw == eOpenOptionReadWrite) {
31857504530SLawrence D'Anna if (::fflush(m_stream) == EOF)
31957504530SLawrence D'Anna error.SetErrorToErrno();
32057504530SLawrence D'Anna }
32151b1e2d2SGreg Clayton }
32214735cabSMichał Górny }
32311751271SLawrence D'Anna if (DescriptorIsValid() && m_own_descriptor) {
32451b1e2d2SGreg Clayton if (::close(m_descriptor) != 0)
32551b1e2d2SGreg Clayton error.SetErrorToErrno();
32651b1e2d2SGreg Clayton }
32751b1e2d2SGreg Clayton m_descriptor = kInvalidDescriptor;
32851b1e2d2SGreg Clayton m_stream = kInvalidStream;
32962c9fe42SLawrence D'Anna m_options = OpenOptions(0);
33044d93782SGreg Clayton m_own_stream = false;
33111751271SLawrence D'Anna m_own_descriptor = false;
332340b0309SGreg Clayton m_is_interactive = eLazyBoolCalculate;
333340b0309SGreg Clayton m_is_real_terminal = eLazyBoolCalculate;
334504f89a7SGreg Clayton return error;
335504f89a7SGreg Clayton }
336504f89a7SGreg Clayton
GetFileSpec(FileSpec & file_spec) const337f913fd6eSLawrence D'Anna Status NativeFile::GetFileSpec(FileSpec &file_spec) const {
33897206d57SZachary Turner Status error;
339b90bee04SChris Bieneman #ifdef F_GETPATH
340b9c1b51eSKate Stone if (IsValid()) {
341968fa38eSGreg Clayton char path[PATH_MAX];
34251b1e2d2SGreg Clayton if (::fcntl(GetDescriptor(), F_GETPATH, path) == -1)
343968fa38eSGreg Clayton error.SetErrorToErrno();
344968fa38eSGreg Clayton else
3458f3be7a3SJonas Devlieghere file_spec.SetFile(path, FileSpec::Style::native);
346b9c1b51eSKate Stone } else {
347968fa38eSGreg Clayton error.SetErrorString("invalid file handle");
348925137cfSGreg Clayton }
34994d08626SGreg Clayton #elif defined(__linux__)
35094d08626SGreg Clayton char proc[64];
35194d08626SGreg Clayton char path[PATH_MAX];
35294d08626SGreg Clayton if (::snprintf(proc, sizeof(proc), "/proc/self/fd/%d", GetDescriptor()) < 0)
35386edbf41SGreg Clayton error.SetErrorString("cannot resolve file descriptor");
354b9c1b51eSKate Stone else {
35594d08626SGreg Clayton ssize_t len;
35694d08626SGreg Clayton if ((len = ::readlink(proc, path, sizeof(path) - 1)) == -1)
35794d08626SGreg Clayton error.SetErrorToErrno();
358b9c1b51eSKate Stone else {
35994d08626SGreg Clayton path[len] = '\0';
3608f3be7a3SJonas Devlieghere file_spec.SetFile(path, FileSpec::Style::native);
36194d08626SGreg Clayton }
36294d08626SGreg Clayton }
363925137cfSGreg Clayton #else
364f913fd6eSLawrence D'Anna error.SetErrorString(
365f913fd6eSLawrence D'Anna "NativeFile::GetFileSpec is not supported on this platform");
366925137cfSGreg Clayton #endif
367968fa38eSGreg Clayton
368968fa38eSGreg Clayton if (error.Fail())
369968fa38eSGreg Clayton file_spec.Clear();
370968fa38eSGreg Clayton return error;
371968fa38eSGreg Clayton }
372968fa38eSGreg Clayton
SeekFromStart(off_t offset,Status * error_ptr)373f913fd6eSLawrence D'Anna off_t NativeFile::SeekFromStart(off_t offset, Status *error_ptr) {
37443d8279fSGreg Clayton off_t result = 0;
375b9c1b51eSKate Stone if (DescriptorIsValid()) {
37643d8279fSGreg Clayton result = ::lseek(m_descriptor, offset, SEEK_SET);
377968fa38eSGreg Clayton
378b9c1b51eSKate Stone if (error_ptr) {
37943d8279fSGreg Clayton if (result == -1)
38043d8279fSGreg Clayton error_ptr->SetErrorToErrno();
381968fa38eSGreg Clayton else
38243d8279fSGreg Clayton error_ptr->Clear();
383968fa38eSGreg Clayton }
384b9c1b51eSKate Stone } else if (StreamIsValid()) {
38543d8279fSGreg Clayton result = ::fseek(m_stream, offset, SEEK_SET);
38643d8279fSGreg Clayton
387b9c1b51eSKate Stone if (error_ptr) {
38843d8279fSGreg Clayton if (result == -1)
38943d8279fSGreg Clayton error_ptr->SetErrorToErrno();
39043d8279fSGreg Clayton else
39143d8279fSGreg Clayton error_ptr->Clear();
39243d8279fSGreg Clayton }
393b9c1b51eSKate Stone } else if (error_ptr) {
39443d8279fSGreg Clayton error_ptr->SetErrorString("invalid file handle");
39543d8279fSGreg Clayton }
39643d8279fSGreg Clayton return result;
397968fa38eSGreg Clayton }
398968fa38eSGreg Clayton
SeekFromCurrent(off_t offset,Status * error_ptr)399f913fd6eSLawrence D'Anna off_t NativeFile::SeekFromCurrent(off_t offset, Status *error_ptr) {
40043d8279fSGreg Clayton off_t result = -1;
401b9c1b51eSKate Stone if (DescriptorIsValid()) {
40243d8279fSGreg Clayton result = ::lseek(m_descriptor, offset, SEEK_CUR);
403968fa38eSGreg Clayton
404b9c1b51eSKate Stone if (error_ptr) {
40543d8279fSGreg Clayton if (result == -1)
40643d8279fSGreg Clayton error_ptr->SetErrorToErrno();
407968fa38eSGreg Clayton else
40843d8279fSGreg Clayton error_ptr->Clear();
409968fa38eSGreg Clayton }
410b9c1b51eSKate Stone } else if (StreamIsValid()) {
41143d8279fSGreg Clayton result = ::fseek(m_stream, offset, SEEK_CUR);
41243d8279fSGreg Clayton
413b9c1b51eSKate Stone if (error_ptr) {
41443d8279fSGreg Clayton if (result == -1)
41543d8279fSGreg Clayton error_ptr->SetErrorToErrno();
41643d8279fSGreg Clayton else
41743d8279fSGreg Clayton error_ptr->Clear();
41843d8279fSGreg Clayton }
419b9c1b51eSKate Stone } else if (error_ptr) {
42043d8279fSGreg Clayton error_ptr->SetErrorString("invalid file handle");
42143d8279fSGreg Clayton }
42243d8279fSGreg Clayton return result;
423968fa38eSGreg Clayton }
424968fa38eSGreg Clayton
SeekFromEnd(off_t offset,Status * error_ptr)425f913fd6eSLawrence D'Anna off_t NativeFile::SeekFromEnd(off_t offset, Status *error_ptr) {
42643d8279fSGreg Clayton off_t result = -1;
427b9c1b51eSKate Stone if (DescriptorIsValid()) {
42843d8279fSGreg Clayton result = ::lseek(m_descriptor, offset, SEEK_END);
429968fa38eSGreg Clayton
430b9c1b51eSKate Stone if (error_ptr) {
43143d8279fSGreg Clayton if (result == -1)
43243d8279fSGreg Clayton error_ptr->SetErrorToErrno();
43343d8279fSGreg Clayton else
43443d8279fSGreg Clayton error_ptr->Clear();
435968fa38eSGreg Clayton }
436b9c1b51eSKate Stone } else if (StreamIsValid()) {
43743d8279fSGreg Clayton result = ::fseek(m_stream, offset, SEEK_END);
43843d8279fSGreg Clayton
439b9c1b51eSKate Stone if (error_ptr) {
44043d8279fSGreg Clayton if (result == -1)
44143d8279fSGreg Clayton error_ptr->SetErrorToErrno();
44243d8279fSGreg Clayton else
44343d8279fSGreg Clayton error_ptr->Clear();
44443d8279fSGreg Clayton }
445b9c1b51eSKate Stone } else if (error_ptr) {
44643d8279fSGreg Clayton error_ptr->SetErrorString("invalid file handle");
44743d8279fSGreg Clayton }
44843d8279fSGreg Clayton return result;
449968fa38eSGreg Clayton }
450968fa38eSGreg Clayton
Flush()451f913fd6eSLawrence D'Anna Status NativeFile::Flush() {
45297206d57SZachary Turner Status error;
453b9c1b51eSKate Stone if (StreamIsValid()) {
454c1a6b128SPavel Labath if (llvm::sys::RetryAfterSignal(EOF, ::fflush, m_stream) == EOF)
45551b1e2d2SGreg Clayton error.SetErrorToErrno();
456b9c1b51eSKate Stone } else if (!DescriptorIsValid()) {
45751b1e2d2SGreg Clayton error.SetErrorString("invalid file handle");
45851b1e2d2SGreg Clayton }
45951b1e2d2SGreg Clayton return error;
46051b1e2d2SGreg Clayton }
46151b1e2d2SGreg Clayton
Sync()462f913fd6eSLawrence D'Anna Status NativeFile::Sync() {
46397206d57SZachary Turner Status error;
464b9c1b51eSKate Stone if (DescriptorIsValid()) {
465b2f1fb29SVirgile Bello #ifdef _WIN32
466b2f1fb29SVirgile Bello int err = FlushFileBuffers((HANDLE)_get_osfhandle(m_descriptor));
467b2f1fb29SVirgile Bello if (err == 0)
468b2f1fb29SVirgile Bello error.SetErrorToGenericError();
469b2f1fb29SVirgile Bello #else
470c1a6b128SPavel Labath if (llvm::sys::RetryAfterSignal(-1, ::fsync, m_descriptor) == -1)
471968fa38eSGreg Clayton error.SetErrorToErrno();
472b2f1fb29SVirgile Bello #endif
473b9c1b51eSKate Stone } else {
474968fa38eSGreg Clayton error.SetErrorString("invalid file handle");
475968fa38eSGreg Clayton }
476968fa38eSGreg Clayton return error;
477968fa38eSGreg Clayton }
478846b64bfSGreg Clayton
47929aac9a5SGreg Clayton #if defined(__APPLE__)
48029aac9a5SGreg Clayton // Darwin kernels only can read/write <= INT_MAX bytes
48129aac9a5SGreg Clayton #define MAX_READ_SIZE INT_MAX
48229aac9a5SGreg Clayton #define MAX_WRITE_SIZE INT_MAX
48329aac9a5SGreg Clayton #endif
48429aac9a5SGreg Clayton
Read(void * buf,size_t & num_bytes)485f913fd6eSLawrence D'Anna Status NativeFile::Read(void *buf, size_t &num_bytes) {
48697206d57SZachary Turner Status error;
48729aac9a5SGreg Clayton
48829aac9a5SGreg Clayton #if defined(MAX_READ_SIZE)
489b9c1b51eSKate Stone if (num_bytes > MAX_READ_SIZE) {
49029aac9a5SGreg Clayton uint8_t *p = (uint8_t *)buf;
49129aac9a5SGreg Clayton size_t bytes_left = num_bytes;
49229aac9a5SGreg Clayton // Init the num_bytes read to zero
49329aac9a5SGreg Clayton num_bytes = 0;
49429aac9a5SGreg Clayton
495b9c1b51eSKate Stone while (bytes_left > 0) {
49629aac9a5SGreg Clayton size_t curr_num_bytes;
49729aac9a5SGreg Clayton if (bytes_left > MAX_READ_SIZE)
49829aac9a5SGreg Clayton curr_num_bytes = MAX_READ_SIZE;
49929aac9a5SGreg Clayton else
50029aac9a5SGreg Clayton curr_num_bytes = bytes_left;
50129aac9a5SGreg Clayton
50229aac9a5SGreg Clayton error = Read(p + num_bytes, curr_num_bytes);
50329aac9a5SGreg Clayton
50429aac9a5SGreg Clayton // Update how many bytes were read
50529aac9a5SGreg Clayton num_bytes += curr_num_bytes;
50629aac9a5SGreg Clayton if (bytes_left < curr_num_bytes)
50729aac9a5SGreg Clayton bytes_left = 0;
50829aac9a5SGreg Clayton else
50929aac9a5SGreg Clayton bytes_left -= curr_num_bytes;
51029aac9a5SGreg Clayton
51129aac9a5SGreg Clayton if (error.Fail())
51229aac9a5SGreg Clayton break;
51329aac9a5SGreg Clayton }
51429aac9a5SGreg Clayton return error;
51529aac9a5SGreg Clayton }
51629aac9a5SGreg Clayton #endif
51729aac9a5SGreg Clayton
51896c09687SGreg Clayton ssize_t bytes_read = -1;
519b9c1b51eSKate Stone if (DescriptorIsValid()) {
520c1a6b128SPavel Labath bytes_read = llvm::sys::RetryAfterSignal(-1, ::read, m_descriptor, buf, num_bytes);
521b9c1b51eSKate Stone if (bytes_read == -1) {
522504f89a7SGreg Clayton error.SetErrorToErrno();
523504f89a7SGreg Clayton num_bytes = 0;
524b9c1b51eSKate Stone } else
525504f89a7SGreg Clayton num_bytes = bytes_read;
526b9c1b51eSKate Stone } else if (StreamIsValid()) {
52796c09687SGreg Clayton bytes_read = ::fread(buf, 1, num_bytes, m_stream);
52896c09687SGreg Clayton
529b9c1b51eSKate Stone if (bytes_read == 0) {
53051b1e2d2SGreg Clayton if (::feof(m_stream))
53151b1e2d2SGreg Clayton error.SetErrorString("feof");
53251b1e2d2SGreg Clayton else if (::ferror(m_stream))
53351b1e2d2SGreg Clayton error.SetErrorString("ferror");
53451b1e2d2SGreg Clayton num_bytes = 0;
535b9c1b51eSKate Stone } else
53651b1e2d2SGreg Clayton num_bytes = bytes_read;
537b9c1b51eSKate Stone } else {
538504f89a7SGreg Clayton num_bytes = 0;
539504f89a7SGreg Clayton error.SetErrorString("invalid file handle");
540504f89a7SGreg Clayton }
541504f89a7SGreg Clayton return error;
542504f89a7SGreg Clayton }
543504f89a7SGreg Clayton
Write(const void * buf,size_t & num_bytes)544f913fd6eSLawrence D'Anna Status NativeFile::Write(const void *buf, size_t &num_bytes) {
54597206d57SZachary Turner Status error;
54629aac9a5SGreg Clayton
54729aac9a5SGreg Clayton #if defined(MAX_WRITE_SIZE)
548b9c1b51eSKate Stone if (num_bytes > MAX_WRITE_SIZE) {
54929aac9a5SGreg Clayton const uint8_t *p = (const uint8_t *)buf;
55029aac9a5SGreg Clayton size_t bytes_left = num_bytes;
55129aac9a5SGreg Clayton // Init the num_bytes written to zero
55229aac9a5SGreg Clayton num_bytes = 0;
55329aac9a5SGreg Clayton
554b9c1b51eSKate Stone while (bytes_left > 0) {
55529aac9a5SGreg Clayton size_t curr_num_bytes;
55629aac9a5SGreg Clayton if (bytes_left > MAX_WRITE_SIZE)
55729aac9a5SGreg Clayton curr_num_bytes = MAX_WRITE_SIZE;
55829aac9a5SGreg Clayton else
55929aac9a5SGreg Clayton curr_num_bytes = bytes_left;
56029aac9a5SGreg Clayton
56129aac9a5SGreg Clayton error = Write(p + num_bytes, curr_num_bytes);
56229aac9a5SGreg Clayton
56329aac9a5SGreg Clayton // Update how many bytes were read
56429aac9a5SGreg Clayton num_bytes += curr_num_bytes;
56529aac9a5SGreg Clayton if (bytes_left < curr_num_bytes)
56629aac9a5SGreg Clayton bytes_left = 0;
56729aac9a5SGreg Clayton else
56829aac9a5SGreg Clayton bytes_left -= curr_num_bytes;
56929aac9a5SGreg Clayton
57029aac9a5SGreg Clayton if (error.Fail())
57129aac9a5SGreg Clayton break;
57229aac9a5SGreg Clayton }
57329aac9a5SGreg Clayton return error;
57429aac9a5SGreg Clayton }
57529aac9a5SGreg Clayton #endif
57629aac9a5SGreg Clayton
57796c09687SGreg Clayton ssize_t bytes_written = -1;
578b9c1b51eSKate Stone if (DescriptorIsValid()) {
579c1a6b128SPavel Labath bytes_written =
580c1a6b128SPavel Labath llvm::sys::RetryAfterSignal(-1, ::write, m_descriptor, buf, num_bytes);
581b9c1b51eSKate Stone if (bytes_written == -1) {
582504f89a7SGreg Clayton error.SetErrorToErrno();
583504f89a7SGreg Clayton num_bytes = 0;
584b9c1b51eSKate Stone } else
585504f89a7SGreg Clayton num_bytes = bytes_written;
586b9c1b51eSKate Stone } else if (StreamIsValid()) {
58796c09687SGreg Clayton bytes_written = ::fwrite(buf, 1, num_bytes, m_stream);
58896c09687SGreg Clayton
589b9c1b51eSKate Stone if (bytes_written == 0) {
59051b1e2d2SGreg Clayton if (::feof(m_stream))
59151b1e2d2SGreg Clayton error.SetErrorString("feof");
59251b1e2d2SGreg Clayton else if (::ferror(m_stream))
59351b1e2d2SGreg Clayton error.SetErrorString("ferror");
59451b1e2d2SGreg Clayton num_bytes = 0;
595b9c1b51eSKate Stone } else
59651b1e2d2SGreg Clayton num_bytes = bytes_written;
59751b1e2d2SGreg Clayton
598b9c1b51eSKate Stone } else {
599504f89a7SGreg Clayton num_bytes = 0;
600504f89a7SGreg Clayton error.SetErrorString("invalid file handle");
601504f89a7SGreg Clayton }
60298688922SZachary Turner
603504f89a7SGreg Clayton return error;
604504f89a7SGreg Clayton }
605504f89a7SGreg Clayton
Read(void * buf,size_t & num_bytes,off_t & offset)606f913fd6eSLawrence D'Anna Status NativeFile::Read(void *buf, size_t &num_bytes, off_t &offset) {
60797206d57SZachary Turner Status error;
60829aac9a5SGreg Clayton
60929aac9a5SGreg Clayton #if defined(MAX_READ_SIZE)
610b9c1b51eSKate Stone if (num_bytes > MAX_READ_SIZE) {
61129aac9a5SGreg Clayton uint8_t *p = (uint8_t *)buf;
61229aac9a5SGreg Clayton size_t bytes_left = num_bytes;
61329aac9a5SGreg Clayton // Init the num_bytes read to zero
61429aac9a5SGreg Clayton num_bytes = 0;
61529aac9a5SGreg Clayton
616b9c1b51eSKate Stone while (bytes_left > 0) {
61729aac9a5SGreg Clayton size_t curr_num_bytes;
61829aac9a5SGreg Clayton if (bytes_left > MAX_READ_SIZE)
61929aac9a5SGreg Clayton curr_num_bytes = MAX_READ_SIZE;
62029aac9a5SGreg Clayton else
62129aac9a5SGreg Clayton curr_num_bytes = bytes_left;
62229aac9a5SGreg Clayton
62329aac9a5SGreg Clayton error = Read(p + num_bytes, curr_num_bytes, offset);
62429aac9a5SGreg Clayton
62529aac9a5SGreg Clayton // Update how many bytes were read
62629aac9a5SGreg Clayton num_bytes += curr_num_bytes;
62729aac9a5SGreg Clayton if (bytes_left < curr_num_bytes)
62829aac9a5SGreg Clayton bytes_left = 0;
62929aac9a5SGreg Clayton else
63029aac9a5SGreg Clayton bytes_left -= curr_num_bytes;
63129aac9a5SGreg Clayton
63229aac9a5SGreg Clayton if (error.Fail())
63329aac9a5SGreg Clayton break;
63429aac9a5SGreg Clayton }
63529aac9a5SGreg Clayton return error;
63629aac9a5SGreg Clayton }
63729aac9a5SGreg Clayton #endif
63829aac9a5SGreg Clayton
63929aac9a5SGreg Clayton #ifndef _WIN32
64051b1e2d2SGreg Clayton int fd = GetDescriptor();
641b9c1b51eSKate Stone if (fd != kInvalidDescriptor) {
642c1a6b128SPavel Labath ssize_t bytes_read =
643c1a6b128SPavel Labath llvm::sys::RetryAfterSignal(-1, ::pread, fd, buf, num_bytes, offset);
644b9c1b51eSKate Stone if (bytes_read < 0) {
645846b64bfSGreg Clayton num_bytes = 0;
646846b64bfSGreg Clayton error.SetErrorToErrno();
647b9c1b51eSKate Stone } else {
648846b64bfSGreg Clayton offset += bytes_read;
649846b64bfSGreg Clayton num_bytes = bytes_read;
650846b64bfSGreg Clayton }
651b9c1b51eSKate Stone } else {
652846b64bfSGreg Clayton num_bytes = 0;
653846b64bfSGreg Clayton error.SetErrorString("invalid file handle");
654846b64bfSGreg Clayton }
655b2f1fb29SVirgile Bello #else
6563a142495SAaron Smith std::lock_guard<std::mutex> guard(offset_access_mutex);
657b2f1fb29SVirgile Bello long cur = ::lseek(m_descriptor, 0, SEEK_CUR);
658b2f1fb29SVirgile Bello SeekFromStart(offset);
65929aac9a5SGreg Clayton error = Read(buf, num_bytes);
660b2f1fb29SVirgile Bello if (!error.Fail())
661b2f1fb29SVirgile Bello SeekFromStart(cur);
662b2f1fb29SVirgile Bello #endif
66329aac9a5SGreg Clayton return error;
664846b64bfSGreg Clayton }
665846b64bfSGreg Clayton
Write(const void * buf,size_t & num_bytes,off_t & offset)666f913fd6eSLawrence D'Anna Status NativeFile::Write(const void *buf, size_t &num_bytes, off_t &offset) {
66797206d57SZachary Turner Status error;
6687965e545SGreg Clayton
66929aac9a5SGreg Clayton #if defined(MAX_WRITE_SIZE)
670b9c1b51eSKate Stone if (num_bytes > MAX_WRITE_SIZE) {
67129aac9a5SGreg Clayton const uint8_t *p = (const uint8_t *)buf;
67229aac9a5SGreg Clayton size_t bytes_left = num_bytes;
67329aac9a5SGreg Clayton // Init the num_bytes written to zero
67429aac9a5SGreg Clayton num_bytes = 0;
67529aac9a5SGreg Clayton
676b9c1b51eSKate Stone while (bytes_left > 0) {
67729aac9a5SGreg Clayton size_t curr_num_bytes;
67829aac9a5SGreg Clayton if (bytes_left > MAX_WRITE_SIZE)
67929aac9a5SGreg Clayton curr_num_bytes = MAX_WRITE_SIZE;
68029aac9a5SGreg Clayton else
68129aac9a5SGreg Clayton curr_num_bytes = bytes_left;
68229aac9a5SGreg Clayton
68329aac9a5SGreg Clayton error = Write(p + num_bytes, curr_num_bytes, offset);
68429aac9a5SGreg Clayton
68529aac9a5SGreg Clayton // Update how many bytes were read
68629aac9a5SGreg Clayton num_bytes += curr_num_bytes;
68729aac9a5SGreg Clayton if (bytes_left < curr_num_bytes)
68829aac9a5SGreg Clayton bytes_left = 0;
68929aac9a5SGreg Clayton else
69029aac9a5SGreg Clayton bytes_left -= curr_num_bytes;
69129aac9a5SGreg Clayton
69229aac9a5SGreg Clayton if (error.Fail())
69329aac9a5SGreg Clayton break;
69429aac9a5SGreg Clayton }
69529aac9a5SGreg Clayton return error;
69629aac9a5SGreg Clayton }
69729aac9a5SGreg Clayton #endif
69829aac9a5SGreg Clayton
69951b1e2d2SGreg Clayton int fd = GetDescriptor();
700b9c1b51eSKate Stone if (fd != kInvalidDescriptor) {
701b2f1fb29SVirgile Bello #ifndef _WIN32
702c1a6b128SPavel Labath ssize_t bytes_written =
703c1a6b128SPavel Labath llvm::sys::RetryAfterSignal(-1, ::pwrite, m_descriptor, buf, num_bytes, offset);
704b9c1b51eSKate Stone if (bytes_written < 0) {
705846b64bfSGreg Clayton num_bytes = 0;
706846b64bfSGreg Clayton error.SetErrorToErrno();
707b9c1b51eSKate Stone } else {
708846b64bfSGreg Clayton offset += bytes_written;
709846b64bfSGreg Clayton num_bytes = bytes_written;
710846b64bfSGreg Clayton }
711b2f1fb29SVirgile Bello #else
7123a142495SAaron Smith std::lock_guard<std::mutex> guard(offset_access_mutex);
713b2f1fb29SVirgile Bello long cur = ::lseek(m_descriptor, 0, SEEK_CUR);
7143a142495SAaron Smith SeekFromStart(offset);
715b2f1fb29SVirgile Bello error = Write(buf, num_bytes);
716b2f1fb29SVirgile Bello long after = ::lseek(m_descriptor, 0, SEEK_CUR);
717b2f1fb29SVirgile Bello
718b2f1fb29SVirgile Bello if (!error.Fail())
719b2f1fb29SVirgile Bello SeekFromStart(cur);
720b2f1fb29SVirgile Bello
721b2f1fb29SVirgile Bello offset = after;
722b2f1fb29SVirgile Bello #endif
723b9c1b51eSKate Stone } else {
724846b64bfSGreg Clayton num_bytes = 0;
725846b64bfSGreg Clayton error.SetErrorString("invalid file handle");
726846b64bfSGreg Clayton }
727846b64bfSGreg Clayton return error;
728846b64bfSGreg Clayton }
729846b64bfSGreg Clayton
PrintfVarArg(const char * format,va_list args)730f913fd6eSLawrence D'Anna size_t NativeFile::PrintfVarArg(const char *format, va_list args) {
731f913fd6eSLawrence D'Anna if (StreamIsValid()) {
732f913fd6eSLawrence D'Anna return ::vfprintf(m_stream, format, args);
733f913fd6eSLawrence D'Anna } else {
734f913fd6eSLawrence D'Anna return File::PrintfVarArg(format, args);
73551b1e2d2SGreg Clayton }
73651b1e2d2SGreg Clayton }
737e0f8f574SDaniel Malea
ConvertOpenOptionsForPOSIXOpen(OpenOptions open_options)73862c9fe42SLawrence D'Anna mode_t File::ConvertOpenOptionsForPOSIXOpen(OpenOptions open_options) {
739e0f8f574SDaniel Malea mode_t mode = 0;
74014735cabSMichał Górny File::OpenOptions rw =
74114735cabSMichał Górny open_options & (File::eOpenOptionReadOnly | File::eOpenOptionWriteOnly |
74214735cabSMichał Górny File::eOpenOptionReadWrite);
74314735cabSMichał Górny if (rw == eOpenOptionReadWrite)
744e0f8f574SDaniel Malea mode |= O_RDWR;
74514735cabSMichał Górny else if (rw == eOpenOptionWriteOnly)
746e0f8f574SDaniel Malea mode |= O_WRONLY;
74714735cabSMichał Górny else if (rw == eOpenOptionReadOnly)
74814735cabSMichał Górny mode |= O_RDONLY;
749e0f8f574SDaniel Malea
750e0f8f574SDaniel Malea if (open_options & eOpenOptionAppend)
751e0f8f574SDaniel Malea mode |= O_APPEND;
752e0f8f574SDaniel Malea
753e0f8f574SDaniel Malea if (open_options & eOpenOptionTruncate)
754e0f8f574SDaniel Malea mode |= O_TRUNC;
755e0f8f574SDaniel Malea
756e0f8f574SDaniel Malea if (open_options & eOpenOptionNonBlocking)
757e0f8f574SDaniel Malea mode |= O_NONBLOCK;
758e0f8f574SDaniel Malea
759e0f8f574SDaniel Malea if (open_options & eOpenOptionCanCreateNewOnly)
760e0f8f574SDaniel Malea mode |= O_CREAT | O_EXCL;
761e0f8f574SDaniel Malea else if (open_options & eOpenOptionCanCreate)
762e0f8f574SDaniel Malea mode |= O_CREAT;
763e0f8f574SDaniel Malea
764e0f8f574SDaniel Malea return mode;
765e0f8f574SDaniel Malea }
766d9b553ecSLawrence D'Anna
7674a7b4beaSMichał Górny llvm::Expected<SerialPort::Options>
OptionsFromURL(llvm::StringRef urlqs)7684a7b4beaSMichał Górny SerialPort::OptionsFromURL(llvm::StringRef urlqs) {
7694a7b4beaSMichał Górny SerialPort::Options serial_options;
77066e06cc8SMichał Górny for (llvm::StringRef x : llvm::split(urlqs, '&')) {
7714a7b4beaSMichał Górny if (x.consume_front("baud=")) {
7724a7b4beaSMichał Górny unsigned int baud_rate;
7734a7b4beaSMichał Górny if (!llvm::to_integer(x, baud_rate, 10))
7744a7b4beaSMichał Górny return llvm::createStringError(llvm::inconvertibleErrorCode(),
7754a7b4beaSMichał Górny "Invalid baud rate: %s",
7764a7b4beaSMichał Górny x.str().c_str());
7774a7b4beaSMichał Górny serial_options.BaudRate = baud_rate;
7784a7b4beaSMichał Górny } else if (x.consume_front("parity=")) {
7794a7b4beaSMichał Górny serial_options.Parity =
7804a7b4beaSMichał Górny llvm::StringSwitch<llvm::Optional<Terminal::Parity>>(x)
7814a7b4beaSMichał Górny .Case("no", Terminal::Parity::No)
7824a7b4beaSMichał Górny .Case("even", Terminal::Parity::Even)
7834a7b4beaSMichał Górny .Case("odd", Terminal::Parity::Odd)
7844a7b4beaSMichał Górny .Case("mark", Terminal::Parity::Mark)
7854a7b4beaSMichał Górny .Case("space", Terminal::Parity::Space)
7864a7b4beaSMichał Górny .Default(llvm::None);
7874a7b4beaSMichał Górny if (!serial_options.Parity)
7884a7b4beaSMichał Górny return llvm::createStringError(
7894a7b4beaSMichał Górny llvm::inconvertibleErrorCode(),
7904a7b4beaSMichał Górny "Invalid parity (must be no, even, odd, mark or space): %s",
7914a7b4beaSMichał Górny x.str().c_str());
79221bb808eSMichał Górny } else if (x.consume_front("parity-check=")) {
79321bb808eSMichał Górny serial_options.ParityCheck =
79421bb808eSMichał Górny llvm::StringSwitch<llvm::Optional<Terminal::ParityCheck>>(x)
79521bb808eSMichał Górny .Case("no", Terminal::ParityCheck::No)
79621bb808eSMichał Górny .Case("replace", Terminal::ParityCheck::ReplaceWithNUL)
79721bb808eSMichał Górny .Case("ignore", Terminal::ParityCheck::Ignore)
79821bb808eSMichał Górny // "mark" mode is not currently supported as it requires special
79921bb808eSMichał Górny // input processing
80021bb808eSMichał Górny // .Case("mark", Terminal::ParityCheck::Mark)
80121bb808eSMichał Górny .Default(llvm::None);
80221bb808eSMichał Górny if (!serial_options.ParityCheck)
80321bb808eSMichał Górny return llvm::createStringError(
80421bb808eSMichał Górny llvm::inconvertibleErrorCode(),
80521bb808eSMichał Górny "Invalid parity-check (must be no, replace, ignore or mark): %s",
80621bb808eSMichał Górny x.str().c_str());
8074a7b4beaSMichał Górny } else if (x.consume_front("stop-bits=")) {
8084a7b4beaSMichał Górny unsigned int stop_bits;
8094a7b4beaSMichał Górny if (!llvm::to_integer(x, stop_bits, 10) ||
8104a7b4beaSMichał Górny (stop_bits != 1 && stop_bits != 2))
8114a7b4beaSMichał Górny return llvm::createStringError(
8124a7b4beaSMichał Górny llvm::inconvertibleErrorCode(),
8134a7b4beaSMichał Górny "Invalid stop bit number (must be 1 or 2): %s", x.str().c_str());
8144a7b4beaSMichał Górny serial_options.StopBits = stop_bits;
8154a7b4beaSMichał Górny } else
8164a7b4beaSMichał Górny return llvm::createStringError(llvm::inconvertibleErrorCode(),
8174a7b4beaSMichał Górny "Unknown parameter: %s", x.str().c_str());
8184a7b4beaSMichał Górny }
8194a7b4beaSMichał Górny return serial_options;
8204a7b4beaSMichał Górny }
8214a7b4beaSMichał Górny
8224a7b4beaSMichał Górny llvm::Expected<std::unique_ptr<SerialPort>>
Create(int fd,OpenOptions options,Options serial_options,bool transfer_ownership)8234a7b4beaSMichał Górny SerialPort::Create(int fd, OpenOptions options, Options serial_options,
8244a7b4beaSMichał Górny bool transfer_ownership) {
8254a7b4beaSMichał Górny std::unique_ptr<SerialPort> out{
8264a7b4beaSMichał Górny new SerialPort(fd, options, serial_options, transfer_ownership)};
8274a7b4beaSMichał Górny
8284a7b4beaSMichał Górny if (!out->GetIsInteractive())
8294a7b4beaSMichał Górny return llvm::createStringError(llvm::inconvertibleErrorCode(),
8304a7b4beaSMichał Górny "the specified file is not a teletype");
8314a7b4beaSMichał Górny
8324a7b4beaSMichał Górny Terminal term{fd};
8334a7b4beaSMichał Górny if (llvm::Error error = term.SetRaw())
834b8c3683dSMichał Górny return std::move(error);
8354a7b4beaSMichał Górny if (serial_options.BaudRate) {
836*5cff5142SKazu Hirata if (llvm::Error error = term.SetBaudRate(serial_options.BaudRate.value()))
837b8c3683dSMichał Górny return std::move(error);
8384a7b4beaSMichał Górny }
8394a7b4beaSMichał Górny if (serial_options.Parity) {
840*5cff5142SKazu Hirata if (llvm::Error error = term.SetParity(serial_options.Parity.value()))
841b8c3683dSMichał Górny return std::move(error);
8424a7b4beaSMichał Górny }
84321bb808eSMichał Górny if (serial_options.ParityCheck) {
8443b7c3a65SKazu Hirata if (llvm::Error error =
845*5cff5142SKazu Hirata term.SetParityCheck(serial_options.ParityCheck.value()))
84621bb808eSMichał Górny return std::move(error);
84721bb808eSMichał Górny }
8484a7b4beaSMichał Górny if (serial_options.StopBits) {
849*5cff5142SKazu Hirata if (llvm::Error error = term.SetStopBits(serial_options.StopBits.value()))
850b8c3683dSMichał Górny return std::move(error);
8514a7b4beaSMichał Górny }
8524a7b4beaSMichał Górny
853ea9e9d61SMartin Storsjö return std::move(out);
8544a7b4beaSMichał Górny }
8554a7b4beaSMichał Górny
SerialPort(int fd,OpenOptions options,SerialPort::Options serial_options,bool transfer_ownership)8564a7b4beaSMichał Górny SerialPort::SerialPort(int fd, OpenOptions options,
8574a7b4beaSMichał Górny SerialPort::Options serial_options,
8584a7b4beaSMichał Górny bool transfer_ownership)
8594a7b4beaSMichał Górny : NativeFile(fd, options, transfer_ownership), m_state(fd) {}
8604a7b4beaSMichał Górny
Close()8614a7b4beaSMichał Górny Status SerialPort::Close() {
8624a7b4beaSMichał Górny m_state.Restore();
8634a7b4beaSMichał Górny return NativeFile::Close();
8644a7b4beaSMichał Górny }
8654a7b4beaSMichał Górny
866d9b553ecSLawrence D'Anna char File::ID = 0;
867d9b553ecSLawrence D'Anna char NativeFile::ID = 0;
8684a7b4beaSMichał Górny char SerialPort::ID = 0;
869