blob: 3de93ebc220b5106d14f225ef8cf19a54f11df11 [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 Clayton504f89a2011-02-08 17:49:02 +000017
Virgile Bellob2f1fb22013-08-23 12:44:05 +000018#ifdef _WIN32
19#include "lldb/Host/windows/windows.h"
Deepak Panickal94667bc2014-02-17 17:43:39 +000020#else
21#include <sys/ioctl.h>
Zachary Turner5821a3b2017-03-20 23:55:20 +000022#include <sys/stat.h>
Pavel Labathb8ad0152017-01-24 14:05:23 +000023#include <termios.h>
Virgile Bellob2f1fb22013-08-23 12:44:05 +000024#endif
25
Zachary Turner190fadc2016-03-22 17:58:09 +000026#include "llvm/Support/ConvertUTF.h"
Zachary Turner07db3f72017-03-21 05:47:57 +000027#include "llvm/Support/FileSystem.h"
Sean Callanan66810412015-10-19 23:11:07 +000028#include "llvm/Support/Process.h" // for llvm::sys::Process::FileDescriptorHasColors()
29
Greg Clayton925137c2011-02-09 01:16:43 +000030#include "lldb/Host/Config.h"
Zachary Turner666cc0b2017-03-04 01:30:05 +000031#include "lldb/Utility/DataBufferHeap.h"
Zachary Turner5713a052017-03-22 18:40:07 +000032#include "lldb/Utility/FileSpec.h"
Zachary Turner6f9e6902017-03-03 20:56:28 +000033#include "lldb/Utility/Log.h"
Greg Clayton504f89a2011-02-08 17:49:02 +000034
35using namespace lldb;
36using namespace lldb_private;
37
Kate Stoneb9c1b512016-09-06 20:57:50 +000038static const char *GetStreamOpenModeFromOptions(uint32_t options) {
39 if (options & File::eOpenOptionAppend) {
40 if (options & File::eOpenOptionRead) {
41 if (options & File::eOpenOptionCanCreateNewOnly)
42 return "a+x";
43 else
44 return "a+";
45 } else if (options & File::eOpenOptionWrite) {
46 if (options & File::eOpenOptionCanCreateNewOnly)
47 return "ax";
48 else
49 return "a";
Greg Clayton51b1e2d2011-02-09 01:08:52 +000050 }
Kate Stoneb9c1b512016-09-06 20:57:50 +000051 } else if (options & File::eOpenOptionRead &&
52 options & File::eOpenOptionWrite) {
53 if (options & File::eOpenOptionCanCreate) {
54 if (options & File::eOpenOptionCanCreateNewOnly)
55 return "w+x";
56 else
57 return "w+";
58 } else
59 return "r+";
60 } else if (options & File::eOpenOptionRead) {
61 return "r";
62 } else if (options & File::eOpenOptionWrite) {
63 return "w";
64 }
65 return NULL;
Greg Clayton51b1e2d2011-02-09 01:08:52 +000066}
67
68int File::kInvalidDescriptor = -1;
Kate Stoneb9c1b512016-09-06 20:57:50 +000069FILE *File::kInvalidStream = NULL;
Greg Clayton51b1e2d2011-02-09 01:08:52 +000070
Kate Stoneb9c1b512016-09-06 20:57:50 +000071File::File(const char *path, uint32_t options, uint32_t permissions)
72 : IOObject(eFDTypeFile, false), m_descriptor(kInvalidDescriptor),
73 m_stream(kInvalidStream), m_options(), m_own_stream(false),
74 m_is_interactive(eLazyBoolCalculate),
75 m_is_real_terminal(eLazyBoolCalculate) {
76 Open(path, options, permissions);
Greg Clayton504f89a2011-02-08 17:49:02 +000077}
78
Kate Stoneb9c1b512016-09-06 20:57:50 +000079File::File(const FileSpec &filespec, uint32_t options, uint32_t permissions)
80 : IOObject(eFDTypeFile, false), m_descriptor(kInvalidDescriptor),
81 m_stream(kInvalidStream), m_options(0), m_own_stream(false),
82 m_is_interactive(eLazyBoolCalculate),
83 m_is_real_terminal(eLazyBoolCalculate)
Greg Clayton340b0302014-02-05 17:57:57 +000084
Daniel Maleae0f8f572013-08-26 23:57:52 +000085{
Kate Stoneb9c1b512016-09-06 20:57:50 +000086 if (filespec) {
87 Open(filespec.GetPath().c_str(), options, permissions);
88 }
Daniel Maleae0f8f572013-08-26 23:57:52 +000089}
90
Kate Stoneb9c1b512016-09-06 20:57:50 +000091File::~File() { Close(); }
Greg Clayton504f89a2011-02-08 17:49:02 +000092
Kate Stoneb9c1b512016-09-06 20:57:50 +000093int File::GetDescriptor() const {
94 if (DescriptorIsValid())
Zachary Turner98688922014-08-06 18:16:26 +000095 return m_descriptor;
Zachary Turner98688922014-08-06 18:16:26 +000096
Kate Stoneb9c1b512016-09-06 20:57:50 +000097 // Don't open the file descriptor if we don't need to, just get it from the
98 // stream if we have one.
99 if (StreamIsValid()) {
100#if defined(LLVM_ON_WIN32)
101 return _fileno(m_stream);
Greg Clayton44d93782014-01-27 23:43:24 +0000102#else
Kate Stoneb9c1b512016-09-06 20:57:50 +0000103 return fileno(m_stream);
Greg Clayton44d93782014-01-27 23:43:24 +0000104#endif
Kate Stoneb9c1b512016-09-06 20:57:50 +0000105 }
Greg Clayton44d93782014-01-27 23:43:24 +0000106
Kate Stoneb9c1b512016-09-06 20:57:50 +0000107 // Invalid descriptor and invalid stream, return invalid descriptor.
108 return kInvalidDescriptor;
109}
Greg Clayton44d93782014-01-27 23:43:24 +0000110
Kate Stoneb9c1b512016-09-06 20:57:50 +0000111IOObject::WaitableHandle File::GetWaitableHandle() { return m_descriptor; }
Greg Clayton44d93782014-01-27 23:43:24 +0000112
Kate Stoneb9c1b512016-09-06 20:57:50 +0000113void File::SetDescriptor(int fd, bool transfer_ownership) {
114 if (IsValid())
115 Close();
116 m_descriptor = fd;
117 m_should_close_fd = transfer_ownership;
118}
119
120FILE *File::GetStream() {
121 if (!StreamIsValid()) {
122 if (DescriptorIsValid()) {
123 const char *mode = GetStreamOpenModeFromOptions(m_options);
124 if (mode) {
125 if (!m_should_close_fd) {
126// We must duplicate the file descriptor if we don't own it because
127// when you call fdopen, the stream will own the fd
128#ifdef _WIN32
129 m_descriptor = ::_dup(GetDescriptor());
130#else
131 m_descriptor = dup(GetDescriptor());
132#endif
133 m_should_close_fd = true;
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000134 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000135
136 do {
137 m_stream = ::fdopen(m_descriptor, mode);
138 } while (m_stream == NULL && errno == EINTR);
139
140 // If we got a stream, then we own the stream and should no
141 // longer own the descriptor because fclose() will close it for us
142
143 if (m_stream) {
144 m_own_stream = true;
145 m_should_close_fd = false;
146 }
147 }
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000148 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000149 }
150 return m_stream;
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000151}
152
Kate Stoneb9c1b512016-09-06 20:57:50 +0000153void File::SetStream(FILE *fh, bool transfer_ownership) {
154 if (IsValid())
155 Close();
156 m_stream = fh;
157 m_own_stream = transfer_ownership;
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000158}
159
Zachary Turner97206d52017-05-12 04:51:55 +0000160Status File::Open(const char *path, uint32_t options, uint32_t permissions) {
161 Status error;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000162 if (IsValid())
163 Close();
Greg Clayton504f89a2011-02-08 17:49:02 +0000164
Kate Stoneb9c1b512016-09-06 20:57:50 +0000165 int oflag = 0;
166 const bool read = options & eOpenOptionRead;
167 const bool write = options & eOpenOptionWrite;
168 if (write) {
169 if (read)
170 oflag |= O_RDWR;
171 else
172 oflag |= O_WRONLY;
Greg Clayton96c09682012-01-04 22:56:43 +0000173
Kate Stoneb9c1b512016-09-06 20:57:50 +0000174 if (options & eOpenOptionAppend)
175 oflag |= O_APPEND;
Greg Clayton96c09682012-01-04 22:56:43 +0000176
Kate Stoneb9c1b512016-09-06 20:57:50 +0000177 if (options & eOpenOptionTruncate)
178 oflag |= O_TRUNC;
179
180 if (options & eOpenOptionCanCreate)
181 oflag |= O_CREAT;
182
183 if (options & eOpenOptionCanCreateNewOnly)
184 oflag |= O_CREAT | O_EXCL;
185 } else if (read) {
186 oflag |= O_RDONLY;
Greg Claytonfbb76342013-11-20 21:07:01 +0000187
Colin Riley909bb7a2013-11-26 15:10:46 +0000188#ifndef _WIN32
Kate Stoneb9c1b512016-09-06 20:57:50 +0000189 if (options & eOpenOptionDontFollowSymlinks)
190 oflag |= O_NOFOLLOW;
Colin Riley909bb7a2013-11-26 15:10:46 +0000191#endif
Kate Stoneb9c1b512016-09-06 20:57:50 +0000192 }
193
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000194#ifndef _WIN32
Kate Stoneb9c1b512016-09-06 20:57:50 +0000195 if (options & eOpenOptionNonBlocking)
196 oflag |= O_NONBLOCK;
197 if (options & eOpenOptionCloseOnExec)
198 oflag |= O_CLOEXEC;
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000199#else
Kate Stoneb9c1b512016-09-06 20:57:50 +0000200 oflag |= O_BINARY;
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000201#endif
Greg Clayton504f89a2011-02-08 17:49:02 +0000202
Kate Stoneb9c1b512016-09-06 20:57:50 +0000203 mode_t mode = 0;
204 if (oflag & O_CREAT) {
205 if (permissions & lldb::eFilePermissionsUserRead)
206 mode |= S_IRUSR;
207 if (permissions & lldb::eFilePermissionsUserWrite)
208 mode |= S_IWUSR;
209 if (permissions & lldb::eFilePermissionsUserExecute)
210 mode |= S_IXUSR;
211 if (permissions & lldb::eFilePermissionsGroupRead)
212 mode |= S_IRGRP;
213 if (permissions & lldb::eFilePermissionsGroupWrite)
214 mode |= S_IWGRP;
215 if (permissions & lldb::eFilePermissionsGroupExecute)
216 mode |= S_IXGRP;
217 if (permissions & lldb::eFilePermissionsWorldRead)
218 mode |= S_IROTH;
219 if (permissions & lldb::eFilePermissionsWorldWrite)
220 mode |= S_IWOTH;
221 if (permissions & lldb::eFilePermissionsWorldExecute)
222 mode |= S_IXOTH;
223 }
Greg Clayton504f89a2011-02-08 17:49:02 +0000224
Kate Stoneb9c1b512016-09-06 20:57:50 +0000225 do {
Hafiz Abid Qadeerf6ee79c2016-12-15 15:00:41 +0000226#ifdef _MSC_VER
Kate Stoneb9c1b512016-09-06 20:57:50 +0000227 std::wstring wpath;
228 if (!llvm::ConvertUTF8toWide(path, wpath)) {
229 m_descriptor = -1;
230 error.SetErrorString("Error converting path to UTF-16");
231 return error;
232 }
233 ::_wsopen_s(&m_descriptor, wpath.c_str(), oflag, _SH_DENYNO, mode);
Zachary Turner190fadc2016-03-22 17:58:09 +0000234#else
Kate Stoneb9c1b512016-09-06 20:57:50 +0000235 m_descriptor = ::open(path, oflag, mode);
Zachary Turner190fadc2016-03-22 17:58:09 +0000236#endif
Kate Stoneb9c1b512016-09-06 20:57:50 +0000237 } while (m_descriptor < 0 && errno == EINTR);
Greg Clayton96c09682012-01-04 22:56:43 +0000238
Kate Stoneb9c1b512016-09-06 20:57:50 +0000239 if (!DescriptorIsValid())
240 error.SetErrorToErrno();
241 else {
242 m_should_close_fd = true;
243 m_options = options;
244 }
245
246 return error;
Greg Clayton504f89a2011-02-08 17:49:02 +0000247}
248
Zachary Turner97206d52017-05-12 04:51:55 +0000249uint32_t File::GetPermissions(const FileSpec &file_spec, Status &error) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000250 if (file_spec) {
Zachary Turner07db3f72017-03-21 05:47:57 +0000251 error.Clear();
252 auto Perms = llvm::sys::fs::getPermissions(file_spec.GetPath());
253 if (Perms)
254 return *Perms;
Zachary Turner97206d52017-05-12 04:51:55 +0000255 error = Status(Perms.getError());
Zachary Turner07db3f72017-03-21 05:47:57 +0000256 return 0;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000257 } else
258 error.SetErrorString("empty file spec");
259 return 0;
Daniel Maleae0f8f572013-08-26 23:57:52 +0000260}
261
Zachary Turner97206d52017-05-12 04:51:55 +0000262uint32_t File::GetPermissions(Status &error) const {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000263 int fd = GetDescriptor();
264 if (fd != kInvalidDescriptor) {
265 struct stat file_stats;
266 if (::fstat(fd, &file_stats) == -1)
267 error.SetErrorToErrno();
268 else {
269 error.Clear();
270 return file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
Daniel Maleae0f8f572013-08-26 23:57:52 +0000271 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000272 } else {
273 error.SetErrorString("invalid file descriptor");
274 }
275 return 0;
Daniel Maleae0f8f572013-08-26 23:57:52 +0000276}
277
Zachary Turner97206d52017-05-12 04:51:55 +0000278Status File::Close() {
279 Status error;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000280 if (StreamIsValid() && m_own_stream) {
281 if (::fclose(m_stream) == EOF)
282 error.SetErrorToErrno();
283 }
Daniel Maleae0f8f572013-08-26 23:57:52 +0000284
Kate Stoneb9c1b512016-09-06 20:57:50 +0000285 if (DescriptorIsValid() && m_should_close_fd) {
286 if (::close(m_descriptor) != 0)
287 error.SetErrorToErrno();
288 }
289 m_descriptor = kInvalidDescriptor;
290 m_stream = kInvalidStream;
291 m_options = 0;
292 m_own_stream = false;
293 m_should_close_fd = false;
294 m_is_interactive = eLazyBoolCalculate;
295 m_is_real_terminal = eLazyBoolCalculate;
296 return error;
Greg Clayton504f89a2011-02-08 17:49:02 +0000297}
Greg Clayton968fa382011-02-08 19:10:53 +0000298
Kate Stoneb9c1b512016-09-06 20:57:50 +0000299void File::Clear() {
300 m_stream = nullptr;
301 m_descriptor = -1;
302 m_options = 0;
303 m_own_stream = false;
304 m_is_interactive = m_supports_colors = m_is_real_terminal =
305 eLazyBoolCalculate;
Enrico Granata744959b2016-01-13 18:11:45 +0000306}
Greg Clayton968fa382011-02-08 19:10:53 +0000307
Zachary Turner97206d52017-05-12 04:51:55 +0000308Status File::GetFileSpec(FileSpec &file_spec) const {
309 Status error;
Chris Bienemanb90bee02017-04-14 22:03:45 +0000310#ifdef F_GETPATH
Kate Stoneb9c1b512016-09-06 20:57:50 +0000311 if (IsValid()) {
Greg Clayton94d08622011-02-09 07:19:18 +0000312 char path[PATH_MAX];
Kate Stoneb9c1b512016-09-06 20:57:50 +0000313 if (::fcntl(GetDescriptor(), F_GETPATH, path) == -1)
314 error.SetErrorToErrno();
Greg Clayton94d08622011-02-09 07:19:18 +0000315 else
Kate Stoneb9c1b512016-09-06 20:57:50 +0000316 file_spec.SetFile(path, false);
317 } else {
318 error.SetErrorString("invalid file handle");
319 }
320#elif defined(__linux__)
321 char proc[64];
322 char path[PATH_MAX];
323 if (::snprintf(proc, sizeof(proc), "/proc/self/fd/%d", GetDescriptor()) < 0)
324 error.SetErrorString("cannot resolve file descriptor");
325 else {
326 ssize_t len;
327 if ((len = ::readlink(proc, path, sizeof(path) - 1)) == -1)
328 error.SetErrorToErrno();
329 else {
330 path[len] = '\0';
331 file_spec.SetFile(path, false);
Greg Clayton94d08622011-02-09 07:19:18 +0000332 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000333 }
Greg Clayton925137c2011-02-09 01:16:43 +0000334#else
Kate Stoneb9c1b512016-09-06 20:57:50 +0000335 error.SetErrorString("File::GetFileSpec is not supported on this platform");
Greg Clayton925137c2011-02-09 01:16:43 +0000336#endif
Greg Clayton968fa382011-02-08 19:10:53 +0000337
Kate Stoneb9c1b512016-09-06 20:57:50 +0000338 if (error.Fail())
339 file_spec.Clear();
340 return error;
Greg Clayton968fa382011-02-08 19:10:53 +0000341}
342
Zachary Turner97206d52017-05-12 04:51:55 +0000343off_t File::SeekFromStart(off_t offset, Status *error_ptr) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000344 off_t result = 0;
345 if (DescriptorIsValid()) {
346 result = ::lseek(m_descriptor, offset, SEEK_SET);
Greg Clayton968fa382011-02-08 19:10:53 +0000347
Kate Stoneb9c1b512016-09-06 20:57:50 +0000348 if (error_ptr) {
349 if (result == -1)
350 error_ptr->SetErrorToErrno();
351 else
352 error_ptr->Clear();
Greg Clayton968fa382011-02-08 19:10:53 +0000353 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000354 } else if (StreamIsValid()) {
355 result = ::fseek(m_stream, offset, SEEK_SET);
356
357 if (error_ptr) {
358 if (result == -1)
359 error_ptr->SetErrorToErrno();
360 else
361 error_ptr->Clear();
Greg Clayton968fa382011-02-08 19:10:53 +0000362 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000363 } else if (error_ptr) {
364 error_ptr->SetErrorString("invalid file handle");
365 }
366 return result;
Greg Clayton968fa382011-02-08 19:10:53 +0000367}
368
Zachary Turner97206d52017-05-12 04:51:55 +0000369off_t File::SeekFromCurrent(off_t offset, Status *error_ptr) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000370 off_t result = -1;
371 if (DescriptorIsValid()) {
372 result = ::lseek(m_descriptor, offset, SEEK_CUR);
373
374 if (error_ptr) {
375 if (result == -1)
376 error_ptr->SetErrorToErrno();
377 else
378 error_ptr->Clear();
Greg Clayton968fa382011-02-08 19:10:53 +0000379 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000380 } else if (StreamIsValid()) {
381 result = ::fseek(m_stream, offset, SEEK_CUR);
382
383 if (error_ptr) {
384 if (result == -1)
385 error_ptr->SetErrorToErrno();
386 else
387 error_ptr->Clear();
Greg Clayton968fa382011-02-08 19:10:53 +0000388 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000389 } else if (error_ptr) {
390 error_ptr->SetErrorString("invalid file handle");
391 }
392 return result;
Greg Clayton968fa382011-02-08 19:10:53 +0000393}
394
Zachary Turner97206d52017-05-12 04:51:55 +0000395off_t File::SeekFromEnd(off_t offset, Status *error_ptr) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000396 off_t result = -1;
397 if (DescriptorIsValid()) {
398 result = ::lseek(m_descriptor, offset, SEEK_END);
399
400 if (error_ptr) {
401 if (result == -1)
402 error_ptr->SetErrorToErrno();
403 else
404 error_ptr->Clear();
Greg Clayton968fa382011-02-08 19:10:53 +0000405 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000406 } else if (StreamIsValid()) {
407 result = ::fseek(m_stream, offset, SEEK_END);
408
409 if (error_ptr) {
410 if (result == -1)
411 error_ptr->SetErrorToErrno();
412 else
413 error_ptr->Clear();
Greg Clayton968fa382011-02-08 19:10:53 +0000414 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000415 } else if (error_ptr) {
416 error_ptr->SetErrorString("invalid file handle");
417 }
418 return result;
Greg Clayton968fa382011-02-08 19:10:53 +0000419}
420
Zachary Turner97206d52017-05-12 04:51:55 +0000421Status File::Flush() {
422 Status error;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000423 if (StreamIsValid()) {
424 int err = 0;
425 do {
426 err = ::fflush(m_stream);
427 } while (err == EOF && errno == EINTR);
428
429 if (err == EOF)
430 error.SetErrorToErrno();
431 } else if (!DescriptorIsValid()) {
432 error.SetErrorString("invalid file handle");
433 }
434 return error;
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000435}
436
Zachary Turner97206d52017-05-12 04:51:55 +0000437Status File::Sync() {
438 Status error;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000439 if (DescriptorIsValid()) {
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000440#ifdef _WIN32
Kate Stoneb9c1b512016-09-06 20:57:50 +0000441 int err = FlushFileBuffers((HANDLE)_get_osfhandle(m_descriptor));
442 if (err == 0)
443 error.SetErrorToGenericError();
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000444#else
Kate Stoneb9c1b512016-09-06 20:57:50 +0000445 int err = 0;
446 do {
447 err = ::fsync(m_descriptor);
448 } while (err == -1 && errno == EINTR);
449
450 if (err == -1)
451 error.SetErrorToErrno();
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000452#endif
Kate Stoneb9c1b512016-09-06 20:57:50 +0000453 } else {
454 error.SetErrorString("invalid file handle");
455 }
456 return error;
Greg Clayton968fa382011-02-08 19:10:53 +0000457}
Greg Clayton846b64b2011-02-08 19:54:44 +0000458
Kate Stoneb9c1b512016-09-06 20:57:50 +0000459#if defined(__APPLE__)
Greg Clayton29aac9a2015-04-09 00:06:44 +0000460// Darwin kernels only can read/write <= INT_MAX bytes
461#define MAX_READ_SIZE INT_MAX
462#define MAX_WRITE_SIZE INT_MAX
463#endif
464
Zachary Turner97206d52017-05-12 04:51:55 +0000465Status File::Read(void *buf, size_t &num_bytes) {
466 Status error;
Greg Clayton29aac9a2015-04-09 00:06:44 +0000467
Kate Stoneb9c1b512016-09-06 20:57:50 +0000468#if defined(MAX_READ_SIZE)
469 if (num_bytes > MAX_READ_SIZE) {
470 uint8_t *p = (uint8_t *)buf;
471 size_t bytes_left = num_bytes;
472 // Init the num_bytes read to zero
473 num_bytes = 0;
Greg Clayton29aac9a2015-04-09 00:06:44 +0000474
Kate Stoneb9c1b512016-09-06 20:57:50 +0000475 while (bytes_left > 0) {
476 size_t curr_num_bytes;
477 if (bytes_left > MAX_READ_SIZE)
478 curr_num_bytes = MAX_READ_SIZE;
479 else
480 curr_num_bytes = bytes_left;
Greg Clayton29aac9a2015-04-09 00:06:44 +0000481
Kate Stoneb9c1b512016-09-06 20:57:50 +0000482 error = Read(p + num_bytes, curr_num_bytes);
Greg Clayton29aac9a2015-04-09 00:06:44 +0000483
Kate Stoneb9c1b512016-09-06 20:57:50 +0000484 // Update how many bytes were read
485 num_bytes += curr_num_bytes;
486 if (bytes_left < curr_num_bytes)
487 bytes_left = 0;
488 else
489 bytes_left -= curr_num_bytes;
Greg Clayton29aac9a2015-04-09 00:06:44 +0000490
Kate Stoneb9c1b512016-09-06 20:57:50 +0000491 if (error.Fail())
492 break;
Greg Clayton504f89a2011-02-08 17:49:02 +0000493 }
494 return error;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000495 }
Greg Clayton29aac9a2015-04-09 00:06:44 +0000496#endif
497
Kate Stoneb9c1b512016-09-06 20:57:50 +0000498 ssize_t bytes_read = -1;
499 if (DescriptorIsValid()) {
500 do {
501 bytes_read = ::read(m_descriptor, buf, num_bytes);
502 } while (bytes_read < 0 && errno == EINTR);
Greg Clayton96c09682012-01-04 22:56:43 +0000503
Kate Stoneb9c1b512016-09-06 20:57:50 +0000504 if (bytes_read == -1) {
505 error.SetErrorToErrno();
506 num_bytes = 0;
507 } else
508 num_bytes = bytes_read;
509 } else if (StreamIsValid()) {
510 bytes_read = ::fread(buf, 1, num_bytes, m_stream);
Greg Clayton96c09682012-01-04 22:56:43 +0000511
Kate Stoneb9c1b512016-09-06 20:57:50 +0000512 if (bytes_read == 0) {
513 if (::feof(m_stream))
514 error.SetErrorString("feof");
515 else if (::ferror(m_stream))
516 error.SetErrorString("ferror");
517 num_bytes = 0;
518 } else
519 num_bytes = bytes_read;
520 } else {
521 num_bytes = 0;
522 error.SetErrorString("invalid file handle");
523 }
524 return error;
Greg Clayton504f89a2011-02-08 17:49:02 +0000525}
526
Zachary Turner97206d52017-05-12 04:51:55 +0000527Status File::Write(const void *buf, size_t &num_bytes) {
528 Status error;
Greg Clayton846b64b2011-02-08 19:54:44 +0000529
Kate Stoneb9c1b512016-09-06 20:57:50 +0000530#if defined(MAX_WRITE_SIZE)
531 if (num_bytes > MAX_WRITE_SIZE) {
532 const uint8_t *p = (const uint8_t *)buf;
533 size_t bytes_left = num_bytes;
534 // Init the num_bytes written to zero
535 num_bytes = 0;
Greg Clayton29aac9a2015-04-09 00:06:44 +0000536
Kate Stoneb9c1b512016-09-06 20:57:50 +0000537 while (bytes_left > 0) {
538 size_t curr_num_bytes;
539 if (bytes_left > MAX_WRITE_SIZE)
540 curr_num_bytes = MAX_WRITE_SIZE;
541 else
542 curr_num_bytes = bytes_left;
Greg Clayton29aac9a2015-04-09 00:06:44 +0000543
Kate Stoneb9c1b512016-09-06 20:57:50 +0000544 error = Write(p + num_bytes, curr_num_bytes);
Greg Clayton29aac9a2015-04-09 00:06:44 +0000545
Kate Stoneb9c1b512016-09-06 20:57:50 +0000546 // Update how many bytes were read
547 num_bytes += curr_num_bytes;
548 if (bytes_left < curr_num_bytes)
549 bytes_left = 0;
550 else
551 bytes_left -= curr_num_bytes;
Greg Clayton29aac9a2015-04-09 00:06:44 +0000552
Kate Stoneb9c1b512016-09-06 20:57:50 +0000553 if (error.Fail())
554 break;
Greg Clayton29aac9a2015-04-09 00:06:44 +0000555 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000556 return error;
557 }
558#endif
559
560 ssize_t bytes_written = -1;
561 if (DescriptorIsValid()) {
562 do {
563 bytes_written = ::write(m_descriptor, buf, num_bytes);
564 } while (bytes_written < 0 && errno == EINTR);
565
566 if (bytes_written == -1) {
567 error.SetErrorToErrno();
568 num_bytes = 0;
569 } else
570 num_bytes = bytes_written;
571 } else if (StreamIsValid()) {
572 bytes_written = ::fwrite(buf, 1, num_bytes, m_stream);
573
574 if (bytes_written == 0) {
575 if (::feof(m_stream))
576 error.SetErrorString("feof");
577 else if (::ferror(m_stream))
578 error.SetErrorString("ferror");
579 num_bytes = 0;
580 } else
581 num_bytes = bytes_written;
582
583 } else {
584 num_bytes = 0;
585 error.SetErrorString("invalid file handle");
586 }
587
588 return error;
589}
590
Zachary Turner97206d52017-05-12 04:51:55 +0000591Status File::Read(void *buf, size_t &num_bytes, off_t &offset) {
592 Status error;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000593
594#if defined(MAX_READ_SIZE)
595 if (num_bytes > MAX_READ_SIZE) {
596 uint8_t *p = (uint8_t *)buf;
597 size_t bytes_left = num_bytes;
598 // Init the num_bytes read to zero
599 num_bytes = 0;
600
601 while (bytes_left > 0) {
602 size_t curr_num_bytes;
603 if (bytes_left > MAX_READ_SIZE)
604 curr_num_bytes = MAX_READ_SIZE;
605 else
606 curr_num_bytes = bytes_left;
607
608 error = Read(p + num_bytes, curr_num_bytes, offset);
609
610 // Update how many bytes were read
611 num_bytes += curr_num_bytes;
612 if (bytes_left < curr_num_bytes)
613 bytes_left = 0;
614 else
615 bytes_left -= curr_num_bytes;
616
617 if (error.Fail())
618 break;
619 }
620 return error;
621 }
Greg Clayton29aac9a2015-04-09 00:06:44 +0000622#endif
623
624#ifndef _WIN32
Kate Stoneb9c1b512016-09-06 20:57:50 +0000625 int fd = GetDescriptor();
626 if (fd != kInvalidDescriptor) {
627 ssize_t bytes_read = -1;
628 do {
629 bytes_read = ::pread(fd, buf, num_bytes, offset);
630 } while (bytes_read < 0 && errno == EINTR);
Greg Clayton96c09682012-01-04 22:56:43 +0000631
Kate Stoneb9c1b512016-09-06 20:57:50 +0000632 if (bytes_read < 0) {
633 num_bytes = 0;
634 error.SetErrorToErrno();
635 } else {
636 offset += bytes_read;
637 num_bytes = bytes_read;
Greg Clayton846b64b2011-02-08 19:54:44 +0000638 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000639 } else {
640 num_bytes = 0;
641 error.SetErrorString("invalid file handle");
642 }
643#else
644 long cur = ::lseek(m_descriptor, 0, SEEK_CUR);
645 SeekFromStart(offset);
646 error = Read(buf, num_bytes);
647 if (!error.Fail())
648 SeekFromStart(cur);
649#endif
650 return error;
651}
652
Zachary Turner97206d52017-05-12 04:51:55 +0000653Status File::Read(size_t &num_bytes, off_t &offset, bool null_terminate,
654 DataBufferSP &data_buffer_sp) {
655 Status error;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000656
657 if (num_bytes > 0) {
658 int fd = GetDescriptor();
659 if (fd != kInvalidDescriptor) {
660 struct stat file_stats;
661 if (::fstat(fd, &file_stats) == 0) {
662 if (file_stats.st_size > offset) {
663 const size_t bytes_left = file_stats.st_size - offset;
664 if (num_bytes > bytes_left)
665 num_bytes = bytes_left;
666
667 size_t num_bytes_plus_nul_char = num_bytes + (null_terminate ? 1 : 0);
668 std::unique_ptr<DataBufferHeap> data_heap_ap;
669 data_heap_ap.reset(new DataBufferHeap());
670 data_heap_ap->SetByteSize(num_bytes_plus_nul_char);
671
672 if (data_heap_ap.get()) {
673 error = Read(data_heap_ap->GetBytes(), num_bytes, offset);
674 if (error.Success()) {
675 // Make sure we read exactly what we asked for and if we got
676 // less, adjust the array
677 if (num_bytes_plus_nul_char < data_heap_ap->GetByteSize())
678 data_heap_ap->SetByteSize(num_bytes_plus_nul_char);
679 data_buffer_sp.reset(data_heap_ap.release());
680 return error;
681 }
682 }
683 } else
684 error.SetErrorString("file is empty");
685 } else
686 error.SetErrorToErrno();
687 } else
688 error.SetErrorString("invalid file handle");
689 } else
690 error.SetErrorString("invalid file handle");
691
692 num_bytes = 0;
693 data_buffer_sp.reset();
694 return error;
695}
696
Zachary Turner97206d52017-05-12 04:51:55 +0000697Status File::Write(const void *buf, size_t &num_bytes, off_t &offset) {
698 Status error;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000699
700#if defined(MAX_WRITE_SIZE)
701 if (num_bytes > MAX_WRITE_SIZE) {
702 const uint8_t *p = (const uint8_t *)buf;
703 size_t bytes_left = num_bytes;
704 // Init the num_bytes written to zero
705 num_bytes = 0;
706
707 while (bytes_left > 0) {
708 size_t curr_num_bytes;
709 if (bytes_left > MAX_WRITE_SIZE)
710 curr_num_bytes = MAX_WRITE_SIZE;
711 else
712 curr_num_bytes = bytes_left;
713
714 error = Write(p + num_bytes, curr_num_bytes, offset);
715
716 // Update how many bytes were read
717 num_bytes += curr_num_bytes;
718 if (bytes_left < curr_num_bytes)
719 bytes_left = 0;
720 else
721 bytes_left -= curr_num_bytes;
722
723 if (error.Fail())
724 break;
725 }
726 return error;
727 }
728#endif
729
730 int fd = GetDescriptor();
731 if (fd != kInvalidDescriptor) {
732#ifndef _WIN32
733 ssize_t bytes_written = -1;
734 do {
735 bytes_written = ::pwrite(m_descriptor, buf, num_bytes, offset);
736 } while (bytes_written < 0 && errno == EINTR);
737
738 if (bytes_written < 0) {
739 num_bytes = 0;
740 error.SetErrorToErrno();
741 } else {
742 offset += bytes_written;
743 num_bytes = bytes_written;
Greg Clayton846b64b2011-02-08 19:54:44 +0000744 }
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000745#else
746 long cur = ::lseek(m_descriptor, 0, SEEK_CUR);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000747 error = Write(buf, num_bytes);
748 long after = ::lseek(m_descriptor, 0, SEEK_CUR);
749
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000750 if (!error.Fail())
Kate Stoneb9c1b512016-09-06 20:57:50 +0000751 SeekFromStart(cur);
752
753 offset = after;
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000754#endif
Kate Stoneb9c1b512016-09-06 20:57:50 +0000755 } else {
Greg Clayton96c09682012-01-04 22:56:43 +0000756 num_bytes = 0;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000757 error.SetErrorString("invalid file handle");
758 }
759 return error;
Greg Clayton846b64b2011-02-08 19:54:44 +0000760}
761
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000762//------------------------------------------------------------------
763// Print some formatted output to the stream.
764//------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +0000765size_t File::Printf(const char *format, ...) {
766 va_list args;
767 va_start(args, format);
768 size_t result = PrintfVarArg(format, args);
769 va_end(args);
770 return result;
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000771}
Greg Clayton846b64b2011-02-08 19:54:44 +0000772
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000773//------------------------------------------------------------------
774// Print some formatted output to the stream.
775//------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +0000776size_t File::PrintfVarArg(const char *format, va_list args) {
777 size_t result = 0;
778 if (DescriptorIsValid()) {
779 char *s = NULL;
780 result = vasprintf(&s, format, args);
781 if (s != NULL) {
782 if (result > 0) {
783 size_t s_len = result;
784 Write(s, s_len);
785 result = s_len;
786 }
787 free(s);
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000788 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000789 } else if (StreamIsValid()) {
790 result = ::vfprintf(m_stream, format, args);
791 }
792 return result;
Greg Clayton51b1e2d2011-02-09 01:08:52 +0000793}
Daniel Maleae0f8f572013-08-26 23:57:52 +0000794
Kate Stoneb9c1b512016-09-06 20:57:50 +0000795mode_t File::ConvertOpenOptionsForPOSIXOpen(uint32_t open_options) {
796 mode_t mode = 0;
797 if (open_options & eOpenOptionRead && open_options & eOpenOptionWrite)
798 mode |= O_RDWR;
799 else if (open_options & eOpenOptionWrite)
800 mode |= O_WRONLY;
Daniel Maleae0f8f572013-08-26 23:57:52 +0000801
Kate Stoneb9c1b512016-09-06 20:57:50 +0000802 if (open_options & eOpenOptionAppend)
803 mode |= O_APPEND;
Daniel Maleae0f8f572013-08-26 23:57:52 +0000804
Kate Stoneb9c1b512016-09-06 20:57:50 +0000805 if (open_options & eOpenOptionTruncate)
806 mode |= O_TRUNC;
Daniel Maleae0f8f572013-08-26 23:57:52 +0000807
Kate Stoneb9c1b512016-09-06 20:57:50 +0000808 if (open_options & eOpenOptionNonBlocking)
809 mode |= O_NONBLOCK;
Daniel Maleae0f8f572013-08-26 23:57:52 +0000810
Kate Stoneb9c1b512016-09-06 20:57:50 +0000811 if (open_options & eOpenOptionCanCreateNewOnly)
812 mode |= O_CREAT | O_EXCL;
813 else if (open_options & eOpenOptionCanCreate)
814 mode |= O_CREAT;
815
816 return mode;
Daniel Maleae0f8f572013-08-26 23:57:52 +0000817}
Greg Clayton340b0302014-02-05 17:57:57 +0000818
Kate Stoneb9c1b512016-09-06 20:57:50 +0000819void File::CalculateInteractiveAndTerminal() {
820 const int fd = GetDescriptor();
821 if (fd >= 0) {
822 m_is_interactive = eLazyBoolNo;
823 m_is_real_terminal = eLazyBoolNo;
Pavel Labath6b734562016-08-08 12:26:57 +0000824#if defined(_WIN32)
Kate Stoneb9c1b512016-09-06 20:57:50 +0000825 if (_isatty(fd)) {
826 m_is_interactive = eLazyBoolYes;
827 m_is_real_terminal = eLazyBoolYes;
Greg Clayton340b0302014-02-05 17:57:57 +0000828 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000829#else
830 if (isatty(fd)) {
831 m_is_interactive = eLazyBoolYes;
832 struct winsize window_size;
833 if (::ioctl(fd, TIOCGWINSZ, &window_size) == 0) {
834 if (window_size.ws_col > 0) {
835 m_is_real_terminal = eLazyBoolYes;
836 if (llvm::sys::Process::FileDescriptorHasColors(fd))
837 m_supports_colors = eLazyBoolYes;
838 }
839 }
840 }
841#endif
842 }
Greg Clayton340b0302014-02-05 17:57:57 +0000843}
844
Kate Stoneb9c1b512016-09-06 20:57:50 +0000845bool File::GetIsInteractive() {
846 if (m_is_interactive == eLazyBoolCalculate)
847 CalculateInteractiveAndTerminal();
848 return m_is_interactive == eLazyBoolYes;
Greg Clayton340b0302014-02-05 17:57:57 +0000849}
850
Kate Stoneb9c1b512016-09-06 20:57:50 +0000851bool File::GetIsRealTerminal() {
852 if (m_is_real_terminal == eLazyBoolCalculate)
853 CalculateInteractiveAndTerminal();
854 return m_is_real_terminal == eLazyBoolYes;
Greg Clayton340b0302014-02-05 17:57:57 +0000855}
856
Kate Stoneb9c1b512016-09-06 20:57:50 +0000857bool File::GetIsTerminalWithColors() {
858 if (m_supports_colors == eLazyBoolCalculate)
859 CalculateInteractiveAndTerminal();
860 return m_supports_colors == eLazyBoolYes;
Sean Callanan66810412015-10-19 23:11:07 +0000861}