blob: bbd11858aaba003bd648148f460ce78f26325e8c [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
Colin Riley909bb7a2013-11-26 15:10:46 +0000240#ifndef _WIN32
Greg Claytonfbb76342013-11-20 21:07:01 +0000241 if (options & eOpenoptionDontFollowSymlinks)
242 oflag |= O_NOFOLLOW;
Colin Riley909bb7a2013-11-26 15:10:46 +0000243#endif
Greg Clayton96c09682012-01-04 22:56:43 +0000244 }
Greg Clayton504f89a2011-02-08 17:49:02 +0000245
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000246#ifndef _WIN32
Greg Clayton504f89a2011-02-08 17:49:02 +0000247 if (options & eOpenOptionNonBlocking)
248 oflag |= O_NONBLOCK;
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000249#else
250 oflag |= O_BINARY;
251#endif
Greg Clayton504f89a2011-02-08 17:49:02 +0000252
Greg Clayton504f89a2011-02-08 17:49:02 +0000253 mode_t mode = 0;
Greg Clayton96c09682012-01-04 22:56:43 +0000254 if (oflag & O_CREAT)
255 {
Greg Claytonfbb76342013-11-20 21:07:01 +0000256 if (permissions & lldb::eFilePermissionsUserRead) mode |= S_IRUSR;
257 if (permissions & lldb::eFilePermissionsUserWrite) mode |= S_IWUSR;
258 if (permissions & lldb::eFilePermissionsUserExecute) mode |= S_IXUSR;
259 if (permissions & lldb::eFilePermissionsGroupRead) mode |= S_IRGRP;
260 if (permissions & lldb::eFilePermissionsGroupWrite) mode |= S_IWGRP;
261 if (permissions & lldb::eFilePermissionsGroupExecute) mode |= S_IXGRP;
262 if (permissions & lldb::eFilePermissionsWorldRead) mode |= S_IROTH;
263 if (permissions & lldb::eFilePermissionsWorldWrite) mode |= S_IWOTH;
264 if (permissions & lldb::eFilePermissionsWorldExecute) mode |= S_IXOTH;
Greg Clayton96c09682012-01-04 22:56:43 +0000265 }
Greg Clayton504f89a2011-02-08 17:49:02 +0000266
Greg Clayton96c09682012-01-04 22:56:43 +0000267 do
268 {
269 m_descriptor = ::open(path, oflag, mode);
270 } while (m_descriptor < 0 && errno == EINTR);
271
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000272 if (!DescriptorIsValid())
Greg Clayton504f89a2011-02-08 17:49:02 +0000273 error.SetErrorToErrno();
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000274 else
275 m_owned = true;
Greg Clayton504f89a2011-02-08 17:49:02 +0000276
277 return error;
278}
279
Daniel Maleae0f8f572013-08-26 23:57:52 +0000280uint32_t
281File::GetPermissions (const char *path, Error &error)
282{
283 if (path && path[0])
284 {
285 struct stat file_stats;
286 if (::stat (path, &file_stats) == -1)
287 error.SetErrorToErrno();
288 else
289 {
290 error.Clear();
Greg Claytonc0293822013-11-22 18:46:55 +0000291 return file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
Daniel Maleae0f8f572013-08-26 23:57:52 +0000292 }
293 }
294 else
295 {
296 if (path)
297 error.SetErrorString ("invalid path");
298 else
299 error.SetErrorString ("empty path");
300 }
301 return 0;
302}
303
304uint32_t
305File::GetPermissions(Error &error) const
306{
307 int fd = GetDescriptor();
308 if (fd != kInvalidDescriptor)
309 {
310 struct stat file_stats;
311 if (::fstat (fd, &file_stats) == -1)
312 error.SetErrorToErrno();
313 else
314 {
315 error.Clear();
Greg Claytonc0293822013-11-22 18:46:55 +0000316 return file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
Daniel Maleae0f8f572013-08-26 23:57:52 +0000317 }
318 }
319 else
320 {
321 error.SetErrorString ("invalid file descriptor");
322 }
323 return 0;
324}
325
326
Greg Clayton504f89a2011-02-08 17:49:02 +0000327Error
328File::Close ()
329{
330 Error error;
331 if (IsValid ())
332 {
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000333 if (m_owned)
334 {
335 if (StreamIsValid())
336 {
337 if (::fclose (m_stream) == EOF)
338 error.SetErrorToErrno();
339 }
340
341 if (DescriptorIsValid())
342 {
343 if (::close (m_descriptor) != 0)
344 error.SetErrorToErrno();
345 }
346 }
347 m_descriptor = kInvalidDescriptor;
348 m_stream = kInvalidStream;
349 m_options = 0;
350 m_owned = false;
Greg Clayton504f89a2011-02-08 17:49:02 +0000351 }
352 return error;
353}
Greg Clayton968fa382011-02-08 19:10:53 +0000354
355
356Error
357File::GetFileSpec (FileSpec &file_spec) const
358{
359 Error error;
Greg Clayton925137c2011-02-09 01:16:43 +0000360#ifdef LLDB_CONFIG_FCNTL_GETPATH_SUPPORTED
Greg Clayton968fa382011-02-08 19:10:53 +0000361 if (IsValid ())
362 {
363 char path[PATH_MAX];
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000364 if (::fcntl(GetDescriptor(), F_GETPATH, path) == -1)
Greg Clayton968fa382011-02-08 19:10:53 +0000365 error.SetErrorToErrno();
366 else
367 file_spec.SetFile (path, false);
368 }
369 else
Greg Clayton925137c2011-02-09 01:16:43 +0000370 {
Greg Clayton968fa382011-02-08 19:10:53 +0000371 error.SetErrorString("invalid file handle");
Greg Clayton925137c2011-02-09 01:16:43 +0000372 }
Greg Clayton94d08622011-02-09 07:19:18 +0000373#elif defined(__linux__)
374 char proc[64];
375 char path[PATH_MAX];
376 if (::snprintf(proc, sizeof(proc), "/proc/self/fd/%d", GetDescriptor()) < 0)
Greg Clayton86edbf42011-10-26 00:56:27 +0000377 error.SetErrorString ("cannot resolve file descriptor");
Greg Clayton94d08622011-02-09 07:19:18 +0000378 else
379 {
380 ssize_t len;
381 if ((len = ::readlink(proc, path, sizeof(path) - 1)) == -1)
382 error.SetErrorToErrno();
383 else
384 {
385 path[len] = '\0';
386 file_spec.SetFile (path, false);
387 }
388 }
Greg Clayton925137c2011-02-09 01:16:43 +0000389#else
Greg Clayton94d08622011-02-09 07:19:18 +0000390 error.SetErrorString ("File::GetFileSpec is not supported on this platform");
Greg Clayton925137c2011-02-09 01:16:43 +0000391#endif
Greg Clayton968fa382011-02-08 19:10:53 +0000392
393 if (error.Fail())
394 file_spec.Clear();
395 return error;
396}
397
Greg Clayton43d82792013-05-22 23:30:09 +0000398off_t
399File::SeekFromStart (off_t offset, Error *error_ptr)
Greg Clayton968fa382011-02-08 19:10:53 +0000400{
Greg Clayton43d82792013-05-22 23:30:09 +0000401 off_t result = 0;
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000402 if (DescriptorIsValid())
Greg Clayton968fa382011-02-08 19:10:53 +0000403 {
Greg Clayton43d82792013-05-22 23:30:09 +0000404 result = ::lseek (m_descriptor, offset, SEEK_SET);
Greg Clayton968fa382011-02-08 19:10:53 +0000405
Greg Clayton43d82792013-05-22 23:30:09 +0000406 if (error_ptr)
407 {
408 if (result == -1)
409 error_ptr->SetErrorToErrno();
410 else
411 error_ptr->Clear();
412 }
Greg Clayton968fa382011-02-08 19:10:53 +0000413 }
Greg Clayton43d82792013-05-22 23:30:09 +0000414 else if (StreamIsValid ())
Greg Clayton968fa382011-02-08 19:10:53 +0000415 {
Greg Clayton43d82792013-05-22 23:30:09 +0000416 result = ::fseek(m_stream, offset, SEEK_SET);
417
418 if (error_ptr)
419 {
420 if (result == -1)
421 error_ptr->SetErrorToErrno();
422 else
423 error_ptr->Clear();
424 }
Greg Clayton968fa382011-02-08 19:10:53 +0000425 }
Greg Clayton43d82792013-05-22 23:30:09 +0000426 else if (error_ptr)
427 {
428 error_ptr->SetErrorString("invalid file handle");
429 }
430 return result;
Greg Clayton968fa382011-02-08 19:10:53 +0000431}
432
Greg Clayton43d82792013-05-22 23:30:09 +0000433off_t
434File::SeekFromCurrent (off_t offset, Error *error_ptr)
Greg Clayton968fa382011-02-08 19:10:53 +0000435{
Greg Clayton43d82792013-05-22 23:30:09 +0000436 off_t result = -1;
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000437 if (DescriptorIsValid())
Greg Clayton968fa382011-02-08 19:10:53 +0000438 {
Greg Clayton43d82792013-05-22 23:30:09 +0000439 result = ::lseek (m_descriptor, offset, SEEK_CUR);
Greg Clayton968fa382011-02-08 19:10:53 +0000440
Greg Clayton43d82792013-05-22 23:30:09 +0000441 if (error_ptr)
442 {
443 if (result == -1)
444 error_ptr->SetErrorToErrno();
445 else
446 error_ptr->Clear();
447 }
Greg Clayton968fa382011-02-08 19:10:53 +0000448 }
Greg Clayton43d82792013-05-22 23:30:09 +0000449 else if (StreamIsValid ())
Greg Clayton968fa382011-02-08 19:10:53 +0000450 {
Greg Clayton43d82792013-05-22 23:30:09 +0000451 result = ::fseek(m_stream, offset, SEEK_CUR);
452
453 if (error_ptr)
454 {
455 if (result == -1)
456 error_ptr->SetErrorToErrno();
457 else
458 error_ptr->Clear();
459 }
Greg Clayton968fa382011-02-08 19:10:53 +0000460 }
Greg Clayton43d82792013-05-22 23:30:09 +0000461 else if (error_ptr)
462 {
463 error_ptr->SetErrorString("invalid file handle");
464 }
465 return result;
Greg Clayton968fa382011-02-08 19:10:53 +0000466}
467
Greg Clayton43d82792013-05-22 23:30:09 +0000468off_t
469File::SeekFromEnd (off_t offset, Error *error_ptr)
Greg Clayton968fa382011-02-08 19:10:53 +0000470{
Greg Clayton43d82792013-05-22 23:30:09 +0000471 off_t result = -1;
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000472 if (DescriptorIsValid())
Greg Clayton968fa382011-02-08 19:10:53 +0000473 {
Greg Clayton43d82792013-05-22 23:30:09 +0000474 result = ::lseek (m_descriptor, offset, SEEK_END);
Greg Clayton968fa382011-02-08 19:10:53 +0000475
Greg Clayton43d82792013-05-22 23:30:09 +0000476 if (error_ptr)
477 {
478 if (result == -1)
479 error_ptr->SetErrorToErrno();
480 else
481 error_ptr->Clear();
482 }
Greg Clayton968fa382011-02-08 19:10:53 +0000483 }
Greg Clayton43d82792013-05-22 23:30:09 +0000484 else if (StreamIsValid ())
Greg Clayton968fa382011-02-08 19:10:53 +0000485 {
Greg Clayton43d82792013-05-22 23:30:09 +0000486 result = ::fseek(m_stream, offset, SEEK_END);
487
488 if (error_ptr)
489 {
490 if (result == -1)
491 error_ptr->SetErrorToErrno();
492 else
493 error_ptr->Clear();
494 }
Greg Clayton968fa382011-02-08 19:10:53 +0000495 }
Greg Clayton43d82792013-05-22 23:30:09 +0000496 else if (error_ptr)
497 {
498 error_ptr->SetErrorString("invalid file handle");
499 }
500 return result;
Greg Clayton968fa382011-02-08 19:10:53 +0000501}
502
503Error
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000504File::Flush ()
505{
506 Error error;
507 if (StreamIsValid())
508 {
Greg Clayton96c09682012-01-04 22:56:43 +0000509 int err = 0;
510 do
511 {
512 err = ::fflush (m_stream);
513 } while (err == EOF && errno == EINTR);
514
515 if (err == EOF)
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000516 error.SetErrorToErrno();
517 }
518 else if (!DescriptorIsValid())
519 {
520 error.SetErrorString("invalid file handle");
521 }
522 return error;
523}
524
525
526Error
Greg Clayton968fa382011-02-08 19:10:53 +0000527File::Sync ()
528{
529 Error error;
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000530 if (DescriptorIsValid())
Greg Clayton968fa382011-02-08 19:10:53 +0000531 {
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000532#ifdef _WIN32
533 int err = FlushFileBuffers((HANDLE)_get_osfhandle(m_descriptor));
534 if (err == 0)
535 error.SetErrorToGenericError();
536#else
Greg Clayton96c09682012-01-04 22:56:43 +0000537 int err = 0;
538 do
539 {
540 err = ::fsync (m_descriptor);
541 } while (err == -1 && errno == EINTR);
542
543 if (err == -1)
Greg Clayton968fa382011-02-08 19:10:53 +0000544 error.SetErrorToErrno();
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000545#endif
Greg Clayton968fa382011-02-08 19:10:53 +0000546 }
547 else
548 {
549 error.SetErrorString("invalid file handle");
550 }
551 return error;
552}
Greg Clayton846b64b2011-02-08 19:54:44 +0000553
Greg Clayton504f89a2011-02-08 17:49:02 +0000554Error
555File::Read (void *buf, size_t &num_bytes)
556{
557 Error error;
Greg Clayton96c09682012-01-04 22:56:43 +0000558 ssize_t bytes_read = -1;
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000559 if (DescriptorIsValid())
Greg Clayton504f89a2011-02-08 17:49:02 +0000560 {
Greg Clayton96c09682012-01-04 22:56:43 +0000561 do
562 {
563 bytes_read = ::read (m_descriptor, buf, num_bytes);
564 } while (bytes_read < 0 && errno == EINTR);
565
Greg Clayton504f89a2011-02-08 17:49:02 +0000566 if (bytes_read == -1)
567 {
568 error.SetErrorToErrno();
569 num_bytes = 0;
570 }
571 else
572 num_bytes = bytes_read;
573 }
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000574 else if (StreamIsValid())
575 {
Greg Clayton96c09682012-01-04 22:56:43 +0000576 bytes_read = ::fread (buf, 1, num_bytes, m_stream);
577
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000578 if (bytes_read == 0)
579 {
580 if (::feof(m_stream))
581 error.SetErrorString ("feof");
582 else if (::ferror (m_stream))
583 error.SetErrorString ("ferror");
584 num_bytes = 0;
585 }
586 else
587 num_bytes = bytes_read;
588 }
Greg Clayton504f89a2011-02-08 17:49:02 +0000589 else
590 {
591 num_bytes = 0;
592 error.SetErrorString("invalid file handle");
593 }
594 return error;
595}
596
597Error
598File::Write (const void *buf, size_t &num_bytes)
599{
600 Error error;
Greg Clayton96c09682012-01-04 22:56:43 +0000601 ssize_t bytes_written = -1;
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000602 if (DescriptorIsValid())
Greg Clayton504f89a2011-02-08 17:49:02 +0000603 {
Greg Clayton96c09682012-01-04 22:56:43 +0000604 do
605 {
606 bytes_written = ::write (m_descriptor, buf, num_bytes);
607 } while (bytes_written < 0 && errno == EINTR);
608
Greg Clayton504f89a2011-02-08 17:49:02 +0000609 if (bytes_written == -1)
610 {
611 error.SetErrorToErrno();
612 num_bytes = 0;
613 }
614 else
615 num_bytes = bytes_written;
616 }
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000617 else if (StreamIsValid())
618 {
Greg Clayton96c09682012-01-04 22:56:43 +0000619 bytes_written = ::fwrite (buf, 1, num_bytes, m_stream);
620
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000621 if (bytes_written == 0)
622 {
623 if (::feof(m_stream))
624 error.SetErrorString ("feof");
625 else if (::ferror (m_stream))
626 error.SetErrorString ("ferror");
627 num_bytes = 0;
628 }
629 else
630 num_bytes = bytes_written;
631
632 }
Greg Clayton504f89a2011-02-08 17:49:02 +0000633 else
634 {
635 num_bytes = 0;
636 error.SetErrorString("invalid file handle");
637 }
638 return error;
639}
640
Greg Clayton846b64b2011-02-08 19:54:44 +0000641
642Error
643File::Read (void *buf, size_t &num_bytes, off_t &offset)
644{
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000645#ifndef _WIN32
Greg Clayton846b64b2011-02-08 19:54:44 +0000646 Error error;
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000647 int fd = GetDescriptor();
648 if (fd != kInvalidDescriptor)
Greg Clayton846b64b2011-02-08 19:54:44 +0000649 {
Greg Clayton96c09682012-01-04 22:56:43 +0000650 ssize_t bytes_read = -1;
651 do
652 {
653 bytes_read = ::pread (fd, buf, num_bytes, offset);
654 } while (bytes_read < 0 && errno == EINTR);
655
Greg Clayton846b64b2011-02-08 19:54:44 +0000656 if (bytes_read < 0)
657 {
658 num_bytes = 0;
659 error.SetErrorToErrno();
660 }
661 else
662 {
663 offset += bytes_read;
664 num_bytes = bytes_read;
665 }
666 }
667 else
668 {
669 num_bytes = 0;
670 error.SetErrorString("invalid file handle");
671 }
672 return error;
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000673#else
674 long cur = ::lseek(m_descriptor, 0, SEEK_CUR);
675 SeekFromStart(offset);
676 Error error = Read(buf, num_bytes);
677 if (!error.Fail())
678 SeekFromStart(cur);
679 return error;
680#endif
Greg Clayton846b64b2011-02-08 19:54:44 +0000681}
682
683Error
Greg Clayton0b0b5122012-08-30 18:15:10 +0000684File::Read (size_t &num_bytes, off_t &offset, bool null_terminate, DataBufferSP &data_buffer_sp)
Greg Clayton96c09682012-01-04 22:56:43 +0000685{
686 Error error;
687
688 if (num_bytes > 0)
689 {
690 int fd = GetDescriptor();
691 if (fd != kInvalidDescriptor)
692 {
693 struct stat file_stats;
694 if (::fstat (fd, &file_stats) == 0)
695 {
696 if (file_stats.st_size > offset)
697 {
698 const size_t bytes_left = file_stats.st_size - offset;
699 if (num_bytes > bytes_left)
700 num_bytes = bytes_left;
701
Greg Clayton7b0992d2013-04-18 22:45:39 +0000702 std::unique_ptr<DataBufferHeap> data_heap_ap;
Greg Clayton0b0b5122012-08-30 18:15:10 +0000703 data_heap_ap.reset(new DataBufferHeap(num_bytes + (null_terminate ? 1 : 0), '\0'));
Greg Clayton96c09682012-01-04 22:56:43 +0000704
705 if (data_heap_ap.get())
706 {
707 error = Read (data_heap_ap->GetBytes(), num_bytes, offset);
708 if (error.Success())
709 {
710 // Make sure we read exactly what we asked for and if we got
711 // less, adjust the array
712 if (num_bytes < data_heap_ap->GetByteSize())
713 data_heap_ap->SetByteSize(num_bytes);
714 data_buffer_sp.reset(data_heap_ap.release());
715 return error;
716 }
717 }
718 }
719 else
720 error.SetErrorString("file is empty");
721 }
722 else
723 error.SetErrorToErrno();
724 }
725 else
726 error.SetErrorString("invalid file handle");
727 }
728 else
729 error.SetErrorString("invalid file handle");
730
731 num_bytes = 0;
732 data_buffer_sp.reset();
733 return error;
734}
735
736Error
Greg Clayton846b64b2011-02-08 19:54:44 +0000737File::Write (const void *buf, size_t &num_bytes, off_t &offset)
738{
739 Error error;
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000740 int fd = GetDescriptor();
741 if (fd != kInvalidDescriptor)
Greg Clayton846b64b2011-02-08 19:54:44 +0000742 {
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000743#ifndef _WIN32
Greg Clayton96c09682012-01-04 22:56:43 +0000744 ssize_t bytes_written = -1;
745 do
746 {
747 bytes_written = ::pwrite (m_descriptor, buf, num_bytes, offset);
748 } while (bytes_written < 0 && errno == EINTR);
749
Greg Clayton846b64b2011-02-08 19:54:44 +0000750 if (bytes_written < 0)
751 {
752 num_bytes = 0;
753 error.SetErrorToErrno();
754 }
755 else
756 {
757 offset += bytes_written;
758 num_bytes = bytes_written;
759 }
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000760#else
761 long cur = ::lseek(m_descriptor, 0, SEEK_CUR);
762 error = Write(buf, num_bytes);
763 long after = ::lseek(m_descriptor, 0, SEEK_CUR);
764
765 if (!error.Fail())
766 SeekFromStart(cur);
767
768 ssize_t bytes_written = after - cur;
769 offset = after;
770#endif
Greg Clayton846b64b2011-02-08 19:54:44 +0000771 }
772 else
773 {
774 num_bytes = 0;
775 error.SetErrorString("invalid file handle");
776 }
777 return error;
778}
779
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000780//------------------------------------------------------------------
781// Print some formatted output to the stream.
782//------------------------------------------------------------------
Greg Claytonc7bece562013-01-25 18:06:21 +0000783size_t
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000784File::Printf (const char *format, ...)
785{
786 va_list args;
787 va_start (args, format);
Greg Claytonc7bece562013-01-25 18:06:21 +0000788 size_t result = PrintfVarArg (format, args);
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000789 va_end (args);
790 return result;
791}
Greg Clayton846b64b2011-02-08 19:54:44 +0000792
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000793//------------------------------------------------------------------
794// Print some formatted output to the stream.
795//------------------------------------------------------------------
Greg Claytonc7bece562013-01-25 18:06:21 +0000796size_t
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000797File::PrintfVarArg (const char *format, va_list args)
798{
Greg Claytonc7bece562013-01-25 18:06:21 +0000799 size_t result = 0;
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000800 if (DescriptorIsValid())
801 {
802 char *s = NULL;
803 result = vasprintf(&s, format, args);
804 if (s != NULL)
805 {
806 if (result > 0)
807 {
808 size_t s_len = result;
809 Write (s, s_len);
810 result = s_len;
811 }
812 free (s);
813 }
814 }
815 else if (StreamIsValid())
816 {
817 result = ::vfprintf (m_stream, format, args);
818 }
819 return result;
820}
Daniel Maleae0f8f572013-08-26 23:57:52 +0000821
822mode_t
823File::ConvertOpenOptionsForPOSIXOpen (uint32_t open_options)
824{
825 mode_t mode = 0;
826 if (open_options & eOpenOptionRead && open_options & eOpenOptionWrite)
827 mode |= O_RDWR;
828 else if (open_options & eOpenOptionWrite)
829 mode |= O_WRONLY;
830
831 if (open_options & eOpenOptionAppend)
832 mode |= O_APPEND;
833
834 if (open_options & eOpenOptionTruncate)
835 mode |= O_TRUNC;
836
837 if (open_options & eOpenOptionNonBlocking)
838 mode |= O_NONBLOCK;
839
840 if (open_options & eOpenOptionCanCreateNewOnly)
841 mode |= O_CREAT | O_EXCL;
842 else if (open_options & eOpenOptionCanCreate)
843 mode |= O_CREAT;
844
845 return mode;
846}