1 //===-- File.cpp ------------------------------------------------*- C++ -*-===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include "lldb/Host/File.h"
11
12 #include <errno.h>
13 #include <fcntl.h>
14 #include <limits.h>
15 #include <stdarg.h>
16 #include <stdio.h>
17
18 #ifdef _WIN32
19 #include "lldb/Host/windows/windows.h"
20 #else
21 #include <sys/ioctl.h>
22 #include <sys/stat.h>
23 #include <termios.h>
24 #include <unistd.h>
25 #endif
26
27 #include "llvm/Support/ConvertUTF.h"
28 #include "llvm/Support/Errno.h"
29 #include "llvm/Support/FileSystem.h"
30 #include "llvm/Support/Process.h"
31
32 #include "lldb/Host/Config.h"
33 #include "lldb/Host/FileSystem.h"
34 #include "lldb/Host/Host.h"
35 #include "lldb/Utility/DataBufferHeap.h"
36 #include "lldb/Utility/FileSpec.h"
37 #include "lldb/Utility/Log.h"
38
39 using namespace lldb;
40 using namespace lldb_private;
41
GetStreamOpenModeFromOptions(uint32_t options)42 static const char *GetStreamOpenModeFromOptions(uint32_t options) {
43 if (options & File::eOpenOptionAppend) {
44 if (options & File::eOpenOptionRead) {
45 if (options & File::eOpenOptionCanCreateNewOnly)
46 return "a+x";
47 else
48 return "a+";
49 } else if (options & File::eOpenOptionWrite) {
50 if (options & File::eOpenOptionCanCreateNewOnly)
51 return "ax";
52 else
53 return "a";
54 }
55 } else if (options & File::eOpenOptionRead &&
56 options & File::eOpenOptionWrite) {
57 if (options & File::eOpenOptionCanCreate) {
58 if (options & File::eOpenOptionCanCreateNewOnly)
59 return "w+x";
60 else
61 return "w+";
62 } else
63 return "r+";
64 } else if (options & File::eOpenOptionRead) {
65 return "r";
66 } else if (options & File::eOpenOptionWrite) {
67 return "w";
68 }
69 return NULL;
70 }
71
72 int File::kInvalidDescriptor = -1;
73 FILE *File::kInvalidStream = NULL;
74
~File()75 File::~File() { Close(); }
76
GetDescriptor() const77 int File::GetDescriptor() const {
78 if (DescriptorIsValid())
79 return m_descriptor;
80
81 // Don't open the file descriptor if we don't need to, just get it from the
82 // stream if we have one.
83 if (StreamIsValid()) {
84 #if defined(_WIN32)
85 return _fileno(m_stream);
86 #else
87 return fileno(m_stream);
88 #endif
89 }
90
91 // Invalid descriptor and invalid stream, return invalid descriptor.
92 return kInvalidDescriptor;
93 }
94
GetWaitableHandle()95 IOObject::WaitableHandle File::GetWaitableHandle() { return m_descriptor; }
96
SetDescriptor(int fd,bool transfer_ownership)97 void File::SetDescriptor(int fd, bool transfer_ownership) {
98 if (IsValid())
99 Close();
100 m_descriptor = fd;
101 m_should_close_fd = transfer_ownership;
102 }
103
GetStream()104 FILE *File::GetStream() {
105 if (!StreamIsValid()) {
106 if (DescriptorIsValid()) {
107 const char *mode = GetStreamOpenModeFromOptions(m_options);
108 if (mode) {
109 if (!m_should_close_fd) {
110 // We must duplicate the file descriptor if we don't own it because when you
111 // call fdopen, the stream will own the fd
112 #ifdef _WIN32
113 m_descriptor = ::_dup(GetDescriptor());
114 #else
115 m_descriptor = dup(GetDescriptor());
116 #endif
117 m_should_close_fd = true;
118 }
119
120 m_stream =
121 llvm::sys::RetryAfterSignal(nullptr, ::fdopen, m_descriptor, mode);
122
123 // If we got a stream, then we own the stream and should no longer own
124 // the descriptor because fclose() will close it for us
125
126 if (m_stream) {
127 m_own_stream = true;
128 m_should_close_fd = false;
129 }
130 }
131 }
132 }
133 return m_stream;
134 }
135
SetStream(FILE * fh,bool transfer_ownership)136 void File::SetStream(FILE *fh, bool transfer_ownership) {
137 if (IsValid())
138 Close();
139 m_stream = fh;
140 m_own_stream = transfer_ownership;
141 }
142
GetPermissions(Status & error) const143 uint32_t File::GetPermissions(Status &error) const {
144 int fd = GetDescriptor();
145 if (fd != kInvalidDescriptor) {
146 struct stat file_stats;
147 if (::fstat(fd, &file_stats) == -1)
148 error.SetErrorToErrno();
149 else {
150 error.Clear();
151 return file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
152 }
153 } else {
154 error.SetErrorString("invalid file descriptor");
155 }
156 return 0;
157 }
158
Close()159 Status File::Close() {
160 Status error;
161 if (StreamIsValid() && m_own_stream) {
162 if (::fclose(m_stream) == EOF)
163 error.SetErrorToErrno();
164 }
165
166 if (DescriptorIsValid() && m_should_close_fd) {
167 if (::close(m_descriptor) != 0)
168 error.SetErrorToErrno();
169 }
170 m_descriptor = kInvalidDescriptor;
171 m_stream = kInvalidStream;
172 m_options = 0;
173 m_own_stream = false;
174 m_should_close_fd = false;
175 m_is_interactive = eLazyBoolCalculate;
176 m_is_real_terminal = eLazyBoolCalculate;
177 return error;
178 }
179
Clear()180 void File::Clear() {
181 m_stream = nullptr;
182 m_descriptor = -1;
183 m_options = 0;
184 m_own_stream = false;
185 m_is_interactive = m_supports_colors = m_is_real_terminal =
186 eLazyBoolCalculate;
187 }
188
GetFileSpec(FileSpec & file_spec) const189 Status File::GetFileSpec(FileSpec &file_spec) const {
190 Status error;
191 #ifdef F_GETPATH
192 if (IsValid()) {
193 char path[PATH_MAX];
194 if (::fcntl(GetDescriptor(), F_GETPATH, path) == -1)
195 error.SetErrorToErrno();
196 else
197 file_spec.SetFile(path, FileSpec::Style::native);
198 } else {
199 error.SetErrorString("invalid file handle");
200 }
201 #elif defined(__linux__)
202 char proc[64];
203 char path[PATH_MAX];
204 if (::snprintf(proc, sizeof(proc), "/proc/self/fd/%d", GetDescriptor()) < 0)
205 error.SetErrorString("cannot resolve file descriptor");
206 else {
207 ssize_t len;
208 if ((len = ::readlink(proc, path, sizeof(path) - 1)) == -1)
209 error.SetErrorToErrno();
210 else {
211 path[len] = '\0';
212 file_spec.SetFile(path, FileSpec::Style::native);
213 }
214 }
215 #else
216 error.SetErrorString("File::GetFileSpec is not supported on this platform");
217 #endif
218
219 if (error.Fail())
220 file_spec.Clear();
221 return error;
222 }
223
SeekFromStart(off_t offset,Status * error_ptr)224 off_t File::SeekFromStart(off_t offset, Status *error_ptr) {
225 off_t result = 0;
226 if (DescriptorIsValid()) {
227 result = ::lseek(m_descriptor, offset, SEEK_SET);
228
229 if (error_ptr) {
230 if (result == -1)
231 error_ptr->SetErrorToErrno();
232 else
233 error_ptr->Clear();
234 }
235 } else if (StreamIsValid()) {
236 result = ::fseek(m_stream, offset, SEEK_SET);
237
238 if (error_ptr) {
239 if (result == -1)
240 error_ptr->SetErrorToErrno();
241 else
242 error_ptr->Clear();
243 }
244 } else if (error_ptr) {
245 error_ptr->SetErrorString("invalid file handle");
246 }
247 return result;
248 }
249
SeekFromCurrent(off_t offset,Status * error_ptr)250 off_t File::SeekFromCurrent(off_t offset, Status *error_ptr) {
251 off_t result = -1;
252 if (DescriptorIsValid()) {
253 result = ::lseek(m_descriptor, offset, SEEK_CUR);
254
255 if (error_ptr) {
256 if (result == -1)
257 error_ptr->SetErrorToErrno();
258 else
259 error_ptr->Clear();
260 }
261 } else if (StreamIsValid()) {
262 result = ::fseek(m_stream, offset, SEEK_CUR);
263
264 if (error_ptr) {
265 if (result == -1)
266 error_ptr->SetErrorToErrno();
267 else
268 error_ptr->Clear();
269 }
270 } else if (error_ptr) {
271 error_ptr->SetErrorString("invalid file handle");
272 }
273 return result;
274 }
275
SeekFromEnd(off_t offset,Status * error_ptr)276 off_t File::SeekFromEnd(off_t offset, Status *error_ptr) {
277 off_t result = -1;
278 if (DescriptorIsValid()) {
279 result = ::lseek(m_descriptor, offset, SEEK_END);
280
281 if (error_ptr) {
282 if (result == -1)
283 error_ptr->SetErrorToErrno();
284 else
285 error_ptr->Clear();
286 }
287 } else if (StreamIsValid()) {
288 result = ::fseek(m_stream, offset, SEEK_END);
289
290 if (error_ptr) {
291 if (result == -1)
292 error_ptr->SetErrorToErrno();
293 else
294 error_ptr->Clear();
295 }
296 } else if (error_ptr) {
297 error_ptr->SetErrorString("invalid file handle");
298 }
299 return result;
300 }
301
Flush()302 Status File::Flush() {
303 Status error;
304 if (StreamIsValid()) {
305 if (llvm::sys::RetryAfterSignal(EOF, ::fflush, m_stream) == EOF)
306 error.SetErrorToErrno();
307 } else if (!DescriptorIsValid()) {
308 error.SetErrorString("invalid file handle");
309 }
310 return error;
311 }
312
Sync()313 Status File::Sync() {
314 Status error;
315 if (DescriptorIsValid()) {
316 #ifdef _WIN32
317 int err = FlushFileBuffers((HANDLE)_get_osfhandle(m_descriptor));
318 if (err == 0)
319 error.SetErrorToGenericError();
320 #else
321 if (llvm::sys::RetryAfterSignal(-1, ::fsync, m_descriptor) == -1)
322 error.SetErrorToErrno();
323 #endif
324 } else {
325 error.SetErrorString("invalid file handle");
326 }
327 return error;
328 }
329
330 #if defined(__APPLE__)
331 // Darwin kernels only can read/write <= INT_MAX bytes
332 #define MAX_READ_SIZE INT_MAX
333 #define MAX_WRITE_SIZE INT_MAX
334 #endif
335
Read(void * buf,size_t & num_bytes)336 Status File::Read(void *buf, size_t &num_bytes) {
337 Status error;
338
339 #if defined(MAX_READ_SIZE)
340 if (num_bytes > MAX_READ_SIZE) {
341 uint8_t *p = (uint8_t *)buf;
342 size_t bytes_left = num_bytes;
343 // Init the num_bytes read to zero
344 num_bytes = 0;
345
346 while (bytes_left > 0) {
347 size_t curr_num_bytes;
348 if (bytes_left > MAX_READ_SIZE)
349 curr_num_bytes = MAX_READ_SIZE;
350 else
351 curr_num_bytes = bytes_left;
352
353 error = Read(p + num_bytes, curr_num_bytes);
354
355 // Update how many bytes were read
356 num_bytes += curr_num_bytes;
357 if (bytes_left < curr_num_bytes)
358 bytes_left = 0;
359 else
360 bytes_left -= curr_num_bytes;
361
362 if (error.Fail())
363 break;
364 }
365 return error;
366 }
367 #endif
368
369 ssize_t bytes_read = -1;
370 if (DescriptorIsValid()) {
371 bytes_read = llvm::sys::RetryAfterSignal(-1, ::read, m_descriptor, buf, num_bytes);
372 if (bytes_read == -1) {
373 error.SetErrorToErrno();
374 num_bytes = 0;
375 } else
376 num_bytes = bytes_read;
377 } else if (StreamIsValid()) {
378 bytes_read = ::fread(buf, 1, num_bytes, m_stream);
379
380 if (bytes_read == 0) {
381 if (::feof(m_stream))
382 error.SetErrorString("feof");
383 else if (::ferror(m_stream))
384 error.SetErrorString("ferror");
385 num_bytes = 0;
386 } else
387 num_bytes = bytes_read;
388 } else {
389 num_bytes = 0;
390 error.SetErrorString("invalid file handle");
391 }
392 return error;
393 }
394
Write(const void * buf,size_t & num_bytes)395 Status File::Write(const void *buf, size_t &num_bytes) {
396 Status error;
397
398 #if defined(MAX_WRITE_SIZE)
399 if (num_bytes > MAX_WRITE_SIZE) {
400 const uint8_t *p = (const uint8_t *)buf;
401 size_t bytes_left = num_bytes;
402 // Init the num_bytes written to zero
403 num_bytes = 0;
404
405 while (bytes_left > 0) {
406 size_t curr_num_bytes;
407 if (bytes_left > MAX_WRITE_SIZE)
408 curr_num_bytes = MAX_WRITE_SIZE;
409 else
410 curr_num_bytes = bytes_left;
411
412 error = Write(p + num_bytes, curr_num_bytes);
413
414 // Update how many bytes were read
415 num_bytes += curr_num_bytes;
416 if (bytes_left < curr_num_bytes)
417 bytes_left = 0;
418 else
419 bytes_left -= curr_num_bytes;
420
421 if (error.Fail())
422 break;
423 }
424 return error;
425 }
426 #endif
427
428 ssize_t bytes_written = -1;
429 if (DescriptorIsValid()) {
430 bytes_written =
431 llvm::sys::RetryAfterSignal(-1, ::write, m_descriptor, buf, num_bytes);
432 if (bytes_written == -1) {
433 error.SetErrorToErrno();
434 num_bytes = 0;
435 } else
436 num_bytes = bytes_written;
437 } else if (StreamIsValid()) {
438 bytes_written = ::fwrite(buf, 1, num_bytes, m_stream);
439
440 if (bytes_written == 0) {
441 if (::feof(m_stream))
442 error.SetErrorString("feof");
443 else if (::ferror(m_stream))
444 error.SetErrorString("ferror");
445 num_bytes = 0;
446 } else
447 num_bytes = bytes_written;
448
449 } else {
450 num_bytes = 0;
451 error.SetErrorString("invalid file handle");
452 }
453
454 return error;
455 }
456
Read(void * buf,size_t & num_bytes,off_t & offset)457 Status File::Read(void *buf, size_t &num_bytes, off_t &offset) {
458 Status error;
459
460 #if defined(MAX_READ_SIZE)
461 if (num_bytes > MAX_READ_SIZE) {
462 uint8_t *p = (uint8_t *)buf;
463 size_t bytes_left = num_bytes;
464 // Init the num_bytes read to zero
465 num_bytes = 0;
466
467 while (bytes_left > 0) {
468 size_t curr_num_bytes;
469 if (bytes_left > MAX_READ_SIZE)
470 curr_num_bytes = MAX_READ_SIZE;
471 else
472 curr_num_bytes = bytes_left;
473
474 error = Read(p + num_bytes, curr_num_bytes, offset);
475
476 // Update how many bytes were read
477 num_bytes += curr_num_bytes;
478 if (bytes_left < curr_num_bytes)
479 bytes_left = 0;
480 else
481 bytes_left -= curr_num_bytes;
482
483 if (error.Fail())
484 break;
485 }
486 return error;
487 }
488 #endif
489
490 #ifndef _WIN32
491 int fd = GetDescriptor();
492 if (fd != kInvalidDescriptor) {
493 ssize_t bytes_read =
494 llvm::sys::RetryAfterSignal(-1, ::pread, fd, buf, num_bytes, offset);
495 if (bytes_read < 0) {
496 num_bytes = 0;
497 error.SetErrorToErrno();
498 } else {
499 offset += bytes_read;
500 num_bytes = bytes_read;
501 }
502 } else {
503 num_bytes = 0;
504 error.SetErrorString("invalid file handle");
505 }
506 #else
507 long cur = ::lseek(m_descriptor, 0, SEEK_CUR);
508 SeekFromStart(offset);
509 error = Read(buf, num_bytes);
510 if (!error.Fail())
511 SeekFromStart(cur);
512 #endif
513 return error;
514 }
515
Read(size_t & num_bytes,off_t & offset,bool null_terminate,DataBufferSP & data_buffer_sp)516 Status File::Read(size_t &num_bytes, off_t &offset, bool null_terminate,
517 DataBufferSP &data_buffer_sp) {
518 Status error;
519
520 if (num_bytes > 0) {
521 int fd = GetDescriptor();
522 if (fd != kInvalidDescriptor) {
523 struct stat file_stats;
524 if (::fstat(fd, &file_stats) == 0) {
525 if (file_stats.st_size > offset) {
526 const size_t bytes_left = file_stats.st_size - offset;
527 if (num_bytes > bytes_left)
528 num_bytes = bytes_left;
529
530 size_t num_bytes_plus_nul_char = num_bytes + (null_terminate ? 1 : 0);
531 std::unique_ptr<DataBufferHeap> data_heap_ap;
532 data_heap_ap.reset(new DataBufferHeap());
533 data_heap_ap->SetByteSize(num_bytes_plus_nul_char);
534
535 if (data_heap_ap.get()) {
536 error = Read(data_heap_ap->GetBytes(), num_bytes, offset);
537 if (error.Success()) {
538 // Make sure we read exactly what we asked for and if we got
539 // less, adjust the array
540 if (num_bytes_plus_nul_char < data_heap_ap->GetByteSize())
541 data_heap_ap->SetByteSize(num_bytes_plus_nul_char);
542 data_buffer_sp.reset(data_heap_ap.release());
543 return error;
544 }
545 }
546 } else
547 error.SetErrorString("file is empty");
548 } else
549 error.SetErrorToErrno();
550 } else
551 error.SetErrorString("invalid file handle");
552 } else
553 error.SetErrorString("invalid file handle");
554
555 num_bytes = 0;
556 data_buffer_sp.reset();
557 return error;
558 }
559
Write(const void * buf,size_t & num_bytes,off_t & offset)560 Status File::Write(const void *buf, size_t &num_bytes, off_t &offset) {
561 Status error;
562
563 #if defined(MAX_WRITE_SIZE)
564 if (num_bytes > MAX_WRITE_SIZE) {
565 const uint8_t *p = (const uint8_t *)buf;
566 size_t bytes_left = num_bytes;
567 // Init the num_bytes written to zero
568 num_bytes = 0;
569
570 while (bytes_left > 0) {
571 size_t curr_num_bytes;
572 if (bytes_left > MAX_WRITE_SIZE)
573 curr_num_bytes = MAX_WRITE_SIZE;
574 else
575 curr_num_bytes = bytes_left;
576
577 error = Write(p + num_bytes, curr_num_bytes, offset);
578
579 // Update how many bytes were read
580 num_bytes += curr_num_bytes;
581 if (bytes_left < curr_num_bytes)
582 bytes_left = 0;
583 else
584 bytes_left -= curr_num_bytes;
585
586 if (error.Fail())
587 break;
588 }
589 return error;
590 }
591 #endif
592
593 int fd = GetDescriptor();
594 if (fd != kInvalidDescriptor) {
595 #ifndef _WIN32
596 ssize_t bytes_written =
597 llvm::sys::RetryAfterSignal(-1, ::pwrite, m_descriptor, buf, num_bytes, offset);
598 if (bytes_written < 0) {
599 num_bytes = 0;
600 error.SetErrorToErrno();
601 } else {
602 offset += bytes_written;
603 num_bytes = bytes_written;
604 }
605 #else
606 long cur = ::lseek(m_descriptor, 0, SEEK_CUR);
607 error = Write(buf, num_bytes);
608 long after = ::lseek(m_descriptor, 0, SEEK_CUR);
609
610 if (!error.Fail())
611 SeekFromStart(cur);
612
613 offset = after;
614 #endif
615 } else {
616 num_bytes = 0;
617 error.SetErrorString("invalid file handle");
618 }
619 return error;
620 }
621
622 //------------------------------------------------------------------
623 // Print some formatted output to the stream.
624 //------------------------------------------------------------------
Printf(const char * format,...)625 size_t File::Printf(const char *format, ...) {
626 va_list args;
627 va_start(args, format);
628 size_t result = PrintfVarArg(format, args);
629 va_end(args);
630 return result;
631 }
632
633 //------------------------------------------------------------------
634 // Print some formatted output to the stream.
635 //------------------------------------------------------------------
PrintfVarArg(const char * format,va_list args)636 size_t File::PrintfVarArg(const char *format, va_list args) {
637 size_t result = 0;
638 if (DescriptorIsValid()) {
639 char *s = NULL;
640 result = vasprintf(&s, format, args);
641 if (s != NULL) {
642 if (result > 0) {
643 size_t s_len = result;
644 Write(s, s_len);
645 result = s_len;
646 }
647 free(s);
648 }
649 } else if (StreamIsValid()) {
650 result = ::vfprintf(m_stream, format, args);
651 }
652 return result;
653 }
654
ConvertOpenOptionsForPOSIXOpen(uint32_t open_options)655 mode_t File::ConvertOpenOptionsForPOSIXOpen(uint32_t open_options) {
656 mode_t mode = 0;
657 if (open_options & eOpenOptionRead && open_options & eOpenOptionWrite)
658 mode |= O_RDWR;
659 else if (open_options & eOpenOptionWrite)
660 mode |= O_WRONLY;
661
662 if (open_options & eOpenOptionAppend)
663 mode |= O_APPEND;
664
665 if (open_options & eOpenOptionTruncate)
666 mode |= O_TRUNC;
667
668 if (open_options & eOpenOptionNonBlocking)
669 mode |= O_NONBLOCK;
670
671 if (open_options & eOpenOptionCanCreateNewOnly)
672 mode |= O_CREAT | O_EXCL;
673 else if (open_options & eOpenOptionCanCreate)
674 mode |= O_CREAT;
675
676 return mode;
677 }
678
CalculateInteractiveAndTerminal()679 void File::CalculateInteractiveAndTerminal() {
680 const int fd = GetDescriptor();
681 if (fd >= 0) {
682 m_is_interactive = eLazyBoolNo;
683 m_is_real_terminal = eLazyBoolNo;
684 #if defined(_WIN32)
685 if (_isatty(fd)) {
686 m_is_interactive = eLazyBoolYes;
687 m_is_real_terminal = eLazyBoolYes;
688 #if defined(ENABLE_VIRTUAL_TERMINAL_PROCESSING)
689 m_supports_colors = eLazyBoolYes;
690 #endif
691 }
692 #else
693 if (isatty(fd)) {
694 m_is_interactive = eLazyBoolYes;
695 struct winsize window_size;
696 if (::ioctl(fd, TIOCGWINSZ, &window_size) == 0) {
697 if (window_size.ws_col > 0) {
698 m_is_real_terminal = eLazyBoolYes;
699 if (llvm::sys::Process::FileDescriptorHasColors(fd))
700 m_supports_colors = eLazyBoolYes;
701 }
702 }
703 }
704 #endif
705 }
706 }
707
GetIsInteractive()708 bool File::GetIsInteractive() {
709 if (m_is_interactive == eLazyBoolCalculate)
710 CalculateInteractiveAndTerminal();
711 return m_is_interactive == eLazyBoolYes;
712 }
713
GetIsRealTerminal()714 bool File::GetIsRealTerminal() {
715 if (m_is_real_terminal == eLazyBoolCalculate)
716 CalculateInteractiveAndTerminal();
717 return m_is_real_terminal == eLazyBoolYes;
718 }
719
GetIsTerminalWithColors()720 bool File::GetIsTerminalWithColors() {
721 if (m_supports_colors == eLazyBoolCalculate)
722 CalculateInteractiveAndTerminal();
723 return m_supports_colors == eLazyBoolYes;
724 }
725