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