blob: e4b7f0542b86335e09447ae653c3f8d78f5ce22b [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>
14
15#include "lldb/Core/Error.h"
Greg Claytonc08c4d32011-02-09 01:16:43 +000016#include "lldb/Host/Config.h"
Greg Claytond35305a2011-02-08 19:54:44 +000017#include "lldb/Host/FileSpec.h"
Greg Clayton60a63ae2011-02-08 17:49:02 +000018
19using namespace lldb;
20using namespace lldb_private;
21
Greg Clayton58928562011-02-09 01:08:52 +000022static const char *
23GetStreamOpenModeFromOptions (uint32_t options)
24{
25 if (options & File::eOpenOptionAppend)
26 {
27 if (options & File::eOpenOptionRead)
28 {
29 if (options & File::eOpenOptionCanCreateNewOnly)
30 return "a+x";
31 else
32 return "a+";
33 }
34 else if (options & File::eOpenOptionWrite)
35 {
36 if (options & File::eOpenOptionCanCreateNewOnly)
37 return "ax";
38 else
39 return "a";
40 }
41 }
42 else if (options & File::eOpenOptionRead && options & File::eOpenOptionWrite)
43 {
44 if (options & File::eOpenOptionCanCreate)
45 {
46 if (options & File::eOpenOptionCanCreateNewOnly)
47 return "w+x";
48 else
49 return "w+";
50 }
51 else
52 return "r+";
53 }
54 else if (options & File::eOpenOptionRead)
55 {
56 return "r";
57 }
58 else if (options & File::eOpenOptionWrite)
59 {
60 return "w";
61 }
62 return NULL;
63}
64
65int File::kInvalidDescriptor = -1;
66FILE * File::kInvalidStream = NULL;
67
Greg Clayton60a63ae2011-02-08 17:49:02 +000068File::File(const char *path, uint32_t options, uint32_t permissions) :
Greg Clayton58928562011-02-09 01:08:52 +000069 m_descriptor (kInvalidDescriptor),
70 m_stream (kInvalidStream),
71 m_options (0),
72 m_owned (false)
Greg Clayton60a63ae2011-02-08 17:49:02 +000073{
74 Open (path, options, permissions);
75}
76
Greg Clayton58928562011-02-09 01:08:52 +000077File::File (const File &rhs) :
78 m_descriptor (kInvalidDescriptor),
79 m_stream (kInvalidStream),
80 m_options (0),
81 m_owned (false)
82{
83 Duplicate (rhs);
84}
85
86
87File &
88File::operator = (const File &rhs)
89{
90 if (this != &rhs)
91 Duplicate (rhs);
92 return *this;
93}
94
Greg Clayton60a63ae2011-02-08 17:49:02 +000095File::~File()
96{
97 Close ();
98}
99
Greg Clayton58928562011-02-09 01:08:52 +0000100
101int
102File::GetDescriptor() const
103{
104 if (DescriptorIsValid())
105 return m_descriptor;
106
107 // Don't open the file descriptor if we don't need to, just get it from the
108 // stream if we have one.
109 if (StreamIsValid())
110 return fileno (m_stream);
111
112 // Invalid descriptor and invalid stream, return invalid descriptor.
113 return kInvalidDescriptor;
114}
115
116void
117File::SetDescriptor (int fd, bool transfer_ownership)
118{
119 if (IsValid())
120 Close();
121 m_descriptor = fd;
122 m_owned = transfer_ownership;
123}
124
125
126FILE *
127File::GetStream ()
128{
129 if (!StreamIsValid())
130 {
131 if (DescriptorIsValid())
132 {
133 const char *mode = GetStreamOpenModeFromOptions (m_options);
134 if (mode)
135 m_stream = ::fdopen (m_descriptor, mode);
136 }
137 }
138 return m_stream;
139}
140
141
142void
143File::SetStream (FILE *fh, bool transfer_ownership)
144{
145 if (IsValid())
146 Close();
147 m_stream = fh;
148 m_owned = transfer_ownership;
149}
150
151Error
152File::Duplicate (const File &rhs)
153{
154 Error error;
155 if (IsValid ())
156 Close();
157
158 if (rhs.DescriptorIsValid())
159 {
160 m_descriptor = ::fcntl(rhs.GetDescriptor(), F_DUPFD);
161 if (!DescriptorIsValid())
162 error.SetErrorToErrno();
163 else
164 {
165 m_options = rhs.m_options;
166 m_owned = true;
167 }
168 }
169 else
170 {
171 error.SetErrorString ("invalid file to duplicate");
172 }
173 return error;
174}
175
Greg Clayton60a63ae2011-02-08 17:49:02 +0000176Error
177File::Open (const char *path, uint32_t options, uint32_t permissions)
178{
179 Error error;
180 if (IsValid())
181 Close ();
182
183 int oflag = 0;
184 if (options & eOpenOptionRead &&
185 options & eOpenOptionWrite )
186 oflag |= O_RDWR;
187 else if (options & eOpenOptionRead)
188 oflag |= O_RDONLY;
189 else if (options & eOpenOptionWrite)
190 oflag |= O_WRONLY;
191
192 if (options & eOpenOptionNonBlocking)
193 oflag |= O_NONBLOCK;
194
195 if (options & eOpenOptionAppend)
196 oflag |= O_APPEND;
Greg Clayton58928562011-02-09 01:08:52 +0000197 else
198 oflag |= O_TRUNC;
Greg Clayton60a63ae2011-02-08 17:49:02 +0000199
200 if (options & eOpenOptionCanCreate)
201 oflag |= O_CREAT;
202
203 if (options & eOpenOptionCanCreateNewOnly)
204 oflag |= O_CREAT | O_EXCL;
205
Greg Clayton60a63ae2011-02-08 17:49:02 +0000206 mode_t mode = 0;
207 if (permissions & ePermissionsUserRead) mode |= S_IRUSR;
208 if (permissions & ePermissionsUserWrite) mode |= S_IWUSR;
209 if (permissions & ePermissionsUserExecute) mode |= S_IXUSR;
210 if (permissions & ePermissionsGroupRead) mode |= S_IRGRP;
211 if (permissions & ePermissionsGroupWrite) mode |= S_IWGRP;
212 if (permissions & ePermissionsGroupExecute) mode |= S_IXGRP;
213 if (permissions & ePermissionsWorldRead) mode |= S_IROTH;
214 if (permissions & ePermissionsWorldWrite) mode |= S_IWOTH;
215 if (permissions & ePermissionsWorldExecute) mode |= S_IXOTH;
216
Greg Clayton58928562011-02-09 01:08:52 +0000217 m_descriptor = ::open(path, oflag, mode);
218 if (!DescriptorIsValid())
Greg Clayton60a63ae2011-02-08 17:49:02 +0000219 error.SetErrorToErrno();
Greg Clayton58928562011-02-09 01:08:52 +0000220 else
221 m_owned = true;
Greg Clayton60a63ae2011-02-08 17:49:02 +0000222
223 return error;
224}
225
226Error
227File::Close ()
228{
229 Error error;
230 if (IsValid ())
231 {
Greg Clayton58928562011-02-09 01:08:52 +0000232 if (m_owned)
233 {
234 if (StreamIsValid())
235 {
236 if (::fclose (m_stream) == EOF)
237 error.SetErrorToErrno();
238 }
239
240 if (DescriptorIsValid())
241 {
242 if (::close (m_descriptor) != 0)
243 error.SetErrorToErrno();
244 }
245 }
246 m_descriptor = kInvalidDescriptor;
247 m_stream = kInvalidStream;
248 m_options = 0;
249 m_owned = false;
Greg Clayton60a63ae2011-02-08 17:49:02 +0000250 }
251 return error;
252}
Greg Clayton882ef052011-02-08 19:10:53 +0000253
254
255Error
256File::GetFileSpec (FileSpec &file_spec) const
257{
258 Error error;
Greg Claytonc08c4d32011-02-09 01:16:43 +0000259#ifdef LLDB_CONFIG_FCNTL_GETPATH_SUPPORTED
Greg Clayton882ef052011-02-08 19:10:53 +0000260 if (IsValid ())
261 {
262 char path[PATH_MAX];
Greg Clayton58928562011-02-09 01:08:52 +0000263 if (::fcntl(GetDescriptor(), F_GETPATH, path) == -1)
Greg Clayton882ef052011-02-08 19:10:53 +0000264 error.SetErrorToErrno();
265 else
266 file_spec.SetFile (path, false);
267 }
268 else
Greg Claytonc08c4d32011-02-09 01:16:43 +0000269 {
Greg Clayton882ef052011-02-08 19:10:53 +0000270 error.SetErrorString("invalid file handle");
Greg Claytonc08c4d32011-02-09 01:16:43 +0000271 }
Greg Clayton419144b2011-02-09 07:19:18 +0000272#elif defined(__linux__)
273 char proc[64];
274 char path[PATH_MAX];
275 if (::snprintf(proc, sizeof(proc), "/proc/self/fd/%d", GetDescriptor()) < 0)
276 error.SetErrorString ("Cannot resolve file descriptor\n");
277 else
278 {
279 ssize_t len;
280 if ((len = ::readlink(proc, path, sizeof(path) - 1)) == -1)
281 error.SetErrorToErrno();
282 else
283 {
284 path[len] = '\0';
285 file_spec.SetFile (path, false);
286 }
287 }
Greg Claytonc08c4d32011-02-09 01:16:43 +0000288#else
Greg Clayton419144b2011-02-09 07:19:18 +0000289 error.SetErrorString ("File::GetFileSpec is not supported on this platform");
Greg Claytonc08c4d32011-02-09 01:16:43 +0000290#endif
Greg Clayton882ef052011-02-08 19:10:53 +0000291
292 if (error.Fail())
293 file_spec.Clear();
294 return error;
295}
296
297Error
298File::SeekFromStart (off_t& offset)
299{
300 Error error;
Greg Clayton58928562011-02-09 01:08:52 +0000301 if (DescriptorIsValid())
Greg Clayton882ef052011-02-08 19:10:53 +0000302 {
Greg Clayton58928562011-02-09 01:08:52 +0000303 offset = ::lseek (m_descriptor, offset, SEEK_SET);
Greg Clayton882ef052011-02-08 19:10:53 +0000304
305 if (offset == -1)
306 error.SetErrorToErrno();
307 }
308 else
309 {
310 error.SetErrorString("invalid file handle");
311 }
312 return error;
313}
314
315Error
316File::SeekFromCurrent (off_t& offset)
317{
318 Error error;
Greg Clayton58928562011-02-09 01:08:52 +0000319 if (DescriptorIsValid())
Greg Clayton882ef052011-02-08 19:10:53 +0000320 {
Greg Clayton58928562011-02-09 01:08:52 +0000321 offset = ::lseek (m_descriptor, offset, SEEK_CUR);
Greg Clayton882ef052011-02-08 19:10:53 +0000322
323 if (offset == -1)
324 error.SetErrorToErrno();
325 }
326 else
327 {
328 error.SetErrorString("invalid file handle");
329 }
330 return error;
331}
332
333Error
334File::SeekFromEnd (off_t& offset)
335{
336 Error error;
Greg Clayton58928562011-02-09 01:08:52 +0000337 if (DescriptorIsValid())
Greg Clayton882ef052011-02-08 19:10:53 +0000338 {
Greg Clayton58928562011-02-09 01:08:52 +0000339 offset = ::lseek (m_descriptor, offset, SEEK_CUR);
Greg Clayton882ef052011-02-08 19:10:53 +0000340
341 if (offset == -1)
342 error.SetErrorToErrno();
343 }
344 else
345 {
346 error.SetErrorString("invalid file handle");
347 }
348 return error;
349}
350
351Error
Greg Clayton58928562011-02-09 01:08:52 +0000352File::Flush ()
353{
354 Error error;
355 if (StreamIsValid())
356 {
357 if (::fflush (m_stream) == EOF)
358 error.SetErrorToErrno();
359 }
360 else if (!DescriptorIsValid())
361 {
362 error.SetErrorString("invalid file handle");
363 }
364 return error;
365}
366
367
368Error
Greg Clayton882ef052011-02-08 19:10:53 +0000369File::Sync ()
370{
371 Error error;
Greg Clayton58928562011-02-09 01:08:52 +0000372 if (DescriptorIsValid())
Greg Clayton882ef052011-02-08 19:10:53 +0000373 {
Greg Clayton58928562011-02-09 01:08:52 +0000374 if (::fsync (m_descriptor) == -1)
Greg Clayton882ef052011-02-08 19:10:53 +0000375 error.SetErrorToErrno();
376 }
377 else
378 {
379 error.SetErrorString("invalid file handle");
380 }
381 return error;
382}
Greg Claytond35305a2011-02-08 19:54:44 +0000383
Greg Clayton60a63ae2011-02-08 17:49:02 +0000384Error
385File::Read (void *buf, size_t &num_bytes)
386{
387 Error error;
Greg Clayton58928562011-02-09 01:08:52 +0000388 if (DescriptorIsValid())
Greg Clayton60a63ae2011-02-08 17:49:02 +0000389 {
Greg Clayton58928562011-02-09 01:08:52 +0000390 ssize_t bytes_read = ::read (m_descriptor, buf, num_bytes);
Greg Clayton60a63ae2011-02-08 17:49:02 +0000391 if (bytes_read == -1)
392 {
393 error.SetErrorToErrno();
394 num_bytes = 0;
395 }
396 else
397 num_bytes = bytes_read;
398 }
Greg Clayton58928562011-02-09 01:08:52 +0000399 else if (StreamIsValid())
400 {
401 size_t bytes_read = ::fread (buf, 1, num_bytes, m_stream);
402 if (bytes_read == 0)
403 {
404 if (::feof(m_stream))
405 error.SetErrorString ("feof");
406 else if (::ferror (m_stream))
407 error.SetErrorString ("ferror");
408 num_bytes = 0;
409 }
410 else
411 num_bytes = bytes_read;
412 }
Greg Clayton60a63ae2011-02-08 17:49:02 +0000413 else
414 {
415 num_bytes = 0;
416 error.SetErrorString("invalid file handle");
417 }
418 return error;
419}
420
421Error
422File::Write (const void *buf, size_t &num_bytes)
423{
424 Error error;
Greg Clayton58928562011-02-09 01:08:52 +0000425 if (DescriptorIsValid())
Greg Clayton60a63ae2011-02-08 17:49:02 +0000426 {
Greg Clayton58928562011-02-09 01:08:52 +0000427 ssize_t bytes_written = ::write (m_descriptor, buf, num_bytes);
Greg Clayton60a63ae2011-02-08 17:49:02 +0000428 if (bytes_written == -1)
429 {
430 error.SetErrorToErrno();
431 num_bytes = 0;
432 }
433 else
434 num_bytes = bytes_written;
435 }
Greg Clayton58928562011-02-09 01:08:52 +0000436 else if (StreamIsValid())
437 {
438 size_t bytes_written = ::fwrite (buf, 1, num_bytes, m_stream);
439 if (bytes_written == 0)
440 {
441 if (::feof(m_stream))
442 error.SetErrorString ("feof");
443 else if (::ferror (m_stream))
444 error.SetErrorString ("ferror");
445 num_bytes = 0;
446 }
447 else
448 num_bytes = bytes_written;
449
450 }
Greg Clayton60a63ae2011-02-08 17:49:02 +0000451 else
452 {
453 num_bytes = 0;
454 error.SetErrorString("invalid file handle");
455 }
456 return error;
457}
458
Greg Claytond35305a2011-02-08 19:54:44 +0000459
460Error
461File::Read (void *buf, size_t &num_bytes, off_t &offset)
462{
463 Error error;
Greg Clayton58928562011-02-09 01:08:52 +0000464 int fd = GetDescriptor();
465 if (fd != kInvalidDescriptor)
Greg Claytond35305a2011-02-08 19:54:44 +0000466 {
Greg Clayton58928562011-02-09 01:08:52 +0000467 ssize_t bytes_read = ::pread (fd, buf, num_bytes, offset);
Greg Claytond35305a2011-02-08 19:54:44 +0000468 if (bytes_read < 0)
469 {
470 num_bytes = 0;
471 error.SetErrorToErrno();
472 }
473 else
474 {
475 offset += bytes_read;
476 num_bytes = bytes_read;
477 }
478 }
479 else
480 {
481 num_bytes = 0;
482 error.SetErrorString("invalid file handle");
483 }
484 return error;
485}
486
487Error
488File::Write (const void *buf, size_t &num_bytes, off_t &offset)
489{
490 Error error;
Greg Clayton58928562011-02-09 01:08:52 +0000491 int fd = GetDescriptor();
492 if (fd != kInvalidDescriptor)
Greg Claytond35305a2011-02-08 19:54:44 +0000493 {
Greg Clayton58928562011-02-09 01:08:52 +0000494 ssize_t bytes_written = ::pwrite (m_descriptor, buf, num_bytes, offset);
Greg Claytond35305a2011-02-08 19:54:44 +0000495 if (bytes_written < 0)
496 {
497 num_bytes = 0;
498 error.SetErrorToErrno();
499 }
500 else
501 {
502 offset += bytes_written;
503 num_bytes = bytes_written;
504 }
505 }
506 else
507 {
508 num_bytes = 0;
509 error.SetErrorString("invalid file handle");
510 }
511 return error;
512}
513
Greg Clayton58928562011-02-09 01:08:52 +0000514//------------------------------------------------------------------
515// Print some formatted output to the stream.
516//------------------------------------------------------------------
517int
518File::Printf (const char *format, ...)
519{
520 va_list args;
521 va_start (args, format);
522 int result = PrintfVarArg (format, args);
523 va_end (args);
524 return result;
525}
Greg Claytond35305a2011-02-08 19:54:44 +0000526
Greg Clayton58928562011-02-09 01:08:52 +0000527//------------------------------------------------------------------
528// Print some formatted output to the stream.
529//------------------------------------------------------------------
530int
531File::PrintfVarArg (const char *format, va_list args)
532{
533 int result = 0;
534 if (DescriptorIsValid())
535 {
536 char *s = NULL;
537 result = vasprintf(&s, format, args);
538 if (s != NULL)
539 {
540 if (result > 0)
541 {
542 size_t s_len = result;
543 Write (s, s_len);
544 result = s_len;
545 }
546 free (s);
547 }
548 }
549 else if (StreamIsValid())
550 {
551 result = ::vfprintf (m_stream, format, args);
552 }
553 return result;
554}