LLDB mainline
FilePosix.cpp
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
10
11#include <cassert>
12#include <climits>
13#include <fcntl.h>
14#include <sys/ioctl.h>
15#include <termios.h>
16#include <unistd.h>
17
19#include "lldb/Utility/Status.h"
20#include "llvm/Support/Errno.h"
21#include "llvm/Support/Process.h"
22
23using namespace lldb_private;
24
25#if defined(__APPLE__)
26// Darwin kernels only can read/write <= INT_MAX bytes. Match the chunking
27// limit used by NativeFileBase::Read/Write.
28#define MAX_READ_SIZE INT_MAX
29#define MAX_WRITE_SIZE INT_MAX
30#endif
31
33 bool transfer_ownership)
34 : NativeFileBase(fh, options, transfer_ownership) {
35#ifndef NDEBUG
36 int fd = fileno(fh);
37 if (fd != -1) {
38 int required_mode = ConvertOpenOptionsForPOSIXOpen(options) & O_ACCMODE;
39 int mode = fcntl(fd, F_GETFL);
40 if (mode != -1) {
41 mode &= O_ACCMODE;
42 // Check that the file is open with a valid subset of the requested file
43 // access mode, e.g. if we expected the file to be writable then ensure it
44 // was opened with O_WRONLY or O_RDWR.
45 assert(
46 (required_mode == O_RDWR && mode == O_RDWR) ||
47 (required_mode == O_RDONLY && (mode == O_RDWR || mode == O_RDONLY) ||
48 (required_mode == O_WRONLY &&
49 (mode == O_RDWR || mode == O_WRONLY))) &&
50 "invalid file access mode");
51 }
52 }
53#endif
54}
55
57 bool transfer_ownership)
58 : NativeFileBase(fd, options, transfer_ownership) {}
59
61 // POSIX poll/select/epoll work directly on file descriptors.
62 return GetDescriptor();
63}
64
67 if (ValueGuard descriptor_guard = DescriptorIsValid()) {
68 if (llvm::sys::RetryAfterSignal(-1, ::fsync, m_descriptor) == -1)
70 } else {
71 error = Status::FromErrorString("invalid file handle");
72 }
73 return error;
74}
75
77 const int fd = GetDescriptor();
78 if (!File::DescriptorIsValid(fd)) {
82 return;
83 }
86 if (isatty(fd)) {
88 struct winsize window_size;
89 if (::ioctl(fd, TIOCGWINSZ, &window_size) == 0) {
90 if (window_size.ws_col > 0) {
92 if (llvm::sys::Process::FileDescriptorHasColors(fd))
94 }
95 }
96 }
97}
98
101#ifdef F_GETPATH
102 if (IsValid()) {
103 char path[PATH_MAX];
104 if (::fcntl(GetDescriptor(), F_GETPATH, path) == -1)
106 else
107 file_spec.SetFile(path, FileSpec::Style::native);
108 } else {
109 error = Status::FromErrorString("invalid file handle");
110 }
111#elif defined(__linux__)
112 char proc[64];
113 char path[PATH_MAX];
114 if (::snprintf(proc, sizeof(proc), "/proc/self/fd/%d", GetDescriptor()) < 0)
115 error = Status::FromErrorString("cannot resolve file descriptor");
116 else {
117 ssize_t len;
118 if ((len = ::readlink(proc, path, sizeof(path) - 1)) == -1)
120 else {
121 path[len] = '\0';
122 file_spec.SetFile(path, FileSpec::Style::native);
123 }
124 }
125#else
127 "NativeFile::GetFileSpec is not supported on this platform");
128#endif
129
130 if (error.Fail())
131 file_spec.Clear();
132 return error;
133}
134
135Status NativeFilePosix::Read(void *buf, size_t &num_bytes, off_t &offset) {
137
138#if defined(MAX_READ_SIZE)
139 if (num_bytes > MAX_READ_SIZE) {
140 uint8_t *p = (uint8_t *)buf;
141 size_t bytes_left = num_bytes;
142 // Init the num_bytes read to zero
143 num_bytes = 0;
144
145 while (bytes_left > 0) {
146 size_t curr_num_bytes;
147 if (bytes_left > MAX_READ_SIZE)
148 curr_num_bytes = MAX_READ_SIZE;
149 else
150 curr_num_bytes = bytes_left;
151
152 error = Read(p + num_bytes, curr_num_bytes, offset);
153
154 // Update how many bytes were read
155 num_bytes += curr_num_bytes;
156 if (bytes_left < curr_num_bytes)
157 bytes_left = 0;
158 else
159 bytes_left -= curr_num_bytes;
160
161 if (error.Fail())
162 break;
163 }
164 return error;
165 }
166#endif
167
168 int fd = GetDescriptor();
169 if (fd != kInvalidDescriptor) {
170 ssize_t bytes_read =
171 llvm::sys::RetryAfterSignal(-1, ::pread, fd, buf, num_bytes, offset);
172 if (bytes_read < 0) {
173 num_bytes = 0;
175 } else {
176 offset += bytes_read;
177 num_bytes = bytes_read;
178 }
179 } else {
180 num_bytes = 0;
181 error = Status::FromErrorString("invalid file handle");
182 }
183 return error;
184}
185
186Status NativeFilePosix::Write(const void *buf, size_t &num_bytes,
187 off_t &offset) {
189
190#if defined(MAX_WRITE_SIZE)
191 if (num_bytes > MAX_WRITE_SIZE) {
192 const uint8_t *p = (const uint8_t *)buf;
193 size_t bytes_left = num_bytes;
194 // Init the num_bytes written to zero
195 num_bytes = 0;
196
197 while (bytes_left > 0) {
198 size_t curr_num_bytes;
199 if (bytes_left > MAX_WRITE_SIZE)
200 curr_num_bytes = MAX_WRITE_SIZE;
201 else
202 curr_num_bytes = bytes_left;
203
204 error = Write(p + num_bytes, curr_num_bytes, offset);
205
206 // Update how many bytes were read
207 num_bytes += curr_num_bytes;
208 if (bytes_left < curr_num_bytes)
209 bytes_left = 0;
210 else
211 bytes_left -= curr_num_bytes;
212
213 if (error.Fail())
214 break;
215 }
216 return error;
217 }
218#endif
219
220 int fd = GetDescriptor();
221 if (fd != kInvalidDescriptor) {
222 ssize_t bytes_written = llvm::sys::RetryAfterSignal(
223 -1, ::pwrite, m_descriptor, buf, num_bytes, offset);
224 if (bytes_written < 0) {
225 num_bytes = 0;
227 } else {
228 offset += bytes_written;
229 num_bytes = bytes_written;
230 }
231 } else {
232 num_bytes = 0;
233 error = Status::FromErrorString("invalid file handle");
234 }
235 return error;
236}
237
238char NativeFilePosix::ID = 0;
static llvm::raw_ostream & error(Stream &strm)
A file utility class.
Definition FileSpec.h:57
void SetFile(llvm::StringRef path, Style style)
Change the file specified with a new path.
Definition FileSpec.cpp:174
void Clear()
Clears the object state.
Definition FileSpec.cpp:259
static int kInvalidDescriptor
Definition FileBase.h:36
LazyBool m_is_real_terminal
Definition FileBase.h:368
LazyBool m_is_interactive
Definition FileBase.h:367
static bool DescriptorIsValid(int descriptor)
Definition FileBase.h:72
static mode_t ConvertOpenOptionsForPOSIXOpen(OpenOptions open_options)
Definition File.cpp:603
LazyBool m_supports_colors
Definition FileBase.h:369
lldb::file_t WaitableHandle
Definition IOObject.h:29
int GetDescriptor() const override
Get underlying OS file descriptor for this file, or kInvalidDescriptor.
Definition File.cpp:243
ValueGuard DescriptorIsValid() const
Definition FileBase.h:442
bool IsValid() const override
IsValid.
Definition File.cpp:229
Status Read(void *dst, size_t &num_bytes, off_t &offset) override
Read bytes from a file from the specified file offset.
Status Sync() override
Sync to disk.
Definition FilePosix.cpp:65
WaitableHandle GetWaitableHandle() override
Get a handle that can be used for OS polling interfaces, such as WaitForMultipleObjects,...
Definition FilePosix.cpp:60
Status Write(const void *src, size_t &num_bytes, off_t &offset) override
Write bytes to a file at the specified file offset.
void CalculateInteractiveAndTerminal() override
Refresh the cached interactive / terminal / color flags by inspecting the underlying descriptor.
Definition FilePosix.cpp:76
Status GetFileSpec(FileSpec &file_spec) const override
Get the file specification for this file, if possible.
Definition FilePosix.cpp:99
An error handling class.
Definition Status.h:118
static Status FromErrno()
Set the current error to errno.
Definition Status.cpp:299
static Status FromErrorString(const char *str)
Definition Status.h:141
A class that represents a running process on the host machine.
#define PATH_MAX