blob: 50513af2dc143c64a8dadaed2a2c50ba95d631da [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 Clayton340b0302014-02-05 17:57:57 +000016#include <stdio.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"
Deepak Panickal94667bc2014-02-17 17:43:39 +000021#else
22#include <sys/ioctl.h>
Virgile Bellob2f1fb22013-08-23 12:44:05 +000023#endif
24
Greg Clayton96c09682012-01-04 22:56:43 +000025#include "lldb/Core/DataBufferHeap.h"
Greg Clayton504f89a2011-02-08 17:49:02 +000026#include "lldb/Core/Error.h"
Zachary Turner98688922014-08-06 18:16:26 +000027#include "lldb/Core/Log.h"
Greg Clayton925137c2011-02-09 01:16:43 +000028#include "lldb/Host/Config.h"
Greg Clayton846b64b2011-02-08 19:54:44 +000029#include "lldb/Host/FileSpec.h"
Greg Clayton504f89a2011-02-08 17:49:02 +000030
31using namespace lldb;
32using namespace lldb_private;
33
Greg Clayton51b1e2d2011-02-09 01:08:52 +000034static const char *
35GetStreamOpenModeFromOptions (uint32_t options)
36{
37 if (options & File::eOpenOptionAppend)
38 {
39 if (options & File::eOpenOptionRead)
40 {
41 if (options & File::eOpenOptionCanCreateNewOnly)
42 return "a+x";
43 else
44 return "a+";
45 }
46 else if (options & File::eOpenOptionWrite)
47 {
48 if (options & File::eOpenOptionCanCreateNewOnly)
49 return "ax";
50 else
51 return "a";
52 }
53 }
54 else if (options & File::eOpenOptionRead && options & File::eOpenOptionWrite)
55 {
56 if (options & File::eOpenOptionCanCreate)
57 {
58 if (options & File::eOpenOptionCanCreateNewOnly)
59 return "w+x";
60 else
61 return "w+";
62 }
63 else
64 return "r+";
65 }
66 else if (options & File::eOpenOptionRead)
67 {
68 return "r";
69 }
70 else if (options & File::eOpenOptionWrite)
71 {
72 return "w";
73 }
74 return NULL;
75}
76
77int File::kInvalidDescriptor = -1;
78FILE * File::kInvalidStream = NULL;
79
Greg Clayton504f89a2011-02-08 17:49:02 +000080File::File(const char *path, uint32_t options, uint32_t permissions) :
Zachary Turner98688922014-08-06 18:16:26 +000081 IOObject(eFDTypeFile, false),
Greg Clayton51b1e2d2011-02-09 01:08:52 +000082 m_descriptor (kInvalidDescriptor),
83 m_stream (kInvalidStream),
Greg Clayton44d93782014-01-27 23:43:24 +000084 m_options (),
85 m_own_stream (false),
Greg Clayton340b0302014-02-05 17:57:57 +000086 m_is_interactive (eLazyBoolCalculate),
87 m_is_real_terminal (eLazyBoolCalculate)
Greg Clayton504f89a2011-02-08 17:49:02 +000088{
89 Open (path, options, permissions);
90}
91
Daniel Maleae0f8f572013-08-26 23:57:52 +000092File::File (const FileSpec& filespec,
93 uint32_t options,
94 uint32_t permissions) :
Zachary Turner98688922014-08-06 18:16:26 +000095 IOObject(eFDTypeFile, false),
Daniel Maleae0f8f572013-08-26 23:57:52 +000096 m_descriptor (kInvalidDescriptor),
97 m_stream (kInvalidStream),
98 m_options (0),
Greg Clayton44d93782014-01-27 23:43:24 +000099 m_own_stream (false),
Greg Clayton340b0302014-02-05 17:57:57 +0000100 m_is_interactive (eLazyBoolCalculate),
101 m_is_real_terminal (eLazyBoolCalculate)
102
Daniel Maleae0f8f572013-08-26 23:57:52 +0000103{
104 if (filespec)
105 {
106 Open (filespec.GetPath().c_str(), options, permissions);
107 }
108}
109
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000110File::File (const File &rhs) :
Zachary Turner98688922014-08-06 18:16:26 +0000111 IOObject(eFDTypeFile, false),
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000112 m_descriptor (kInvalidDescriptor),
113 m_stream (kInvalidStream),
114 m_options (0),
Greg Clayton44d93782014-01-27 23:43:24 +0000115 m_own_stream (false),
Greg Clayton340b0302014-02-05 17:57:57 +0000116 m_is_interactive (eLazyBoolCalculate),
117 m_is_real_terminal (eLazyBoolCalculate)
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000118{
119 Duplicate (rhs);
120}
121
122
123File &
124File::operator = (const File &rhs)
125{
126 if (this != &rhs)
127 Duplicate (rhs);
128 return *this;
129}
130
Greg Clayton504f89a2011-02-08 17:49:02 +0000131File::~File()
132{
133 Close ();
134}
135
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000136
137int
138File::GetDescriptor() const
139{
140 if (DescriptorIsValid())
141 return m_descriptor;
142
143 // Don't open the file descriptor if we don't need to, just get it from the
144 // stream if we have one.
145 if (StreamIsValid())
146 return fileno (m_stream);
147
148 // Invalid descriptor and invalid stream, return invalid descriptor.
149 return kInvalidDescriptor;
150}
151
Zachary Turner98688922014-08-06 18:16:26 +0000152IOObject::WaitableHandle
153File::GetWaitableHandle()
154{
155 return m_descriptor;
156}
157
158
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000159void
160File::SetDescriptor (int fd, bool transfer_ownership)
161{
162 if (IsValid())
163 Close();
164 m_descriptor = fd;
Zachary Turner98688922014-08-06 18:16:26 +0000165 m_should_close_fd = transfer_ownership;
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000166}
167
168
169FILE *
170File::GetStream ()
171{
172 if (!StreamIsValid())
173 {
174 if (DescriptorIsValid())
175 {
176 const char *mode = GetStreamOpenModeFromOptions (m_options);
177 if (mode)
Greg Clayton96c09682012-01-04 22:56:43 +0000178 {
Zachary Turner98688922014-08-06 18:16:26 +0000179 if (!m_should_close_fd)
Greg Clayton44d93782014-01-27 23:43:24 +0000180 {
181 // We must duplicate the file descriptor if we don't own it because
182 // when you call fdopen, the stream will own the fd
183#ifdef _WIN32
184 m_descriptor = ::_dup(GetDescriptor());
185#else
186 m_descriptor = ::fcntl(GetDescriptor(), F_DUPFD);
187#endif
Zachary Turner98688922014-08-06 18:16:26 +0000188 m_should_close_fd = true;
Greg Clayton44d93782014-01-27 23:43:24 +0000189 }
190
Greg Clayton96c09682012-01-04 22:56:43 +0000191 do
192 {
193 m_stream = ::fdopen (m_descriptor, mode);
194 } while (m_stream == NULL && errno == EINTR);
Greg Clayton44d93782014-01-27 23:43:24 +0000195
196 // If we got a stream, then we own the stream and should no
197 // longer own the descriptor because fclose() will close it for us
198
199 if (m_stream)
200 {
201 m_own_stream = true;
Zachary Turner98688922014-08-06 18:16:26 +0000202 m_should_close_fd = false;
Greg Clayton44d93782014-01-27 23:43:24 +0000203 }
Greg Clayton96c09682012-01-04 22:56:43 +0000204 }
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000205 }
206 }
207 return m_stream;
208}
209
210
211void
212File::SetStream (FILE *fh, bool transfer_ownership)
213{
214 if (IsValid())
215 Close();
216 m_stream = fh;
Greg Clayton44d93782014-01-27 23:43:24 +0000217 m_own_stream = transfer_ownership;
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000218}
219
220Error
221File::Duplicate (const File &rhs)
222{
223 Error error;
224 if (IsValid ())
225 Close();
226
227 if (rhs.DescriptorIsValid())
228 {
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000229#ifdef _WIN32
230 m_descriptor = ::_dup(rhs.GetDescriptor());
231#else
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000232 m_descriptor = ::fcntl(rhs.GetDescriptor(), F_DUPFD);
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000233#endif
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000234 if (!DescriptorIsValid())
235 error.SetErrorToErrno();
236 else
237 {
238 m_options = rhs.m_options;
Zachary Turner98688922014-08-06 18:16:26 +0000239 m_should_close_fd = true;
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000240 }
241 }
242 else
243 {
244 error.SetErrorString ("invalid file to duplicate");
245 }
246 return error;
247}
248
Greg Clayton504f89a2011-02-08 17:49:02 +0000249Error
250File::Open (const char *path, uint32_t options, uint32_t permissions)
251{
252 Error error;
253 if (IsValid())
254 Close ();
255
256 int oflag = 0;
Greg Clayton96c09682012-01-04 22:56:43 +0000257 const bool read = options & eOpenOptionRead;
258 const bool write = options & eOpenOptionWrite;
259 if (write)
260 {
261 if (read)
262 oflag |= O_RDWR;
263 else
264 oflag |= O_WRONLY;
265
266 if (options & eOpenOptionAppend)
267 oflag |= O_APPEND;
268
269 if (options & eOpenOptionTruncate)
270 oflag |= O_TRUNC;
271
272 if (options & eOpenOptionCanCreate)
273 oflag |= O_CREAT;
274
275 if (options & eOpenOptionCanCreateNewOnly)
276 oflag |= O_CREAT | O_EXCL;
277 }
278 else if (read)
279 {
Greg Clayton504f89a2011-02-08 17:49:02 +0000280 oflag |= O_RDONLY;
Greg Claytonfbb76342013-11-20 21:07:01 +0000281
Colin Riley909bb7a2013-11-26 15:10:46 +0000282#ifndef _WIN32
Greg Claytonfbb76342013-11-20 21:07:01 +0000283 if (options & eOpenoptionDontFollowSymlinks)
284 oflag |= O_NOFOLLOW;
Colin Riley909bb7a2013-11-26 15:10:46 +0000285#endif
Greg Clayton96c09682012-01-04 22:56:43 +0000286 }
Greg Clayton504f89a2011-02-08 17:49:02 +0000287
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000288#ifndef _WIN32
Greg Clayton504f89a2011-02-08 17:49:02 +0000289 if (options & eOpenOptionNonBlocking)
290 oflag |= O_NONBLOCK;
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000291#else
292 oflag |= O_BINARY;
293#endif
Greg Clayton504f89a2011-02-08 17:49:02 +0000294
Greg Clayton504f89a2011-02-08 17:49:02 +0000295 mode_t mode = 0;
Greg Clayton96c09682012-01-04 22:56:43 +0000296 if (oflag & O_CREAT)
297 {
Greg Claytonfbb76342013-11-20 21:07:01 +0000298 if (permissions & lldb::eFilePermissionsUserRead) mode |= S_IRUSR;
299 if (permissions & lldb::eFilePermissionsUserWrite) mode |= S_IWUSR;
300 if (permissions & lldb::eFilePermissionsUserExecute) mode |= S_IXUSR;
301 if (permissions & lldb::eFilePermissionsGroupRead) mode |= S_IRGRP;
302 if (permissions & lldb::eFilePermissionsGroupWrite) mode |= S_IWGRP;
303 if (permissions & lldb::eFilePermissionsGroupExecute) mode |= S_IXGRP;
304 if (permissions & lldb::eFilePermissionsWorldRead) mode |= S_IROTH;
305 if (permissions & lldb::eFilePermissionsWorldWrite) mode |= S_IWOTH;
306 if (permissions & lldb::eFilePermissionsWorldExecute) mode |= S_IXOTH;
Greg Clayton96c09682012-01-04 22:56:43 +0000307 }
Greg Clayton504f89a2011-02-08 17:49:02 +0000308
Greg Clayton96c09682012-01-04 22:56:43 +0000309 do
310 {
311 m_descriptor = ::open(path, oflag, mode);
312 } while (m_descriptor < 0 && errno == EINTR);
313
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000314 if (!DescriptorIsValid())
Greg Clayton504f89a2011-02-08 17:49:02 +0000315 error.SetErrorToErrno();
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000316 else
Greg Clayton44d93782014-01-27 23:43:24 +0000317 {
Zachary Turner98688922014-08-06 18:16:26 +0000318 m_should_close_fd = true;
Greg Clayton44d93782014-01-27 23:43:24 +0000319 m_options = options;
320 }
Greg Clayton504f89a2011-02-08 17:49:02 +0000321
322 return error;
323}
324
Daniel Maleae0f8f572013-08-26 23:57:52 +0000325uint32_t
326File::GetPermissions (const char *path, Error &error)
327{
328 if (path && path[0])
329 {
330 struct stat file_stats;
331 if (::stat (path, &file_stats) == -1)
332 error.SetErrorToErrno();
333 else
334 {
335 error.Clear();
Greg Claytonc0293822013-11-22 18:46:55 +0000336 return file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
Daniel Maleae0f8f572013-08-26 23:57:52 +0000337 }
338 }
339 else
340 {
341 if (path)
342 error.SetErrorString ("invalid path");
343 else
344 error.SetErrorString ("empty path");
345 }
346 return 0;
347}
348
349uint32_t
350File::GetPermissions(Error &error) const
351{
352 int fd = GetDescriptor();
353 if (fd != kInvalidDescriptor)
354 {
355 struct stat file_stats;
356 if (::fstat (fd, &file_stats) == -1)
357 error.SetErrorToErrno();
358 else
359 {
360 error.Clear();
Greg Claytonc0293822013-11-22 18:46:55 +0000361 return file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
Daniel Maleae0f8f572013-08-26 23:57:52 +0000362 }
363 }
364 else
365 {
366 error.SetErrorString ("invalid file descriptor");
367 }
368 return 0;
369}
370
371
Greg Clayton504f89a2011-02-08 17:49:02 +0000372Error
373File::Close ()
374{
375 Error error;
Greg Clayton44d93782014-01-27 23:43:24 +0000376 if (StreamIsValid() && m_own_stream)
Greg Clayton504f89a2011-02-08 17:49:02 +0000377 {
Greg Clayton44d93782014-01-27 23:43:24 +0000378 if (::fclose (m_stream) == EOF)
379 error.SetErrorToErrno();
Greg Clayton504f89a2011-02-08 17:49:02 +0000380 }
Greg Clayton44d93782014-01-27 23:43:24 +0000381
Zachary Turner98688922014-08-06 18:16:26 +0000382 if (DescriptorIsValid() && m_should_close_fd)
Greg Clayton44d93782014-01-27 23:43:24 +0000383 {
384 if (::close (m_descriptor) != 0)
385 error.SetErrorToErrno();
386 }
387 m_descriptor = kInvalidDescriptor;
388 m_stream = kInvalidStream;
389 m_options = 0;
390 m_own_stream = false;
Zachary Turner98688922014-08-06 18:16:26 +0000391 m_should_close_fd = false;
Greg Clayton340b0302014-02-05 17:57:57 +0000392 m_is_interactive = eLazyBoolCalculate;
393 m_is_real_terminal = eLazyBoolCalculate;
Greg Clayton504f89a2011-02-08 17:49:02 +0000394 return error;
395}
Greg Clayton968fa382011-02-08 19:10:53 +0000396
397
398Error
399File::GetFileSpec (FileSpec &file_spec) const
400{
401 Error error;
Greg Clayton925137c2011-02-09 01:16:43 +0000402#ifdef LLDB_CONFIG_FCNTL_GETPATH_SUPPORTED
Greg Clayton968fa382011-02-08 19:10:53 +0000403 if (IsValid ())
404 {
405 char path[PATH_MAX];
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000406 if (::fcntl(GetDescriptor(), F_GETPATH, path) == -1)
Greg Clayton968fa382011-02-08 19:10:53 +0000407 error.SetErrorToErrno();
408 else
409 file_spec.SetFile (path, false);
410 }
411 else
Greg Clayton925137c2011-02-09 01:16:43 +0000412 {
Greg Clayton968fa382011-02-08 19:10:53 +0000413 error.SetErrorString("invalid file handle");
Greg Clayton925137c2011-02-09 01:16:43 +0000414 }
Greg Clayton94d08622011-02-09 07:19:18 +0000415#elif defined(__linux__)
416 char proc[64];
417 char path[PATH_MAX];
418 if (::snprintf(proc, sizeof(proc), "/proc/self/fd/%d", GetDescriptor()) < 0)
Greg Clayton86edbf42011-10-26 00:56:27 +0000419 error.SetErrorString ("cannot resolve file descriptor");
Greg Clayton94d08622011-02-09 07:19:18 +0000420 else
421 {
422 ssize_t len;
423 if ((len = ::readlink(proc, path, sizeof(path) - 1)) == -1)
424 error.SetErrorToErrno();
425 else
426 {
427 path[len] = '\0';
428 file_spec.SetFile (path, false);
429 }
430 }
Greg Clayton925137c2011-02-09 01:16:43 +0000431#else
Greg Clayton94d08622011-02-09 07:19:18 +0000432 error.SetErrorString ("File::GetFileSpec is not supported on this platform");
Greg Clayton925137c2011-02-09 01:16:43 +0000433#endif
Greg Clayton968fa382011-02-08 19:10:53 +0000434
435 if (error.Fail())
436 file_spec.Clear();
437 return error;
438}
439
Greg Clayton43d82792013-05-22 23:30:09 +0000440off_t
441File::SeekFromStart (off_t offset, Error *error_ptr)
Greg Clayton968fa382011-02-08 19:10:53 +0000442{
Greg Clayton43d82792013-05-22 23:30:09 +0000443 off_t result = 0;
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000444 if (DescriptorIsValid())
Greg Clayton968fa382011-02-08 19:10:53 +0000445 {
Greg Clayton43d82792013-05-22 23:30:09 +0000446 result = ::lseek (m_descriptor, offset, SEEK_SET);
Greg Clayton968fa382011-02-08 19:10:53 +0000447
Greg Clayton43d82792013-05-22 23:30:09 +0000448 if (error_ptr)
449 {
450 if (result == -1)
451 error_ptr->SetErrorToErrno();
452 else
453 error_ptr->Clear();
454 }
Greg Clayton968fa382011-02-08 19:10:53 +0000455 }
Greg Clayton43d82792013-05-22 23:30:09 +0000456 else if (StreamIsValid ())
Greg Clayton968fa382011-02-08 19:10:53 +0000457 {
Greg Clayton43d82792013-05-22 23:30:09 +0000458 result = ::fseek(m_stream, offset, SEEK_SET);
459
460 if (error_ptr)
461 {
462 if (result == -1)
463 error_ptr->SetErrorToErrno();
464 else
465 error_ptr->Clear();
466 }
Greg Clayton968fa382011-02-08 19:10:53 +0000467 }
Greg Clayton43d82792013-05-22 23:30:09 +0000468 else if (error_ptr)
469 {
470 error_ptr->SetErrorString("invalid file handle");
471 }
472 return result;
Greg Clayton968fa382011-02-08 19:10:53 +0000473}
474
Greg Clayton43d82792013-05-22 23:30:09 +0000475off_t
476File::SeekFromCurrent (off_t offset, Error *error_ptr)
Greg Clayton968fa382011-02-08 19:10:53 +0000477{
Greg Clayton43d82792013-05-22 23:30:09 +0000478 off_t result = -1;
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000479 if (DescriptorIsValid())
Greg Clayton968fa382011-02-08 19:10:53 +0000480 {
Greg Clayton43d82792013-05-22 23:30:09 +0000481 result = ::lseek (m_descriptor, offset, SEEK_CUR);
Greg Clayton968fa382011-02-08 19:10:53 +0000482
Greg Clayton43d82792013-05-22 23:30:09 +0000483 if (error_ptr)
484 {
485 if (result == -1)
486 error_ptr->SetErrorToErrno();
487 else
488 error_ptr->Clear();
489 }
Greg Clayton968fa382011-02-08 19:10:53 +0000490 }
Greg Clayton43d82792013-05-22 23:30:09 +0000491 else if (StreamIsValid ())
Greg Clayton968fa382011-02-08 19:10:53 +0000492 {
Greg Clayton43d82792013-05-22 23:30:09 +0000493 result = ::fseek(m_stream, offset, SEEK_CUR);
494
495 if (error_ptr)
496 {
497 if (result == -1)
498 error_ptr->SetErrorToErrno();
499 else
500 error_ptr->Clear();
501 }
Greg Clayton968fa382011-02-08 19:10:53 +0000502 }
Greg Clayton43d82792013-05-22 23:30:09 +0000503 else if (error_ptr)
504 {
505 error_ptr->SetErrorString("invalid file handle");
506 }
507 return result;
Greg Clayton968fa382011-02-08 19:10:53 +0000508}
509
Greg Clayton43d82792013-05-22 23:30:09 +0000510off_t
511File::SeekFromEnd (off_t offset, Error *error_ptr)
Greg Clayton968fa382011-02-08 19:10:53 +0000512{
Greg Clayton43d82792013-05-22 23:30:09 +0000513 off_t result = -1;
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000514 if (DescriptorIsValid())
Greg Clayton968fa382011-02-08 19:10:53 +0000515 {
Greg Clayton43d82792013-05-22 23:30:09 +0000516 result = ::lseek (m_descriptor, offset, SEEK_END);
Greg Clayton968fa382011-02-08 19:10:53 +0000517
Greg Clayton43d82792013-05-22 23:30:09 +0000518 if (error_ptr)
519 {
520 if (result == -1)
521 error_ptr->SetErrorToErrno();
522 else
523 error_ptr->Clear();
524 }
Greg Clayton968fa382011-02-08 19:10:53 +0000525 }
Greg Clayton43d82792013-05-22 23:30:09 +0000526 else if (StreamIsValid ())
Greg Clayton968fa382011-02-08 19:10:53 +0000527 {
Greg Clayton43d82792013-05-22 23:30:09 +0000528 result = ::fseek(m_stream, offset, SEEK_END);
529
530 if (error_ptr)
531 {
532 if (result == -1)
533 error_ptr->SetErrorToErrno();
534 else
535 error_ptr->Clear();
536 }
Greg Clayton968fa382011-02-08 19:10:53 +0000537 }
Greg Clayton43d82792013-05-22 23:30:09 +0000538 else if (error_ptr)
539 {
540 error_ptr->SetErrorString("invalid file handle");
541 }
542 return result;
Greg Clayton968fa382011-02-08 19:10:53 +0000543}
544
545Error
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000546File::Flush ()
547{
548 Error error;
549 if (StreamIsValid())
550 {
Greg Clayton96c09682012-01-04 22:56:43 +0000551 int err = 0;
552 do
553 {
554 err = ::fflush (m_stream);
555 } while (err == EOF && errno == EINTR);
556
557 if (err == EOF)
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000558 error.SetErrorToErrno();
559 }
560 else if (!DescriptorIsValid())
561 {
562 error.SetErrorString("invalid file handle");
563 }
564 return error;
565}
566
567
568Error
Greg Clayton968fa382011-02-08 19:10:53 +0000569File::Sync ()
570{
571 Error error;
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000572 if (DescriptorIsValid())
Greg Clayton968fa382011-02-08 19:10:53 +0000573 {
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000574#ifdef _WIN32
575 int err = FlushFileBuffers((HANDLE)_get_osfhandle(m_descriptor));
576 if (err == 0)
577 error.SetErrorToGenericError();
578#else
Greg Clayton96c09682012-01-04 22:56:43 +0000579 int err = 0;
580 do
581 {
582 err = ::fsync (m_descriptor);
583 } while (err == -1 && errno == EINTR);
584
585 if (err == -1)
Greg Clayton968fa382011-02-08 19:10:53 +0000586 error.SetErrorToErrno();
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000587#endif
Greg Clayton968fa382011-02-08 19:10:53 +0000588 }
589 else
590 {
591 error.SetErrorString("invalid file handle");
592 }
593 return error;
594}
Greg Clayton846b64b2011-02-08 19:54:44 +0000595
Greg Clayton504f89a2011-02-08 17:49:02 +0000596Error
597File::Read (void *buf, size_t &num_bytes)
598{
599 Error error;
Greg Clayton96c09682012-01-04 22:56:43 +0000600 ssize_t bytes_read = -1;
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000601 if (DescriptorIsValid())
Greg Clayton504f89a2011-02-08 17:49:02 +0000602 {
Greg Clayton96c09682012-01-04 22:56:43 +0000603 do
604 {
605 bytes_read = ::read (m_descriptor, buf, num_bytes);
606 } while (bytes_read < 0 && errno == EINTR);
607
Greg Clayton504f89a2011-02-08 17:49:02 +0000608 if (bytes_read == -1)
609 {
610 error.SetErrorToErrno();
611 num_bytes = 0;
612 }
613 else
614 num_bytes = bytes_read;
615 }
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000616 else if (StreamIsValid())
617 {
Greg Clayton96c09682012-01-04 22:56:43 +0000618 bytes_read = ::fread (buf, 1, num_bytes, m_stream);
619
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000620 if (bytes_read == 0)
621 {
622 if (::feof(m_stream))
623 error.SetErrorString ("feof");
624 else if (::ferror (m_stream))
625 error.SetErrorString ("ferror");
626 num_bytes = 0;
627 }
628 else
629 num_bytes = bytes_read;
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
639Error
640File::Write (const void *buf, size_t &num_bytes)
641{
642 Error error;
Greg Clayton96c09682012-01-04 22:56:43 +0000643 ssize_t bytes_written = -1;
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000644 if (DescriptorIsValid())
Greg Clayton504f89a2011-02-08 17:49:02 +0000645 {
Greg Clayton96c09682012-01-04 22:56:43 +0000646 do
647 {
648 bytes_written = ::write (m_descriptor, buf, num_bytes);
649 } while (bytes_written < 0 && errno == EINTR);
650
Greg Clayton504f89a2011-02-08 17:49:02 +0000651 if (bytes_written == -1)
652 {
653 error.SetErrorToErrno();
654 num_bytes = 0;
655 }
656 else
657 num_bytes = bytes_written;
658 }
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000659 else if (StreamIsValid())
660 {
Greg Clayton96c09682012-01-04 22:56:43 +0000661 bytes_written = ::fwrite (buf, 1, num_bytes, m_stream);
662
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000663 if (bytes_written == 0)
664 {
665 if (::feof(m_stream))
666 error.SetErrorString ("feof");
667 else if (::ferror (m_stream))
668 error.SetErrorString ("ferror");
669 num_bytes = 0;
670 }
671 else
672 num_bytes = bytes_written;
673
674 }
Greg Clayton504f89a2011-02-08 17:49:02 +0000675 else
676 {
677 num_bytes = 0;
678 error.SetErrorString("invalid file handle");
679 }
Zachary Turner98688922014-08-06 18:16:26 +0000680
Greg Clayton504f89a2011-02-08 17:49:02 +0000681 return error;
682}
683
Greg Clayton846b64b2011-02-08 19:54:44 +0000684
685Error
686File::Read (void *buf, size_t &num_bytes, off_t &offset)
687{
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000688#ifndef _WIN32
Greg Clayton846b64b2011-02-08 19:54:44 +0000689 Error error;
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000690 int fd = GetDescriptor();
691 if (fd != kInvalidDescriptor)
Greg Clayton846b64b2011-02-08 19:54:44 +0000692 {
Greg Clayton96c09682012-01-04 22:56:43 +0000693 ssize_t bytes_read = -1;
694 do
695 {
696 bytes_read = ::pread (fd, buf, num_bytes, offset);
697 } while (bytes_read < 0 && errno == EINTR);
698
Greg Clayton846b64b2011-02-08 19:54:44 +0000699 if (bytes_read < 0)
700 {
701 num_bytes = 0;
702 error.SetErrorToErrno();
703 }
704 else
705 {
706 offset += bytes_read;
707 num_bytes = bytes_read;
708 }
709 }
710 else
711 {
712 num_bytes = 0;
713 error.SetErrorString("invalid file handle");
714 }
715 return error;
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000716#else
717 long cur = ::lseek(m_descriptor, 0, SEEK_CUR);
718 SeekFromStart(offset);
719 Error error = Read(buf, num_bytes);
720 if (!error.Fail())
721 SeekFromStart(cur);
722 return error;
723#endif
Greg Clayton846b64b2011-02-08 19:54:44 +0000724}
725
726Error
Greg Clayton0b0b5122012-08-30 18:15:10 +0000727File::Read (size_t &num_bytes, off_t &offset, bool null_terminate, DataBufferSP &data_buffer_sp)
Greg Clayton96c09682012-01-04 22:56:43 +0000728{
729 Error error;
730
731 if (num_bytes > 0)
732 {
733 int fd = GetDescriptor();
734 if (fd != kInvalidDescriptor)
735 {
736 struct stat file_stats;
737 if (::fstat (fd, &file_stats) == 0)
738 {
739 if (file_stats.st_size > offset)
740 {
741 const size_t bytes_left = file_stats.st_size - offset;
742 if (num_bytes > bytes_left)
743 num_bytes = bytes_left;
744
Greg Clayton7b0992d2013-04-18 22:45:39 +0000745 std::unique_ptr<DataBufferHeap> data_heap_ap;
Greg Clayton0b0b5122012-08-30 18:15:10 +0000746 data_heap_ap.reset(new DataBufferHeap(num_bytes + (null_terminate ? 1 : 0), '\0'));
Greg Clayton96c09682012-01-04 22:56:43 +0000747
748 if (data_heap_ap.get())
749 {
750 error = Read (data_heap_ap->GetBytes(), num_bytes, offset);
751 if (error.Success())
752 {
753 // Make sure we read exactly what we asked for and if we got
754 // less, adjust the array
755 if (num_bytes < data_heap_ap->GetByteSize())
756 data_heap_ap->SetByteSize(num_bytes);
757 data_buffer_sp.reset(data_heap_ap.release());
758 return error;
759 }
760 }
761 }
762 else
763 error.SetErrorString("file is empty");
764 }
765 else
766 error.SetErrorToErrno();
767 }
768 else
769 error.SetErrorString("invalid file handle");
770 }
771 else
772 error.SetErrorString("invalid file handle");
773
774 num_bytes = 0;
775 data_buffer_sp.reset();
776 return error;
777}
778
779Error
Greg Clayton846b64b2011-02-08 19:54:44 +0000780File::Write (const void *buf, size_t &num_bytes, off_t &offset)
781{
782 Error error;
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000783 int fd = GetDescriptor();
784 if (fd != kInvalidDescriptor)
Greg Clayton846b64b2011-02-08 19:54:44 +0000785 {
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000786#ifndef _WIN32
Greg Clayton96c09682012-01-04 22:56:43 +0000787 ssize_t bytes_written = -1;
788 do
789 {
790 bytes_written = ::pwrite (m_descriptor, buf, num_bytes, offset);
791 } while (bytes_written < 0 && errno == EINTR);
792
Greg Clayton846b64b2011-02-08 19:54:44 +0000793 if (bytes_written < 0)
794 {
795 num_bytes = 0;
796 error.SetErrorToErrno();
797 }
798 else
799 {
800 offset += bytes_written;
801 num_bytes = bytes_written;
802 }
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000803#else
804 long cur = ::lseek(m_descriptor, 0, SEEK_CUR);
805 error = Write(buf, num_bytes);
806 long after = ::lseek(m_descriptor, 0, SEEK_CUR);
807
808 if (!error.Fail())
809 SeekFromStart(cur);
810
811 ssize_t bytes_written = after - cur;
812 offset = after;
813#endif
Greg Clayton846b64b2011-02-08 19:54:44 +0000814 }
815 else
816 {
817 num_bytes = 0;
818 error.SetErrorString("invalid file handle");
819 }
820 return error;
821}
822
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000823//------------------------------------------------------------------
824// Print some formatted output to the stream.
825//------------------------------------------------------------------
Greg Claytonc7bece562013-01-25 18:06:21 +0000826size_t
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000827File::Printf (const char *format, ...)
828{
829 va_list args;
830 va_start (args, format);
Greg Claytonc7bece562013-01-25 18:06:21 +0000831 size_t result = PrintfVarArg (format, args);
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000832 va_end (args);
833 return result;
834}
Greg Clayton846b64b2011-02-08 19:54:44 +0000835
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000836//------------------------------------------------------------------
837// Print some formatted output to the stream.
838//------------------------------------------------------------------
Greg Claytonc7bece562013-01-25 18:06:21 +0000839size_t
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000840File::PrintfVarArg (const char *format, va_list args)
841{
Greg Claytonc7bece562013-01-25 18:06:21 +0000842 size_t result = 0;
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000843 if (DescriptorIsValid())
844 {
845 char *s = NULL;
846 result = vasprintf(&s, format, args);
847 if (s != NULL)
848 {
849 if (result > 0)
850 {
851 size_t s_len = result;
852 Write (s, s_len);
853 result = s_len;
854 }
855 free (s);
856 }
857 }
858 else if (StreamIsValid())
859 {
860 result = ::vfprintf (m_stream, format, args);
861 }
862 return result;
863}
Daniel Maleae0f8f572013-08-26 23:57:52 +0000864
865mode_t
866File::ConvertOpenOptionsForPOSIXOpen (uint32_t open_options)
867{
868 mode_t mode = 0;
869 if (open_options & eOpenOptionRead && open_options & eOpenOptionWrite)
870 mode |= O_RDWR;
871 else if (open_options & eOpenOptionWrite)
872 mode |= O_WRONLY;
873
874 if (open_options & eOpenOptionAppend)
875 mode |= O_APPEND;
876
877 if (open_options & eOpenOptionTruncate)
878 mode |= O_TRUNC;
879
880 if (open_options & eOpenOptionNonBlocking)
881 mode |= O_NONBLOCK;
882
883 if (open_options & eOpenOptionCanCreateNewOnly)
884 mode |= O_CREAT | O_EXCL;
885 else if (open_options & eOpenOptionCanCreate)
886 mode |= O_CREAT;
887
888 return mode;
889}
Greg Clayton340b0302014-02-05 17:57:57 +0000890
891void
892File::CalculateInteractiveAndTerminal ()
893{
894 const int fd = GetDescriptor();
895 if (fd >= 0)
896 {
897 m_is_interactive = eLazyBoolNo;
898 m_is_real_terminal = eLazyBoolNo;
Hafiz Abid Qadeer6eff1012014-03-12 10:45:23 +0000899#ifdef _WIN32
Deepak Panickal6419e982014-03-03 15:53:37 +0000900 if (_isatty(fd))
901 {
902 m_is_interactive = eLazyBoolYes;
903 m_is_real_terminal = eLazyBoolYes;
904 }
905#else
Greg Clayton340b0302014-02-05 17:57:57 +0000906 if (isatty(fd))
907 {
908 m_is_interactive = eLazyBoolYes;
909 struct winsize window_size;
910 if (::ioctl (fd, TIOCGWINSZ, &window_size) == 0)
911 {
912 if (window_size.ws_col > 0)
913 m_is_real_terminal = eLazyBoolYes;
914 }
915 }
Deepak Panickal94667bc2014-02-17 17:43:39 +0000916#endif
Greg Clayton340b0302014-02-05 17:57:57 +0000917 }
918}
919
920bool
921File::GetIsInteractive ()
922{
923 if (m_is_interactive == eLazyBoolCalculate)
924 CalculateInteractiveAndTerminal ();
925 return m_is_interactive == eLazyBoolYes;
926}
927
928bool
929File::GetIsRealTerminal ()
930{
931 if (m_is_real_terminal == eLazyBoolCalculate)
932 CalculateInteractiveAndTerminal();
933 return m_is_real_terminal == eLazyBoolYes;
934}
935