blob: e2dd32cca00b0c6a84e70391993669f728198e17 [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 Claytond35305a2011-02-08 19:54:44 +000016#include "lldb/Host/FileSpec.h"
Greg Clayton60a63ae2011-02-08 17:49:02 +000017
18using namespace lldb;
19using namespace lldb_private;
20
Greg Clayton58928562011-02-09 01:08:52 +000021static const char *
22GetStreamOpenModeFromOptions (uint32_t options)
23{
24 if (options & File::eOpenOptionAppend)
25 {
26 if (options & File::eOpenOptionRead)
27 {
28 if (options & File::eOpenOptionCanCreateNewOnly)
29 return "a+x";
30 else
31 return "a+";
32 }
33 else if (options & File::eOpenOptionWrite)
34 {
35 if (options & File::eOpenOptionCanCreateNewOnly)
36 return "ax";
37 else
38 return "a";
39 }
40 }
41 else if (options & File::eOpenOptionRead && options & File::eOpenOptionWrite)
42 {
43 if (options & File::eOpenOptionCanCreate)
44 {
45 if (options & File::eOpenOptionCanCreateNewOnly)
46 return "w+x";
47 else
48 return "w+";
49 }
50 else
51 return "r+";
52 }
53 else if (options & File::eOpenOptionRead)
54 {
55 return "r";
56 }
57 else if (options & File::eOpenOptionWrite)
58 {
59 return "w";
60 }
61 return NULL;
62}
63
64int File::kInvalidDescriptor = -1;
65FILE * File::kInvalidStream = NULL;
66
Greg Clayton60a63ae2011-02-08 17:49:02 +000067File::File(const char *path, uint32_t options, uint32_t permissions) :
Greg Clayton58928562011-02-09 01:08:52 +000068 m_descriptor (kInvalidDescriptor),
69 m_stream (kInvalidStream),
70 m_options (0),
71 m_owned (false)
Greg Clayton60a63ae2011-02-08 17:49:02 +000072{
73 Open (path, options, permissions);
74}
75
Greg Clayton58928562011-02-09 01:08:52 +000076File::File (const File &rhs) :
77 m_descriptor (kInvalidDescriptor),
78 m_stream (kInvalidStream),
79 m_options (0),
80 m_owned (false)
81{
82 Duplicate (rhs);
83}
84
85
86File &
87File::operator = (const File &rhs)
88{
89 if (this != &rhs)
90 Duplicate (rhs);
91 return *this;
92}
93
Greg Clayton60a63ae2011-02-08 17:49:02 +000094File::~File()
95{
96 Close ();
97}
98
Greg Clayton58928562011-02-09 01:08:52 +000099
100int
101File::GetDescriptor() const
102{
103 if (DescriptorIsValid())
104 return m_descriptor;
105
106 // Don't open the file descriptor if we don't need to, just get it from the
107 // stream if we have one.
108 if (StreamIsValid())
109 return fileno (m_stream);
110
111 // Invalid descriptor and invalid stream, return invalid descriptor.
112 return kInvalidDescriptor;
113}
114
115void
116File::SetDescriptor (int fd, bool transfer_ownership)
117{
118 if (IsValid())
119 Close();
120 m_descriptor = fd;
121 m_owned = transfer_ownership;
122}
123
124
125FILE *
126File::GetStream ()
127{
128 if (!StreamIsValid())
129 {
130 if (DescriptorIsValid())
131 {
132 const char *mode = GetStreamOpenModeFromOptions (m_options);
133 if (mode)
134 m_stream = ::fdopen (m_descriptor, mode);
135 }
136 }
137 return m_stream;
138}
139
140
141void
142File::SetStream (FILE *fh, bool transfer_ownership)
143{
144 if (IsValid())
145 Close();
146 m_stream = fh;
147 m_owned = transfer_ownership;
148}
149
150Error
151File::Duplicate (const File &rhs)
152{
153 Error error;
154 if (IsValid ())
155 Close();
156
157 if (rhs.DescriptorIsValid())
158 {
159 m_descriptor = ::fcntl(rhs.GetDescriptor(), F_DUPFD);
160 if (!DescriptorIsValid())
161 error.SetErrorToErrno();
162 else
163 {
164 m_options = rhs.m_options;
165 m_owned = true;
166 }
167 }
168 else
169 {
170 error.SetErrorString ("invalid file to duplicate");
171 }
172 return error;
173}
174
Greg Clayton60a63ae2011-02-08 17:49:02 +0000175Error
176File::Open (const char *path, uint32_t options, uint32_t permissions)
177{
178 Error error;
179 if (IsValid())
180 Close ();
181
182 int oflag = 0;
183 if (options & eOpenOptionRead &&
184 options & eOpenOptionWrite )
185 oflag |= O_RDWR;
186 else if (options & eOpenOptionRead)
187 oflag |= O_RDONLY;
188 else if (options & eOpenOptionWrite)
189 oflag |= O_WRONLY;
190
191 if (options & eOpenOptionNonBlocking)
192 oflag |= O_NONBLOCK;
193
194 if (options & eOpenOptionAppend)
195 oflag |= O_APPEND;
Greg Clayton58928562011-02-09 01:08:52 +0000196 else
197 oflag |= O_TRUNC;
Greg Clayton60a63ae2011-02-08 17:49:02 +0000198
199 if (options & eOpenOptionCanCreate)
200 oflag |= O_CREAT;
201
202 if (options & eOpenOptionCanCreateNewOnly)
203 oflag |= O_CREAT | O_EXCL;
204
Greg Clayton60a63ae2011-02-08 17:49:02 +0000205
206 if (options & eOpenOptionSharedLock)
207 oflag |= O_SHLOCK;
208
209 if (options & eOpenOptionExclusiveLock)
210 oflag |= O_EXLOCK;
211
212 mode_t mode = 0;
213 if (permissions & ePermissionsUserRead) mode |= S_IRUSR;
214 if (permissions & ePermissionsUserWrite) mode |= S_IWUSR;
215 if (permissions & ePermissionsUserExecute) mode |= S_IXUSR;
216 if (permissions & ePermissionsGroupRead) mode |= S_IRGRP;
217 if (permissions & ePermissionsGroupWrite) mode |= S_IWGRP;
218 if (permissions & ePermissionsGroupExecute) mode |= S_IXGRP;
219 if (permissions & ePermissionsWorldRead) mode |= S_IROTH;
220 if (permissions & ePermissionsWorldWrite) mode |= S_IWOTH;
221 if (permissions & ePermissionsWorldExecute) mode |= S_IXOTH;
222
Greg Clayton58928562011-02-09 01:08:52 +0000223 m_descriptor = ::open(path, oflag, mode);
224 if (!DescriptorIsValid())
Greg Clayton60a63ae2011-02-08 17:49:02 +0000225 error.SetErrorToErrno();
Greg Clayton58928562011-02-09 01:08:52 +0000226 else
227 m_owned = true;
Greg Clayton60a63ae2011-02-08 17:49:02 +0000228
229 return error;
230}
231
232Error
233File::Close ()
234{
235 Error error;
236 if (IsValid ())
237 {
Greg Clayton58928562011-02-09 01:08:52 +0000238 if (m_owned)
239 {
240 if (StreamIsValid())
241 {
242 if (::fclose (m_stream) == EOF)
243 error.SetErrorToErrno();
244 }
245
246 if (DescriptorIsValid())
247 {
248 if (::close (m_descriptor) != 0)
249 error.SetErrorToErrno();
250 }
251 }
252 m_descriptor = kInvalidDescriptor;
253 m_stream = kInvalidStream;
254 m_options = 0;
255 m_owned = false;
Greg Clayton60a63ae2011-02-08 17:49:02 +0000256 }
257 return error;
258}
Greg Clayton882ef052011-02-08 19:10:53 +0000259
260
261Error
262File::GetFileSpec (FileSpec &file_spec) const
263{
264 Error error;
265 if (IsValid ())
266 {
267 char path[PATH_MAX];
Greg Clayton58928562011-02-09 01:08:52 +0000268 if (::fcntl(GetDescriptor(), F_GETPATH, path) == -1)
Greg Clayton882ef052011-02-08 19:10:53 +0000269 error.SetErrorToErrno();
270 else
271 file_spec.SetFile (path, false);
272 }
273 else
274 error.SetErrorString("invalid file handle");
275
276 if (error.Fail())
277 file_spec.Clear();
278 return error;
279}
280
281Error
282File::SeekFromStart (off_t& offset)
283{
284 Error error;
Greg Clayton58928562011-02-09 01:08:52 +0000285 if (DescriptorIsValid())
Greg Clayton882ef052011-02-08 19:10:53 +0000286 {
Greg Clayton58928562011-02-09 01:08:52 +0000287 offset = ::lseek (m_descriptor, offset, SEEK_SET);
Greg Clayton882ef052011-02-08 19:10:53 +0000288
289 if (offset == -1)
290 error.SetErrorToErrno();
291 }
292 else
293 {
294 error.SetErrorString("invalid file handle");
295 }
296 return error;
297}
298
299Error
300File::SeekFromCurrent (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_CUR);
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::SeekFromEnd (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
Greg Clayton58928562011-02-09 01:08:52 +0000336File::Flush ()
337{
338 Error error;
339 if (StreamIsValid())
340 {
341 if (::fflush (m_stream) == EOF)
342 error.SetErrorToErrno();
343 }
344 else if (!DescriptorIsValid())
345 {
346 error.SetErrorString("invalid file handle");
347 }
348 return error;
349}
350
351
352Error
Greg Clayton882ef052011-02-08 19:10:53 +0000353File::Sync ()
354{
355 Error error;
Greg Clayton58928562011-02-09 01:08:52 +0000356 if (DescriptorIsValid())
Greg Clayton882ef052011-02-08 19:10:53 +0000357 {
Greg Clayton58928562011-02-09 01:08:52 +0000358 if (::fsync (m_descriptor) == -1)
Greg Clayton882ef052011-02-08 19:10:53 +0000359 error.SetErrorToErrno();
360 }
361 else
362 {
363 error.SetErrorString("invalid file handle");
364 }
365 return error;
366}
Greg Claytond35305a2011-02-08 19:54:44 +0000367
Greg Clayton60a63ae2011-02-08 17:49:02 +0000368Error
369File::Read (void *buf, size_t &num_bytes)
370{
371 Error error;
Greg Clayton58928562011-02-09 01:08:52 +0000372 if (DescriptorIsValid())
Greg Clayton60a63ae2011-02-08 17:49:02 +0000373 {
Greg Clayton58928562011-02-09 01:08:52 +0000374 ssize_t bytes_read = ::read (m_descriptor, buf, num_bytes);
Greg Clayton60a63ae2011-02-08 17:49:02 +0000375 if (bytes_read == -1)
376 {
377 error.SetErrorToErrno();
378 num_bytes = 0;
379 }
380 else
381 num_bytes = bytes_read;
382 }
Greg Clayton58928562011-02-09 01:08:52 +0000383 else if (StreamIsValid())
384 {
385 size_t bytes_read = ::fread (buf, 1, num_bytes, m_stream);
386 if (bytes_read == 0)
387 {
388 if (::feof(m_stream))
389 error.SetErrorString ("feof");
390 else if (::ferror (m_stream))
391 error.SetErrorString ("ferror");
392 num_bytes = 0;
393 }
394 else
395 num_bytes = bytes_read;
396 }
Greg Clayton60a63ae2011-02-08 17:49:02 +0000397 else
398 {
399 num_bytes = 0;
400 error.SetErrorString("invalid file handle");
401 }
402 return error;
403}
404
405Error
406File::Write (const void *buf, size_t &num_bytes)
407{
408 Error error;
Greg Clayton58928562011-02-09 01:08:52 +0000409 if (DescriptorIsValid())
Greg Clayton60a63ae2011-02-08 17:49:02 +0000410 {
Greg Clayton58928562011-02-09 01:08:52 +0000411 ssize_t bytes_written = ::write (m_descriptor, buf, num_bytes);
Greg Clayton60a63ae2011-02-08 17:49:02 +0000412 if (bytes_written == -1)
413 {
414 error.SetErrorToErrno();
415 num_bytes = 0;
416 }
417 else
418 num_bytes = bytes_written;
419 }
Greg Clayton58928562011-02-09 01:08:52 +0000420 else if (StreamIsValid())
421 {
422 size_t bytes_written = ::fwrite (buf, 1, num_bytes, m_stream);
423 if (bytes_written == 0)
424 {
425 if (::feof(m_stream))
426 error.SetErrorString ("feof");
427 else if (::ferror (m_stream))
428 error.SetErrorString ("ferror");
429 num_bytes = 0;
430 }
431 else
432 num_bytes = bytes_written;
433
434 }
Greg Clayton60a63ae2011-02-08 17:49:02 +0000435 else
436 {
437 num_bytes = 0;
438 error.SetErrorString("invalid file handle");
439 }
440 return error;
441}
442
Greg Claytond35305a2011-02-08 19:54:44 +0000443
444Error
445File::Read (void *buf, size_t &num_bytes, off_t &offset)
446{
447 Error error;
Greg Clayton58928562011-02-09 01:08:52 +0000448 int fd = GetDescriptor();
449 if (fd != kInvalidDescriptor)
Greg Claytond35305a2011-02-08 19:54:44 +0000450 {
Greg Clayton58928562011-02-09 01:08:52 +0000451 ssize_t bytes_read = ::pread (fd, buf, num_bytes, offset);
Greg Claytond35305a2011-02-08 19:54:44 +0000452 if (bytes_read < 0)
453 {
454 num_bytes = 0;
455 error.SetErrorToErrno();
456 }
457 else
458 {
459 offset += bytes_read;
460 num_bytes = bytes_read;
461 }
462 }
463 else
464 {
465 num_bytes = 0;
466 error.SetErrorString("invalid file handle");
467 }
468 return error;
469}
470
471Error
472File::Write (const void *buf, size_t &num_bytes, off_t &offset)
473{
474 Error error;
Greg Clayton58928562011-02-09 01:08:52 +0000475 int fd = GetDescriptor();
476 if (fd != kInvalidDescriptor)
Greg Claytond35305a2011-02-08 19:54:44 +0000477 {
Greg Clayton58928562011-02-09 01:08:52 +0000478 ssize_t bytes_written = ::pwrite (m_descriptor, buf, num_bytes, offset);
Greg Claytond35305a2011-02-08 19:54:44 +0000479 if (bytes_written < 0)
480 {
481 num_bytes = 0;
482 error.SetErrorToErrno();
483 }
484 else
485 {
486 offset += bytes_written;
487 num_bytes = bytes_written;
488 }
489 }
490 else
491 {
492 num_bytes = 0;
493 error.SetErrorString("invalid file handle");
494 }
495 return error;
496}
497
Greg Clayton58928562011-02-09 01:08:52 +0000498//------------------------------------------------------------------
499// Print some formatted output to the stream.
500//------------------------------------------------------------------
501int
502File::Printf (const char *format, ...)
503{
504 va_list args;
505 va_start (args, format);
506 int result = PrintfVarArg (format, args);
507 va_end (args);
508 return result;
509}
Greg Claytond35305a2011-02-08 19:54:44 +0000510
Greg Clayton58928562011-02-09 01:08:52 +0000511//------------------------------------------------------------------
512// Print some formatted output to the stream.
513//------------------------------------------------------------------
514int
515File::PrintfVarArg (const char *format, va_list args)
516{
517 int result = 0;
518 if (DescriptorIsValid())
519 {
520 char *s = NULL;
521 result = vasprintf(&s, format, args);
522 if (s != NULL)
523 {
524 if (result > 0)
525 {
526 size_t s_len = result;
527 Write (s, s_len);
528 result = s_len;
529 }
530 free (s);
531 }
532 }
533 else if (StreamIsValid())
534 {
535 result = ::vfprintf (m_stream, format, args);
536 }
537 return result;
538}