1 | //===-- File.h --------------------------------------------------*- C++ -*-===// |
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 | |
9 | #ifndef LLDB_HOST_FILE_H |
10 | #define LLDB_HOST_FILE_H |
11 | |
12 | #include "lldb/Host/PosixApi.h" |
13 | #include "lldb/Host/Terminal.h" |
14 | #include "lldb/Utility/IOObject.h" |
15 | #include "lldb/Utility/Status.h" |
16 | #include "lldb/lldb-private.h" |
17 | #include "llvm/ADT/BitmaskEnum.h" |
18 | |
19 | #include <cstdarg> |
20 | #include <cstdio> |
21 | #include <mutex> |
22 | #include <optional> |
23 | #include <sys/types.h> |
24 | |
25 | namespace lldb_private { |
26 | |
27 | LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE(); |
28 | |
29 | /// \class File File.h "lldb/Host/File.h" |
30 | /// An abstract base class for files. |
31 | /// |
32 | /// Files will often be NativeFiles, which provides a wrapper |
33 | /// around host OS file functionality. But it |
34 | /// is also possible to subclass file to provide objects that have file |
35 | /// or stream functionality but are not backed by any host OS file. |
36 | class File : public IOObject { |
37 | public: |
38 | static int kInvalidDescriptor; |
39 | static FILE *kInvalidStream; |
40 | |
41 | // NB this enum is used in the lldb platform gdb-remote packet |
42 | // vFile:open: and existing values cannot be modified. |
43 | // |
44 | // The first set of values is defined by gdb headers and can be found |
45 | // in the documentation at: |
46 | // * https://sourceware.org/gdb/onlinedocs/gdb/Open-Flags.html#Open-Flags |
47 | // |
48 | // The second half are LLDB extensions and use the highest uint32_t bits |
49 | // to avoid risk of collisions with future gdb remote protocol changes. |
50 | enum OpenOptions : uint32_t { |
51 | eOpenOptionReadOnly = 0x0, // Open file for reading (only) |
52 | eOpenOptionWriteOnly = 0x1, // Open file for writing (only) |
53 | eOpenOptionReadWrite = 0x2, // Open file for both reading and writing |
54 | eOpenOptionAppend = |
55 | 0x8, // Don't truncate file when opening, append to end of file |
56 | eOpenOptionCanCreate = 0x200, // Create file if doesn't already exist |
57 | eOpenOptionTruncate = 0x400, // Truncate file when opening |
58 | eOpenOptionCanCreateNewOnly = |
59 | 0x800, // Can create file only if it doesn't already exist |
60 | |
61 | eOpenOptionNonBlocking = (1u << 28), // File reads |
62 | eOpenOptionDontFollowSymlinks = (1u << 29), |
63 | eOpenOptionCloseOnExec = |
64 | (1u << 30), // Close the file when executing a new process |
65 | eOpenOptionInvalid = (1u << 31), // Used as invalid value |
66 | LLVM_MARK_AS_BITMASK_ENUM(/* largest_value= */ eOpenOptionInvalid) |
67 | }; |
68 | |
69 | static mode_t ConvertOpenOptionsForPOSIXOpen(OpenOptions open_options); |
70 | static llvm::Expected<OpenOptions> GetOptionsFromMode(llvm::StringRef mode); |
71 | static bool DescriptorIsValid(int descriptor) { return descriptor >= 0; }; |
72 | static llvm::Expected<const char *> |
73 | GetStreamOpenModeFromOptions(OpenOptions options); |
74 | |
75 | File() : IOObject(eFDTypeFile){}; |
76 | |
77 | /// Read bytes from a file from the current file position into buf. |
78 | /// |
79 | /// NOTE: This function is NOT thread safe. Use the read function |
80 | /// that takes an "off_t &offset" to ensure correct operation in multi- |
81 | /// threaded environments. |
82 | /// |
83 | /// \param[in,out] num_bytes |
84 | /// Pass in the size of buf. Read will pass out the number |
85 | /// of bytes read. Zero bytes read with no error indicates |
86 | /// EOF. |
87 | /// |
88 | /// \return |
89 | /// success, ENOTSUP, or another error. |
90 | Status Read(void *buf, size_t &num_bytes) override; |
91 | |
92 | /// Write bytes from buf to a file at the current file position. |
93 | /// |
94 | /// NOTE: This function is NOT thread safe. Use the write function |
95 | /// that takes an "off_t &offset" to ensure correct operation in multi- |
96 | /// threaded environments. |
97 | /// |
98 | /// \param[in,out] num_bytes |
99 | /// Pass in the size of buf. Write will pass out the number |
100 | /// of bytes written. Write will attempt write the full number |
101 | /// of bytes and will not return early except on error. |
102 | /// |
103 | /// \return |
104 | /// success, ENOTSUP, or another error. |
105 | Status Write(const void *buf, size_t &num_bytes) override; |
106 | |
107 | /// IsValid |
108 | /// |
109 | /// \return |
110 | /// true iff the file is valid. |
111 | bool IsValid() const override; |
112 | |
113 | /// Flush any buffers and release any resources owned by the file. |
114 | /// After Close() the file will be invalid. |
115 | /// |
116 | /// \return |
117 | /// success or an error. |
118 | Status Close() override; |
119 | |
120 | /// Get a handle that can be used for OS polling interfaces, such |
121 | /// as WaitForMultipleObjects, select, or epoll. This may return |
122 | /// IOObject::kInvalidHandleValue if none is available. This will |
123 | /// generally be the same as the file descriptor, this function |
124 | /// is not interchangeable with GetDescriptor(). A WaitableHandle |
125 | /// must only be used for polling, not actual I/O. |
126 | /// |
127 | /// \return |
128 | /// a valid handle or IOObject::kInvalidHandleValue |
129 | WaitableHandle GetWaitableHandle() override; |
130 | |
131 | /// Get the file specification for this file, if possible. |
132 | /// |
133 | /// \param[out] file_spec |
134 | /// the file specification. |
135 | /// \return |
136 | /// ENOTSUP, success, or another error. |
137 | virtual Status GetFileSpec(FileSpec &file_spec) const; |
138 | |
139 | /// Get underlying OS file descriptor for this file, or kInvalidDescriptor. |
140 | /// If the descriptor is valid, then it may be used directly for I/O |
141 | /// However, the File may also perform it's own buffering, so avoid using |
142 | /// this if it is not necessary, or use Flush() appropriately. |
143 | /// |
144 | /// \return |
145 | /// a valid file descriptor for this file or kInvalidDescriptor |
146 | virtual int GetDescriptor() const; |
147 | |
148 | /// Get the underlying libc stream for this file, or NULL. |
149 | /// |
150 | /// Not all valid files will have a FILE* stream. This should only be |
151 | /// used if absolutely necessary, such as to interact with 3rd party |
152 | /// libraries that need FILE* streams. |
153 | /// |
154 | /// \return |
155 | /// a valid stream or NULL; |
156 | virtual FILE *GetStream(); |
157 | |
158 | /// Seek to an offset relative to the beginning of the file. |
159 | /// |
160 | /// NOTE: This function is NOT thread safe, other threads that |
161 | /// access this object might also change the current file position. For |
162 | /// thread safe reads and writes see the following functions: @see |
163 | /// File::Read (void *, size_t, off_t &) \see File::Write (const void *, |
164 | /// size_t, off_t &) |
165 | /// |
166 | /// \param[in] offset |
167 | /// The offset to seek to within the file relative to the |
168 | /// beginning of the file. |
169 | /// |
170 | /// \param[in] error_ptr |
171 | /// A pointer to a lldb_private::Status object that will be |
172 | /// filled in if non-nullptr. |
173 | /// |
174 | /// \return |
175 | /// The resulting seek offset, or -1 on error. |
176 | virtual off_t SeekFromStart(off_t offset, Status *error_ptr = nullptr); |
177 | |
178 | /// Seek to an offset relative to the current file position. |
179 | /// |
180 | /// NOTE: This function is NOT thread safe, other threads that |
181 | /// access this object might also change the current file position. For |
182 | /// thread safe reads and writes see the following functions: @see |
183 | /// File::Read (void *, size_t, off_t &) \see File::Write (const void *, |
184 | /// size_t, off_t &) |
185 | /// |
186 | /// \param[in] offset |
187 | /// The offset to seek to within the file relative to the |
188 | /// current file position. |
189 | /// |
190 | /// \param[in] error_ptr |
191 | /// A pointer to a lldb_private::Status object that will be |
192 | /// filled in if non-nullptr. |
193 | /// |
194 | /// \return |
195 | /// The resulting seek offset, or -1 on error. |
196 | virtual off_t SeekFromCurrent(off_t offset, Status *error_ptr = nullptr); |
197 | |
198 | /// Seek to an offset relative to the end of the file. |
199 | /// |
200 | /// NOTE: This function is NOT thread safe, other threads that |
201 | /// access this object might also change the current file position. For |
202 | /// thread safe reads and writes see the following functions: @see |
203 | /// File::Read (void *, size_t, off_t &) \see File::Write (const void *, |
204 | /// size_t, off_t &) |
205 | /// |
206 | /// \param[in,out] offset |
207 | /// The offset to seek to within the file relative to the |
208 | /// end of the file which gets filled in with the resulting |
209 | /// absolute file offset. |
210 | /// |
211 | /// \param[in] error_ptr |
212 | /// A pointer to a lldb_private::Status object that will be |
213 | /// filled in if non-nullptr. |
214 | /// |
215 | /// \return |
216 | /// The resulting seek offset, or -1 on error. |
217 | virtual off_t SeekFromEnd(off_t offset, Status *error_ptr = nullptr); |
218 | |
219 | /// Read bytes from a file from the specified file offset. |
220 | /// |
221 | /// NOTE: This function is thread safe in that clients manager their |
222 | /// own file position markers and reads on other threads won't mess up the |
223 | /// current read. |
224 | /// |
225 | /// \param[in] dst |
226 | /// A buffer where to put the bytes that are read. |
227 | /// |
228 | /// \param[in,out] num_bytes |
229 | /// The number of bytes to read from the current file position |
230 | /// which gets modified with the number of bytes that were read. |
231 | /// |
232 | /// \param[in,out] offset |
233 | /// The offset within the file from which to read \a num_bytes |
234 | /// bytes. This offset gets incremented by the number of bytes |
235 | /// that were read. |
236 | /// |
237 | /// \return |
238 | /// An error object that indicates success or the reason for |
239 | /// failure. |
240 | virtual Status Read(void *dst, size_t &num_bytes, off_t &offset); |
241 | |
242 | /// Write bytes to a file at the specified file offset. |
243 | /// |
244 | /// NOTE: This function is thread safe in that clients manager their |
245 | /// own file position markers, though clients will need to implement their |
246 | /// own locking externally to avoid multiple people writing to the file at |
247 | /// the same time. |
248 | /// |
249 | /// \param[in] src |
250 | /// A buffer containing the bytes to write. |
251 | /// |
252 | /// \param[in,out] num_bytes |
253 | /// The number of bytes to write to the file at offset \a offset. |
254 | /// \a num_bytes gets modified with the number of bytes that |
255 | /// were read. |
256 | /// |
257 | /// \param[in,out] offset |
258 | /// The offset within the file at which to write \a num_bytes |
259 | /// bytes. This offset gets incremented by the number of bytes |
260 | /// that were written. |
261 | /// |
262 | /// \return |
263 | /// An error object that indicates success or the reason for |
264 | /// failure. |
265 | virtual Status Write(const void *src, size_t &num_bytes, off_t &offset); |
266 | |
267 | /// Flush the current stream |
268 | /// |
269 | /// \return |
270 | /// An error object that indicates success or the reason for |
271 | /// failure. |
272 | virtual Status Flush(); |
273 | |
274 | /// Sync to disk. |
275 | /// |
276 | /// \return |
277 | /// An error object that indicates success or the reason for |
278 | /// failure. |
279 | virtual Status Sync(); |
280 | |
281 | /// Output printf formatted output to the stream. |
282 | /// |
283 | /// NOTE: this is not virtual, because it just calls the va_list |
284 | /// version of the function. |
285 | /// |
286 | /// Print some formatted output to the stream. |
287 | /// |
288 | /// \param[in] format |
289 | /// A printf style format string. |
290 | /// |
291 | /// \param[in] ... |
292 | /// Variable arguments that are needed for the printf style |
293 | /// format string \a format. |
294 | size_t Printf(const char *format, ...) __attribute__((format(printf, 2, 3))); |
295 | |
296 | /// Output printf formatted output to the stream. |
297 | /// |
298 | /// Print some formatted output to the stream. |
299 | /// |
300 | /// \param[in] format |
301 | /// A printf style format string. |
302 | /// |
303 | /// \param[in] args |
304 | /// Variable arguments that are needed for the printf style |
305 | /// format string \a format. |
306 | virtual size_t PrintfVarArg(const char *format, va_list args); |
307 | |
308 | /// Return the OpenOptions for this file. |
309 | /// |
310 | /// Some options like eOpenOptionDontFollowSymlinks only make |
311 | /// sense when a file is being opened (or not at all) |
312 | /// and may not be preserved for this method. But any valid |
313 | /// File should return either eOpenOptionReadOnly, eOpenOptionWriteOnly |
314 | /// or eOpenOptionReadWrite here. |
315 | /// |
316 | /// \return |
317 | /// OpenOptions flags for this file, or an error. |
318 | virtual llvm::Expected<OpenOptions> GetOptions() const; |
319 | |
320 | llvm::Expected<const char *> GetOpenMode() const { |
321 | auto opts = GetOptions(); |
322 | if (!opts) |
323 | return opts.takeError(); |
324 | return GetStreamOpenModeFromOptions(options: opts.get()); |
325 | } |
326 | |
327 | /// Get the permissions for a this file. |
328 | /// |
329 | /// \return |
330 | /// Bits logical OR'ed together from the permission bits defined |
331 | /// in lldb_private::File::Permissions. |
332 | uint32_t GetPermissions(Status &error) const; |
333 | |
334 | /// Return true if this file is interactive. |
335 | /// |
336 | /// \return |
337 | /// True if this file is a terminal (tty or pty), false |
338 | /// otherwise. |
339 | bool GetIsInteractive(); |
340 | |
341 | /// Return true if this file from a real terminal. |
342 | /// |
343 | /// Just knowing a file is a interactive isn't enough, we also need to know |
344 | /// if the terminal has a width and height so we can do cursor movement and |
345 | /// other terminal manipulations by sending escape sequences. |
346 | /// |
347 | /// \return |
348 | /// True if this file is a terminal (tty, not a pty) that has |
349 | /// a non-zero width and height, false otherwise. |
350 | bool GetIsRealTerminal(); |
351 | |
352 | /// Return true if this file is a terminal which supports colors. |
353 | /// |
354 | /// \return |
355 | /// True iff this is a terminal and it supports colors. |
356 | bool GetIsTerminalWithColors(); |
357 | |
358 | operator bool() const { return IsValid(); }; |
359 | |
360 | bool operator!() const { return !IsValid(); }; |
361 | |
362 | static char ID; |
363 | virtual bool isA(const void *classID) const { return classID == &ID; } |
364 | static bool classof(const File *file) { return file->isA(classID: &ID); } |
365 | |
366 | protected: |
367 | LazyBool m_is_interactive = eLazyBoolCalculate; |
368 | LazyBool m_is_real_terminal = eLazyBoolCalculate; |
369 | LazyBool m_supports_colors = eLazyBoolCalculate; |
370 | |
371 | void CalculateInteractiveAndTerminal(); |
372 | |
373 | private: |
374 | File(const File &) = delete; |
375 | const File &operator=(const File &) = delete; |
376 | }; |
377 | |
378 | class NativeFile : public File { |
379 | public: |
380 | NativeFile() : m_descriptor(kInvalidDescriptor), m_stream(kInvalidStream) {} |
381 | |
382 | NativeFile(FILE *fh, bool transfer_ownership) |
383 | : m_descriptor(kInvalidDescriptor), m_own_descriptor(false), m_stream(fh), |
384 | m_options(), m_own_stream(transfer_ownership) {} |
385 | |
386 | NativeFile(int fd, OpenOptions options, bool transfer_ownership) |
387 | : m_descriptor(fd), m_own_descriptor(transfer_ownership), |
388 | m_stream(kInvalidStream), m_options(options), m_own_stream(false) {} |
389 | |
390 | ~NativeFile() override { Close(); } |
391 | |
392 | bool IsValid() const override; |
393 | |
394 | Status Read(void *buf, size_t &num_bytes) override; |
395 | Status Write(const void *buf, size_t &num_bytes) override; |
396 | Status Close() override; |
397 | WaitableHandle GetWaitableHandle() override; |
398 | Status GetFileSpec(FileSpec &file_spec) const override; |
399 | int GetDescriptor() const override; |
400 | FILE *GetStream() override; |
401 | off_t SeekFromStart(off_t offset, Status *error_ptr = nullptr) override; |
402 | off_t SeekFromCurrent(off_t offset, Status *error_ptr = nullptr) override; |
403 | off_t SeekFromEnd(off_t offset, Status *error_ptr = nullptr) override; |
404 | Status Read(void *dst, size_t &num_bytes, off_t &offset) override; |
405 | Status Write(const void *src, size_t &num_bytes, off_t &offset) override; |
406 | Status Flush() override; |
407 | Status Sync() override; |
408 | size_t PrintfVarArg(const char *format, va_list args) override; |
409 | llvm::Expected<OpenOptions> GetOptions() const override; |
410 | |
411 | static char ID; |
412 | bool isA(const void *classID) const override { |
413 | return classID == &ID || File::isA(classID); |
414 | } |
415 | static bool classof(const File *file) { return file->isA(classID: &ID); } |
416 | |
417 | protected: |
418 | struct ValueGuard { |
419 | ValueGuard(std::mutex &m, bool b) : guard(m, std::adopt_lock), value(b) {} |
420 | std::lock_guard<std::mutex> guard; |
421 | bool value; |
422 | operator bool() { return value; } |
423 | }; |
424 | |
425 | bool DescriptorIsValidUnlocked() const { |
426 | |
427 | return File::DescriptorIsValid(descriptor: m_descriptor); |
428 | } |
429 | |
430 | bool StreamIsValidUnlocked() const { return m_stream != kInvalidStream; } |
431 | |
432 | ValueGuard DescriptorIsValid() const { |
433 | m_descriptor_mutex.lock(); |
434 | return ValueGuard(m_descriptor_mutex, DescriptorIsValidUnlocked()); |
435 | } |
436 | |
437 | ValueGuard StreamIsValid() const { |
438 | m_stream_mutex.lock(); |
439 | return ValueGuard(m_stream_mutex, StreamIsValidUnlocked()); |
440 | } |
441 | |
442 | int m_descriptor; |
443 | bool m_own_descriptor = false; |
444 | mutable std::mutex m_descriptor_mutex; |
445 | |
446 | FILE *m_stream; |
447 | mutable std::mutex m_stream_mutex; |
448 | |
449 | OpenOptions m_options{}; |
450 | bool m_own_stream = false; |
451 | std::mutex offset_access_mutex; |
452 | |
453 | private: |
454 | NativeFile(const NativeFile &) = delete; |
455 | const NativeFile &operator=(const NativeFile &) = delete; |
456 | }; |
457 | |
458 | class SerialPort : public NativeFile { |
459 | public: |
460 | struct Options { |
461 | std::optional<unsigned int> BaudRate; |
462 | std::optional<Terminal::Parity> Parity; |
463 | std::optional<Terminal::ParityCheck> ParityCheck; |
464 | std::optional<unsigned int> StopBits; |
465 | }; |
466 | |
467 | // Obtain Options corresponding to the passed URL query string |
468 | // (i.e. the part after '?'). |
469 | static llvm::Expected<Options> OptionsFromURL(llvm::StringRef urlqs); |
470 | |
471 | static llvm::Expected<std::unique_ptr<SerialPort>> |
472 | Create(int fd, OpenOptions options, Options serial_options, |
473 | bool transfer_ownership); |
474 | |
475 | bool IsValid() const override { |
476 | return NativeFile::IsValid() && m_is_interactive == eLazyBoolYes; |
477 | } |
478 | |
479 | Status Close() override; |
480 | |
481 | static char ID; |
482 | bool isA(const void *classID) const override { |
483 | return classID == &ID || File::isA(classID); |
484 | } |
485 | static bool classof(const File *file) { return file->isA(classID: &ID); } |
486 | |
487 | private: |
488 | SerialPort(int fd, OpenOptions options, Options serial_options, |
489 | bool transfer_ownership); |
490 | |
491 | SerialPort(const SerialPort &) = delete; |
492 | const SerialPort &operator=(const SerialPort &) = delete; |
493 | |
494 | TerminalState m_state; |
495 | }; |
496 | |
497 | } // namespace lldb_private |
498 | |
499 | #endif // LLDB_HOST_FILE_H |
500 | |