1 //===-- File.cpp ------------------------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "lldb/Host/File.h"
20 #include "lldb/Host/windows/windows.h"
22 #include <sys/ioctl.h>
25 #include "lldb/Core/DataBufferHeap.h"
26 #include "lldb/Core/Error.h"
27 #include "lldb/Host/Config.h"
28 #include "lldb/Host/FileSpec.h"
31 using namespace lldb_private;
34 GetStreamOpenModeFromOptions (uint32_t options)
36 if (options & File::eOpenOptionAppend)
38 if (options & File::eOpenOptionRead)
40 if (options & File::eOpenOptionCanCreateNewOnly)
45 else if (options & File::eOpenOptionWrite)
47 if (options & File::eOpenOptionCanCreateNewOnly)
53 else if (options & File::eOpenOptionRead && options & File::eOpenOptionWrite)
55 if (options & File::eOpenOptionCanCreate)
57 if (options & File::eOpenOptionCanCreateNewOnly)
65 else if (options & File::eOpenOptionRead)
69 else if (options & File::eOpenOptionWrite)
76 int File::kInvalidDescriptor = -1;
77 FILE * File::kInvalidStream = NULL;
79 File::File(const char *path, uint32_t options, uint32_t permissions) :
80 m_descriptor (kInvalidDescriptor),
81 m_stream (kInvalidStream),
84 m_own_descriptor (false),
85 m_is_interactive (eLazyBoolCalculate),
86 m_is_real_terminal (eLazyBoolCalculate)
88 Open (path, options, permissions);
91 File::File (const FileSpec& filespec,
93 uint32_t permissions) :
94 m_descriptor (kInvalidDescriptor),
95 m_stream (kInvalidStream),
98 m_own_descriptor (false),
99 m_is_interactive (eLazyBoolCalculate),
100 m_is_real_terminal (eLazyBoolCalculate)
105 Open (filespec.GetPath().c_str(), options, permissions);
109 File::File (const File &rhs) :
110 m_descriptor (kInvalidDescriptor),
111 m_stream (kInvalidStream),
113 m_own_stream (false),
114 m_own_descriptor (false),
115 m_is_interactive (eLazyBoolCalculate),
116 m_is_real_terminal (eLazyBoolCalculate)
123 File::operator = (const File &rhs)
137 File::GetDescriptor() const
139 if (DescriptorIsValid())
142 // Don't open the file descriptor if we don't need to, just get it from the
143 // stream if we have one.
145 return fileno (m_stream);
147 // Invalid descriptor and invalid stream, return invalid descriptor.
148 return kInvalidDescriptor;
152 File::SetDescriptor (int fd, bool transfer_ownership)
157 m_own_descriptor = transfer_ownership;
164 if (!StreamIsValid())
166 if (DescriptorIsValid())
168 const char *mode = GetStreamOpenModeFromOptions (m_options);
171 if (!m_own_descriptor)
173 // We must duplicate the file descriptor if we don't own it because
174 // when you call fdopen, the stream will own the fd
176 m_descriptor = ::_dup(GetDescriptor());
178 m_descriptor = ::fcntl(GetDescriptor(), F_DUPFD);
180 m_own_descriptor = true;
185 m_stream = ::fdopen (m_descriptor, mode);
186 } while (m_stream == NULL && errno == EINTR);
188 // If we got a stream, then we own the stream and should no
189 // longer own the descriptor because fclose() will close it for us
194 m_own_descriptor = false;
204 File::SetStream (FILE *fh, bool transfer_ownership)
209 m_own_stream = transfer_ownership;
213 File::Duplicate (const File &rhs)
219 if (rhs.DescriptorIsValid())
222 m_descriptor = ::_dup(rhs.GetDescriptor());
224 m_descriptor = ::fcntl(rhs.GetDescriptor(), F_DUPFD);
226 if (!DescriptorIsValid())
227 error.SetErrorToErrno();
230 m_options = rhs.m_options;
231 m_own_descriptor = true;
236 error.SetErrorString ("invalid file to duplicate");
242 File::Open (const char *path, uint32_t options, uint32_t permissions)
249 const bool read = options & eOpenOptionRead;
250 const bool write = options & eOpenOptionWrite;
258 if (options & eOpenOptionAppend)
261 if (options & eOpenOptionTruncate)
264 if (options & eOpenOptionCanCreate)
267 if (options & eOpenOptionCanCreateNewOnly)
268 oflag |= O_CREAT | O_EXCL;
275 if (options & eOpenoptionDontFollowSymlinks)
281 if (options & eOpenOptionNonBlocking)
290 if (permissions & lldb::eFilePermissionsUserRead) mode |= S_IRUSR;
291 if (permissions & lldb::eFilePermissionsUserWrite) mode |= S_IWUSR;
292 if (permissions & lldb::eFilePermissionsUserExecute) mode |= S_IXUSR;
293 if (permissions & lldb::eFilePermissionsGroupRead) mode |= S_IRGRP;
294 if (permissions & lldb::eFilePermissionsGroupWrite) mode |= S_IWGRP;
295 if (permissions & lldb::eFilePermissionsGroupExecute) mode |= S_IXGRP;
296 if (permissions & lldb::eFilePermissionsWorldRead) mode |= S_IROTH;
297 if (permissions & lldb::eFilePermissionsWorldWrite) mode |= S_IWOTH;
298 if (permissions & lldb::eFilePermissionsWorldExecute) mode |= S_IXOTH;
303 m_descriptor = ::open(path, oflag, mode);
304 } while (m_descriptor < 0 && errno == EINTR);
306 if (!DescriptorIsValid())
307 error.SetErrorToErrno();
310 m_own_descriptor = true;
318 File::GetPermissions (const char *path, Error &error)
322 struct stat file_stats;
323 if (::stat (path, &file_stats) == -1)
324 error.SetErrorToErrno();
328 return file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
334 error.SetErrorString ("invalid path");
336 error.SetErrorString ("empty path");
342 File::GetPermissions(Error &error) const
344 int fd = GetDescriptor();
345 if (fd != kInvalidDescriptor)
347 struct stat file_stats;
348 if (::fstat (fd, &file_stats) == -1)
349 error.SetErrorToErrno();
353 return file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
358 error.SetErrorString ("invalid file descriptor");
368 if (StreamIsValid() && m_own_stream)
370 if (::fclose (m_stream) == EOF)
371 error.SetErrorToErrno();
374 if (DescriptorIsValid() && m_own_descriptor)
376 if (::close (m_descriptor) != 0)
377 error.SetErrorToErrno();
379 m_descriptor = kInvalidDescriptor;
380 m_stream = kInvalidStream;
382 m_own_stream = false;
383 m_own_descriptor = false;
384 m_is_interactive = eLazyBoolCalculate;
385 m_is_real_terminal = eLazyBoolCalculate;
391 File::GetFileSpec (FileSpec &file_spec) const
394 #ifdef LLDB_CONFIG_FCNTL_GETPATH_SUPPORTED
398 if (::fcntl(GetDescriptor(), F_GETPATH, path) == -1)
399 error.SetErrorToErrno();
401 file_spec.SetFile (path, false);
405 error.SetErrorString("invalid file handle");
407 #elif defined(__linux__)
410 if (::snprintf(proc, sizeof(proc), "/proc/self/fd/%d", GetDescriptor()) < 0)
411 error.SetErrorString ("cannot resolve file descriptor");
415 if ((len = ::readlink(proc, path, sizeof(path) - 1)) == -1)
416 error.SetErrorToErrno();
420 file_spec.SetFile (path, false);
424 error.SetErrorString ("File::GetFileSpec is not supported on this platform");
433 File::SeekFromStart (off_t offset, Error *error_ptr)
436 if (DescriptorIsValid())
438 result = ::lseek (m_descriptor, offset, SEEK_SET);
443 error_ptr->SetErrorToErrno();
448 else if (StreamIsValid ())
450 result = ::fseek(m_stream, offset, SEEK_SET);
455 error_ptr->SetErrorToErrno();
462 error_ptr->SetErrorString("invalid file handle");
468 File::SeekFromCurrent (off_t offset, Error *error_ptr)
471 if (DescriptorIsValid())
473 result = ::lseek (m_descriptor, offset, SEEK_CUR);
478 error_ptr->SetErrorToErrno();
483 else if (StreamIsValid ())
485 result = ::fseek(m_stream, offset, SEEK_CUR);
490 error_ptr->SetErrorToErrno();
497 error_ptr->SetErrorString("invalid file handle");
503 File::SeekFromEnd (off_t offset, Error *error_ptr)
506 if (DescriptorIsValid())
508 result = ::lseek (m_descriptor, offset, SEEK_END);
513 error_ptr->SetErrorToErrno();
518 else if (StreamIsValid ())
520 result = ::fseek(m_stream, offset, SEEK_END);
525 error_ptr->SetErrorToErrno();
532 error_ptr->SetErrorString("invalid file handle");
546 err = ::fflush (m_stream);
547 } while (err == EOF && errno == EINTR);
550 error.SetErrorToErrno();
552 else if (!DescriptorIsValid())
554 error.SetErrorString("invalid file handle");
564 if (DescriptorIsValid())
567 int err = FlushFileBuffers((HANDLE)_get_osfhandle(m_descriptor));
569 error.SetErrorToGenericError();
574 err = ::fsync (m_descriptor);
575 } while (err == -1 && errno == EINTR);
578 error.SetErrorToErrno();
583 error.SetErrorString("invalid file handle");
589 File::Read (void *buf, size_t &num_bytes)
592 ssize_t bytes_read = -1;
593 if (DescriptorIsValid())
597 bytes_read = ::read (m_descriptor, buf, num_bytes);
598 } while (bytes_read < 0 && errno == EINTR);
600 if (bytes_read == -1)
602 error.SetErrorToErrno();
606 num_bytes = bytes_read;
608 else if (StreamIsValid())
610 bytes_read = ::fread (buf, 1, num_bytes, m_stream);
614 if (::feof(m_stream))
615 error.SetErrorString ("feof");
616 else if (::ferror (m_stream))
617 error.SetErrorString ("ferror");
621 num_bytes = bytes_read;
626 error.SetErrorString("invalid file handle");
632 File::Write (const void *buf, size_t &num_bytes)
635 ssize_t bytes_written = -1;
636 if (DescriptorIsValid())
640 bytes_written = ::write (m_descriptor, buf, num_bytes);
641 } while (bytes_written < 0 && errno == EINTR);
643 if (bytes_written == -1)
645 error.SetErrorToErrno();
649 num_bytes = bytes_written;
651 else if (StreamIsValid())
653 bytes_written = ::fwrite (buf, 1, num_bytes, m_stream);
655 if (bytes_written == 0)
657 if (::feof(m_stream))
658 error.SetErrorString ("feof");
659 else if (::ferror (m_stream))
660 error.SetErrorString ("ferror");
664 num_bytes = bytes_written;
670 error.SetErrorString("invalid file handle");
677 File::Read (void *buf, size_t &num_bytes, off_t &offset)
681 int fd = GetDescriptor();
682 if (fd != kInvalidDescriptor)
684 ssize_t bytes_read = -1;
687 bytes_read = ::pread (fd, buf, num_bytes, offset);
688 } while (bytes_read < 0 && errno == EINTR);
693 error.SetErrorToErrno();
697 offset += bytes_read;
698 num_bytes = bytes_read;
704 error.SetErrorString("invalid file handle");
708 long cur = ::lseek(m_descriptor, 0, SEEK_CUR);
709 SeekFromStart(offset);
710 Error error = Read(buf, num_bytes);
718 File::Read (size_t &num_bytes, off_t &offset, bool null_terminate, DataBufferSP &data_buffer_sp)
724 int fd = GetDescriptor();
725 if (fd != kInvalidDescriptor)
727 struct stat file_stats;
728 if (::fstat (fd, &file_stats) == 0)
730 if (file_stats.st_size > offset)
732 const size_t bytes_left = file_stats.st_size - offset;
733 if (num_bytes > bytes_left)
734 num_bytes = bytes_left;
736 std::unique_ptr<DataBufferHeap> data_heap_ap;
737 data_heap_ap.reset(new DataBufferHeap(num_bytes + (null_terminate ? 1 : 0), '\0'));
739 if (data_heap_ap.get())
741 error = Read (data_heap_ap->GetBytes(), num_bytes, offset);
744 // Make sure we read exactly what we asked for and if we got
745 // less, adjust the array
746 if (num_bytes < data_heap_ap->GetByteSize())
747 data_heap_ap->SetByteSize(num_bytes);
748 data_buffer_sp.reset(data_heap_ap.release());
754 error.SetErrorString("file is empty");
757 error.SetErrorToErrno();
760 error.SetErrorString("invalid file handle");
763 error.SetErrorString("invalid file handle");
766 data_buffer_sp.reset();
771 File::Write (const void *buf, size_t &num_bytes, off_t &offset)
774 int fd = GetDescriptor();
775 if (fd != kInvalidDescriptor)
778 ssize_t bytes_written = -1;
781 bytes_written = ::pwrite (m_descriptor, buf, num_bytes, offset);
782 } while (bytes_written < 0 && errno == EINTR);
784 if (bytes_written < 0)
787 error.SetErrorToErrno();
791 offset += bytes_written;
792 num_bytes = bytes_written;
795 long cur = ::lseek(m_descriptor, 0, SEEK_CUR);
796 error = Write(buf, num_bytes);
797 long after = ::lseek(m_descriptor, 0, SEEK_CUR);
802 ssize_t bytes_written = after - cur;
809 error.SetErrorString("invalid file handle");
814 //------------------------------------------------------------------
815 // Print some formatted output to the stream.
816 //------------------------------------------------------------------
818 File::Printf (const char *format, ...)
821 va_start (args, format);
822 size_t result = PrintfVarArg (format, args);
827 //------------------------------------------------------------------
828 // Print some formatted output to the stream.
829 //------------------------------------------------------------------
831 File::PrintfVarArg (const char *format, va_list args)
834 if (DescriptorIsValid())
837 result = vasprintf(&s, format, args);
842 size_t s_len = result;
849 else if (StreamIsValid())
851 result = ::vfprintf (m_stream, format, args);
857 File::ConvertOpenOptionsForPOSIXOpen (uint32_t open_options)
860 if (open_options & eOpenOptionRead && open_options & eOpenOptionWrite)
862 else if (open_options & eOpenOptionWrite)
865 if (open_options & eOpenOptionAppend)
868 if (open_options & eOpenOptionTruncate)
871 if (open_options & eOpenOptionNonBlocking)
874 if (open_options & eOpenOptionCanCreateNewOnly)
875 mode |= O_CREAT | O_EXCL;
876 else if (open_options & eOpenOptionCanCreate)
883 File::CalculateInteractiveAndTerminal ()
885 const int fd = GetDescriptor();
888 m_is_interactive = eLazyBoolNo;
889 m_is_real_terminal = eLazyBoolNo;
893 m_is_interactive = eLazyBoolYes;
894 struct winsize window_size;
895 if (::ioctl (fd, TIOCGWINSZ, &window_size) == 0)
897 if (window_size.ws_col > 0)
898 m_is_real_terminal = eLazyBoolYes;
906 File::GetIsInteractive ()
908 if (m_is_interactive == eLazyBoolCalculate)
909 CalculateInteractiveAndTerminal ();
910 return m_is_interactive == eLazyBoolYes;
914 File::GetIsRealTerminal ()
916 if (m_is_real_terminal == eLazyBoolCalculate)
917 CalculateInteractiveAndTerminal();
918 return m_is_real_terminal == eLazyBoolYes;