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