blob: 91fc8bd6b7beedc855c1a750b0262e307ea20c58 [file] [log] [blame]
Greg Claytonfbb76342013-11-20 21:07:01 +00001//===-- File.cpp ------------------------------------------------*- C++ -*-===//
Greg Clayton504f89a2011-02-08 17:49:02 +00002//
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
Greg Clayton504f89a2011-02-08 17:49:02 +000010#include "lldb/Host/File.h"
11
Greg Clayton96c09682012-01-04 22:56:43 +000012#include <errno.h>
Greg Clayton504f89a2011-02-08 17:49:02 +000013#include <fcntl.h>
Stephen Wilson8acdbb82011-04-08 13:36:44 +000014#include <limits.h>
Greg Claytonf4dd5432011-02-09 21:12:40 +000015#include <stdarg.h>
Greg Clayton2b4d9b72011-04-01 18:18:34 +000016#include <sys/stat.h>
Greg Clayton504f89a2011-02-08 17:49:02 +000017
Virgile Bellob2f1fb22013-08-23 12:44:05 +000018#ifdef _WIN32
19#include "lldb/Host/windows/windows.h"
20#endif
21
Greg Clayton96c09682012-01-04 22:56:43 +000022#include "lldb/Core/DataBufferHeap.h"
Greg Clayton504f89a2011-02-08 17:49:02 +000023#include "lldb/Core/Error.h"
Greg Clayton925137c2011-02-09 01:16:43 +000024#include "lldb/Host/Config.h"
Greg Clayton846b64b2011-02-08 19:54:44 +000025#include "lldb/Host/FileSpec.h"
Greg Clayton504f89a2011-02-08 17:49:02 +000026
27using namespace lldb;
28using namespace lldb_private;
29
Greg Clayton51b1e2d2011-02-09 01:08:52 +000030static const char *
31GetStreamOpenModeFromOptions (uint32_t options)
32{
33 if (options & File::eOpenOptionAppend)
34 {
35 if (options & File::eOpenOptionRead)
36 {
37 if (options & File::eOpenOptionCanCreateNewOnly)
38 return "a+x";
39 else
40 return "a+";
41 }
42 else if (options & File::eOpenOptionWrite)
43 {
44 if (options & File::eOpenOptionCanCreateNewOnly)
45 return "ax";
46 else
47 return "a";
48 }
49 }
50 else if (options & File::eOpenOptionRead && options & File::eOpenOptionWrite)
51 {
52 if (options & File::eOpenOptionCanCreate)
53 {
54 if (options & File::eOpenOptionCanCreateNewOnly)
55 return "w+x";
56 else
57 return "w+";
58 }
59 else
60 return "r+";
61 }
62 else if (options & File::eOpenOptionRead)
63 {
64 return "r";
65 }
66 else if (options & File::eOpenOptionWrite)
67 {
68 return "w";
69 }
70 return NULL;
71}
72
73int File::kInvalidDescriptor = -1;
74FILE * File::kInvalidStream = NULL;
75
Greg Clayton504f89a2011-02-08 17:49:02 +000076File::File(const char *path, uint32_t options, uint32_t permissions) :
Greg Clayton51b1e2d2011-02-09 01:08:52 +000077 m_descriptor (kInvalidDescriptor),
78 m_stream (kInvalidStream),
79 m_options (0),
80 m_owned (false)
Greg Clayton504f89a2011-02-08 17:49:02 +000081{
82 Open (path, options, permissions);
83}
84
Daniel Maleae0f8f572013-08-26 23:57:52 +000085File::File (const FileSpec& filespec,
86 uint32_t options,
87 uint32_t permissions) :
88 m_descriptor (kInvalidDescriptor),
89 m_stream (kInvalidStream),
90 m_options (0),
91 m_owned (false)
92{
93 if (filespec)
94 {
95 Open (filespec.GetPath().c_str(), options, permissions);
96 }
97}
98
Greg Clayton51b1e2d2011-02-09 01:08:52 +000099File::File (const File &rhs) :
100 m_descriptor (kInvalidDescriptor),
101 m_stream (kInvalidStream),
102 m_options (0),
103 m_owned (false)
104{
105 Duplicate (rhs);
106}
107
108
109File &
110File::operator = (const File &rhs)
111{
112 if (this != &rhs)
113 Duplicate (rhs);
114 return *this;
115}
116
Greg Clayton504f89a2011-02-08 17:49:02 +0000117File::~File()
118{
119 Close ();
120}
121
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000122
123int
124File::GetDescriptor() const
125{
126 if (DescriptorIsValid())
127 return m_descriptor;
128
129 // Don't open the file descriptor if we don't need to, just get it from the
130 // stream if we have one.
131 if (StreamIsValid())
132 return fileno (m_stream);
133
134 // Invalid descriptor and invalid stream, return invalid descriptor.
135 return kInvalidDescriptor;
136}
137
138void
139File::SetDescriptor (int fd, bool transfer_ownership)
140{
141 if (IsValid())
142 Close();
143 m_descriptor = fd;
144 m_owned = transfer_ownership;
145}
146
147
148FILE *
149File::GetStream ()
150{
151 if (!StreamIsValid())
152 {
153 if (DescriptorIsValid())
154 {
155 const char *mode = GetStreamOpenModeFromOptions (m_options);
156 if (mode)
Greg Clayton96c09682012-01-04 22:56:43 +0000157 {
158 do
159 {
160 m_stream = ::fdopen (m_descriptor, mode);
161 } while (m_stream == NULL && errno == EINTR);
162 }
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000163 }
164 }
165 return m_stream;
166}
167
168
169void
170File::SetStream (FILE *fh, bool transfer_ownership)
171{
172 if (IsValid())
173 Close();
174 m_stream = fh;
175 m_owned = transfer_ownership;
176}
177
178Error
179File::Duplicate (const File &rhs)
180{
181 Error error;
182 if (IsValid ())
183 Close();
184
185 if (rhs.DescriptorIsValid())
186 {
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000187#ifdef _WIN32
188 m_descriptor = ::_dup(rhs.GetDescriptor());
189#else
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000190 m_descriptor = ::fcntl(rhs.GetDescriptor(), F_DUPFD);
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000191#endif
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000192 if (!DescriptorIsValid())
193 error.SetErrorToErrno();
194 else
195 {
196 m_options = rhs.m_options;
197 m_owned = true;
198 }
199 }
200 else
201 {
202 error.SetErrorString ("invalid file to duplicate");
203 }
204 return error;
205}
206
Greg Clayton504f89a2011-02-08 17:49:02 +0000207Error
208File::Open (const char *path, uint32_t options, uint32_t permissions)
209{
210 Error error;
211 if (IsValid())
212 Close ();
213
214 int oflag = 0;
Greg Clayton96c09682012-01-04 22:56:43 +0000215 const bool read = options & eOpenOptionRead;
216 const bool write = options & eOpenOptionWrite;
217 if (write)
218 {
219 if (read)
220 oflag |= O_RDWR;
221 else
222 oflag |= O_WRONLY;
223
224 if (options & eOpenOptionAppend)
225 oflag |= O_APPEND;
226
227 if (options & eOpenOptionTruncate)
228 oflag |= O_TRUNC;
229
230 if (options & eOpenOptionCanCreate)
231 oflag |= O_CREAT;
232
233 if (options & eOpenOptionCanCreateNewOnly)
234 oflag |= O_CREAT | O_EXCL;
235 }
236 else if (read)
237 {
Greg Clayton504f89a2011-02-08 17:49:02 +0000238 oflag |= O_RDONLY;
Greg Claytonfbb76342013-11-20 21:07:01 +0000239
240 if (options & eOpenoptionDontFollowSymlinks)
241 oflag |= O_NOFOLLOW;
Greg Clayton96c09682012-01-04 22:56:43 +0000242 }
Greg Clayton504f89a2011-02-08 17:49:02 +0000243
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000244#ifndef _WIN32
Greg Clayton504f89a2011-02-08 17:49:02 +0000245 if (options & eOpenOptionNonBlocking)
246 oflag |= O_NONBLOCK;
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000247#else
248 oflag |= O_BINARY;
249#endif
Greg Clayton504f89a2011-02-08 17:49:02 +0000250
Greg Clayton504f89a2011-02-08 17:49:02 +0000251 mode_t mode = 0;
Greg Clayton96c09682012-01-04 22:56:43 +0000252 if (oflag & O_CREAT)
253 {
Greg Claytonfbb76342013-11-20 21:07:01 +0000254 if (permissions & lldb::eFilePermissionsUserRead) mode |= S_IRUSR;
255 if (permissions & lldb::eFilePermissionsUserWrite) mode |= S_IWUSR;
256 if (permissions & lldb::eFilePermissionsUserExecute) mode |= S_IXUSR;
257 if (permissions & lldb::eFilePermissionsGroupRead) mode |= S_IRGRP;
258 if (permissions & lldb::eFilePermissionsGroupWrite) mode |= S_IWGRP;
259 if (permissions & lldb::eFilePermissionsGroupExecute) mode |= S_IXGRP;
260 if (permissions & lldb::eFilePermissionsWorldRead) mode |= S_IROTH;
261 if (permissions & lldb::eFilePermissionsWorldWrite) mode |= S_IWOTH;
262 if (permissions & lldb::eFilePermissionsWorldExecute) mode |= S_IXOTH;
Greg Clayton96c09682012-01-04 22:56:43 +0000263 }
Greg Clayton504f89a2011-02-08 17:49:02 +0000264
Greg Clayton96c09682012-01-04 22:56:43 +0000265 do
266 {
267 m_descriptor = ::open(path, oflag, mode);
268 } while (m_descriptor < 0 && errno == EINTR);
269
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000270 if (!DescriptorIsValid())
Greg Clayton504f89a2011-02-08 17:49:02 +0000271 error.SetErrorToErrno();
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000272 else
273 m_owned = true;
Greg Clayton504f89a2011-02-08 17:49:02 +0000274
275 return error;
276}
277
Daniel Maleae0f8f572013-08-26 23:57:52 +0000278uint32_t
279File::GetPermissions (const char *path, Error &error)
280{
281 if (path && path[0])
282 {
283 struct stat file_stats;
284 if (::stat (path, &file_stats) == -1)
285 error.SetErrorToErrno();
286 else
287 {
288 error.Clear();
Greg Claytonc0293822013-11-22 18:46:55 +0000289 return file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
Daniel Maleae0f8f572013-08-26 23:57:52 +0000290 }
291 }
292 else
293 {
294 if (path)
295 error.SetErrorString ("invalid path");
296 else
297 error.SetErrorString ("empty path");
298 }
299 return 0;
300}
301
302uint32_t
303File::GetPermissions(Error &error) const
304{
305 int fd = GetDescriptor();
306 if (fd != kInvalidDescriptor)
307 {
308 struct stat file_stats;
309 if (::fstat (fd, &file_stats) == -1)
310 error.SetErrorToErrno();
311 else
312 {
313 error.Clear();
Greg Claytonc0293822013-11-22 18:46:55 +0000314 return file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
Daniel Maleae0f8f572013-08-26 23:57:52 +0000315 }
316 }
317 else
318 {
319 error.SetErrorString ("invalid file descriptor");
320 }
321 return 0;
322}
323
324
Greg Clayton504f89a2011-02-08 17:49:02 +0000325Error
326File::Close ()
327{
328 Error error;
329 if (IsValid ())
330 {
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000331 if (m_owned)
332 {
333 if (StreamIsValid())
334 {
335 if (::fclose (m_stream) == EOF)
336 error.SetErrorToErrno();
337 }
338
339 if (DescriptorIsValid())
340 {
341 if (::close (m_descriptor) != 0)
342 error.SetErrorToErrno();
343 }
344 }
345 m_descriptor = kInvalidDescriptor;
346 m_stream = kInvalidStream;
347 m_options = 0;
348 m_owned = false;
Greg Clayton504f89a2011-02-08 17:49:02 +0000349 }
350 return error;
351}
Greg Clayton968fa382011-02-08 19:10:53 +0000352
353
354Error
355File::GetFileSpec (FileSpec &file_spec) const
356{
357 Error error;
Greg Clayton925137c2011-02-09 01:16:43 +0000358#ifdef LLDB_CONFIG_FCNTL_GETPATH_SUPPORTED
Greg Clayton968fa382011-02-08 19:10:53 +0000359 if (IsValid ())
360 {
361 char path[PATH_MAX];
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000362 if (::fcntl(GetDescriptor(), F_GETPATH, path) == -1)
Greg Clayton968fa382011-02-08 19:10:53 +0000363 error.SetErrorToErrno();
364 else
365 file_spec.SetFile (path, false);
366 }
367 else
Greg Clayton925137c2011-02-09 01:16:43 +0000368 {
Greg Clayton968fa382011-02-08 19:10:53 +0000369 error.SetErrorString("invalid file handle");
Greg Clayton925137c2011-02-09 01:16:43 +0000370 }
Greg Clayton94d08622011-02-09 07:19:18 +0000371#elif defined(__linux__)
372 char proc[64];
373 char path[PATH_MAX];
374 if (::snprintf(proc, sizeof(proc), "/proc/self/fd/%d", GetDescriptor()) < 0)
Greg Clayton86edbf42011-10-26 00:56:27 +0000375 error.SetErrorString ("cannot resolve file descriptor");
Greg Clayton94d08622011-02-09 07:19:18 +0000376 else
377 {
378 ssize_t len;
379 if ((len = ::readlink(proc, path, sizeof(path) - 1)) == -1)
380 error.SetErrorToErrno();
381 else
382 {
383 path[len] = '\0';
384 file_spec.SetFile (path, false);
385 }
386 }
Greg Clayton925137c2011-02-09 01:16:43 +0000387#else
Greg Clayton94d08622011-02-09 07:19:18 +0000388 error.SetErrorString ("File::GetFileSpec is not supported on this platform");
Greg Clayton925137c2011-02-09 01:16:43 +0000389#endif
Greg Clayton968fa382011-02-08 19:10:53 +0000390
391 if (error.Fail())
392 file_spec.Clear();
393 return error;
394}
395
Greg Clayton43d82792013-05-22 23:30:09 +0000396off_t
397File::SeekFromStart (off_t offset, Error *error_ptr)
Greg Clayton968fa382011-02-08 19:10:53 +0000398{
Greg Clayton43d82792013-05-22 23:30:09 +0000399 off_t result = 0;
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000400 if (DescriptorIsValid())
Greg Clayton968fa382011-02-08 19:10:53 +0000401 {
Greg Clayton43d82792013-05-22 23:30:09 +0000402 result = ::lseek (m_descriptor, offset, SEEK_SET);
Greg Clayton968fa382011-02-08 19:10:53 +0000403
Greg Clayton43d82792013-05-22 23:30:09 +0000404 if (error_ptr)
405 {
406 if (result == -1)
407 error_ptr->SetErrorToErrno();
408 else
409 error_ptr->Clear();
410 }
Greg Clayton968fa382011-02-08 19:10:53 +0000411 }
Greg Clayton43d82792013-05-22 23:30:09 +0000412 else if (StreamIsValid ())
Greg Clayton968fa382011-02-08 19:10:53 +0000413 {
Greg Clayton43d82792013-05-22 23:30:09 +0000414 result = ::fseek(m_stream, offset, SEEK_SET);
415
416 if (error_ptr)
417 {
418 if (result == -1)
419 error_ptr->SetErrorToErrno();
420 else
421 error_ptr->Clear();
422 }
Greg Clayton968fa382011-02-08 19:10:53 +0000423 }
Greg Clayton43d82792013-05-22 23:30:09 +0000424 else if (error_ptr)
425 {
426 error_ptr->SetErrorString("invalid file handle");
427 }
428 return result;
Greg Clayton968fa382011-02-08 19:10:53 +0000429}
430
Greg Clayton43d82792013-05-22 23:30:09 +0000431off_t
432File::SeekFromCurrent (off_t offset, Error *error_ptr)
Greg Clayton968fa382011-02-08 19:10:53 +0000433{
Greg Clayton43d82792013-05-22 23:30:09 +0000434 off_t result = -1;
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000435 if (DescriptorIsValid())
Greg Clayton968fa382011-02-08 19:10:53 +0000436 {
Greg Clayton43d82792013-05-22 23:30:09 +0000437 result = ::lseek (m_descriptor, offset, SEEK_CUR);
Greg Clayton968fa382011-02-08 19:10:53 +0000438
Greg Clayton43d82792013-05-22 23:30:09 +0000439 if (error_ptr)
440 {
441 if (result == -1)
442 error_ptr->SetErrorToErrno();
443 else
444 error_ptr->Clear();
445 }
Greg Clayton968fa382011-02-08 19:10:53 +0000446 }
Greg Clayton43d82792013-05-22 23:30:09 +0000447 else if (StreamIsValid ())
Greg Clayton968fa382011-02-08 19:10:53 +0000448 {
Greg Clayton43d82792013-05-22 23:30:09 +0000449 result = ::fseek(m_stream, offset, SEEK_CUR);
450
451 if (error_ptr)
452 {
453 if (result == -1)
454 error_ptr->SetErrorToErrno();
455 else
456 error_ptr->Clear();
457 }
Greg Clayton968fa382011-02-08 19:10:53 +0000458 }
Greg Clayton43d82792013-05-22 23:30:09 +0000459 else if (error_ptr)
460 {
461 error_ptr->SetErrorString("invalid file handle");
462 }
463 return result;
Greg Clayton968fa382011-02-08 19:10:53 +0000464}
465
Greg Clayton43d82792013-05-22 23:30:09 +0000466off_t
467File::SeekFromEnd (off_t offset, Error *error_ptr)
Greg Clayton968fa382011-02-08 19:10:53 +0000468{
Greg Clayton43d82792013-05-22 23:30:09 +0000469 off_t result = -1;
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000470 if (DescriptorIsValid())
Greg Clayton968fa382011-02-08 19:10:53 +0000471 {
Greg Clayton43d82792013-05-22 23:30:09 +0000472 result = ::lseek (m_descriptor, offset, SEEK_END);
Greg Clayton968fa382011-02-08 19:10:53 +0000473
Greg Clayton43d82792013-05-22 23:30:09 +0000474 if (error_ptr)
475 {
476 if (result == -1)
477 error_ptr->SetErrorToErrno();
478 else
479 error_ptr->Clear();
480 }
Greg Clayton968fa382011-02-08 19:10:53 +0000481 }
Greg Clayton43d82792013-05-22 23:30:09 +0000482 else if (StreamIsValid ())
Greg Clayton968fa382011-02-08 19:10:53 +0000483 {
Greg Clayton43d82792013-05-22 23:30:09 +0000484 result = ::fseek(m_stream, offset, SEEK_END);
485
486 if (error_ptr)
487 {
488 if (result == -1)
489 error_ptr->SetErrorToErrno();
490 else
491 error_ptr->Clear();
492 }
Greg Clayton968fa382011-02-08 19:10:53 +0000493 }
Greg Clayton43d82792013-05-22 23:30:09 +0000494 else if (error_ptr)
495 {
496 error_ptr->SetErrorString("invalid file handle");
497 }
498 return result;
Greg Clayton968fa382011-02-08 19:10:53 +0000499}
500
501Error
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000502File::Flush ()
503{
504 Error error;
505 if (StreamIsValid())
506 {
Greg Clayton96c09682012-01-04 22:56:43 +0000507 int err = 0;
508 do
509 {
510 err = ::fflush (m_stream);
511 } while (err == EOF && errno == EINTR);
512
513 if (err == EOF)
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000514 error.SetErrorToErrno();
515 }
516 else if (!DescriptorIsValid())
517 {
518 error.SetErrorString("invalid file handle");
519 }
520 return error;
521}
522
523
524Error
Greg Clayton968fa382011-02-08 19:10:53 +0000525File::Sync ()
526{
527 Error error;
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000528 if (DescriptorIsValid())
Greg Clayton968fa382011-02-08 19:10:53 +0000529 {
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000530#ifdef _WIN32
531 int err = FlushFileBuffers((HANDLE)_get_osfhandle(m_descriptor));
532 if (err == 0)
533 error.SetErrorToGenericError();
534#else
Greg Clayton96c09682012-01-04 22:56:43 +0000535 int err = 0;
536 do
537 {
538 err = ::fsync (m_descriptor);
539 } while (err == -1 && errno == EINTR);
540
541 if (err == -1)
Greg Clayton968fa382011-02-08 19:10:53 +0000542 error.SetErrorToErrno();
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000543#endif
Greg Clayton968fa382011-02-08 19:10:53 +0000544 }
545 else
546 {
547 error.SetErrorString("invalid file handle");
548 }
549 return error;
550}
Greg Clayton846b64b2011-02-08 19:54:44 +0000551
Greg Clayton504f89a2011-02-08 17:49:02 +0000552Error
553File::Read (void *buf, size_t &num_bytes)
554{
555 Error error;
Greg Clayton96c09682012-01-04 22:56:43 +0000556 ssize_t bytes_read = -1;
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000557 if (DescriptorIsValid())
Greg Clayton504f89a2011-02-08 17:49:02 +0000558 {
Greg Clayton96c09682012-01-04 22:56:43 +0000559 do
560 {
561 bytes_read = ::read (m_descriptor, buf, num_bytes);
562 } while (bytes_read < 0 && errno == EINTR);
563
Greg Clayton504f89a2011-02-08 17:49:02 +0000564 if (bytes_read == -1)
565 {
566 error.SetErrorToErrno();
567 num_bytes = 0;
568 }
569 else
570 num_bytes = bytes_read;
571 }
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000572 else if (StreamIsValid())
573 {
Greg Clayton96c09682012-01-04 22:56:43 +0000574 bytes_read = ::fread (buf, 1, num_bytes, m_stream);
575
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000576 if (bytes_read == 0)
577 {
578 if (::feof(m_stream))
579 error.SetErrorString ("feof");
580 else if (::ferror (m_stream))
581 error.SetErrorString ("ferror");
582 num_bytes = 0;
583 }
584 else
585 num_bytes = bytes_read;
586 }
Greg Clayton504f89a2011-02-08 17:49:02 +0000587 else
588 {
589 num_bytes = 0;
590 error.SetErrorString("invalid file handle");
591 }
592 return error;
593}
594
595Error
596File::Write (const void *buf, size_t &num_bytes)
597{
598 Error error;
Greg Clayton96c09682012-01-04 22:56:43 +0000599 ssize_t bytes_written = -1;
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000600 if (DescriptorIsValid())
Greg Clayton504f89a2011-02-08 17:49:02 +0000601 {
Greg Clayton96c09682012-01-04 22:56:43 +0000602 do
603 {
604 bytes_written = ::write (m_descriptor, buf, num_bytes);
605 } while (bytes_written < 0 && errno == EINTR);
606
Greg Clayton504f89a2011-02-08 17:49:02 +0000607 if (bytes_written == -1)
608 {
609 error.SetErrorToErrno();
610 num_bytes = 0;
611 }
612 else
613 num_bytes = bytes_written;
614 }
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000615 else if (StreamIsValid())
616 {
Greg Clayton96c09682012-01-04 22:56:43 +0000617 bytes_written = ::fwrite (buf, 1, num_bytes, m_stream);
618
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000619 if (bytes_written == 0)
620 {
621 if (::feof(m_stream))
622 error.SetErrorString ("feof");
623 else if (::ferror (m_stream))
624 error.SetErrorString ("ferror");
625 num_bytes = 0;
626 }
627 else
628 num_bytes = bytes_written;
629
630 }
Greg Clayton504f89a2011-02-08 17:49:02 +0000631 else
632 {
633 num_bytes = 0;
634 error.SetErrorString("invalid file handle");
635 }
636 return error;
637}
638
Greg Clayton846b64b2011-02-08 19:54:44 +0000639
640Error
641File::Read (void *buf, size_t &num_bytes, off_t &offset)
642{
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000643#ifndef _WIN32
Greg Clayton846b64b2011-02-08 19:54:44 +0000644 Error error;
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000645 int fd = GetDescriptor();
646 if (fd != kInvalidDescriptor)
Greg Clayton846b64b2011-02-08 19:54:44 +0000647 {
Greg Clayton96c09682012-01-04 22:56:43 +0000648 ssize_t bytes_read = -1;
649 do
650 {
651 bytes_read = ::pread (fd, buf, num_bytes, offset);
652 } while (bytes_read < 0 && errno == EINTR);
653
Greg Clayton846b64b2011-02-08 19:54:44 +0000654 if (bytes_read < 0)
655 {
656 num_bytes = 0;
657 error.SetErrorToErrno();
658 }
659 else
660 {
661 offset += bytes_read;
662 num_bytes = bytes_read;
663 }
664 }
665 else
666 {
667 num_bytes = 0;
668 error.SetErrorString("invalid file handle");
669 }
670 return error;
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000671#else
672 long cur = ::lseek(m_descriptor, 0, SEEK_CUR);
673 SeekFromStart(offset);
674 Error error = Read(buf, num_bytes);
675 if (!error.Fail())
676 SeekFromStart(cur);
677 return error;
678#endif
Greg Clayton846b64b2011-02-08 19:54:44 +0000679}
680
681Error
Greg Clayton0b0b5122012-08-30 18:15:10 +0000682File::Read (size_t &num_bytes, off_t &offset, bool null_terminate, DataBufferSP &data_buffer_sp)
Greg Clayton96c09682012-01-04 22:56:43 +0000683{
684 Error error;
685
686 if (num_bytes > 0)
687 {
688 int fd = GetDescriptor();
689 if (fd != kInvalidDescriptor)
690 {
691 struct stat file_stats;
692 if (::fstat (fd, &file_stats) == 0)
693 {
694 if (file_stats.st_size > offset)
695 {
696 const size_t bytes_left = file_stats.st_size - offset;
697 if (num_bytes > bytes_left)
698 num_bytes = bytes_left;
699
Greg Clayton7b0992d2013-04-18 22:45:39 +0000700 std::unique_ptr<DataBufferHeap> data_heap_ap;
Greg Clayton0b0b5122012-08-30 18:15:10 +0000701 data_heap_ap.reset(new DataBufferHeap(num_bytes + (null_terminate ? 1 : 0), '\0'));
Greg Clayton96c09682012-01-04 22:56:43 +0000702
703 if (data_heap_ap.get())
704 {
705 error = Read (data_heap_ap->GetBytes(), num_bytes, offset);
706 if (error.Success())
707 {
708 // Make sure we read exactly what we asked for and if we got
709 // less, adjust the array
710 if (num_bytes < data_heap_ap->GetByteSize())
711 data_heap_ap->SetByteSize(num_bytes);
712 data_buffer_sp.reset(data_heap_ap.release());
713 return error;
714 }
715 }
716 }
717 else
718 error.SetErrorString("file is empty");
719 }
720 else
721 error.SetErrorToErrno();
722 }
723 else
724 error.SetErrorString("invalid file handle");
725 }
726 else
727 error.SetErrorString("invalid file handle");
728
729 num_bytes = 0;
730 data_buffer_sp.reset();
731 return error;
732}
733
734Error
Greg Clayton846b64b2011-02-08 19:54:44 +0000735File::Write (const void *buf, size_t &num_bytes, off_t &offset)
736{
737 Error error;
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000738 int fd = GetDescriptor();
739 if (fd != kInvalidDescriptor)
Greg Clayton846b64b2011-02-08 19:54:44 +0000740 {
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000741#ifndef _WIN32
Greg Clayton96c09682012-01-04 22:56:43 +0000742 ssize_t bytes_written = -1;
743 do
744 {
745 bytes_written = ::pwrite (m_descriptor, buf, num_bytes, offset);
746 } while (bytes_written < 0 && errno == EINTR);
747
Greg Clayton846b64b2011-02-08 19:54:44 +0000748 if (bytes_written < 0)
749 {
750 num_bytes = 0;
751 error.SetErrorToErrno();
752 }
753 else
754 {
755 offset += bytes_written;
756 num_bytes = bytes_written;
757 }
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000758#else
759 long cur = ::lseek(m_descriptor, 0, SEEK_CUR);
760 error = Write(buf, num_bytes);
761 long after = ::lseek(m_descriptor, 0, SEEK_CUR);
762
763 if (!error.Fail())
764 SeekFromStart(cur);
765
766 ssize_t bytes_written = after - cur;
767 offset = after;
768#endif
Greg Clayton846b64b2011-02-08 19:54:44 +0000769 }
770 else
771 {
772 num_bytes = 0;
773 error.SetErrorString("invalid file handle");
774 }
775 return error;
776}
777
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000778//------------------------------------------------------------------
779// Print some formatted output to the stream.
780//------------------------------------------------------------------
Greg Claytonc7bece562013-01-25 18:06:21 +0000781size_t
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000782File::Printf (const char *format, ...)
783{
784 va_list args;
785 va_start (args, format);
Greg Claytonc7bece562013-01-25 18:06:21 +0000786 size_t result = PrintfVarArg (format, args);
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000787 va_end (args);
788 return result;
789}
Greg Clayton846b64b2011-02-08 19:54:44 +0000790
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000791//------------------------------------------------------------------
792// Print some formatted output to the stream.
793//------------------------------------------------------------------
Greg Claytonc7bece562013-01-25 18:06:21 +0000794size_t
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000795File::PrintfVarArg (const char *format, va_list args)
796{
Greg Claytonc7bece562013-01-25 18:06:21 +0000797 size_t result = 0;
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000798 if (DescriptorIsValid())
799 {
800 char *s = NULL;
801 result = vasprintf(&s, format, args);
802 if (s != NULL)
803 {
804 if (result > 0)
805 {
806 size_t s_len = result;
807 Write (s, s_len);
808 result = s_len;
809 }
810 free (s);
811 }
812 }
813 else if (StreamIsValid())
814 {
815 result = ::vfprintf (m_stream, format, args);
816 }
817 return result;
818}
Daniel Maleae0f8f572013-08-26 23:57:52 +0000819
820mode_t
821File::ConvertOpenOptionsForPOSIXOpen (uint32_t open_options)
822{
823 mode_t mode = 0;
824 if (open_options & eOpenOptionRead && open_options & eOpenOptionWrite)
825 mode |= O_RDWR;
826 else if (open_options & eOpenOptionWrite)
827 mode |= O_WRONLY;
828
829 if (open_options & eOpenOptionAppend)
830 mode |= O_APPEND;
831
832 if (open_options & eOpenOptionTruncate)
833 mode |= O_TRUNC;
834
835 if (open_options & eOpenOptionNonBlocking)
836 mode |= O_NONBLOCK;
837
838 if (open_options & eOpenOptionCanCreateNewOnly)
839 mode |= O_CREAT | O_EXCL;
840 else if (open_options & eOpenOptionCanCreate)
841 mode |= O_CREAT;
842
843 return mode;
844}