blob: ae0bf887974012faa6c1f9968617c73ebc35cc66 [file] [log] [blame]
Greg Clayton60a63ae2011-02-08 17:49:02 +00001//===-- 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
Greg Clayton2f28ece2012-01-04 22:56:43 +000013#include <errno.h>
Greg Clayton60a63ae2011-02-08 17:49:02 +000014#include <fcntl.h>
Stephen Wilsonec2d9782011-04-08 13:36:44 +000015#include <limits.h>
Greg Clayton80949d42011-02-09 21:12:40 +000016#include <stdarg.h>
Greg Clayton25708252011-04-01 18:18:34 +000017#include <sys/stat.h>
Greg Clayton60a63ae2011-02-08 17:49:02 +000018
Greg Clayton2f28ece2012-01-04 22:56:43 +000019#include "lldb/Core/DataBufferHeap.h"
Greg Clayton60a63ae2011-02-08 17:49:02 +000020#include "lldb/Core/Error.h"
Greg Claytonc08c4d32011-02-09 01:16:43 +000021#include "lldb/Host/Config.h"
Greg Claytond35305a2011-02-08 19:54:44 +000022#include "lldb/Host/FileSpec.h"
Greg Clayton60a63ae2011-02-08 17:49:02 +000023
24using namespace lldb;
25using namespace lldb_private;
26
Greg Clayton58928562011-02-09 01:08:52 +000027static const char *
28GetStreamOpenModeFromOptions (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
70int File::kInvalidDescriptor = -1;
71FILE * File::kInvalidStream = NULL;
72
Greg Clayton60a63ae2011-02-08 17:49:02 +000073File::File(const char *path, uint32_t options, uint32_t permissions) :
Greg Clayton58928562011-02-09 01:08:52 +000074 m_descriptor (kInvalidDescriptor),
75 m_stream (kInvalidStream),
76 m_options (0),
77 m_owned (false)
Greg Clayton60a63ae2011-02-08 17:49:02 +000078{
79 Open (path, options, permissions);
80}
81
Greg Clayton58928562011-02-09 01:08:52 +000082File::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
92File &
93File::operator = (const File &rhs)
94{
95 if (this != &rhs)
96 Duplicate (rhs);
97 return *this;
98}
99
Greg Clayton60a63ae2011-02-08 17:49:02 +0000100File::~File()
101{
102 Close ();
103}
104
Greg Clayton58928562011-02-09 01:08:52 +0000105
106int
107File::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
121void
122File::SetDescriptor (int fd, bool transfer_ownership)
123{
124 if (IsValid())
125 Close();
126 m_descriptor = fd;
127 m_owned = transfer_ownership;
128}
129
130
131FILE *
132File::GetStream ()
133{
134 if (!StreamIsValid())
135 {
136 if (DescriptorIsValid())
137 {
138 const char *mode = GetStreamOpenModeFromOptions (m_options);
139 if (mode)
Greg Clayton2f28ece2012-01-04 22:56:43 +0000140 {
141 do
142 {
143 m_stream = ::fdopen (m_descriptor, mode);
144 } while (m_stream == NULL && errno == EINTR);
145 }
Greg Clayton58928562011-02-09 01:08:52 +0000146 }
147 }
148 return m_stream;
149}
150
151
152void
153File::SetStream (FILE *fh, bool transfer_ownership)
154{
155 if (IsValid())
156 Close();
157 m_stream = fh;
158 m_owned = transfer_ownership;
159}
160
161Error
162File::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
Greg Clayton60a63ae2011-02-08 17:49:02 +0000186Error
187File::Open (const char *path, uint32_t options, uint32_t permissions)
188{
189 Error error;
190 if (IsValid())
191 Close ();
192
193 int oflag = 0;
Greg Clayton2f28ece2012-01-04 22:56:43 +0000194 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 {
Greg Clayton60a63ae2011-02-08 17:49:02 +0000217 oflag |= O_RDONLY;
Greg Clayton2f28ece2012-01-04 22:56:43 +0000218 }
Greg Clayton60a63ae2011-02-08 17:49:02 +0000219
220 if (options & eOpenOptionNonBlocking)
221 oflag |= O_NONBLOCK;
222
Greg Clayton60a63ae2011-02-08 17:49:02 +0000223 mode_t mode = 0;
Greg Clayton2f28ece2012-01-04 22:56:43 +0000224 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 }
Greg Clayton60a63ae2011-02-08 17:49:02 +0000236
Greg Clayton2f28ece2012-01-04 22:56:43 +0000237 do
238 {
239 m_descriptor = ::open(path, oflag, mode);
240 } while (m_descriptor < 0 && errno == EINTR);
241
Greg Clayton58928562011-02-09 01:08:52 +0000242 if (!DescriptorIsValid())
Greg Clayton60a63ae2011-02-08 17:49:02 +0000243 error.SetErrorToErrno();
Greg Clayton58928562011-02-09 01:08:52 +0000244 else
245 m_owned = true;
Greg Clayton60a63ae2011-02-08 17:49:02 +0000246
247 return error;
248}
249
250Error
251File::Close ()
252{
253 Error error;
254 if (IsValid ())
255 {
Greg Clayton58928562011-02-09 01:08:52 +0000256 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;
Greg Clayton60a63ae2011-02-08 17:49:02 +0000274 }
275 return error;
276}
Greg Clayton882ef052011-02-08 19:10:53 +0000277
278
279Error
280File::GetFileSpec (FileSpec &file_spec) const
281{
282 Error error;
Greg Claytonc08c4d32011-02-09 01:16:43 +0000283#ifdef LLDB_CONFIG_FCNTL_GETPATH_SUPPORTED
Greg Clayton882ef052011-02-08 19:10:53 +0000284 if (IsValid ())
285 {
286 char path[PATH_MAX];
Greg Clayton58928562011-02-09 01:08:52 +0000287 if (::fcntl(GetDescriptor(), F_GETPATH, path) == -1)
Greg Clayton882ef052011-02-08 19:10:53 +0000288 error.SetErrorToErrno();
289 else
290 file_spec.SetFile (path, false);
291 }
292 else
Greg Claytonc08c4d32011-02-09 01:16:43 +0000293 {
Greg Clayton882ef052011-02-08 19:10:53 +0000294 error.SetErrorString("invalid file handle");
Greg Claytonc08c4d32011-02-09 01:16:43 +0000295 }
Greg Clayton419144b2011-02-09 07:19:18 +0000296#elif defined(__linux__)
297 char proc[64];
298 char path[PATH_MAX];
299 if (::snprintf(proc, sizeof(proc), "/proc/self/fd/%d", GetDescriptor()) < 0)
Greg Clayton9c236732011-10-26 00:56:27 +0000300 error.SetErrorString ("cannot resolve file descriptor");
Greg Clayton419144b2011-02-09 07:19:18 +0000301 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 }
Greg Claytonc08c4d32011-02-09 01:16:43 +0000312#else
Greg Clayton419144b2011-02-09 07:19:18 +0000313 error.SetErrorString ("File::GetFileSpec is not supported on this platform");
Greg Claytonc08c4d32011-02-09 01:16:43 +0000314#endif
Greg Clayton882ef052011-02-08 19:10:53 +0000315
316 if (error.Fail())
317 file_spec.Clear();
318 return error;
319}
320
321Error
322File::SeekFromStart (off_t& offset)
323{
324 Error error;
Greg Clayton58928562011-02-09 01:08:52 +0000325 if (DescriptorIsValid())
Greg Clayton882ef052011-02-08 19:10:53 +0000326 {
Greg Clayton58928562011-02-09 01:08:52 +0000327 offset = ::lseek (m_descriptor, offset, SEEK_SET);
Greg Clayton882ef052011-02-08 19:10:53 +0000328
329 if (offset == -1)
330 error.SetErrorToErrno();
331 }
332 else
333 {
334 error.SetErrorString("invalid file handle");
335 }
336 return error;
337}
338
339Error
340File::SeekFromCurrent (off_t& offset)
341{
342 Error error;
Greg Clayton58928562011-02-09 01:08:52 +0000343 if (DescriptorIsValid())
Greg Clayton882ef052011-02-08 19:10:53 +0000344 {
Greg Clayton58928562011-02-09 01:08:52 +0000345 offset = ::lseek (m_descriptor, offset, SEEK_CUR);
Greg Clayton882ef052011-02-08 19:10:53 +0000346
347 if (offset == -1)
348 error.SetErrorToErrno();
349 }
350 else
351 {
352 error.SetErrorString("invalid file handle");
353 }
354 return error;
355}
356
357Error
358File::SeekFromEnd (off_t& offset)
359{
360 Error error;
Greg Clayton58928562011-02-09 01:08:52 +0000361 if (DescriptorIsValid())
Greg Clayton882ef052011-02-08 19:10:53 +0000362 {
Greg Clayton42dc5a52012-10-30 17:04:45 +0000363 offset = ::lseek (m_descriptor, offset, SEEK_END);
Greg Clayton882ef052011-02-08 19:10:53 +0000364
365 if (offset == -1)
366 error.SetErrorToErrno();
367 }
368 else
369 {
370 error.SetErrorString("invalid file handle");
371 }
372 return error;
373}
374
375Error
Greg Clayton58928562011-02-09 01:08:52 +0000376File::Flush ()
377{
378 Error error;
379 if (StreamIsValid())
380 {
Greg Clayton2f28ece2012-01-04 22:56:43 +0000381 int err = 0;
382 do
383 {
384 err = ::fflush (m_stream);
385 } while (err == EOF && errno == EINTR);
386
387 if (err == EOF)
Greg Clayton58928562011-02-09 01:08:52 +0000388 error.SetErrorToErrno();
389 }
390 else if (!DescriptorIsValid())
391 {
392 error.SetErrorString("invalid file handle");
393 }
394 return error;
395}
396
397
398Error
Greg Clayton882ef052011-02-08 19:10:53 +0000399File::Sync ()
400{
401 Error error;
Greg Clayton58928562011-02-09 01:08:52 +0000402 if (DescriptorIsValid())
Greg Clayton882ef052011-02-08 19:10:53 +0000403 {
Greg Clayton2f28ece2012-01-04 22:56:43 +0000404 int err = 0;
405 do
406 {
407 err = ::fsync (m_descriptor);
408 } while (err == -1 && errno == EINTR);
409
410 if (err == -1)
Greg Clayton882ef052011-02-08 19:10:53 +0000411 error.SetErrorToErrno();
412 }
413 else
414 {
415 error.SetErrorString("invalid file handle");
416 }
417 return error;
418}
Greg Claytond35305a2011-02-08 19:54:44 +0000419
Greg Clayton60a63ae2011-02-08 17:49:02 +0000420Error
421File::Read (void *buf, size_t &num_bytes)
422{
423 Error error;
Greg Clayton2f28ece2012-01-04 22:56:43 +0000424 ssize_t bytes_read = -1;
Greg Clayton58928562011-02-09 01:08:52 +0000425 if (DescriptorIsValid())
Greg Clayton60a63ae2011-02-08 17:49:02 +0000426 {
Greg Clayton2f28ece2012-01-04 22:56:43 +0000427 do
428 {
429 bytes_read = ::read (m_descriptor, buf, num_bytes);
430 } while (bytes_read < 0 && errno == EINTR);
431
Greg Clayton60a63ae2011-02-08 17:49:02 +0000432 if (bytes_read == -1)
433 {
434 error.SetErrorToErrno();
435 num_bytes = 0;
436 }
437 else
438 num_bytes = bytes_read;
439 }
Greg Clayton58928562011-02-09 01:08:52 +0000440 else if (StreamIsValid())
441 {
Greg Clayton2f28ece2012-01-04 22:56:43 +0000442 bytes_read = ::fread (buf, 1, num_bytes, m_stream);
443
Greg Clayton58928562011-02-09 01:08:52 +0000444 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 }
Greg Clayton60a63ae2011-02-08 17:49:02 +0000455 else
456 {
457 num_bytes = 0;
458 error.SetErrorString("invalid file handle");
459 }
460 return error;
461}
462
463Error
464File::Write (const void *buf, size_t &num_bytes)
465{
466 Error error;
Greg Clayton2f28ece2012-01-04 22:56:43 +0000467 ssize_t bytes_written = -1;
Greg Clayton58928562011-02-09 01:08:52 +0000468 if (DescriptorIsValid())
Greg Clayton60a63ae2011-02-08 17:49:02 +0000469 {
Greg Clayton2f28ece2012-01-04 22:56:43 +0000470 do
471 {
472 bytes_written = ::write (m_descriptor, buf, num_bytes);
473 } while (bytes_written < 0 && errno == EINTR);
474
Greg Clayton60a63ae2011-02-08 17:49:02 +0000475 if (bytes_written == -1)
476 {
477 error.SetErrorToErrno();
478 num_bytes = 0;
479 }
480 else
481 num_bytes = bytes_written;
482 }
Greg Clayton58928562011-02-09 01:08:52 +0000483 else if (StreamIsValid())
484 {
Greg Clayton2f28ece2012-01-04 22:56:43 +0000485 bytes_written = ::fwrite (buf, 1, num_bytes, m_stream);
486
Greg Clayton58928562011-02-09 01:08:52 +0000487 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 }
Greg Clayton60a63ae2011-02-08 17:49:02 +0000499 else
500 {
501 num_bytes = 0;
502 error.SetErrorString("invalid file handle");
503 }
504 return error;
505}
506
Greg Claytond35305a2011-02-08 19:54:44 +0000507
508Error
509File::Read (void *buf, size_t &num_bytes, off_t &offset)
510{
511 Error error;
Greg Clayton58928562011-02-09 01:08:52 +0000512 int fd = GetDescriptor();
513 if (fd != kInvalidDescriptor)
Greg Claytond35305a2011-02-08 19:54:44 +0000514 {
Greg Clayton2f28ece2012-01-04 22:56:43 +0000515 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
Greg Claytond35305a2011-02-08 19:54:44 +0000521 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
540Error
Greg Claytonfc04d242012-08-30 18:15:10 +0000541File::Read (size_t &num_bytes, off_t &offset, bool null_terminate, DataBufferSP &data_buffer_sp)
Greg Clayton2f28ece2012-01-04 22:56:43 +0000542{
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;
Greg Claytonfc04d242012-08-30 18:15:10 +0000560 data_heap_ap.reset(new DataBufferHeap(num_bytes + (null_terminate ? 1 : 0), '\0'));
Greg Clayton2f28ece2012-01-04 22:56:43 +0000561
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
593Error
Greg Claytond35305a2011-02-08 19:54:44 +0000594File::Write (const void *buf, size_t &num_bytes, off_t &offset)
595{
596 Error error;
Greg Clayton58928562011-02-09 01:08:52 +0000597 int fd = GetDescriptor();
598 if (fd != kInvalidDescriptor)
Greg Claytond35305a2011-02-08 19:54:44 +0000599 {
Greg Clayton2f28ece2012-01-04 22:56:43 +0000600 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
Greg Claytond35305a2011-02-08 19:54:44 +0000606 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
Greg Clayton58928562011-02-09 01:08:52 +0000625//------------------------------------------------------------------
626// Print some formatted output to the stream.
627//------------------------------------------------------------------
Greg Clayton36da2aa2013-01-25 18:06:21 +0000628size_t
Greg Clayton58928562011-02-09 01:08:52 +0000629File::Printf (const char *format, ...)
630{
631 va_list args;
632 va_start (args, format);
Greg Clayton36da2aa2013-01-25 18:06:21 +0000633 size_t result = PrintfVarArg (format, args);
Greg Clayton58928562011-02-09 01:08:52 +0000634 va_end (args);
635 return result;
636}
Greg Claytond35305a2011-02-08 19:54:44 +0000637
Greg Clayton58928562011-02-09 01:08:52 +0000638//------------------------------------------------------------------
639// Print some formatted output to the stream.
640//------------------------------------------------------------------
Greg Clayton36da2aa2013-01-25 18:06:21 +0000641size_t
Greg Clayton58928562011-02-09 01:08:52 +0000642File::PrintfVarArg (const char *format, va_list args)
643{
Greg Clayton36da2aa2013-01-25 18:06:21 +0000644 size_t result = 0;
Greg Clayton58928562011-02-09 01:08:52 +0000645 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}