blob: addd43515405124b629c51eea97fbe5a2da6eac2 [file] [log] [blame]
Greg Clayton504f89a2011-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
Greg Clayton96c09682012-01-04 22:56:43 +000013#include <errno.h>
Greg Clayton504f89a2011-02-08 17:49:02 +000014#include <fcntl.h>
Stephen Wilson8acdbb82011-04-08 13:36:44 +000015#include <limits.h>
Greg Claytonf4dd5432011-02-09 21:12:40 +000016#include <stdarg.h>
Greg Clayton2b4d9b72011-04-01 18:18:34 +000017#include <sys/stat.h>
Greg Clayton504f89a2011-02-08 17:49:02 +000018
Virgile Bellob2f1fb22013-08-23 12:44:05 +000019#ifdef _WIN32
20#include "lldb/Host/windows/windows.h"
21#endif
22
Greg Clayton96c09682012-01-04 22:56:43 +000023#include "lldb/Core/DataBufferHeap.h"
Greg Clayton504f89a2011-02-08 17:49:02 +000024#include "lldb/Core/Error.h"
Greg Clayton925137c2011-02-09 01:16:43 +000025#include "lldb/Host/Config.h"
Greg Clayton846b64b2011-02-08 19:54:44 +000026#include "lldb/Host/FileSpec.h"
Greg Clayton504f89a2011-02-08 17:49:02 +000027
28using namespace lldb;
29using namespace lldb_private;
30
Greg Clayton51b1e2d2011-02-09 01:08:52 +000031static const char *
32GetStreamOpenModeFromOptions (uint32_t options)
33{
34 if (options & File::eOpenOptionAppend)
35 {
36 if (options & File::eOpenOptionRead)
37 {
38 if (options & File::eOpenOptionCanCreateNewOnly)
39 return "a+x";
40 else
41 return "a+";
42 }
43 else if (options & File::eOpenOptionWrite)
44 {
45 if (options & File::eOpenOptionCanCreateNewOnly)
46 return "ax";
47 else
48 return "a";
49 }
50 }
51 else if (options & File::eOpenOptionRead && options & File::eOpenOptionWrite)
52 {
53 if (options & File::eOpenOptionCanCreate)
54 {
55 if (options & File::eOpenOptionCanCreateNewOnly)
56 return "w+x";
57 else
58 return "w+";
59 }
60 else
61 return "r+";
62 }
63 else if (options & File::eOpenOptionRead)
64 {
65 return "r";
66 }
67 else if (options & File::eOpenOptionWrite)
68 {
69 return "w";
70 }
71 return NULL;
72}
73
74int File::kInvalidDescriptor = -1;
75FILE * File::kInvalidStream = NULL;
76
Greg Clayton504f89a2011-02-08 17:49:02 +000077File::File(const char *path, uint32_t options, uint32_t permissions) :
Greg Clayton51b1e2d2011-02-09 01:08:52 +000078 m_descriptor (kInvalidDescriptor),
79 m_stream (kInvalidStream),
80 m_options (0),
81 m_owned (false)
Greg Clayton504f89a2011-02-08 17:49:02 +000082{
83 Open (path, options, permissions);
84}
85
Daniel Maleae0f8f572013-08-26 23:57:52 +000086File::File (const FileSpec& filespec,
87 uint32_t options,
88 uint32_t permissions) :
89 m_descriptor (kInvalidDescriptor),
90 m_stream (kInvalidStream),
91 m_options (0),
92 m_owned (false)
93{
94 if (filespec)
95 {
96 Open (filespec.GetPath().c_str(), options, permissions);
97 }
98}
99
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000100File::File (const File &rhs) :
101 m_descriptor (kInvalidDescriptor),
102 m_stream (kInvalidStream),
103 m_options (0),
104 m_owned (false)
105{
106 Duplicate (rhs);
107}
108
109
110File &
111File::operator = (const File &rhs)
112{
113 if (this != &rhs)
114 Duplicate (rhs);
115 return *this;
116}
117
Greg Clayton504f89a2011-02-08 17:49:02 +0000118File::~File()
119{
120 Close ();
121}
122
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000123
124int
125File::GetDescriptor() const
126{
127 if (DescriptorIsValid())
128 return m_descriptor;
129
130 // Don't open the file descriptor if we don't need to, just get it from the
131 // stream if we have one.
132 if (StreamIsValid())
133 return fileno (m_stream);
134
135 // Invalid descriptor and invalid stream, return invalid descriptor.
136 return kInvalidDescriptor;
137}
138
139void
140File::SetDescriptor (int fd, bool transfer_ownership)
141{
142 if (IsValid())
143 Close();
144 m_descriptor = fd;
145 m_owned = transfer_ownership;
146}
147
148
149FILE *
150File::GetStream ()
151{
152 if (!StreamIsValid())
153 {
154 if (DescriptorIsValid())
155 {
156 const char *mode = GetStreamOpenModeFromOptions (m_options);
157 if (mode)
Greg Clayton96c09682012-01-04 22:56:43 +0000158 {
159 do
160 {
161 m_stream = ::fdopen (m_descriptor, mode);
162 } while (m_stream == NULL && errno == EINTR);
163 }
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000164 }
165 }
166 return m_stream;
167}
168
169
170void
171File::SetStream (FILE *fh, bool transfer_ownership)
172{
173 if (IsValid())
174 Close();
175 m_stream = fh;
176 m_owned = transfer_ownership;
177}
178
179Error
180File::Duplicate (const File &rhs)
181{
182 Error error;
183 if (IsValid ())
184 Close();
185
186 if (rhs.DescriptorIsValid())
187 {
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000188#ifdef _WIN32
189 m_descriptor = ::_dup(rhs.GetDescriptor());
190#else
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000191 m_descriptor = ::fcntl(rhs.GetDescriptor(), F_DUPFD);
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000192#endif
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000193 if (!DescriptorIsValid())
194 error.SetErrorToErrno();
195 else
196 {
197 m_options = rhs.m_options;
198 m_owned = true;
199 }
200 }
201 else
202 {
203 error.SetErrorString ("invalid file to duplicate");
204 }
205 return error;
206}
207
Greg Clayton504f89a2011-02-08 17:49:02 +0000208Error
209File::Open (const char *path, uint32_t options, uint32_t permissions)
210{
211 Error error;
212 if (IsValid())
213 Close ();
214
215 int oflag = 0;
Greg Clayton96c09682012-01-04 22:56:43 +0000216 const bool read = options & eOpenOptionRead;
217 const bool write = options & eOpenOptionWrite;
218 if (write)
219 {
220 if (read)
221 oflag |= O_RDWR;
222 else
223 oflag |= O_WRONLY;
224
225 if (options & eOpenOptionAppend)
226 oflag |= O_APPEND;
227
228 if (options & eOpenOptionTruncate)
229 oflag |= O_TRUNC;
230
231 if (options & eOpenOptionCanCreate)
232 oflag |= O_CREAT;
233
234 if (options & eOpenOptionCanCreateNewOnly)
235 oflag |= O_CREAT | O_EXCL;
236 }
237 else if (read)
238 {
Greg Clayton504f89a2011-02-08 17:49:02 +0000239 oflag |= O_RDONLY;
Greg Clayton96c09682012-01-04 22:56:43 +0000240 }
Greg Clayton504f89a2011-02-08 17:49:02 +0000241
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000242#ifndef _WIN32
Greg Clayton504f89a2011-02-08 17:49:02 +0000243 if (options & eOpenOptionNonBlocking)
244 oflag |= O_NONBLOCK;
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000245#else
246 oflag |= O_BINARY;
247#endif
Greg Clayton504f89a2011-02-08 17:49:02 +0000248
Greg Clayton504f89a2011-02-08 17:49:02 +0000249 mode_t mode = 0;
Greg Clayton96c09682012-01-04 22:56:43 +0000250 if (oflag & O_CREAT)
251 {
252 if (permissions & ePermissionsUserRead) mode |= S_IRUSR;
253 if (permissions & ePermissionsUserWrite) mode |= S_IWUSR;
254 if (permissions & ePermissionsUserExecute) mode |= S_IXUSR;
255 if (permissions & ePermissionsGroupRead) mode |= S_IRGRP;
256 if (permissions & ePermissionsGroupWrite) mode |= S_IWGRP;
257 if (permissions & ePermissionsGroupExecute) mode |= S_IXGRP;
258 if (permissions & ePermissionsWorldRead) mode |= S_IROTH;
259 if (permissions & ePermissionsWorldWrite) mode |= S_IWOTH;
260 if (permissions & ePermissionsWorldExecute) mode |= S_IXOTH;
261 }
Greg Clayton504f89a2011-02-08 17:49:02 +0000262
Greg Clayton96c09682012-01-04 22:56:43 +0000263 do
264 {
265 m_descriptor = ::open(path, oflag, mode);
266 } while (m_descriptor < 0 && errno == EINTR);
267
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000268 if (!DescriptorIsValid())
Greg Clayton504f89a2011-02-08 17:49:02 +0000269 error.SetErrorToErrno();
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000270 else
271 m_owned = true;
Greg Clayton504f89a2011-02-08 17:49:02 +0000272
273 return error;
274}
275
Daniel Maleae0f8f572013-08-26 23:57:52 +0000276uint32_t
277File::GetPermissions (const char *path, Error &error)
278{
279 if (path && path[0])
280 {
281 struct stat file_stats;
282 if (::stat (path, &file_stats) == -1)
283 error.SetErrorToErrno();
284 else
285 {
286 error.Clear();
287 return file_stats.st_mode; // All bits from lldb_private::File::Permissions match those in POSIX mode bits
288 }
289 }
290 else
291 {
292 if (path)
293 error.SetErrorString ("invalid path");
294 else
295 error.SetErrorString ("empty path");
296 }
297 return 0;
298}
299
300uint32_t
301File::GetPermissions(Error &error) const
302{
303 int fd = GetDescriptor();
304 if (fd != kInvalidDescriptor)
305 {
306 struct stat file_stats;
307 if (::fstat (fd, &file_stats) == -1)
308 error.SetErrorToErrno();
309 else
310 {
311 error.Clear();
312 return file_stats.st_mode; // All bits from lldb_private::File::Permissions match those in POSIX mode bits
313 }
314 }
315 else
316 {
317 error.SetErrorString ("invalid file descriptor");
318 }
319 return 0;
320}
321
322
Greg Clayton504f89a2011-02-08 17:49:02 +0000323Error
324File::Close ()
325{
326 Error error;
327 if (IsValid ())
328 {
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000329 if (m_owned)
330 {
331 if (StreamIsValid())
332 {
333 if (::fclose (m_stream) == EOF)
334 error.SetErrorToErrno();
335 }
336
337 if (DescriptorIsValid())
338 {
339 if (::close (m_descriptor) != 0)
340 error.SetErrorToErrno();
341 }
342 }
343 m_descriptor = kInvalidDescriptor;
344 m_stream = kInvalidStream;
345 m_options = 0;
346 m_owned = false;
Greg Clayton504f89a2011-02-08 17:49:02 +0000347 }
348 return error;
349}
Greg Clayton968fa382011-02-08 19:10:53 +0000350
351
352Error
353File::GetFileSpec (FileSpec &file_spec) const
354{
355 Error error;
Greg Clayton925137c2011-02-09 01:16:43 +0000356#ifdef LLDB_CONFIG_FCNTL_GETPATH_SUPPORTED
Greg Clayton968fa382011-02-08 19:10:53 +0000357 if (IsValid ())
358 {
359 char path[PATH_MAX];
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000360 if (::fcntl(GetDescriptor(), F_GETPATH, path) == -1)
Greg Clayton968fa382011-02-08 19:10:53 +0000361 error.SetErrorToErrno();
362 else
363 file_spec.SetFile (path, false);
364 }
365 else
Greg Clayton925137c2011-02-09 01:16:43 +0000366 {
Greg Clayton968fa382011-02-08 19:10:53 +0000367 error.SetErrorString("invalid file handle");
Greg Clayton925137c2011-02-09 01:16:43 +0000368 }
Greg Clayton94d08622011-02-09 07:19:18 +0000369#elif defined(__linux__)
370 char proc[64];
371 char path[PATH_MAX];
372 if (::snprintf(proc, sizeof(proc), "/proc/self/fd/%d", GetDescriptor()) < 0)
Greg Clayton86edbf42011-10-26 00:56:27 +0000373 error.SetErrorString ("cannot resolve file descriptor");
Greg Clayton94d08622011-02-09 07:19:18 +0000374 else
375 {
376 ssize_t len;
377 if ((len = ::readlink(proc, path, sizeof(path) - 1)) == -1)
378 error.SetErrorToErrno();
379 else
380 {
381 path[len] = '\0';
382 file_spec.SetFile (path, false);
383 }
384 }
Greg Clayton925137c2011-02-09 01:16:43 +0000385#else
Greg Clayton94d08622011-02-09 07:19:18 +0000386 error.SetErrorString ("File::GetFileSpec is not supported on this platform");
Greg Clayton925137c2011-02-09 01:16:43 +0000387#endif
Greg Clayton968fa382011-02-08 19:10:53 +0000388
389 if (error.Fail())
390 file_spec.Clear();
391 return error;
392}
393
Greg Clayton43d82792013-05-22 23:30:09 +0000394off_t
395File::SeekFromStart (off_t offset, Error *error_ptr)
Greg Clayton968fa382011-02-08 19:10:53 +0000396{
Greg Clayton43d82792013-05-22 23:30:09 +0000397 off_t result = 0;
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000398 if (DescriptorIsValid())
Greg Clayton968fa382011-02-08 19:10:53 +0000399 {
Greg Clayton43d82792013-05-22 23:30:09 +0000400 result = ::lseek (m_descriptor, offset, SEEK_SET);
Greg Clayton968fa382011-02-08 19:10:53 +0000401
Greg Clayton43d82792013-05-22 23:30:09 +0000402 if (error_ptr)
403 {
404 if (result == -1)
405 error_ptr->SetErrorToErrno();
406 else
407 error_ptr->Clear();
408 }
Greg Clayton968fa382011-02-08 19:10:53 +0000409 }
Greg Clayton43d82792013-05-22 23:30:09 +0000410 else if (StreamIsValid ())
Greg Clayton968fa382011-02-08 19:10:53 +0000411 {
Greg Clayton43d82792013-05-22 23:30:09 +0000412 result = ::fseek(m_stream, offset, SEEK_SET);
413
414 if (error_ptr)
415 {
416 if (result == -1)
417 error_ptr->SetErrorToErrno();
418 else
419 error_ptr->Clear();
420 }
Greg Clayton968fa382011-02-08 19:10:53 +0000421 }
Greg Clayton43d82792013-05-22 23:30:09 +0000422 else if (error_ptr)
423 {
424 error_ptr->SetErrorString("invalid file handle");
425 }
426 return result;
Greg Clayton968fa382011-02-08 19:10:53 +0000427}
428
Greg Clayton43d82792013-05-22 23:30:09 +0000429off_t
430File::SeekFromCurrent (off_t offset, Error *error_ptr)
Greg Clayton968fa382011-02-08 19:10:53 +0000431{
Greg Clayton43d82792013-05-22 23:30:09 +0000432 off_t result = -1;
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000433 if (DescriptorIsValid())
Greg Clayton968fa382011-02-08 19:10:53 +0000434 {
Greg Clayton43d82792013-05-22 23:30:09 +0000435 result = ::lseek (m_descriptor, offset, SEEK_CUR);
Greg Clayton968fa382011-02-08 19:10:53 +0000436
Greg Clayton43d82792013-05-22 23:30:09 +0000437 if (error_ptr)
438 {
439 if (result == -1)
440 error_ptr->SetErrorToErrno();
441 else
442 error_ptr->Clear();
443 }
Greg Clayton968fa382011-02-08 19:10:53 +0000444 }
Greg Clayton43d82792013-05-22 23:30:09 +0000445 else if (StreamIsValid ())
Greg Clayton968fa382011-02-08 19:10:53 +0000446 {
Greg Clayton43d82792013-05-22 23:30:09 +0000447 result = ::fseek(m_stream, offset, SEEK_CUR);
448
449 if (error_ptr)
450 {
451 if (result == -1)
452 error_ptr->SetErrorToErrno();
453 else
454 error_ptr->Clear();
455 }
Greg Clayton968fa382011-02-08 19:10:53 +0000456 }
Greg Clayton43d82792013-05-22 23:30:09 +0000457 else if (error_ptr)
458 {
459 error_ptr->SetErrorString("invalid file handle");
460 }
461 return result;
Greg Clayton968fa382011-02-08 19:10:53 +0000462}
463
Greg Clayton43d82792013-05-22 23:30:09 +0000464off_t
465File::SeekFromEnd (off_t offset, Error *error_ptr)
Greg Clayton968fa382011-02-08 19:10:53 +0000466{
Greg Clayton43d82792013-05-22 23:30:09 +0000467 off_t result = -1;
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000468 if (DescriptorIsValid())
Greg Clayton968fa382011-02-08 19:10:53 +0000469 {
Greg Clayton43d82792013-05-22 23:30:09 +0000470 result = ::lseek (m_descriptor, offset, SEEK_END);
Greg Clayton968fa382011-02-08 19:10:53 +0000471
Greg Clayton43d82792013-05-22 23:30:09 +0000472 if (error_ptr)
473 {
474 if (result == -1)
475 error_ptr->SetErrorToErrno();
476 else
477 error_ptr->Clear();
478 }
Greg Clayton968fa382011-02-08 19:10:53 +0000479 }
Greg Clayton43d82792013-05-22 23:30:09 +0000480 else if (StreamIsValid ())
Greg Clayton968fa382011-02-08 19:10:53 +0000481 {
Greg Clayton43d82792013-05-22 23:30:09 +0000482 result = ::fseek(m_stream, offset, SEEK_END);
483
484 if (error_ptr)
485 {
486 if (result == -1)
487 error_ptr->SetErrorToErrno();
488 else
489 error_ptr->Clear();
490 }
Greg Clayton968fa382011-02-08 19:10:53 +0000491 }
Greg Clayton43d82792013-05-22 23:30:09 +0000492 else if (error_ptr)
493 {
494 error_ptr->SetErrorString("invalid file handle");
495 }
496 return result;
Greg Clayton968fa382011-02-08 19:10:53 +0000497}
498
499Error
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000500File::Flush ()
501{
502 Error error;
503 if (StreamIsValid())
504 {
Greg Clayton96c09682012-01-04 22:56:43 +0000505 int err = 0;
506 do
507 {
508 err = ::fflush (m_stream);
509 } while (err == EOF && errno == EINTR);
510
511 if (err == EOF)
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000512 error.SetErrorToErrno();
513 }
514 else if (!DescriptorIsValid())
515 {
516 error.SetErrorString("invalid file handle");
517 }
518 return error;
519}
520
521
522Error
Greg Clayton968fa382011-02-08 19:10:53 +0000523File::Sync ()
524{
525 Error error;
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000526 if (DescriptorIsValid())
Greg Clayton968fa382011-02-08 19:10:53 +0000527 {
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000528#ifdef _WIN32
529 int err = FlushFileBuffers((HANDLE)_get_osfhandle(m_descriptor));
530 if (err == 0)
531 error.SetErrorToGenericError();
532#else
Greg Clayton96c09682012-01-04 22:56:43 +0000533 int err = 0;
534 do
535 {
536 err = ::fsync (m_descriptor);
537 } while (err == -1 && errno == EINTR);
538
539 if (err == -1)
Greg Clayton968fa382011-02-08 19:10:53 +0000540 error.SetErrorToErrno();
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000541#endif
Greg Clayton968fa382011-02-08 19:10:53 +0000542 }
543 else
544 {
545 error.SetErrorString("invalid file handle");
546 }
547 return error;
548}
Greg Clayton846b64b2011-02-08 19:54:44 +0000549
Greg Clayton504f89a2011-02-08 17:49:02 +0000550Error
551File::Read (void *buf, size_t &num_bytes)
552{
553 Error error;
Greg Clayton96c09682012-01-04 22:56:43 +0000554 ssize_t bytes_read = -1;
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000555 if (DescriptorIsValid())
Greg Clayton504f89a2011-02-08 17:49:02 +0000556 {
Greg Clayton96c09682012-01-04 22:56:43 +0000557 do
558 {
559 bytes_read = ::read (m_descriptor, buf, num_bytes);
560 } while (bytes_read < 0 && errno == EINTR);
561
Greg Clayton504f89a2011-02-08 17:49:02 +0000562 if (bytes_read == -1)
563 {
564 error.SetErrorToErrno();
565 num_bytes = 0;
566 }
567 else
568 num_bytes = bytes_read;
569 }
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000570 else if (StreamIsValid())
571 {
Greg Clayton96c09682012-01-04 22:56:43 +0000572 bytes_read = ::fread (buf, 1, num_bytes, m_stream);
573
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000574 if (bytes_read == 0)
575 {
576 if (::feof(m_stream))
577 error.SetErrorString ("feof");
578 else if (::ferror (m_stream))
579 error.SetErrorString ("ferror");
580 num_bytes = 0;
581 }
582 else
583 num_bytes = bytes_read;
584 }
Greg Clayton504f89a2011-02-08 17:49:02 +0000585 else
586 {
587 num_bytes = 0;
588 error.SetErrorString("invalid file handle");
589 }
590 return error;
591}
592
593Error
594File::Write (const void *buf, size_t &num_bytes)
595{
596 Error error;
Greg Clayton96c09682012-01-04 22:56:43 +0000597 ssize_t bytes_written = -1;
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000598 if (DescriptorIsValid())
Greg Clayton504f89a2011-02-08 17:49:02 +0000599 {
Greg Clayton96c09682012-01-04 22:56:43 +0000600 do
601 {
602 bytes_written = ::write (m_descriptor, buf, num_bytes);
603 } while (bytes_written < 0 && errno == EINTR);
604
Greg Clayton504f89a2011-02-08 17:49:02 +0000605 if (bytes_written == -1)
606 {
607 error.SetErrorToErrno();
608 num_bytes = 0;
609 }
610 else
611 num_bytes = bytes_written;
612 }
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000613 else if (StreamIsValid())
614 {
Greg Clayton96c09682012-01-04 22:56:43 +0000615 bytes_written = ::fwrite (buf, 1, num_bytes, m_stream);
616
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000617 if (bytes_written == 0)
618 {
619 if (::feof(m_stream))
620 error.SetErrorString ("feof");
621 else if (::ferror (m_stream))
622 error.SetErrorString ("ferror");
623 num_bytes = 0;
624 }
625 else
626 num_bytes = bytes_written;
627
628 }
Greg Clayton504f89a2011-02-08 17:49:02 +0000629 else
630 {
631 num_bytes = 0;
632 error.SetErrorString("invalid file handle");
633 }
634 return error;
635}
636
Greg Clayton846b64b2011-02-08 19:54:44 +0000637
638Error
639File::Read (void *buf, size_t &num_bytes, off_t &offset)
640{
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000641#ifndef _WIN32
Greg Clayton846b64b2011-02-08 19:54:44 +0000642 Error error;
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000643 int fd = GetDescriptor();
644 if (fd != kInvalidDescriptor)
Greg Clayton846b64b2011-02-08 19:54:44 +0000645 {
Greg Clayton96c09682012-01-04 22:56:43 +0000646 ssize_t bytes_read = -1;
647 do
648 {
649 bytes_read = ::pread (fd, buf, num_bytes, offset);
650 } while (bytes_read < 0 && errno == EINTR);
651
Greg Clayton846b64b2011-02-08 19:54:44 +0000652 if (bytes_read < 0)
653 {
654 num_bytes = 0;
655 error.SetErrorToErrno();
656 }
657 else
658 {
659 offset += bytes_read;
660 num_bytes = bytes_read;
661 }
662 }
663 else
664 {
665 num_bytes = 0;
666 error.SetErrorString("invalid file handle");
667 }
668 return error;
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000669#else
670 long cur = ::lseek(m_descriptor, 0, SEEK_CUR);
671 SeekFromStart(offset);
672 Error error = Read(buf, num_bytes);
673 if (!error.Fail())
674 SeekFromStart(cur);
675 return error;
676#endif
Greg Clayton846b64b2011-02-08 19:54:44 +0000677}
678
679Error
Greg Clayton0b0b5122012-08-30 18:15:10 +0000680File::Read (size_t &num_bytes, off_t &offset, bool null_terminate, DataBufferSP &data_buffer_sp)
Greg Clayton96c09682012-01-04 22:56:43 +0000681{
682 Error error;
683
684 if (num_bytes > 0)
685 {
686 int fd = GetDescriptor();
687 if (fd != kInvalidDescriptor)
688 {
689 struct stat file_stats;
690 if (::fstat (fd, &file_stats) == 0)
691 {
692 if (file_stats.st_size > offset)
693 {
694 const size_t bytes_left = file_stats.st_size - offset;
695 if (num_bytes > bytes_left)
696 num_bytes = bytes_left;
697
Greg Clayton7b0992d2013-04-18 22:45:39 +0000698 std::unique_ptr<DataBufferHeap> data_heap_ap;
Greg Clayton0b0b5122012-08-30 18:15:10 +0000699 data_heap_ap.reset(new DataBufferHeap(num_bytes + (null_terminate ? 1 : 0), '\0'));
Greg Clayton96c09682012-01-04 22:56:43 +0000700
701 if (data_heap_ap.get())
702 {
703 error = Read (data_heap_ap->GetBytes(), num_bytes, offset);
704 if (error.Success())
705 {
706 // Make sure we read exactly what we asked for and if we got
707 // less, adjust the array
708 if (num_bytes < data_heap_ap->GetByteSize())
709 data_heap_ap->SetByteSize(num_bytes);
710 data_buffer_sp.reset(data_heap_ap.release());
711 return error;
712 }
713 }
714 }
715 else
716 error.SetErrorString("file is empty");
717 }
718 else
719 error.SetErrorToErrno();
720 }
721 else
722 error.SetErrorString("invalid file handle");
723 }
724 else
725 error.SetErrorString("invalid file handle");
726
727 num_bytes = 0;
728 data_buffer_sp.reset();
729 return error;
730}
731
732Error
Greg Clayton846b64b2011-02-08 19:54:44 +0000733File::Write (const void *buf, size_t &num_bytes, off_t &offset)
734{
735 Error error;
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000736 int fd = GetDescriptor();
737 if (fd != kInvalidDescriptor)
Greg Clayton846b64b2011-02-08 19:54:44 +0000738 {
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000739#ifndef _WIN32
Greg Clayton96c09682012-01-04 22:56:43 +0000740 ssize_t bytes_written = -1;
741 do
742 {
743 bytes_written = ::pwrite (m_descriptor, buf, num_bytes, offset);
744 } while (bytes_written < 0 && errno == EINTR);
745
Greg Clayton846b64b2011-02-08 19:54:44 +0000746 if (bytes_written < 0)
747 {
748 num_bytes = 0;
749 error.SetErrorToErrno();
750 }
751 else
752 {
753 offset += bytes_written;
754 num_bytes = bytes_written;
755 }
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000756#else
757 long cur = ::lseek(m_descriptor, 0, SEEK_CUR);
758 error = Write(buf, num_bytes);
759 long after = ::lseek(m_descriptor, 0, SEEK_CUR);
760
761 if (!error.Fail())
762 SeekFromStart(cur);
763
764 ssize_t bytes_written = after - cur;
765 offset = after;
766#endif
Greg Clayton846b64b2011-02-08 19:54:44 +0000767 }
768 else
769 {
770 num_bytes = 0;
771 error.SetErrorString("invalid file handle");
772 }
773 return error;
774}
775
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000776//------------------------------------------------------------------
777// Print some formatted output to the stream.
778//------------------------------------------------------------------
Greg Claytonc7bece562013-01-25 18:06:21 +0000779size_t
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000780File::Printf (const char *format, ...)
781{
782 va_list args;
783 va_start (args, format);
Greg Claytonc7bece562013-01-25 18:06:21 +0000784 size_t result = PrintfVarArg (format, args);
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000785 va_end (args);
786 return result;
787}
Greg Clayton846b64b2011-02-08 19:54:44 +0000788
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000789//------------------------------------------------------------------
790// Print some formatted output to the stream.
791//------------------------------------------------------------------
Greg Claytonc7bece562013-01-25 18:06:21 +0000792size_t
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000793File::PrintfVarArg (const char *format, va_list args)
794{
Greg Claytonc7bece562013-01-25 18:06:21 +0000795 size_t result = 0;
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000796 if (DescriptorIsValid())
797 {
798 char *s = NULL;
799 result = vasprintf(&s, format, args);
800 if (s != NULL)
801 {
802 if (result > 0)
803 {
804 size_t s_len = result;
805 Write (s, s_len);
806 result = s_len;
807 }
808 free (s);
809 }
810 }
811 else if (StreamIsValid())
812 {
813 result = ::vfprintf (m_stream, format, args);
814 }
815 return result;
816}
Daniel Maleae0f8f572013-08-26 23:57:52 +0000817
818mode_t
819File::ConvertOpenOptionsForPOSIXOpen (uint32_t open_options)
820{
821 mode_t mode = 0;
822 if (open_options & eOpenOptionRead && open_options & eOpenOptionWrite)
823 mode |= O_RDWR;
824 else if (open_options & eOpenOptionWrite)
825 mode |= O_WRONLY;
826
827 if (open_options & eOpenOptionAppend)
828 mode |= O_APPEND;
829
830 if (open_options & eOpenOptionTruncate)
831 mode |= O_TRUNC;
832
833 if (open_options & eOpenOptionNonBlocking)
834 mode |= O_NONBLOCK;
835
836 if (open_options & eOpenOptionCanCreateNewOnly)
837 mode |= O_CREAT | O_EXCL;
838 else if (open_options & eOpenOptionCanCreate)
839 mode |= O_CREAT;
840
841 return mode;
842}