• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 *
GetStreamOpenModeFromOptions(uint32_t options)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 
File(const char * path,uint32_t options,uint32_t permissions)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 
File(const File & rhs)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 &
operator =(const File & rhs)93 File::operator = (const File &rhs)
94 {
95     if (this != &rhs)
96         Duplicate (rhs);
97     return *this;
98 }
99 
~File()100 File::~File()
101 {
102     Close ();
103 }
104 
105 
106 int
GetDescriptor() const107 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
SetDescriptor(int fd,bool transfer_ownership)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 *
GetStream()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
SetStream(FILE * fh,bool transfer_ownership)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
Duplicate(const File & rhs)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
Open(const char * path,uint32_t options,uint32_t permissions)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
Close()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
GetFileSpec(FileSpec & file_spec) const280 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 off_t
SeekFromStart(off_t offset,Error * error_ptr)322 File::SeekFromStart (off_t offset, Error *error_ptr)
323 {
324     off_t result = 0;
325     if (DescriptorIsValid())
326     {
327         result = ::lseek (m_descriptor, offset, SEEK_SET);
328 
329         if (error_ptr)
330         {
331             if (result == -1)
332                 error_ptr->SetErrorToErrno();
333             else
334                 error_ptr->Clear();
335         }
336     }
337     else if (StreamIsValid ())
338     {
339         result = ::fseek(m_stream, offset, SEEK_SET);
340 
341         if (error_ptr)
342         {
343             if (result == -1)
344                 error_ptr->SetErrorToErrno();
345             else
346                 error_ptr->Clear();
347         }
348     }
349     else if (error_ptr)
350     {
351         error_ptr->SetErrorString("invalid file handle");
352     }
353     return result;
354 }
355 
356 off_t
SeekFromCurrent(off_t offset,Error * error_ptr)357 File::SeekFromCurrent (off_t offset,  Error *error_ptr)
358 {
359     off_t result = -1;
360     if (DescriptorIsValid())
361     {
362         result = ::lseek (m_descriptor, offset, SEEK_CUR);
363 
364         if (error_ptr)
365         {
366             if (result == -1)
367                 error_ptr->SetErrorToErrno();
368             else
369                 error_ptr->Clear();
370         }
371     }
372     else if (StreamIsValid ())
373     {
374         result = ::fseek(m_stream, offset, SEEK_CUR);
375 
376         if (error_ptr)
377         {
378             if (result == -1)
379                 error_ptr->SetErrorToErrno();
380             else
381                 error_ptr->Clear();
382         }
383     }
384     else if (error_ptr)
385     {
386         error_ptr->SetErrorString("invalid file handle");
387     }
388     return result;
389 }
390 
391 off_t
SeekFromEnd(off_t offset,Error * error_ptr)392 File::SeekFromEnd (off_t offset, Error *error_ptr)
393 {
394     off_t result = -1;
395     if (DescriptorIsValid())
396     {
397         result = ::lseek (m_descriptor, offset, SEEK_END);
398 
399         if (error_ptr)
400         {
401             if (result == -1)
402                 error_ptr->SetErrorToErrno();
403             else
404                 error_ptr->Clear();
405         }
406     }
407     else if (StreamIsValid ())
408     {
409         result = ::fseek(m_stream, offset, SEEK_END);
410 
411         if (error_ptr)
412         {
413             if (result == -1)
414                 error_ptr->SetErrorToErrno();
415             else
416                 error_ptr->Clear();
417         }
418     }
419     else if (error_ptr)
420     {
421         error_ptr->SetErrorString("invalid file handle");
422     }
423     return result;
424 }
425 
426 Error
Flush()427 File::Flush ()
428 {
429     Error error;
430     if (StreamIsValid())
431     {
432         int err = 0;
433         do
434         {
435             err = ::fflush (m_stream);
436         } while (err == EOF && errno == EINTR);
437 
438         if (err == EOF)
439             error.SetErrorToErrno();
440     }
441     else if (!DescriptorIsValid())
442     {
443         error.SetErrorString("invalid file handle");
444     }
445     return error;
446 }
447 
448 
449 Error
Sync()450 File::Sync ()
451 {
452     Error error;
453     if (DescriptorIsValid())
454     {
455         int err = 0;
456         do
457         {
458             err = ::fsync (m_descriptor);
459         } while (err == -1 && errno == EINTR);
460 
461         if (err == -1)
462             error.SetErrorToErrno();
463     }
464     else
465     {
466         error.SetErrorString("invalid file handle");
467     }
468     return error;
469 }
470 
471 Error
Read(void * buf,size_t & num_bytes)472 File::Read (void *buf, size_t &num_bytes)
473 {
474     Error error;
475     ssize_t bytes_read = -1;
476     if (DescriptorIsValid())
477     {
478         do
479         {
480             bytes_read = ::read (m_descriptor, buf, num_bytes);
481         } while (bytes_read < 0 && errno == EINTR);
482 
483         if (bytes_read == -1)
484         {
485             error.SetErrorToErrno();
486             num_bytes = 0;
487         }
488         else
489             num_bytes = bytes_read;
490     }
491     else if (StreamIsValid())
492     {
493         bytes_read = ::fread (buf, 1, num_bytes, m_stream);
494 
495         if (bytes_read == 0)
496         {
497             if (::feof(m_stream))
498                 error.SetErrorString ("feof");
499             else if (::ferror (m_stream))
500                 error.SetErrorString ("ferror");
501             num_bytes = 0;
502         }
503         else
504             num_bytes = bytes_read;
505     }
506     else
507     {
508         num_bytes = 0;
509         error.SetErrorString("invalid file handle");
510     }
511     return error;
512 }
513 
514 Error
Write(const void * buf,size_t & num_bytes)515 File::Write (const void *buf, size_t &num_bytes)
516 {
517     Error error;
518     ssize_t bytes_written = -1;
519     if (DescriptorIsValid())
520     {
521         do
522         {
523             bytes_written = ::write (m_descriptor, buf, num_bytes);
524         } while (bytes_written < 0 && errno == EINTR);
525 
526         if (bytes_written == -1)
527         {
528             error.SetErrorToErrno();
529             num_bytes = 0;
530         }
531         else
532             num_bytes = bytes_written;
533     }
534     else if (StreamIsValid())
535     {
536         bytes_written = ::fwrite (buf, 1, num_bytes, m_stream);
537 
538         if (bytes_written == 0)
539         {
540             if (::feof(m_stream))
541                 error.SetErrorString ("feof");
542             else if (::ferror (m_stream))
543                 error.SetErrorString ("ferror");
544             num_bytes = 0;
545         }
546         else
547             num_bytes = bytes_written;
548 
549     }
550     else
551     {
552         num_bytes = 0;
553         error.SetErrorString("invalid file handle");
554     }
555     return error;
556 }
557 
558 
559 Error
Read(void * buf,size_t & num_bytes,off_t & offset)560 File::Read (void *buf, size_t &num_bytes, off_t &offset)
561 {
562     Error error;
563     int fd = GetDescriptor();
564     if (fd != kInvalidDescriptor)
565     {
566         ssize_t bytes_read = -1;
567         do
568         {
569             bytes_read = ::pread (fd, buf, num_bytes, offset);
570         } while (bytes_read < 0 && errno == EINTR);
571 
572         if (bytes_read < 0)
573         {
574             num_bytes = 0;
575             error.SetErrorToErrno();
576         }
577         else
578         {
579             offset += bytes_read;
580             num_bytes = bytes_read;
581         }
582     }
583     else
584     {
585         num_bytes = 0;
586         error.SetErrorString("invalid file handle");
587     }
588     return error;
589 }
590 
591 Error
Read(size_t & num_bytes,off_t & offset,bool null_terminate,DataBufferSP & data_buffer_sp)592 File::Read (size_t &num_bytes, off_t &offset, bool null_terminate, DataBufferSP &data_buffer_sp)
593 {
594     Error error;
595 
596     if (num_bytes > 0)
597     {
598         int fd = GetDescriptor();
599         if (fd != kInvalidDescriptor)
600         {
601             struct stat file_stats;
602             if (::fstat (fd, &file_stats) == 0)
603             {
604                 if (file_stats.st_size > offset)
605                 {
606                     const size_t bytes_left = file_stats.st_size - offset;
607                     if (num_bytes > bytes_left)
608                         num_bytes = bytes_left;
609 
610                     std::unique_ptr<DataBufferHeap> data_heap_ap;
611                     data_heap_ap.reset(new DataBufferHeap(num_bytes + (null_terminate ? 1 : 0), '\0'));
612 
613                     if (data_heap_ap.get())
614                     {
615                         error = Read (data_heap_ap->GetBytes(), num_bytes, offset);
616                         if (error.Success())
617                         {
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());
623                             return error;
624                         }
625                     }
626                 }
627                 else
628                     error.SetErrorString("file is empty");
629             }
630             else
631                 error.SetErrorToErrno();
632         }
633         else
634             error.SetErrorString("invalid file handle");
635     }
636     else
637         error.SetErrorString("invalid file handle");
638 
639     num_bytes = 0;
640     data_buffer_sp.reset();
641     return error;
642 }
643 
644 Error
Write(const void * buf,size_t & num_bytes,off_t & offset)645 File::Write (const void *buf, size_t &num_bytes, off_t &offset)
646 {
647     Error error;
648     int fd = GetDescriptor();
649     if (fd != kInvalidDescriptor)
650     {
651         ssize_t bytes_written = -1;
652         do
653         {
654             bytes_written = ::pwrite (m_descriptor, buf, num_bytes, offset);
655         } while (bytes_written < 0 && errno == EINTR);
656 
657         if (bytes_written < 0)
658         {
659             num_bytes = 0;
660             error.SetErrorToErrno();
661         }
662         else
663         {
664             offset += bytes_written;
665             num_bytes = bytes_written;
666         }
667     }
668     else
669     {
670         num_bytes = 0;
671         error.SetErrorString("invalid file handle");
672     }
673     return error;
674 }
675 
676 //------------------------------------------------------------------
677 // Print some formatted output to the stream.
678 //------------------------------------------------------------------
679 size_t
Printf(const char * format,...)680 File::Printf (const char *format, ...)
681 {
682     va_list args;
683     va_start (args, format);
684     size_t result = PrintfVarArg (format, args);
685     va_end (args);
686     return result;
687 }
688 
689 //------------------------------------------------------------------
690 // Print some formatted output to the stream.
691 //------------------------------------------------------------------
692 size_t
PrintfVarArg(const char * format,va_list args)693 File::PrintfVarArg (const char *format, va_list args)
694 {
695     size_t result = 0;
696     if (DescriptorIsValid())
697     {
698         char *s = NULL;
699         result = vasprintf(&s, format, args);
700         if (s != NULL)
701         {
702             if (result > 0)
703             {
704                 size_t s_len = result;
705                 Write (s, s_len);
706                 result = s_len;
707             }
708             free (s);
709         }
710     }
711     else if (StreamIsValid())
712     {
713         result = ::vfprintf (m_stream, format, args);
714     }
715     return result;
716 }
717