blob: 5a97bc9870273b9611da075a6beae31d77235274 [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>
Greg Clayton80949d42011-02-09 21:12:40 +000014#include <stdarg.h>
Greg Clayton25708252011-04-01 18:18:34 +000015#include <sys/stat.h>
Greg Clayton60a63ae2011-02-08 17:49:02 +000016
17#include "lldb/Core/Error.h"
Greg Claytonc08c4d32011-02-09 01:16:43 +000018#include "lldb/Host/Config.h"
Greg Claytond35305a2011-02-08 19:54:44 +000019#include "lldb/Host/FileSpec.h"
Greg Clayton60a63ae2011-02-08 17:49:02 +000020
21using namespace lldb;
22using namespace lldb_private;
23
Greg Clayton58928562011-02-09 01:08:52 +000024static const char *
25GetStreamOpenModeFromOptions (uint32_t options)
26{
27 if (options & File::eOpenOptionAppend)
28 {
29 if (options & File::eOpenOptionRead)
30 {
31 if (options & File::eOpenOptionCanCreateNewOnly)
32 return "a+x";
33 else
34 return "a+";
35 }
36 else if (options & File::eOpenOptionWrite)
37 {
38 if (options & File::eOpenOptionCanCreateNewOnly)
39 return "ax";
40 else
41 return "a";
42 }
43 }
44 else if (options & File::eOpenOptionRead && options & File::eOpenOptionWrite)
45 {
46 if (options & File::eOpenOptionCanCreate)
47 {
48 if (options & File::eOpenOptionCanCreateNewOnly)
49 return "w+x";
50 else
51 return "w+";
52 }
53 else
54 return "r+";
55 }
56 else if (options & File::eOpenOptionRead)
57 {
58 return "r";
59 }
60 else if (options & File::eOpenOptionWrite)
61 {
62 return "w";
63 }
64 return NULL;
65}
66
67int File::kInvalidDescriptor = -1;
68FILE * File::kInvalidStream = NULL;
69
Greg Clayton60a63ae2011-02-08 17:49:02 +000070File::File(const char *path, uint32_t options, uint32_t permissions) :
Greg Clayton58928562011-02-09 01:08:52 +000071 m_descriptor (kInvalidDescriptor),
72 m_stream (kInvalidStream),
73 m_options (0),
74 m_owned (false)
Greg Clayton60a63ae2011-02-08 17:49:02 +000075{
76 Open (path, options, permissions);
77}
78
Greg Clayton58928562011-02-09 01:08:52 +000079File::File (const File &rhs) :
80 m_descriptor (kInvalidDescriptor),
81 m_stream (kInvalidStream),
82 m_options (0),
83 m_owned (false)
84{
85 Duplicate (rhs);
86}
87
88
89File &
90File::operator = (const File &rhs)
91{
92 if (this != &rhs)
93 Duplicate (rhs);
94 return *this;
95}
96
Greg Clayton60a63ae2011-02-08 17:49:02 +000097File::~File()
98{
99 Close ();
100}
101
Greg Clayton58928562011-02-09 01:08:52 +0000102
103int
104File::GetDescriptor() const
105{
106 if (DescriptorIsValid())
107 return m_descriptor;
108
109 // Don't open the file descriptor if we don't need to, just get it from the
110 // stream if we have one.
111 if (StreamIsValid())
112 return fileno (m_stream);
113
114 // Invalid descriptor and invalid stream, return invalid descriptor.
115 return kInvalidDescriptor;
116}
117
118void
119File::SetDescriptor (int fd, bool transfer_ownership)
120{
121 if (IsValid())
122 Close();
123 m_descriptor = fd;
124 m_owned = transfer_ownership;
125}
126
127
128FILE *
129File::GetStream ()
130{
131 if (!StreamIsValid())
132 {
133 if (DescriptorIsValid())
134 {
135 const char *mode = GetStreamOpenModeFromOptions (m_options);
136 if (mode)
137 m_stream = ::fdopen (m_descriptor, mode);
138 }
139 }
140 return m_stream;
141}
142
143
144void
145File::SetStream (FILE *fh, bool transfer_ownership)
146{
147 if (IsValid())
148 Close();
149 m_stream = fh;
150 m_owned = transfer_ownership;
151}
152
153Error
154File::Duplicate (const File &rhs)
155{
156 Error error;
157 if (IsValid ())
158 Close();
159
160 if (rhs.DescriptorIsValid())
161 {
162 m_descriptor = ::fcntl(rhs.GetDescriptor(), F_DUPFD);
163 if (!DescriptorIsValid())
164 error.SetErrorToErrno();
165 else
166 {
167 m_options = rhs.m_options;
168 m_owned = true;
169 }
170 }
171 else
172 {
173 error.SetErrorString ("invalid file to duplicate");
174 }
175 return error;
176}
177
Greg Clayton60a63ae2011-02-08 17:49:02 +0000178Error
179File::Open (const char *path, uint32_t options, uint32_t permissions)
180{
181 Error error;
182 if (IsValid())
183 Close ();
184
185 int oflag = 0;
186 if (options & eOpenOptionRead &&
187 options & eOpenOptionWrite )
188 oflag |= O_RDWR;
189 else if (options & eOpenOptionRead)
190 oflag |= O_RDONLY;
191 else if (options & eOpenOptionWrite)
192 oflag |= O_WRONLY;
193
194 if (options & eOpenOptionNonBlocking)
195 oflag |= O_NONBLOCK;
196
197 if (options & eOpenOptionAppend)
198 oflag |= O_APPEND;
Greg Clayton58928562011-02-09 01:08:52 +0000199 else
200 oflag |= O_TRUNC;
Greg Clayton60a63ae2011-02-08 17:49:02 +0000201
202 if (options & eOpenOptionCanCreate)
203 oflag |= O_CREAT;
204
205 if (options & eOpenOptionCanCreateNewOnly)
206 oflag |= O_CREAT | O_EXCL;
207
Greg Clayton60a63ae2011-02-08 17:49:02 +0000208 mode_t mode = 0;
209 if (permissions & ePermissionsUserRead) mode |= S_IRUSR;
210 if (permissions & ePermissionsUserWrite) mode |= S_IWUSR;
211 if (permissions & ePermissionsUserExecute) mode |= S_IXUSR;
212 if (permissions & ePermissionsGroupRead) mode |= S_IRGRP;
213 if (permissions & ePermissionsGroupWrite) mode |= S_IWGRP;
214 if (permissions & ePermissionsGroupExecute) mode |= S_IXGRP;
215 if (permissions & ePermissionsWorldRead) mode |= S_IROTH;
216 if (permissions & ePermissionsWorldWrite) mode |= S_IWOTH;
217 if (permissions & ePermissionsWorldExecute) mode |= S_IXOTH;
218
Greg Clayton58928562011-02-09 01:08:52 +0000219 m_descriptor = ::open(path, oflag, mode);
220 if (!DescriptorIsValid())
Greg Clayton60a63ae2011-02-08 17:49:02 +0000221 error.SetErrorToErrno();
Greg Clayton58928562011-02-09 01:08:52 +0000222 else
223 m_owned = true;
Greg Clayton60a63ae2011-02-08 17:49:02 +0000224
225 return error;
226}
227
228Error
229File::Close ()
230{
231 Error error;
232 if (IsValid ())
233 {
Greg Clayton58928562011-02-09 01:08:52 +0000234 if (m_owned)
235 {
236 if (StreamIsValid())
237 {
238 if (::fclose (m_stream) == EOF)
239 error.SetErrorToErrno();
240 }
241
242 if (DescriptorIsValid())
243 {
244 if (::close (m_descriptor) != 0)
245 error.SetErrorToErrno();
246 }
247 }
248 m_descriptor = kInvalidDescriptor;
249 m_stream = kInvalidStream;
250 m_options = 0;
251 m_owned = false;
Greg Clayton60a63ae2011-02-08 17:49:02 +0000252 }
253 return error;
254}
Greg Clayton882ef052011-02-08 19:10:53 +0000255
256
257Error
258File::GetFileSpec (FileSpec &file_spec) const
259{
260 Error error;
Greg Claytonc08c4d32011-02-09 01:16:43 +0000261#ifdef LLDB_CONFIG_FCNTL_GETPATH_SUPPORTED
Greg Clayton882ef052011-02-08 19:10:53 +0000262 if (IsValid ())
263 {
264 char path[PATH_MAX];
Greg Clayton58928562011-02-09 01:08:52 +0000265 if (::fcntl(GetDescriptor(), F_GETPATH, path) == -1)
Greg Clayton882ef052011-02-08 19:10:53 +0000266 error.SetErrorToErrno();
267 else
268 file_spec.SetFile (path, false);
269 }
270 else
Greg Claytonc08c4d32011-02-09 01:16:43 +0000271 {
Greg Clayton882ef052011-02-08 19:10:53 +0000272 error.SetErrorString("invalid file handle");
Greg Claytonc08c4d32011-02-09 01:16:43 +0000273 }
Greg Clayton419144b2011-02-09 07:19:18 +0000274#elif defined(__linux__)
275 char proc[64];
276 char path[PATH_MAX];
277 if (::snprintf(proc, sizeof(proc), "/proc/self/fd/%d", GetDescriptor()) < 0)
278 error.SetErrorString ("Cannot resolve file descriptor\n");
279 else
280 {
281 ssize_t len;
282 if ((len = ::readlink(proc, path, sizeof(path) - 1)) == -1)
283 error.SetErrorToErrno();
284 else
285 {
286 path[len] = '\0';
287 file_spec.SetFile (path, false);
288 }
289 }
Greg Claytonc08c4d32011-02-09 01:16:43 +0000290#else
Greg Clayton419144b2011-02-09 07:19:18 +0000291 error.SetErrorString ("File::GetFileSpec is not supported on this platform");
Greg Claytonc08c4d32011-02-09 01:16:43 +0000292#endif
Greg Clayton882ef052011-02-08 19:10:53 +0000293
294 if (error.Fail())
295 file_spec.Clear();
296 return error;
297}
298
299Error
300File::SeekFromStart (off_t& offset)
301{
302 Error error;
Greg Clayton58928562011-02-09 01:08:52 +0000303 if (DescriptorIsValid())
Greg Clayton882ef052011-02-08 19:10:53 +0000304 {
Greg Clayton58928562011-02-09 01:08:52 +0000305 offset = ::lseek (m_descriptor, offset, SEEK_SET);
Greg Clayton882ef052011-02-08 19:10:53 +0000306
307 if (offset == -1)
308 error.SetErrorToErrno();
309 }
310 else
311 {
312 error.SetErrorString("invalid file handle");
313 }
314 return error;
315}
316
317Error
318File::SeekFromCurrent (off_t& offset)
319{
320 Error error;
Greg Clayton58928562011-02-09 01:08:52 +0000321 if (DescriptorIsValid())
Greg Clayton882ef052011-02-08 19:10:53 +0000322 {
Greg Clayton58928562011-02-09 01:08:52 +0000323 offset = ::lseek (m_descriptor, offset, SEEK_CUR);
Greg Clayton882ef052011-02-08 19:10:53 +0000324
325 if (offset == -1)
326 error.SetErrorToErrno();
327 }
328 else
329 {
330 error.SetErrorString("invalid file handle");
331 }
332 return error;
333}
334
335Error
336File::SeekFromEnd (off_t& offset)
337{
338 Error error;
Greg Clayton58928562011-02-09 01:08:52 +0000339 if (DescriptorIsValid())
Greg Clayton882ef052011-02-08 19:10:53 +0000340 {
Greg Clayton58928562011-02-09 01:08:52 +0000341 offset = ::lseek (m_descriptor, offset, SEEK_CUR);
Greg Clayton882ef052011-02-08 19:10:53 +0000342
343 if (offset == -1)
344 error.SetErrorToErrno();
345 }
346 else
347 {
348 error.SetErrorString("invalid file handle");
349 }
350 return error;
351}
352
353Error
Greg Clayton58928562011-02-09 01:08:52 +0000354File::Flush ()
355{
356 Error error;
357 if (StreamIsValid())
358 {
359 if (::fflush (m_stream) == EOF)
360 error.SetErrorToErrno();
361 }
362 else if (!DescriptorIsValid())
363 {
364 error.SetErrorString("invalid file handle");
365 }
366 return error;
367}
368
369
370Error
Greg Clayton882ef052011-02-08 19:10:53 +0000371File::Sync ()
372{
373 Error error;
Greg Clayton58928562011-02-09 01:08:52 +0000374 if (DescriptorIsValid())
Greg Clayton882ef052011-02-08 19:10:53 +0000375 {
Greg Clayton58928562011-02-09 01:08:52 +0000376 if (::fsync (m_descriptor) == -1)
Greg Clayton882ef052011-02-08 19:10:53 +0000377 error.SetErrorToErrno();
378 }
379 else
380 {
381 error.SetErrorString("invalid file handle");
382 }
383 return error;
384}
Greg Claytond35305a2011-02-08 19:54:44 +0000385
Greg Clayton60a63ae2011-02-08 17:49:02 +0000386Error
387File::Read (void *buf, size_t &num_bytes)
388{
389 Error error;
Greg Clayton58928562011-02-09 01:08:52 +0000390 if (DescriptorIsValid())
Greg Clayton60a63ae2011-02-08 17:49:02 +0000391 {
Greg Clayton58928562011-02-09 01:08:52 +0000392 ssize_t bytes_read = ::read (m_descriptor, buf, num_bytes);
Greg Clayton60a63ae2011-02-08 17:49:02 +0000393 if (bytes_read == -1)
394 {
395 error.SetErrorToErrno();
396 num_bytes = 0;
397 }
398 else
399 num_bytes = bytes_read;
400 }
Greg Clayton58928562011-02-09 01:08:52 +0000401 else if (StreamIsValid())
402 {
403 size_t bytes_read = ::fread (buf, 1, num_bytes, m_stream);
404 if (bytes_read == 0)
405 {
406 if (::feof(m_stream))
407 error.SetErrorString ("feof");
408 else if (::ferror (m_stream))
409 error.SetErrorString ("ferror");
410 num_bytes = 0;
411 }
412 else
413 num_bytes = bytes_read;
414 }
Greg Clayton60a63ae2011-02-08 17:49:02 +0000415 else
416 {
417 num_bytes = 0;
418 error.SetErrorString("invalid file handle");
419 }
420 return error;
421}
422
423Error
424File::Write (const void *buf, size_t &num_bytes)
425{
426 Error error;
Greg Clayton58928562011-02-09 01:08:52 +0000427 if (DescriptorIsValid())
Greg Clayton60a63ae2011-02-08 17:49:02 +0000428 {
Greg Clayton58928562011-02-09 01:08:52 +0000429 ssize_t bytes_written = ::write (m_descriptor, buf, num_bytes);
Greg Clayton60a63ae2011-02-08 17:49:02 +0000430 if (bytes_written == -1)
431 {
432 error.SetErrorToErrno();
433 num_bytes = 0;
434 }
435 else
436 num_bytes = bytes_written;
437 }
Greg Clayton58928562011-02-09 01:08:52 +0000438 else if (StreamIsValid())
439 {
440 size_t bytes_written = ::fwrite (buf, 1, num_bytes, m_stream);
441 if (bytes_written == 0)
442 {
443 if (::feof(m_stream))
444 error.SetErrorString ("feof");
445 else if (::ferror (m_stream))
446 error.SetErrorString ("ferror");
447 num_bytes = 0;
448 }
449 else
450 num_bytes = bytes_written;
451
452 }
Greg Clayton60a63ae2011-02-08 17:49:02 +0000453 else
454 {
455 num_bytes = 0;
456 error.SetErrorString("invalid file handle");
457 }
458 return error;
459}
460
Greg Claytond35305a2011-02-08 19:54:44 +0000461
462Error
463File::Read (void *buf, size_t &num_bytes, off_t &offset)
464{
465 Error error;
Greg Clayton58928562011-02-09 01:08:52 +0000466 int fd = GetDescriptor();
467 if (fd != kInvalidDescriptor)
Greg Claytond35305a2011-02-08 19:54:44 +0000468 {
Greg Clayton58928562011-02-09 01:08:52 +0000469 ssize_t bytes_read = ::pread (fd, buf, num_bytes, offset);
Greg Claytond35305a2011-02-08 19:54:44 +0000470 if (bytes_read < 0)
471 {
472 num_bytes = 0;
473 error.SetErrorToErrno();
474 }
475 else
476 {
477 offset += bytes_read;
478 num_bytes = bytes_read;
479 }
480 }
481 else
482 {
483 num_bytes = 0;
484 error.SetErrorString("invalid file handle");
485 }
486 return error;
487}
488
489Error
490File::Write (const void *buf, size_t &num_bytes, off_t &offset)
491{
492 Error error;
Greg Clayton58928562011-02-09 01:08:52 +0000493 int fd = GetDescriptor();
494 if (fd != kInvalidDescriptor)
Greg Claytond35305a2011-02-08 19:54:44 +0000495 {
Greg Clayton58928562011-02-09 01:08:52 +0000496 ssize_t bytes_written = ::pwrite (m_descriptor, buf, num_bytes, offset);
Greg Claytond35305a2011-02-08 19:54:44 +0000497 if (bytes_written < 0)
498 {
499 num_bytes = 0;
500 error.SetErrorToErrno();
501 }
502 else
503 {
504 offset += bytes_written;
505 num_bytes = bytes_written;
506 }
507 }
508 else
509 {
510 num_bytes = 0;
511 error.SetErrorString("invalid file handle");
512 }
513 return error;
514}
515
Greg Clayton58928562011-02-09 01:08:52 +0000516//------------------------------------------------------------------
517// Print some formatted output to the stream.
518//------------------------------------------------------------------
519int
520File::Printf (const char *format, ...)
521{
522 va_list args;
523 va_start (args, format);
524 int result = PrintfVarArg (format, args);
525 va_end (args);
526 return result;
527}
Greg Claytond35305a2011-02-08 19:54:44 +0000528
Greg Clayton58928562011-02-09 01:08:52 +0000529//------------------------------------------------------------------
530// Print some formatted output to the stream.
531//------------------------------------------------------------------
532int
533File::PrintfVarArg (const char *format, va_list args)
534{
535 int result = 0;
536 if (DescriptorIsValid())
537 {
538 char *s = NULL;
539 result = vasprintf(&s, format, args);
540 if (s != NULL)
541 {
542 if (result > 0)
543 {
544 size_t s_len = result;
545 Write (s, s_len);
546 result = s_len;
547 }
548 free (s);
549 }
550 }
551 else if (StreamIsValid())
552 {
553 result = ::vfprintf (m_stream, format, args);
554 }
555 return result;
556}