blob: a12cd3aeeac34550c859a24a6d96cb578bee96d5 [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
13#include <fcntl.h>
Stephen Wilsonec2d9782011-04-08 13:36:44 +000014#include <limits.h>
Greg Clayton80949d42011-02-09 21:12:40 +000015#include <stdarg.h>
Greg Clayton25708252011-04-01 18:18:34 +000016#include <sys/stat.h>
Greg Clayton60a63ae2011-02-08 17:49:02 +000017
18#include "lldb/Core/Error.h"
Greg Claytonc08c4d32011-02-09 01:16:43 +000019#include "lldb/Host/Config.h"
Greg Claytond35305a2011-02-08 19:54:44 +000020#include "lldb/Host/FileSpec.h"
Greg Clayton60a63ae2011-02-08 17:49:02 +000021
22using namespace lldb;
23using namespace lldb_private;
24
Greg Clayton58928562011-02-09 01:08:52 +000025static const char *
26GetStreamOpenModeFromOptions (uint32_t options)
27{
28 if (options & File::eOpenOptionAppend)
29 {
30 if (options & File::eOpenOptionRead)
31 {
32 if (options & File::eOpenOptionCanCreateNewOnly)
33 return "a+x";
34 else
35 return "a+";
36 }
37 else if (options & File::eOpenOptionWrite)
38 {
39 if (options & File::eOpenOptionCanCreateNewOnly)
40 return "ax";
41 else
42 return "a";
43 }
44 }
45 else if (options & File::eOpenOptionRead && options & File::eOpenOptionWrite)
46 {
47 if (options & File::eOpenOptionCanCreate)
48 {
49 if (options & File::eOpenOptionCanCreateNewOnly)
50 return "w+x";
51 else
52 return "w+";
53 }
54 else
55 return "r+";
56 }
57 else if (options & File::eOpenOptionRead)
58 {
59 return "r";
60 }
61 else if (options & File::eOpenOptionWrite)
62 {
63 return "w";
64 }
65 return NULL;
66}
67
68int File::kInvalidDescriptor = -1;
69FILE * File::kInvalidStream = NULL;
70
Greg Clayton60a63ae2011-02-08 17:49:02 +000071File::File(const char *path, uint32_t options, uint32_t permissions) :
Greg Clayton58928562011-02-09 01:08:52 +000072 m_descriptor (kInvalidDescriptor),
73 m_stream (kInvalidStream),
74 m_options (0),
75 m_owned (false)
Greg Clayton60a63ae2011-02-08 17:49:02 +000076{
77 Open (path, options, permissions);
78}
79
Greg Clayton58928562011-02-09 01:08:52 +000080File::File (const File &rhs) :
81 m_descriptor (kInvalidDescriptor),
82 m_stream (kInvalidStream),
83 m_options (0),
84 m_owned (false)
85{
86 Duplicate (rhs);
87}
88
89
90File &
91File::operator = (const File &rhs)
92{
93 if (this != &rhs)
94 Duplicate (rhs);
95 return *this;
96}
97
Greg Clayton60a63ae2011-02-08 17:49:02 +000098File::~File()
99{
100 Close ();
101}
102
Greg Clayton58928562011-02-09 01:08:52 +0000103
104int
105File::GetDescriptor() const
106{
107 if (DescriptorIsValid())
108 return m_descriptor;
109
110 // Don't open the file descriptor if we don't need to, just get it from the
111 // stream if we have one.
112 if (StreamIsValid())
113 return fileno (m_stream);
114
115 // Invalid descriptor and invalid stream, return invalid descriptor.
116 return kInvalidDescriptor;
117}
118
119void
120File::SetDescriptor (int fd, bool transfer_ownership)
121{
122 if (IsValid())
123 Close();
124 m_descriptor = fd;
125 m_owned = transfer_ownership;
126}
127
128
129FILE *
130File::GetStream ()
131{
132 if (!StreamIsValid())
133 {
134 if (DescriptorIsValid())
135 {
136 const char *mode = GetStreamOpenModeFromOptions (m_options);
137 if (mode)
138 m_stream = ::fdopen (m_descriptor, mode);
139 }
140 }
141 return m_stream;
142}
143
144
145void
146File::SetStream (FILE *fh, bool transfer_ownership)
147{
148 if (IsValid())
149 Close();
150 m_stream = fh;
151 m_owned = transfer_ownership;
152}
153
154Error
155File::Duplicate (const File &rhs)
156{
157 Error error;
158 if (IsValid ())
159 Close();
160
161 if (rhs.DescriptorIsValid())
162 {
163 m_descriptor = ::fcntl(rhs.GetDescriptor(), F_DUPFD);
164 if (!DescriptorIsValid())
165 error.SetErrorToErrno();
166 else
167 {
168 m_options = rhs.m_options;
169 m_owned = true;
170 }
171 }
172 else
173 {
174 error.SetErrorString ("invalid file to duplicate");
175 }
176 return error;
177}
178
Greg Clayton60a63ae2011-02-08 17:49:02 +0000179Error
180File::Open (const char *path, uint32_t options, uint32_t permissions)
181{
182 Error error;
183 if (IsValid())
184 Close ();
185
186 int oflag = 0;
187 if (options & eOpenOptionRead &&
188 options & eOpenOptionWrite )
189 oflag |= O_RDWR;
190 else if (options & eOpenOptionRead)
191 oflag |= O_RDONLY;
192 else if (options & eOpenOptionWrite)
193 oflag |= O_WRONLY;
194
195 if (options & eOpenOptionNonBlocking)
196 oflag |= O_NONBLOCK;
197
198 if (options & eOpenOptionAppend)
199 oflag |= O_APPEND;
Greg Clayton58928562011-02-09 01:08:52 +0000200 else
201 oflag |= O_TRUNC;
Greg Clayton60a63ae2011-02-08 17:49:02 +0000202
203 if (options & eOpenOptionCanCreate)
204 oflag |= O_CREAT;
205
206 if (options & eOpenOptionCanCreateNewOnly)
207 oflag |= O_CREAT | O_EXCL;
208
Greg Clayton60a63ae2011-02-08 17:49:02 +0000209 mode_t mode = 0;
210 if (permissions & ePermissionsUserRead) mode |= S_IRUSR;
211 if (permissions & ePermissionsUserWrite) mode |= S_IWUSR;
212 if (permissions & ePermissionsUserExecute) mode |= S_IXUSR;
213 if (permissions & ePermissionsGroupRead) mode |= S_IRGRP;
214 if (permissions & ePermissionsGroupWrite) mode |= S_IWGRP;
215 if (permissions & ePermissionsGroupExecute) mode |= S_IXGRP;
216 if (permissions & ePermissionsWorldRead) mode |= S_IROTH;
217 if (permissions & ePermissionsWorldWrite) mode |= S_IWOTH;
218 if (permissions & ePermissionsWorldExecute) mode |= S_IXOTH;
219
Greg Clayton58928562011-02-09 01:08:52 +0000220 m_descriptor = ::open(path, oflag, mode);
221 if (!DescriptorIsValid())
Greg Clayton60a63ae2011-02-08 17:49:02 +0000222 error.SetErrorToErrno();
Greg Clayton58928562011-02-09 01:08:52 +0000223 else
224 m_owned = true;
Greg Clayton60a63ae2011-02-08 17:49:02 +0000225
226 return error;
227}
228
229Error
230File::Close ()
231{
232 Error error;
233 if (IsValid ())
234 {
Greg Clayton58928562011-02-09 01:08:52 +0000235 if (m_owned)
236 {
237 if (StreamIsValid())
238 {
239 if (::fclose (m_stream) == EOF)
240 error.SetErrorToErrno();
241 }
242
243 if (DescriptorIsValid())
244 {
245 if (::close (m_descriptor) != 0)
246 error.SetErrorToErrno();
247 }
248 }
249 m_descriptor = kInvalidDescriptor;
250 m_stream = kInvalidStream;
251 m_options = 0;
252 m_owned = false;
Greg Clayton60a63ae2011-02-08 17:49:02 +0000253 }
254 return error;
255}
Greg Clayton882ef052011-02-08 19:10:53 +0000256
257
258Error
259File::GetFileSpec (FileSpec &file_spec) const
260{
261 Error error;
Greg Claytonc08c4d32011-02-09 01:16:43 +0000262#ifdef LLDB_CONFIG_FCNTL_GETPATH_SUPPORTED
Greg Clayton882ef052011-02-08 19:10:53 +0000263 if (IsValid ())
264 {
265 char path[PATH_MAX];
Greg Clayton58928562011-02-09 01:08:52 +0000266 if (::fcntl(GetDescriptor(), F_GETPATH, path) == -1)
Greg Clayton882ef052011-02-08 19:10:53 +0000267 error.SetErrorToErrno();
268 else
269 file_spec.SetFile (path, false);
270 }
271 else
Greg Claytonc08c4d32011-02-09 01:16:43 +0000272 {
Greg Clayton882ef052011-02-08 19:10:53 +0000273 error.SetErrorString("invalid file handle");
Greg Claytonc08c4d32011-02-09 01:16:43 +0000274 }
Greg Clayton419144b2011-02-09 07:19:18 +0000275#elif defined(__linux__)
276 char proc[64];
277 char path[PATH_MAX];
278 if (::snprintf(proc, sizeof(proc), "/proc/self/fd/%d", GetDescriptor()) < 0)
Greg Clayton9c236732011-10-26 00:56:27 +0000279 error.SetErrorString ("cannot resolve file descriptor");
Greg Clayton419144b2011-02-09 07:19:18 +0000280 else
281 {
282 ssize_t len;
283 if ((len = ::readlink(proc, path, sizeof(path) - 1)) == -1)
284 error.SetErrorToErrno();
285 else
286 {
287 path[len] = '\0';
288 file_spec.SetFile (path, false);
289 }
290 }
Greg Claytonc08c4d32011-02-09 01:16:43 +0000291#else
Greg Clayton419144b2011-02-09 07:19:18 +0000292 error.SetErrorString ("File::GetFileSpec is not supported on this platform");
Greg Claytonc08c4d32011-02-09 01:16:43 +0000293#endif
Greg Clayton882ef052011-02-08 19:10:53 +0000294
295 if (error.Fail())
296 file_spec.Clear();
297 return error;
298}
299
300Error
301File::SeekFromStart (off_t& offset)
302{
303 Error error;
Greg Clayton58928562011-02-09 01:08:52 +0000304 if (DescriptorIsValid())
Greg Clayton882ef052011-02-08 19:10:53 +0000305 {
Greg Clayton58928562011-02-09 01:08:52 +0000306 offset = ::lseek (m_descriptor, offset, SEEK_SET);
Greg Clayton882ef052011-02-08 19:10:53 +0000307
308 if (offset == -1)
309 error.SetErrorToErrno();
310 }
311 else
312 {
313 error.SetErrorString("invalid file handle");
314 }
315 return error;
316}
317
318Error
319File::SeekFromCurrent (off_t& offset)
320{
321 Error error;
Greg Clayton58928562011-02-09 01:08:52 +0000322 if (DescriptorIsValid())
Greg Clayton882ef052011-02-08 19:10:53 +0000323 {
Greg Clayton58928562011-02-09 01:08:52 +0000324 offset = ::lseek (m_descriptor, offset, SEEK_CUR);
Greg Clayton882ef052011-02-08 19:10:53 +0000325
326 if (offset == -1)
327 error.SetErrorToErrno();
328 }
329 else
330 {
331 error.SetErrorString("invalid file handle");
332 }
333 return error;
334}
335
336Error
337File::SeekFromEnd (off_t& offset)
338{
339 Error error;
Greg Clayton58928562011-02-09 01:08:52 +0000340 if (DescriptorIsValid())
Greg Clayton882ef052011-02-08 19:10:53 +0000341 {
Greg Clayton58928562011-02-09 01:08:52 +0000342 offset = ::lseek (m_descriptor, offset, SEEK_CUR);
Greg Clayton882ef052011-02-08 19:10:53 +0000343
344 if (offset == -1)
345 error.SetErrorToErrno();
346 }
347 else
348 {
349 error.SetErrorString("invalid file handle");
350 }
351 return error;
352}
353
354Error
Greg Clayton58928562011-02-09 01:08:52 +0000355File::Flush ()
356{
357 Error error;
358 if (StreamIsValid())
359 {
360 if (::fflush (m_stream) == EOF)
361 error.SetErrorToErrno();
362 }
363 else if (!DescriptorIsValid())
364 {
365 error.SetErrorString("invalid file handle");
366 }
367 return error;
368}
369
370
371Error
Greg Clayton882ef052011-02-08 19:10:53 +0000372File::Sync ()
373{
374 Error error;
Greg Clayton58928562011-02-09 01:08:52 +0000375 if (DescriptorIsValid())
Greg Clayton882ef052011-02-08 19:10:53 +0000376 {
Greg Clayton58928562011-02-09 01:08:52 +0000377 if (::fsync (m_descriptor) == -1)
Greg Clayton882ef052011-02-08 19:10:53 +0000378 error.SetErrorToErrno();
379 }
380 else
381 {
382 error.SetErrorString("invalid file handle");
383 }
384 return error;
385}
Greg Claytond35305a2011-02-08 19:54:44 +0000386
Greg Clayton60a63ae2011-02-08 17:49:02 +0000387Error
388File::Read (void *buf, size_t &num_bytes)
389{
390 Error error;
Greg Clayton58928562011-02-09 01:08:52 +0000391 if (DescriptorIsValid())
Greg Clayton60a63ae2011-02-08 17:49:02 +0000392 {
Greg Clayton58928562011-02-09 01:08:52 +0000393 ssize_t bytes_read = ::read (m_descriptor, buf, num_bytes);
Greg Clayton60a63ae2011-02-08 17:49:02 +0000394 if (bytes_read == -1)
395 {
396 error.SetErrorToErrno();
397 num_bytes = 0;
398 }
399 else
400 num_bytes = bytes_read;
401 }
Greg Clayton58928562011-02-09 01:08:52 +0000402 else if (StreamIsValid())
403 {
404 size_t bytes_read = ::fread (buf, 1, num_bytes, m_stream);
405 if (bytes_read == 0)
406 {
407 if (::feof(m_stream))
408 error.SetErrorString ("feof");
409 else if (::ferror (m_stream))
410 error.SetErrorString ("ferror");
411 num_bytes = 0;
412 }
413 else
414 num_bytes = bytes_read;
415 }
Greg Clayton60a63ae2011-02-08 17:49:02 +0000416 else
417 {
418 num_bytes = 0;
419 error.SetErrorString("invalid file handle");
420 }
421 return error;
422}
423
424Error
425File::Write (const void *buf, size_t &num_bytes)
426{
427 Error error;
Greg Clayton58928562011-02-09 01:08:52 +0000428 if (DescriptorIsValid())
Greg Clayton60a63ae2011-02-08 17:49:02 +0000429 {
Greg Clayton58928562011-02-09 01:08:52 +0000430 ssize_t bytes_written = ::write (m_descriptor, buf, num_bytes);
Greg Clayton60a63ae2011-02-08 17:49:02 +0000431 if (bytes_written == -1)
432 {
433 error.SetErrorToErrno();
434 num_bytes = 0;
435 }
436 else
437 num_bytes = bytes_written;
438 }
Greg Clayton58928562011-02-09 01:08:52 +0000439 else if (StreamIsValid())
440 {
441 size_t bytes_written = ::fwrite (buf, 1, num_bytes, m_stream);
442 if (bytes_written == 0)
443 {
444 if (::feof(m_stream))
445 error.SetErrorString ("feof");
446 else if (::ferror (m_stream))
447 error.SetErrorString ("ferror");
448 num_bytes = 0;
449 }
450 else
451 num_bytes = bytes_written;
452
453 }
Greg Clayton60a63ae2011-02-08 17:49:02 +0000454 else
455 {
456 num_bytes = 0;
457 error.SetErrorString("invalid file handle");
458 }
459 return error;
460}
461
Greg Claytond35305a2011-02-08 19:54:44 +0000462
463Error
464File::Read (void *buf, size_t &num_bytes, off_t &offset)
465{
466 Error error;
Greg Clayton58928562011-02-09 01:08:52 +0000467 int fd = GetDescriptor();
468 if (fd != kInvalidDescriptor)
Greg Claytond35305a2011-02-08 19:54:44 +0000469 {
Greg Clayton58928562011-02-09 01:08:52 +0000470 ssize_t bytes_read = ::pread (fd, buf, num_bytes, offset);
Greg Claytond35305a2011-02-08 19:54:44 +0000471 if (bytes_read < 0)
472 {
473 num_bytes = 0;
474 error.SetErrorToErrno();
475 }
476 else
477 {
478 offset += bytes_read;
479 num_bytes = bytes_read;
480 }
481 }
482 else
483 {
484 num_bytes = 0;
485 error.SetErrorString("invalid file handle");
486 }
487 return error;
488}
489
490Error
491File::Write (const void *buf, size_t &num_bytes, off_t &offset)
492{
493 Error error;
Greg Clayton58928562011-02-09 01:08:52 +0000494 int fd = GetDescriptor();
495 if (fd != kInvalidDescriptor)
Greg Claytond35305a2011-02-08 19:54:44 +0000496 {
Greg Clayton58928562011-02-09 01:08:52 +0000497 ssize_t bytes_written = ::pwrite (m_descriptor, buf, num_bytes, offset);
Greg Claytond35305a2011-02-08 19:54:44 +0000498 if (bytes_written < 0)
499 {
500 num_bytes = 0;
501 error.SetErrorToErrno();
502 }
503 else
504 {
505 offset += bytes_written;
506 num_bytes = bytes_written;
507 }
508 }
509 else
510 {
511 num_bytes = 0;
512 error.SetErrorString("invalid file handle");
513 }
514 return error;
515}
516
Greg Clayton58928562011-02-09 01:08:52 +0000517//------------------------------------------------------------------
518// Print some formatted output to the stream.
519//------------------------------------------------------------------
520int
521File::Printf (const char *format, ...)
522{
523 va_list args;
524 va_start (args, format);
525 int result = PrintfVarArg (format, args);
526 va_end (args);
527 return result;
528}
Greg Claytond35305a2011-02-08 19:54:44 +0000529
Greg Clayton58928562011-02-09 01:08:52 +0000530//------------------------------------------------------------------
531// Print some formatted output to the stream.
532//------------------------------------------------------------------
533int
534File::PrintfVarArg (const char *format, va_list args)
535{
536 int result = 0;
537 if (DescriptorIsValid())
538 {
539 char *s = NULL;
540 result = vasprintf(&s, format, args);
541 if (s != NULL)
542 {
543 if (result > 0)
544 {
545 size_t s_len = result;
546 Write (s, s_len);
547 result = s_len;
548 }
549 free (s);
550 }
551 }
552 else if (StreamIsValid())
553 {
554 result = ::vfprintf (m_stream, format, args);
555 }
556 return result;
557}