blob: 343312fb484cb679f3bec65df63db6449c4f5be3 [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
Greg Clayton51b1e2d2011-02-09 01:08:52 +000086File::File (const File &rhs) :
87 m_descriptor (kInvalidDescriptor),
88 m_stream (kInvalidStream),
89 m_options (0),
90 m_owned (false)
91{
92 Duplicate (rhs);
93}
94
95
96File &
97File::operator = (const File &rhs)
98{
99 if (this != &rhs)
100 Duplicate (rhs);
101 return *this;
102}
103
Greg Clayton504f89a2011-02-08 17:49:02 +0000104File::~File()
105{
106 Close ();
107}
108
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000109
110int
111File::GetDescriptor() const
112{
113 if (DescriptorIsValid())
114 return m_descriptor;
115
116 // Don't open the file descriptor if we don't need to, just get it from the
117 // stream if we have one.
118 if (StreamIsValid())
119 return fileno (m_stream);
120
121 // Invalid descriptor and invalid stream, return invalid descriptor.
122 return kInvalidDescriptor;
123}
124
125void
126File::SetDescriptor (int fd, bool transfer_ownership)
127{
128 if (IsValid())
129 Close();
130 m_descriptor = fd;
131 m_owned = transfer_ownership;
132}
133
134
135FILE *
136File::GetStream ()
137{
138 if (!StreamIsValid())
139 {
140 if (DescriptorIsValid())
141 {
142 const char *mode = GetStreamOpenModeFromOptions (m_options);
143 if (mode)
Greg Clayton96c09682012-01-04 22:56:43 +0000144 {
145 do
146 {
147 m_stream = ::fdopen (m_descriptor, mode);
148 } while (m_stream == NULL && errno == EINTR);
149 }
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000150 }
151 }
152 return m_stream;
153}
154
155
156void
157File::SetStream (FILE *fh, bool transfer_ownership)
158{
159 if (IsValid())
160 Close();
161 m_stream = fh;
162 m_owned = transfer_ownership;
163}
164
165Error
166File::Duplicate (const File &rhs)
167{
168 Error error;
169 if (IsValid ())
170 Close();
171
172 if (rhs.DescriptorIsValid())
173 {
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000174#ifdef _WIN32
175 m_descriptor = ::_dup(rhs.GetDescriptor());
176#else
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000177 m_descriptor = ::fcntl(rhs.GetDescriptor(), F_DUPFD);
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000178#endif
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000179 if (!DescriptorIsValid())
180 error.SetErrorToErrno();
181 else
182 {
183 m_options = rhs.m_options;
184 m_owned = true;
185 }
186 }
187 else
188 {
189 error.SetErrorString ("invalid file to duplicate");
190 }
191 return error;
192}
193
Greg Clayton504f89a2011-02-08 17:49:02 +0000194Error
195File::Open (const char *path, uint32_t options, uint32_t permissions)
196{
197 Error error;
198 if (IsValid())
199 Close ();
200
201 int oflag = 0;
Greg Clayton96c09682012-01-04 22:56:43 +0000202 const bool read = options & eOpenOptionRead;
203 const bool write = options & eOpenOptionWrite;
204 if (write)
205 {
206 if (read)
207 oflag |= O_RDWR;
208 else
209 oflag |= O_WRONLY;
210
211 if (options & eOpenOptionAppend)
212 oflag |= O_APPEND;
213
214 if (options & eOpenOptionTruncate)
215 oflag |= O_TRUNC;
216
217 if (options & eOpenOptionCanCreate)
218 oflag |= O_CREAT;
219
220 if (options & eOpenOptionCanCreateNewOnly)
221 oflag |= O_CREAT | O_EXCL;
222 }
223 else if (read)
224 {
Greg Clayton504f89a2011-02-08 17:49:02 +0000225 oflag |= O_RDONLY;
Greg Clayton96c09682012-01-04 22:56:43 +0000226 }
Greg Clayton504f89a2011-02-08 17:49:02 +0000227
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000228#ifndef _WIN32
Greg Clayton504f89a2011-02-08 17:49:02 +0000229 if (options & eOpenOptionNonBlocking)
230 oflag |= O_NONBLOCK;
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000231#else
232 oflag |= O_BINARY;
233#endif
Greg Clayton504f89a2011-02-08 17:49:02 +0000234
Greg Clayton504f89a2011-02-08 17:49:02 +0000235 mode_t mode = 0;
Greg Clayton96c09682012-01-04 22:56:43 +0000236 if (oflag & O_CREAT)
237 {
238 if (permissions & ePermissionsUserRead) mode |= S_IRUSR;
239 if (permissions & ePermissionsUserWrite) mode |= S_IWUSR;
240 if (permissions & ePermissionsUserExecute) mode |= S_IXUSR;
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000241#ifndef _WIN32
Greg Clayton96c09682012-01-04 22:56:43 +0000242 if (permissions & ePermissionsGroupRead) mode |= S_IRGRP;
243 if (permissions & ePermissionsGroupWrite) mode |= S_IWGRP;
244 if (permissions & ePermissionsGroupExecute) mode |= S_IXGRP;
245 if (permissions & ePermissionsWorldRead) mode |= S_IROTH;
246 if (permissions & ePermissionsWorldWrite) mode |= S_IWOTH;
247 if (permissions & ePermissionsWorldExecute) mode |= S_IXOTH;
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000248#endif
Greg Clayton96c09682012-01-04 22:56:43 +0000249 }
Greg Clayton504f89a2011-02-08 17:49:02 +0000250
Greg Clayton96c09682012-01-04 22:56:43 +0000251 do
252 {
253 m_descriptor = ::open(path, oflag, mode);
254 } while (m_descriptor < 0 && errno == EINTR);
255
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000256 if (!DescriptorIsValid())
Greg Clayton504f89a2011-02-08 17:49:02 +0000257 error.SetErrorToErrno();
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000258 else
259 m_owned = true;
Greg Clayton504f89a2011-02-08 17:49:02 +0000260
261 return error;
262}
263
264Error
265File::Close ()
266{
267 Error error;
268 if (IsValid ())
269 {
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000270 if (m_owned)
271 {
272 if (StreamIsValid())
273 {
274 if (::fclose (m_stream) == EOF)
275 error.SetErrorToErrno();
276 }
277
278 if (DescriptorIsValid())
279 {
280 if (::close (m_descriptor) != 0)
281 error.SetErrorToErrno();
282 }
283 }
284 m_descriptor = kInvalidDescriptor;
285 m_stream = kInvalidStream;
286 m_options = 0;
287 m_owned = false;
Greg Clayton504f89a2011-02-08 17:49:02 +0000288 }
289 return error;
290}
Greg Clayton968fa382011-02-08 19:10:53 +0000291
292
293Error
294File::GetFileSpec (FileSpec &file_spec) const
295{
296 Error error;
Greg Clayton925137c2011-02-09 01:16:43 +0000297#ifdef LLDB_CONFIG_FCNTL_GETPATH_SUPPORTED
Greg Clayton968fa382011-02-08 19:10:53 +0000298 if (IsValid ())
299 {
300 char path[PATH_MAX];
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000301 if (::fcntl(GetDescriptor(), F_GETPATH, path) == -1)
Greg Clayton968fa382011-02-08 19:10:53 +0000302 error.SetErrorToErrno();
303 else
304 file_spec.SetFile (path, false);
305 }
306 else
Greg Clayton925137c2011-02-09 01:16:43 +0000307 {
Greg Clayton968fa382011-02-08 19:10:53 +0000308 error.SetErrorString("invalid file handle");
Greg Clayton925137c2011-02-09 01:16:43 +0000309 }
Greg Clayton94d08622011-02-09 07:19:18 +0000310#elif defined(__linux__)
311 char proc[64];
312 char path[PATH_MAX];
313 if (::snprintf(proc, sizeof(proc), "/proc/self/fd/%d", GetDescriptor()) < 0)
Greg Clayton86edbf42011-10-26 00:56:27 +0000314 error.SetErrorString ("cannot resolve file descriptor");
Greg Clayton94d08622011-02-09 07:19:18 +0000315 else
316 {
317 ssize_t len;
318 if ((len = ::readlink(proc, path, sizeof(path) - 1)) == -1)
319 error.SetErrorToErrno();
320 else
321 {
322 path[len] = '\0';
323 file_spec.SetFile (path, false);
324 }
325 }
Greg Clayton925137c2011-02-09 01:16:43 +0000326#else
Greg Clayton94d08622011-02-09 07:19:18 +0000327 error.SetErrorString ("File::GetFileSpec is not supported on this platform");
Greg Clayton925137c2011-02-09 01:16:43 +0000328#endif
Greg Clayton968fa382011-02-08 19:10:53 +0000329
330 if (error.Fail())
331 file_spec.Clear();
332 return error;
333}
334
Greg Clayton43d82792013-05-22 23:30:09 +0000335off_t
336File::SeekFromStart (off_t offset, Error *error_ptr)
Greg Clayton968fa382011-02-08 19:10:53 +0000337{
Greg Clayton43d82792013-05-22 23:30:09 +0000338 off_t result = 0;
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000339 if (DescriptorIsValid())
Greg Clayton968fa382011-02-08 19:10:53 +0000340 {
Greg Clayton43d82792013-05-22 23:30:09 +0000341 result = ::lseek (m_descriptor, offset, SEEK_SET);
Greg Clayton968fa382011-02-08 19:10:53 +0000342
Greg Clayton43d82792013-05-22 23:30:09 +0000343 if (error_ptr)
344 {
345 if (result == -1)
346 error_ptr->SetErrorToErrno();
347 else
348 error_ptr->Clear();
349 }
Greg Clayton968fa382011-02-08 19:10:53 +0000350 }
Greg Clayton43d82792013-05-22 23:30:09 +0000351 else if (StreamIsValid ())
Greg Clayton968fa382011-02-08 19:10:53 +0000352 {
Greg Clayton43d82792013-05-22 23:30:09 +0000353 result = ::fseek(m_stream, offset, SEEK_SET);
354
355 if (error_ptr)
356 {
357 if (result == -1)
358 error_ptr->SetErrorToErrno();
359 else
360 error_ptr->Clear();
361 }
Greg Clayton968fa382011-02-08 19:10:53 +0000362 }
Greg Clayton43d82792013-05-22 23:30:09 +0000363 else if (error_ptr)
364 {
365 error_ptr->SetErrorString("invalid file handle");
366 }
367 return result;
Greg Clayton968fa382011-02-08 19:10:53 +0000368}
369
Greg Clayton43d82792013-05-22 23:30:09 +0000370off_t
371File::SeekFromCurrent (off_t offset, Error *error_ptr)
Greg Clayton968fa382011-02-08 19:10:53 +0000372{
Greg Clayton43d82792013-05-22 23:30:09 +0000373 off_t result = -1;
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000374 if (DescriptorIsValid())
Greg Clayton968fa382011-02-08 19:10:53 +0000375 {
Greg Clayton43d82792013-05-22 23:30:09 +0000376 result = ::lseek (m_descriptor, offset, SEEK_CUR);
Greg Clayton968fa382011-02-08 19:10:53 +0000377
Greg Clayton43d82792013-05-22 23:30:09 +0000378 if (error_ptr)
379 {
380 if (result == -1)
381 error_ptr->SetErrorToErrno();
382 else
383 error_ptr->Clear();
384 }
Greg Clayton968fa382011-02-08 19:10:53 +0000385 }
Greg Clayton43d82792013-05-22 23:30:09 +0000386 else if (StreamIsValid ())
Greg Clayton968fa382011-02-08 19:10:53 +0000387 {
Greg Clayton43d82792013-05-22 23:30:09 +0000388 result = ::fseek(m_stream, offset, SEEK_CUR);
389
390 if (error_ptr)
391 {
392 if (result == -1)
393 error_ptr->SetErrorToErrno();
394 else
395 error_ptr->Clear();
396 }
Greg Clayton968fa382011-02-08 19:10:53 +0000397 }
Greg Clayton43d82792013-05-22 23:30:09 +0000398 else if (error_ptr)
399 {
400 error_ptr->SetErrorString("invalid file handle");
401 }
402 return result;
Greg Clayton968fa382011-02-08 19:10:53 +0000403}
404
Greg Clayton43d82792013-05-22 23:30:09 +0000405off_t
406File::SeekFromEnd (off_t offset, Error *error_ptr)
Greg Clayton968fa382011-02-08 19:10:53 +0000407{
Greg Clayton43d82792013-05-22 23:30:09 +0000408 off_t result = -1;
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000409 if (DescriptorIsValid())
Greg Clayton968fa382011-02-08 19:10:53 +0000410 {
Greg Clayton43d82792013-05-22 23:30:09 +0000411 result = ::lseek (m_descriptor, offset, SEEK_END);
Greg Clayton968fa382011-02-08 19:10:53 +0000412
Greg Clayton43d82792013-05-22 23:30:09 +0000413 if (error_ptr)
414 {
415 if (result == -1)
416 error_ptr->SetErrorToErrno();
417 else
418 error_ptr->Clear();
419 }
Greg Clayton968fa382011-02-08 19:10:53 +0000420 }
Greg Clayton43d82792013-05-22 23:30:09 +0000421 else if (StreamIsValid ())
Greg Clayton968fa382011-02-08 19:10:53 +0000422 {
Greg Clayton43d82792013-05-22 23:30:09 +0000423 result = ::fseek(m_stream, offset, SEEK_END);
424
425 if (error_ptr)
426 {
427 if (result == -1)
428 error_ptr->SetErrorToErrno();
429 else
430 error_ptr->Clear();
431 }
Greg Clayton968fa382011-02-08 19:10:53 +0000432 }
Greg Clayton43d82792013-05-22 23:30:09 +0000433 else if (error_ptr)
434 {
435 error_ptr->SetErrorString("invalid file handle");
436 }
437 return result;
Greg Clayton968fa382011-02-08 19:10:53 +0000438}
439
440Error
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000441File::Flush ()
442{
443 Error error;
444 if (StreamIsValid())
445 {
Greg Clayton96c09682012-01-04 22:56:43 +0000446 int err = 0;
447 do
448 {
449 err = ::fflush (m_stream);
450 } while (err == EOF && errno == EINTR);
451
452 if (err == EOF)
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000453 error.SetErrorToErrno();
454 }
455 else if (!DescriptorIsValid())
456 {
457 error.SetErrorString("invalid file handle");
458 }
459 return error;
460}
461
462
463Error
Greg Clayton968fa382011-02-08 19:10:53 +0000464File::Sync ()
465{
466 Error error;
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000467 if (DescriptorIsValid())
Greg Clayton968fa382011-02-08 19:10:53 +0000468 {
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000469#ifdef _WIN32
470 int err = FlushFileBuffers((HANDLE)_get_osfhandle(m_descriptor));
471 if (err == 0)
472 error.SetErrorToGenericError();
473#else
Greg Clayton96c09682012-01-04 22:56:43 +0000474 int err = 0;
475 do
476 {
477 err = ::fsync (m_descriptor);
478 } while (err == -1 && errno == EINTR);
479
480 if (err == -1)
Greg Clayton968fa382011-02-08 19:10:53 +0000481 error.SetErrorToErrno();
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000482#endif
Greg Clayton968fa382011-02-08 19:10:53 +0000483 }
484 else
485 {
486 error.SetErrorString("invalid file handle");
487 }
488 return error;
489}
Greg Clayton846b64b2011-02-08 19:54:44 +0000490
Greg Clayton504f89a2011-02-08 17:49:02 +0000491Error
492File::Read (void *buf, size_t &num_bytes)
493{
494 Error error;
Greg Clayton96c09682012-01-04 22:56:43 +0000495 ssize_t bytes_read = -1;
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000496 if (DescriptorIsValid())
Greg Clayton504f89a2011-02-08 17:49:02 +0000497 {
Greg Clayton96c09682012-01-04 22:56:43 +0000498 do
499 {
500 bytes_read = ::read (m_descriptor, buf, num_bytes);
501 } while (bytes_read < 0 && errno == EINTR);
502
Greg Clayton504f89a2011-02-08 17:49:02 +0000503 if (bytes_read == -1)
504 {
505 error.SetErrorToErrno();
506 num_bytes = 0;
507 }
508 else
509 num_bytes = bytes_read;
510 }
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000511 else if (StreamIsValid())
512 {
Greg Clayton96c09682012-01-04 22:56:43 +0000513 bytes_read = ::fread (buf, 1, num_bytes, m_stream);
514
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000515 if (bytes_read == 0)
516 {
517 if (::feof(m_stream))
518 error.SetErrorString ("feof");
519 else if (::ferror (m_stream))
520 error.SetErrorString ("ferror");
521 num_bytes = 0;
522 }
523 else
524 num_bytes = bytes_read;
525 }
Greg Clayton504f89a2011-02-08 17:49:02 +0000526 else
527 {
528 num_bytes = 0;
529 error.SetErrorString("invalid file handle");
530 }
531 return error;
532}
533
534Error
535File::Write (const void *buf, size_t &num_bytes)
536{
537 Error error;
Greg Clayton96c09682012-01-04 22:56:43 +0000538 ssize_t bytes_written = -1;
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000539 if (DescriptorIsValid())
Greg Clayton504f89a2011-02-08 17:49:02 +0000540 {
Greg Clayton96c09682012-01-04 22:56:43 +0000541 do
542 {
543 bytes_written = ::write (m_descriptor, buf, num_bytes);
544 } while (bytes_written < 0 && errno == EINTR);
545
Greg Clayton504f89a2011-02-08 17:49:02 +0000546 if (bytes_written == -1)
547 {
548 error.SetErrorToErrno();
549 num_bytes = 0;
550 }
551 else
552 num_bytes = bytes_written;
553 }
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000554 else if (StreamIsValid())
555 {
Greg Clayton96c09682012-01-04 22:56:43 +0000556 bytes_written = ::fwrite (buf, 1, num_bytes, m_stream);
557
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000558 if (bytes_written == 0)
559 {
560 if (::feof(m_stream))
561 error.SetErrorString ("feof");
562 else if (::ferror (m_stream))
563 error.SetErrorString ("ferror");
564 num_bytes = 0;
565 }
566 else
567 num_bytes = bytes_written;
568
569 }
Greg Clayton504f89a2011-02-08 17:49:02 +0000570 else
571 {
572 num_bytes = 0;
573 error.SetErrorString("invalid file handle");
574 }
575 return error;
576}
577
Greg Clayton846b64b2011-02-08 19:54:44 +0000578
579Error
580File::Read (void *buf, size_t &num_bytes, off_t &offset)
581{
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000582#ifndef _WIN32
Greg Clayton846b64b2011-02-08 19:54:44 +0000583 Error error;
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000584 int fd = GetDescriptor();
585 if (fd != kInvalidDescriptor)
Greg Clayton846b64b2011-02-08 19:54:44 +0000586 {
Greg Clayton96c09682012-01-04 22:56:43 +0000587 ssize_t bytes_read = -1;
588 do
589 {
590 bytes_read = ::pread (fd, buf, num_bytes, offset);
591 } while (bytes_read < 0 && errno == EINTR);
592
Greg Clayton846b64b2011-02-08 19:54:44 +0000593 if (bytes_read < 0)
594 {
595 num_bytes = 0;
596 error.SetErrorToErrno();
597 }
598 else
599 {
600 offset += bytes_read;
601 num_bytes = bytes_read;
602 }
603 }
604 else
605 {
606 num_bytes = 0;
607 error.SetErrorString("invalid file handle");
608 }
609 return error;
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000610#else
611 long cur = ::lseek(m_descriptor, 0, SEEK_CUR);
612 SeekFromStart(offset);
613 Error error = Read(buf, num_bytes);
614 if (!error.Fail())
615 SeekFromStart(cur);
616 return error;
617#endif
Greg Clayton846b64b2011-02-08 19:54:44 +0000618}
619
620Error
Greg Clayton0b0b5122012-08-30 18:15:10 +0000621File::Read (size_t &num_bytes, off_t &offset, bool null_terminate, DataBufferSP &data_buffer_sp)
Greg Clayton96c09682012-01-04 22:56:43 +0000622{
623 Error error;
624
625 if (num_bytes > 0)
626 {
627 int fd = GetDescriptor();
628 if (fd != kInvalidDescriptor)
629 {
630 struct stat file_stats;
631 if (::fstat (fd, &file_stats) == 0)
632 {
633 if (file_stats.st_size > offset)
634 {
635 const size_t bytes_left = file_stats.st_size - offset;
636 if (num_bytes > bytes_left)
637 num_bytes = bytes_left;
638
Greg Clayton7b0992d2013-04-18 22:45:39 +0000639 std::unique_ptr<DataBufferHeap> data_heap_ap;
Greg Clayton0b0b5122012-08-30 18:15:10 +0000640 data_heap_ap.reset(new DataBufferHeap(num_bytes + (null_terminate ? 1 : 0), '\0'));
Greg Clayton96c09682012-01-04 22:56:43 +0000641
642 if (data_heap_ap.get())
643 {
644 error = Read (data_heap_ap->GetBytes(), num_bytes, offset);
645 if (error.Success())
646 {
647 // Make sure we read exactly what we asked for and if we got
648 // less, adjust the array
649 if (num_bytes < data_heap_ap->GetByteSize())
650 data_heap_ap->SetByteSize(num_bytes);
651 data_buffer_sp.reset(data_heap_ap.release());
652 return error;
653 }
654 }
655 }
656 else
657 error.SetErrorString("file is empty");
658 }
659 else
660 error.SetErrorToErrno();
661 }
662 else
663 error.SetErrorString("invalid file handle");
664 }
665 else
666 error.SetErrorString("invalid file handle");
667
668 num_bytes = 0;
669 data_buffer_sp.reset();
670 return error;
671}
672
673Error
Greg Clayton846b64b2011-02-08 19:54:44 +0000674File::Write (const void *buf, size_t &num_bytes, off_t &offset)
675{
676 Error error;
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000677 int fd = GetDescriptor();
678 if (fd != kInvalidDescriptor)
Greg Clayton846b64b2011-02-08 19:54:44 +0000679 {
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000680#ifndef _WIN32
Greg Clayton96c09682012-01-04 22:56:43 +0000681 ssize_t bytes_written = -1;
682 do
683 {
684 bytes_written = ::pwrite (m_descriptor, buf, num_bytes, offset);
685 } while (bytes_written < 0 && errno == EINTR);
686
Greg Clayton846b64b2011-02-08 19:54:44 +0000687 if (bytes_written < 0)
688 {
689 num_bytes = 0;
690 error.SetErrorToErrno();
691 }
692 else
693 {
694 offset += bytes_written;
695 num_bytes = bytes_written;
696 }
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000697#else
698 long cur = ::lseek(m_descriptor, 0, SEEK_CUR);
699 error = Write(buf, num_bytes);
700 long after = ::lseek(m_descriptor, 0, SEEK_CUR);
701
702 if (!error.Fail())
703 SeekFromStart(cur);
704
705 ssize_t bytes_written = after - cur;
706 offset = after;
707#endif
Greg Clayton846b64b2011-02-08 19:54:44 +0000708 }
709 else
710 {
711 num_bytes = 0;
712 error.SetErrorString("invalid file handle");
713 }
714 return error;
715}
716
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000717//------------------------------------------------------------------
718// Print some formatted output to the stream.
719//------------------------------------------------------------------
Greg Claytonc7bece562013-01-25 18:06:21 +0000720size_t
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000721File::Printf (const char *format, ...)
722{
723 va_list args;
724 va_start (args, format);
Greg Claytonc7bece562013-01-25 18:06:21 +0000725 size_t result = PrintfVarArg (format, args);
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000726 va_end (args);
727 return result;
728}
Greg Clayton846b64b2011-02-08 19:54:44 +0000729
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000730//------------------------------------------------------------------
731// Print some formatted output to the stream.
732//------------------------------------------------------------------
Greg Claytonc7bece562013-01-25 18:06:21 +0000733size_t
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000734File::PrintfVarArg (const char *format, va_list args)
735{
Greg Claytonc7bece562013-01-25 18:06:21 +0000736 size_t result = 0;
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000737 if (DescriptorIsValid())
738 {
739 char *s = NULL;
740 result = vasprintf(&s, format, args);
741 if (s != NULL)
742 {
743 if (result > 0)
744 {
745 size_t s_len = result;
746 Write (s, s_len);
747 result = s_len;
748 }
749 free (s);
750 }
751 }
752 else if (StreamIsValid())
753 {
754 result = ::vfprintf (m_stream, format, args);
755 }
756 return result;
757}