1 //===-- FileSpec.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 //===----------------------------------------------------------------------===//
11 #include "lldb/Host/File.h"
19 #include "lldb/Core/DataBufferHeap.h"
20 #include "lldb/Core/Error.h"
21 #include "lldb/Host/Config.h"
22 #include "lldb/Host/FileSpec.h"
25 using namespace lldb_private;
28 GetStreamOpenModeFromOptions (uint32_t options)
30 if (options & File::eOpenOptionAppend)
32 if (options & File::eOpenOptionRead)
34 if (options & File::eOpenOptionCanCreateNewOnly)
39 else if (options & File::eOpenOptionWrite)
41 if (options & File::eOpenOptionCanCreateNewOnly)
47 else if (options & File::eOpenOptionRead && options & File::eOpenOptionWrite)
49 if (options & File::eOpenOptionCanCreate)
51 if (options & File::eOpenOptionCanCreateNewOnly)
59 else if (options & File::eOpenOptionRead)
63 else if (options & File::eOpenOptionWrite)
70 int File::kInvalidDescriptor = -1;
71 FILE * File::kInvalidStream = NULL;
73 File::File(const char *path, uint32_t options, uint32_t permissions) :
74 m_descriptor (kInvalidDescriptor),
75 m_stream (kInvalidStream),
79 Open (path, options, permissions);
82 File::File (const File &rhs) :
83 m_descriptor (kInvalidDescriptor),
84 m_stream (kInvalidStream),
93 File::operator = (const File &rhs)
107 File::GetDescriptor() const
109 if (DescriptorIsValid())
112 // Don't open the file descriptor if we don't need to, just get it from the
113 // stream if we have one.
115 return fileno (m_stream);
117 // Invalid descriptor and invalid stream, return invalid descriptor.
118 return kInvalidDescriptor;
122 File::SetDescriptor (int fd, bool transfer_ownership)
127 m_owned = transfer_ownership;
134 if (!StreamIsValid())
136 if (DescriptorIsValid())
138 const char *mode = GetStreamOpenModeFromOptions (m_options);
143 m_stream = ::fdopen (m_descriptor, mode);
144 } while (m_stream == NULL && errno == EINTR);
153 File::SetStream (FILE *fh, bool transfer_ownership)
158 m_owned = transfer_ownership;
162 File::Duplicate (const File &rhs)
168 if (rhs.DescriptorIsValid())
170 m_descriptor = ::fcntl(rhs.GetDescriptor(), F_DUPFD);
171 if (!DescriptorIsValid())
172 error.SetErrorToErrno();
175 m_options = rhs.m_options;
181 error.SetErrorString ("invalid file to duplicate");
187 File::Open (const char *path, uint32_t options, uint32_t permissions)
194 const bool read = options & eOpenOptionRead;
195 const bool write = options & eOpenOptionWrite;
203 if (options & eOpenOptionAppend)
206 if (options & eOpenOptionTruncate)
209 if (options & eOpenOptionCanCreate)
212 if (options & eOpenOptionCanCreateNewOnly)
213 oflag |= O_CREAT | O_EXCL;
220 if (options & eOpenOptionNonBlocking)
226 if (permissions & ePermissionsUserRead) mode |= S_IRUSR;
227 if (permissions & ePermissionsUserWrite) mode |= S_IWUSR;
228 if (permissions & ePermissionsUserExecute) mode |= S_IXUSR;
229 if (permissions & ePermissionsGroupRead) mode |= S_IRGRP;
230 if (permissions & ePermissionsGroupWrite) mode |= S_IWGRP;
231 if (permissions & ePermissionsGroupExecute) mode |= S_IXGRP;
232 if (permissions & ePermissionsWorldRead) mode |= S_IROTH;
233 if (permissions & ePermissionsWorldWrite) mode |= S_IWOTH;
234 if (permissions & ePermissionsWorldExecute) mode |= S_IXOTH;
239 m_descriptor = ::open(path, oflag, mode);
240 } while (m_descriptor < 0 && errno == EINTR);
242 if (!DescriptorIsValid())
243 error.SetErrorToErrno();
260 if (::fclose (m_stream) == EOF)
261 error.SetErrorToErrno();
264 if (DescriptorIsValid())
266 if (::close (m_descriptor) != 0)
267 error.SetErrorToErrno();
270 m_descriptor = kInvalidDescriptor;
271 m_stream = kInvalidStream;
280 File::GetFileSpec (FileSpec &file_spec) const
283 #ifdef LLDB_CONFIG_FCNTL_GETPATH_SUPPORTED
287 if (::fcntl(GetDescriptor(), F_GETPATH, path) == -1)
288 error.SetErrorToErrno();
290 file_spec.SetFile (path, false);
294 error.SetErrorString("invalid file handle");
296 #elif defined(__linux__)
299 if (::snprintf(proc, sizeof(proc), "/proc/self/fd/%d", GetDescriptor()) < 0)
300 error.SetErrorString ("cannot resolve file descriptor");
304 if ((len = ::readlink(proc, path, sizeof(path) - 1)) == -1)
305 error.SetErrorToErrno();
309 file_spec.SetFile (path, false);
313 error.SetErrorString ("File::GetFileSpec is not supported on this platform");
322 File::SeekFromStart (off_t offset, Error *error_ptr)
325 if (DescriptorIsValid())
327 result = ::lseek (m_descriptor, offset, SEEK_SET);
332 error_ptr->SetErrorToErrno();
337 else if (StreamIsValid ())
339 result = ::fseek(m_stream, offset, SEEK_SET);
344 error_ptr->SetErrorToErrno();
351 error_ptr->SetErrorString("invalid file handle");
357 File::SeekFromCurrent (off_t offset, Error *error_ptr)
360 if (DescriptorIsValid())
362 result = ::lseek (m_descriptor, offset, SEEK_CUR);
367 error_ptr->SetErrorToErrno();
372 else if (StreamIsValid ())
374 result = ::fseek(m_stream, offset, SEEK_CUR);
379 error_ptr->SetErrorToErrno();
386 error_ptr->SetErrorString("invalid file handle");
392 File::SeekFromEnd (off_t offset, Error *error_ptr)
395 if (DescriptorIsValid())
397 result = ::lseek (m_descriptor, offset, SEEK_END);
402 error_ptr->SetErrorToErrno();
407 else if (StreamIsValid ())
409 result = ::fseek(m_stream, offset, SEEK_END);
414 error_ptr->SetErrorToErrno();
421 error_ptr->SetErrorString("invalid file handle");
435 err = ::fflush (m_stream);
436 } while (err == EOF && errno == EINTR);
439 error.SetErrorToErrno();
441 else if (!DescriptorIsValid())
443 error.SetErrorString("invalid file handle");
453 if (DescriptorIsValid())
458 err = ::fsync (m_descriptor);
459 } while (err == -1 && errno == EINTR);
462 error.SetErrorToErrno();
466 error.SetErrorString("invalid file handle");
472 File::Read (void *buf, size_t &num_bytes)
475 ssize_t bytes_read = -1;
476 if (DescriptorIsValid())
480 bytes_read = ::read (m_descriptor, buf, num_bytes);
481 } while (bytes_read < 0 && errno == EINTR);
483 if (bytes_read == -1)
485 error.SetErrorToErrno();
489 num_bytes = bytes_read;
491 else if (StreamIsValid())
493 bytes_read = ::fread (buf, 1, num_bytes, m_stream);
497 if (::feof(m_stream))
498 error.SetErrorString ("feof");
499 else if (::ferror (m_stream))
500 error.SetErrorString ("ferror");
504 num_bytes = bytes_read;
509 error.SetErrorString("invalid file handle");
515 File::Write (const void *buf, size_t &num_bytes)
518 ssize_t bytes_written = -1;
519 if (DescriptorIsValid())
523 bytes_written = ::write (m_descriptor, buf, num_bytes);
524 } while (bytes_written < 0 && errno == EINTR);
526 if (bytes_written == -1)
528 error.SetErrorToErrno();
532 num_bytes = bytes_written;
534 else if (StreamIsValid())
536 bytes_written = ::fwrite (buf, 1, num_bytes, m_stream);
538 if (bytes_written == 0)
540 if (::feof(m_stream))
541 error.SetErrorString ("feof");
542 else if (::ferror (m_stream))
543 error.SetErrorString ("ferror");
547 num_bytes = bytes_written;
553 error.SetErrorString("invalid file handle");
560 File::Read (void *buf, size_t &num_bytes, off_t &offset)
563 int fd = GetDescriptor();
564 if (fd != kInvalidDescriptor)
566 ssize_t bytes_read = -1;
569 bytes_read = ::pread (fd, buf, num_bytes, offset);
570 } while (bytes_read < 0 && errno == EINTR);
575 error.SetErrorToErrno();
579 offset += bytes_read;
580 num_bytes = bytes_read;
586 error.SetErrorString("invalid file handle");
592 File::Read (size_t &num_bytes, off_t &offset, bool null_terminate, DataBufferSP &data_buffer_sp)
598 int fd = GetDescriptor();
599 if (fd != kInvalidDescriptor)
601 struct stat file_stats;
602 if (::fstat (fd, &file_stats) == 0)
604 if (file_stats.st_size > offset)
606 const size_t bytes_left = file_stats.st_size - offset;
607 if (num_bytes > bytes_left)
608 num_bytes = bytes_left;
610 std::unique_ptr<DataBufferHeap> data_heap_ap;
611 data_heap_ap.reset(new DataBufferHeap(num_bytes + (null_terminate ? 1 : 0), '\0'));
613 if (data_heap_ap.get())
615 error = Read (data_heap_ap->GetBytes(), num_bytes, offset);
618 // Make sure we read exactly what we asked for and if we got
619 // less, adjust the array
620 if (num_bytes < data_heap_ap->GetByteSize())
621 data_heap_ap->SetByteSize(num_bytes);
622 data_buffer_sp.reset(data_heap_ap.release());
628 error.SetErrorString("file is empty");
631 error.SetErrorToErrno();
634 error.SetErrorString("invalid file handle");
637 error.SetErrorString("invalid file handle");
640 data_buffer_sp.reset();
645 File::Write (const void *buf, size_t &num_bytes, off_t &offset)
648 int fd = GetDescriptor();
649 if (fd != kInvalidDescriptor)
651 ssize_t bytes_written = -1;
654 bytes_written = ::pwrite (m_descriptor, buf, num_bytes, offset);
655 } while (bytes_written < 0 && errno == EINTR);
657 if (bytes_written < 0)
660 error.SetErrorToErrno();
664 offset += bytes_written;
665 num_bytes = bytes_written;
671 error.SetErrorString("invalid file handle");
676 //------------------------------------------------------------------
677 // Print some formatted output to the stream.
678 //------------------------------------------------------------------
680 File::Printf (const char *format, ...)
683 va_start (args, format);
684 size_t result = PrintfVarArg (format, args);
689 //------------------------------------------------------------------
690 // Print some formatted output to the stream.
691 //------------------------------------------------------------------
693 File::PrintfVarArg (const char *format, va_list args)
696 if (DescriptorIsValid())
699 result = vasprintf(&s, format, args);
704 size_t s_len = result;
711 else if (StreamIsValid())
713 result = ::vfprintf (m_stream, format, args);