blob: e8ba529de9447fb8ce499172f3a8dacff8614e92 [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 }
272#else
273 error.SetErrorString ("fcntl (fd, F_GETPATH, ...) is not supported on this platform");
274#endif
Greg Clayton882ef052011-02-08 19:10:53 +0000275
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}