File.cpp revision 309124
1258884Semaste//===-- File.cpp ------------------------------------------------*- C++ -*-===//
2254721Semaste//
3254721Semaste//                     The LLVM Compiler Infrastructure
4254721Semaste//
5254721Semaste// This file is distributed under the University of Illinois Open Source
6254721Semaste// License. See LICENSE.TXT for details.
7254721Semaste//
8254721Semaste//===----------------------------------------------------------------------===//
9254721Semaste
10254721Semaste#include "lldb/Host/File.h"
11254721Semaste
12254721Semaste#include <errno.h>
13254721Semaste#include <fcntl.h>
14254721Semaste#include <limits.h>
15254721Semaste#include <stdarg.h>
16262528Semaste#include <stdio.h>
17254721Semaste
18258054Semaste#ifdef _WIN32
19258054Semaste#include "lldb/Host/windows/windows.h"
20262528Semaste#else
21262528Semaste#include <sys/ioctl.h>
22258054Semaste#endif
23258054Semaste
24309124Sdim#include "llvm/Support/ConvertUTF.h"
25296417Sdim#include "llvm/Support/Process.h" // for llvm::sys::Process::FileDescriptorHasColors()
26296417Sdim
27254721Semaste#include "lldb/Core/DataBufferHeap.h"
28254721Semaste#include "lldb/Core/Error.h"
29276479Sdim#include "lldb/Core/Log.h"
30254721Semaste#include "lldb/Host/Config.h"
31254721Semaste#include "lldb/Host/FileSpec.h"
32309124Sdim#include "lldb/Host/FileSystem.h"
33254721Semaste
34254721Semasteusing namespace lldb;
35254721Semasteusing namespace lldb_private;
36254721Semaste
37254721Semastestatic const char *
38254721SemasteGetStreamOpenModeFromOptions (uint32_t options)
39254721Semaste{
40254721Semaste    if (options & File::eOpenOptionAppend)
41254721Semaste    {
42254721Semaste        if (options & File::eOpenOptionRead)
43254721Semaste        {
44254721Semaste            if (options & File::eOpenOptionCanCreateNewOnly)
45254721Semaste                return "a+x";
46254721Semaste            else
47254721Semaste                return "a+";
48254721Semaste        }
49254721Semaste        else if (options & File::eOpenOptionWrite)
50254721Semaste        {
51254721Semaste            if (options & File::eOpenOptionCanCreateNewOnly)
52254721Semaste                return "ax";
53254721Semaste            else
54254721Semaste                return "a";
55254721Semaste        }
56254721Semaste    }
57254721Semaste    else if (options & File::eOpenOptionRead && options & File::eOpenOptionWrite)
58254721Semaste    {
59254721Semaste        if (options & File::eOpenOptionCanCreate)
60254721Semaste        {
61254721Semaste            if (options & File::eOpenOptionCanCreateNewOnly)
62254721Semaste                return "w+x";
63254721Semaste            else
64254721Semaste                return "w+";
65254721Semaste        }
66254721Semaste        else
67254721Semaste            return "r+";
68254721Semaste    }
69254721Semaste    else if (options & File::eOpenOptionRead)
70254721Semaste    {
71254721Semaste        return "r";
72254721Semaste    }
73254721Semaste    else if (options & File::eOpenOptionWrite)
74254721Semaste    {
75254721Semaste        return "w";
76254721Semaste    }
77254721Semaste    return NULL;
78254721Semaste}
79254721Semaste
80254721Semasteint File::kInvalidDescriptor = -1;
81254721SemasteFILE * File::kInvalidStream = NULL;
82254721Semaste
83254721SemasteFile::File(const char *path, uint32_t options, uint32_t permissions) :
84276479Sdim    IOObject(eFDTypeFile, false),
85254721Semaste    m_descriptor (kInvalidDescriptor),
86254721Semaste    m_stream (kInvalidStream),
87262528Semaste    m_options (),
88262528Semaste    m_own_stream (false),
89262528Semaste    m_is_interactive (eLazyBoolCalculate),
90262528Semaste    m_is_real_terminal (eLazyBoolCalculate)
91254721Semaste{
92254721Semaste    Open (path, options, permissions);
93254721Semaste}
94254721Semaste
95258054SemasteFile::File (const FileSpec& filespec,
96258054Semaste            uint32_t options,
97258054Semaste            uint32_t permissions) :
98276479Sdim    IOObject(eFDTypeFile, false),
99258054Semaste    m_descriptor (kInvalidDescriptor),
100258054Semaste    m_stream (kInvalidStream),
101258054Semaste    m_options (0),
102262528Semaste    m_own_stream (false),
103262528Semaste    m_is_interactive (eLazyBoolCalculate),
104262528Semaste    m_is_real_terminal (eLazyBoolCalculate)
105262528Semaste
106258054Semaste{
107258054Semaste    if (filespec)
108258054Semaste    {
109258054Semaste        Open (filespec.GetPath().c_str(), options, permissions);
110258054Semaste    }
111258054Semaste}
112258054Semaste
113254721SemasteFile::~File()
114254721Semaste{
115254721Semaste    Close ();
116254721Semaste}
117254721Semaste
118254721Semaste
119254721Semasteint
120254721SemasteFile::GetDescriptor() const
121254721Semaste{
122254721Semaste    if (DescriptorIsValid())
123254721Semaste        return m_descriptor;
124254721Semaste
125254721Semaste    // Don't open the file descriptor if we don't need to, just get it from the
126254721Semaste    // stream if we have one.
127254721Semaste    if (StreamIsValid())
128296417Sdim    {
129296417Sdim#if defined(LLVM_ON_WIN32)
130296417Sdim        return _fileno(m_stream);
131296417Sdim#else
132296417Sdim        return fileno(m_stream);
133296417Sdim#endif
134296417Sdim    }
135254721Semaste
136254721Semaste    // Invalid descriptor and invalid stream, return invalid descriptor.
137254721Semaste    return kInvalidDescriptor;
138254721Semaste}
139254721Semaste
140276479SdimIOObject::WaitableHandle
141276479SdimFile::GetWaitableHandle()
142276479Sdim{
143276479Sdim    return m_descriptor;
144276479Sdim}
145276479Sdim
146276479Sdim
147254721Semastevoid
148254721SemasteFile::SetDescriptor (int fd, bool transfer_ownership)
149254721Semaste{
150254721Semaste    if (IsValid())
151254721Semaste        Close();
152254721Semaste    m_descriptor = fd;
153276479Sdim    m_should_close_fd = transfer_ownership;
154254721Semaste}
155254721Semaste
156254721Semaste
157254721SemasteFILE *
158254721SemasteFile::GetStream ()
159254721Semaste{
160254721Semaste    if (!StreamIsValid())
161254721Semaste    {
162254721Semaste        if (DescriptorIsValid())
163254721Semaste        {
164254721Semaste            const char *mode = GetStreamOpenModeFromOptions (m_options);
165254721Semaste            if (mode)
166254721Semaste            {
167276479Sdim                if (!m_should_close_fd)
168262528Semaste                {
169262528Semaste                    // We must duplicate the file descriptor if we don't own it because
170262528Semaste                    // when you call fdopen, the stream will own the fd
171262528Semaste#ifdef _WIN32
172262528Semaste                    m_descriptor = ::_dup(GetDescriptor());
173262528Semaste#else
174309124Sdim                    m_descriptor = dup(GetDescriptor());
175262528Semaste#endif
176276479Sdim                    m_should_close_fd = true;
177262528Semaste                }
178262528Semaste
179254721Semaste                do
180254721Semaste                {
181254721Semaste                    m_stream = ::fdopen (m_descriptor, mode);
182254721Semaste                } while (m_stream == NULL && errno == EINTR);
183262528Semaste
184262528Semaste                // If we got a stream, then we own the stream and should no
185262528Semaste                // longer own the descriptor because fclose() will close it for us
186262528Semaste
187262528Semaste                if (m_stream)
188262528Semaste                {
189262528Semaste                    m_own_stream = true;
190276479Sdim                    m_should_close_fd = false;
191262528Semaste                }
192254721Semaste            }
193254721Semaste        }
194254721Semaste    }
195254721Semaste    return m_stream;
196254721Semaste}
197254721Semaste
198254721Semastevoid
199254721SemasteFile::SetStream (FILE *fh, bool transfer_ownership)
200254721Semaste{
201254721Semaste    if (IsValid())
202254721Semaste        Close();
203254721Semaste    m_stream = fh;
204262528Semaste    m_own_stream = transfer_ownership;
205254721Semaste}
206254721Semaste
207254721SemasteError
208254721SemasteFile::Open (const char *path, uint32_t options, uint32_t permissions)
209254721Semaste{
210254721Semaste    Error error;
211254721Semaste    if (IsValid())
212254721Semaste        Close ();
213254721Semaste
214254721Semaste    int oflag = 0;
215254721Semaste    const bool read = options & eOpenOptionRead;
216254721Semaste    const bool write = options & eOpenOptionWrite;
217254721Semaste    if (write)
218254721Semaste    {
219254721Semaste        if (read)
220254721Semaste            oflag |= O_RDWR;
221254721Semaste        else
222254721Semaste            oflag |= O_WRONLY;
223254721Semaste
224254721Semaste        if (options & eOpenOptionAppend)
225254721Semaste            oflag |= O_APPEND;
226254721Semaste
227254721Semaste        if (options & eOpenOptionTruncate)
228254721Semaste            oflag |= O_TRUNC;
229254721Semaste
230254721Semaste        if (options & eOpenOptionCanCreate)
231254721Semaste            oflag |= O_CREAT;
232254721Semaste
233254721Semaste        if (options & eOpenOptionCanCreateNewOnly)
234254721Semaste            oflag |= O_CREAT | O_EXCL;
235254721Semaste    }
236254721Semaste    else if (read)
237254721Semaste    {
238254721Semaste        oflag |= O_RDONLY;
239258884Semaste
240258884Semaste#ifndef _WIN32
241309124Sdim        if (options & eOpenOptionDontFollowSymlinks)
242258884Semaste            oflag |= O_NOFOLLOW;
243258884Semaste#endif
244254721Semaste    }
245254721Semaste
246258054Semaste#ifndef _WIN32
247254721Semaste    if (options & eOpenOptionNonBlocking)
248254721Semaste        oflag |= O_NONBLOCK;
249288943Sdim    if (options & eOpenOptionCloseOnExec)
250288943Sdim        oflag |= O_CLOEXEC;
251258054Semaste#else
252258054Semaste    oflag |= O_BINARY;
253258054Semaste#endif
254254721Semaste
255254721Semaste    mode_t mode = 0;
256254721Semaste    if (oflag & O_CREAT)
257254721Semaste    {
258258884Semaste        if (permissions & lldb::eFilePermissionsUserRead)     mode |= S_IRUSR;
259258884Semaste        if (permissions & lldb::eFilePermissionsUserWrite)    mode |= S_IWUSR;
260258884Semaste        if (permissions & lldb::eFilePermissionsUserExecute)  mode |= S_IXUSR;
261258884Semaste        if (permissions & lldb::eFilePermissionsGroupRead)    mode |= S_IRGRP;
262258884Semaste        if (permissions & lldb::eFilePermissionsGroupWrite)   mode |= S_IWGRP;
263258884Semaste        if (permissions & lldb::eFilePermissionsGroupExecute) mode |= S_IXGRP;
264258884Semaste        if (permissions & lldb::eFilePermissionsWorldRead)    mode |= S_IROTH;
265258884Semaste        if (permissions & lldb::eFilePermissionsWorldWrite)   mode |= S_IWOTH;
266258884Semaste        if (permissions & lldb::eFilePermissionsWorldExecute) mode |= S_IXOTH;
267254721Semaste    }
268254721Semaste
269254721Semaste    do
270254721Semaste    {
271309124Sdim#ifdef _WIN32
272309124Sdim        std::wstring wpath;
273309124Sdim        if (!llvm::ConvertUTF8toWide(path, wpath))
274309124Sdim        {
275309124Sdim            m_descriptor = -1;
276309124Sdim            error.SetErrorString("Error converting path to UTF-16");
277309124Sdim            return error;
278309124Sdim        }
279309124Sdim        ::_wsopen_s(&m_descriptor, wpath.c_str(), oflag, _SH_DENYNO, mode);
280309124Sdim#else
281254721Semaste        m_descriptor = ::open(path, oflag, mode);
282309124Sdim#endif
283254721Semaste    } while (m_descriptor < 0 && errno == EINTR);
284254721Semaste
285254721Semaste    if (!DescriptorIsValid())
286254721Semaste        error.SetErrorToErrno();
287254721Semaste    else
288262528Semaste    {
289276479Sdim        m_should_close_fd = true;
290262528Semaste        m_options = options;
291262528Semaste    }
292254721Semaste
293254721Semaste    return error;
294254721Semaste}
295254721Semaste
296258054Semasteuint32_t
297288943SdimFile::GetPermissions(const FileSpec &file_spec, Error &error)
298258054Semaste{
299288943Sdim    if (file_spec)
300258054Semaste    {
301258054Semaste        struct stat file_stats;
302309124Sdim        int stat_result = FileSystem::Stat(file_spec.GetCString(), &file_stats);
303309124Sdim        if (stat_result == -1)
304258054Semaste            error.SetErrorToErrno();
305258054Semaste        else
306258054Semaste        {
307258054Semaste            error.Clear();
308258884Semaste            return file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
309258054Semaste        }
310258054Semaste    }
311258054Semaste    else
312288943Sdim        error.SetErrorString ("empty file spec");
313258054Semaste    return 0;
314258054Semaste}
315258054Semaste
316258054Semasteuint32_t
317258054SemasteFile::GetPermissions(Error &error) const
318258054Semaste{
319258054Semaste    int fd = GetDescriptor();
320258054Semaste    if (fd != kInvalidDescriptor)
321258054Semaste    {
322258054Semaste        struct stat file_stats;
323258054Semaste        if (::fstat (fd, &file_stats) == -1)
324258054Semaste            error.SetErrorToErrno();
325258054Semaste        else
326258054Semaste        {
327258054Semaste            error.Clear();
328258884Semaste            return file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
329258054Semaste        }
330258054Semaste    }
331258054Semaste    else
332258054Semaste    {
333258054Semaste        error.SetErrorString ("invalid file descriptor");
334258054Semaste    }
335258054Semaste    return 0;
336258054Semaste}
337258054Semaste
338258054Semaste
339254721SemasteError
340254721SemasteFile::Close ()
341254721Semaste{
342254721Semaste    Error error;
343262528Semaste    if (StreamIsValid() && m_own_stream)
344254721Semaste    {
345262528Semaste        if (::fclose (m_stream) == EOF)
346262528Semaste            error.SetErrorToErrno();
347254721Semaste    }
348262528Semaste
349276479Sdim    if (DescriptorIsValid() && m_should_close_fd)
350262528Semaste    {
351262528Semaste        if (::close (m_descriptor) != 0)
352262528Semaste            error.SetErrorToErrno();
353262528Semaste    }
354262528Semaste    m_descriptor = kInvalidDescriptor;
355262528Semaste    m_stream = kInvalidStream;
356262528Semaste    m_options = 0;
357262528Semaste    m_own_stream = false;
358276479Sdim    m_should_close_fd = false;
359262528Semaste    m_is_interactive = eLazyBoolCalculate;
360262528Semaste    m_is_real_terminal = eLazyBoolCalculate;
361254721Semaste    return error;
362254721Semaste}
363254721Semaste
364309124Sdimvoid
365309124SdimFile::Clear ()
366309124Sdim{
367309124Sdim    m_stream = nullptr;
368309124Sdim    m_descriptor = -1;
369309124Sdim    m_options = 0;
370309124Sdim    m_own_stream = false;
371309124Sdim    m_is_interactive = m_supports_colors = m_is_real_terminal = eLazyBoolCalculate;
372309124Sdim}
373254721Semaste
374254721SemasteError
375254721SemasteFile::GetFileSpec (FileSpec &file_spec) const
376254721Semaste{
377254721Semaste    Error error;
378254721Semaste#ifdef LLDB_CONFIG_FCNTL_GETPATH_SUPPORTED
379254721Semaste    if (IsValid ())
380254721Semaste    {
381254721Semaste        char path[PATH_MAX];
382254721Semaste        if (::fcntl(GetDescriptor(), F_GETPATH, path) == -1)
383254721Semaste            error.SetErrorToErrno();
384254721Semaste        else
385254721Semaste            file_spec.SetFile (path, false);
386254721Semaste    }
387254721Semaste    else
388254721Semaste    {
389254721Semaste        error.SetErrorString("invalid file handle");
390254721Semaste    }
391254721Semaste#elif defined(__linux__)
392254721Semaste    char proc[64];
393254721Semaste    char path[PATH_MAX];
394254721Semaste    if (::snprintf(proc, sizeof(proc), "/proc/self/fd/%d", GetDescriptor()) < 0)
395254721Semaste        error.SetErrorString ("cannot resolve file descriptor");
396254721Semaste    else
397254721Semaste    {
398254721Semaste        ssize_t len;
399254721Semaste        if ((len = ::readlink(proc, path, sizeof(path) - 1)) == -1)
400254721Semaste            error.SetErrorToErrno();
401254721Semaste        else
402254721Semaste        {
403254721Semaste            path[len] = '\0';
404254721Semaste            file_spec.SetFile (path, false);
405254721Semaste        }
406254721Semaste    }
407254721Semaste#else
408254721Semaste    error.SetErrorString ("File::GetFileSpec is not supported on this platform");
409254721Semaste#endif
410254721Semaste
411254721Semaste    if (error.Fail())
412254721Semaste        file_spec.Clear();
413254721Semaste    return error;
414254721Semaste}
415254721Semaste
416254721Semasteoff_t
417254721SemasteFile::SeekFromStart (off_t offset, Error *error_ptr)
418254721Semaste{
419254721Semaste    off_t result = 0;
420254721Semaste    if (DescriptorIsValid())
421254721Semaste    {
422254721Semaste        result = ::lseek (m_descriptor, offset, SEEK_SET);
423254721Semaste
424254721Semaste        if (error_ptr)
425254721Semaste        {
426254721Semaste            if (result == -1)
427254721Semaste                error_ptr->SetErrorToErrno();
428254721Semaste            else
429254721Semaste                error_ptr->Clear();
430254721Semaste        }
431254721Semaste    }
432254721Semaste    else if (StreamIsValid ())
433254721Semaste    {
434254721Semaste        result = ::fseek(m_stream, offset, SEEK_SET);
435254721Semaste
436254721Semaste        if (error_ptr)
437254721Semaste        {
438254721Semaste            if (result == -1)
439254721Semaste                error_ptr->SetErrorToErrno();
440254721Semaste            else
441254721Semaste                error_ptr->Clear();
442254721Semaste        }
443254721Semaste    }
444254721Semaste    else if (error_ptr)
445254721Semaste    {
446254721Semaste        error_ptr->SetErrorString("invalid file handle");
447254721Semaste    }
448254721Semaste    return result;
449254721Semaste}
450254721Semaste
451254721Semasteoff_t
452254721SemasteFile::SeekFromCurrent (off_t offset,  Error *error_ptr)
453254721Semaste{
454254721Semaste    off_t result = -1;
455254721Semaste    if (DescriptorIsValid())
456254721Semaste    {
457254721Semaste        result = ::lseek (m_descriptor, offset, SEEK_CUR);
458254721Semaste
459254721Semaste        if (error_ptr)
460254721Semaste        {
461254721Semaste            if (result == -1)
462254721Semaste                error_ptr->SetErrorToErrno();
463254721Semaste            else
464254721Semaste                error_ptr->Clear();
465254721Semaste        }
466254721Semaste    }
467254721Semaste    else if (StreamIsValid ())
468254721Semaste    {
469254721Semaste        result = ::fseek(m_stream, offset, SEEK_CUR);
470254721Semaste
471254721Semaste        if (error_ptr)
472254721Semaste        {
473254721Semaste            if (result == -1)
474254721Semaste                error_ptr->SetErrorToErrno();
475254721Semaste            else
476254721Semaste                error_ptr->Clear();
477254721Semaste        }
478254721Semaste    }
479254721Semaste    else if (error_ptr)
480254721Semaste    {
481254721Semaste        error_ptr->SetErrorString("invalid file handle");
482254721Semaste    }
483254721Semaste    return result;
484254721Semaste}
485254721Semaste
486254721Semasteoff_t
487254721SemasteFile::SeekFromEnd (off_t offset, Error *error_ptr)
488254721Semaste{
489254721Semaste    off_t result = -1;
490254721Semaste    if (DescriptorIsValid())
491254721Semaste    {
492254721Semaste        result = ::lseek (m_descriptor, offset, SEEK_END);
493254721Semaste
494254721Semaste        if (error_ptr)
495254721Semaste        {
496254721Semaste            if (result == -1)
497254721Semaste                error_ptr->SetErrorToErrno();
498254721Semaste            else
499254721Semaste                error_ptr->Clear();
500254721Semaste        }
501254721Semaste    }
502254721Semaste    else if (StreamIsValid ())
503254721Semaste    {
504254721Semaste        result = ::fseek(m_stream, offset, SEEK_END);
505254721Semaste
506254721Semaste        if (error_ptr)
507254721Semaste        {
508254721Semaste            if (result == -1)
509254721Semaste                error_ptr->SetErrorToErrno();
510254721Semaste            else
511254721Semaste                error_ptr->Clear();
512254721Semaste        }
513254721Semaste    }
514254721Semaste    else if (error_ptr)
515254721Semaste    {
516254721Semaste        error_ptr->SetErrorString("invalid file handle");
517254721Semaste    }
518254721Semaste    return result;
519254721Semaste}
520254721Semaste
521254721SemasteError
522254721SemasteFile::Flush ()
523254721Semaste{
524254721Semaste    Error error;
525254721Semaste    if (StreamIsValid())
526254721Semaste    {
527254721Semaste        int err = 0;
528254721Semaste        do
529254721Semaste        {
530254721Semaste            err = ::fflush (m_stream);
531254721Semaste        } while (err == EOF && errno == EINTR);
532254721Semaste
533254721Semaste        if (err == EOF)
534254721Semaste            error.SetErrorToErrno();
535254721Semaste    }
536254721Semaste    else if (!DescriptorIsValid())
537254721Semaste    {
538254721Semaste        error.SetErrorString("invalid file handle");
539254721Semaste    }
540254721Semaste    return error;
541254721Semaste}
542254721Semaste
543254721Semaste
544254721SemasteError
545254721SemasteFile::Sync ()
546254721Semaste{
547254721Semaste    Error error;
548254721Semaste    if (DescriptorIsValid())
549254721Semaste    {
550258054Semaste#ifdef _WIN32
551258054Semaste        int err = FlushFileBuffers((HANDLE)_get_osfhandle(m_descriptor));
552258054Semaste        if (err == 0)
553258054Semaste            error.SetErrorToGenericError();
554258054Semaste#else
555254721Semaste        int err = 0;
556254721Semaste        do
557254721Semaste        {
558254721Semaste            err = ::fsync (m_descriptor);
559254721Semaste        } while (err == -1 && errno == EINTR);
560254721Semaste
561254721Semaste        if (err == -1)
562254721Semaste            error.SetErrorToErrno();
563258054Semaste#endif
564254721Semaste    }
565254721Semaste    else
566254721Semaste    {
567254721Semaste        error.SetErrorString("invalid file handle");
568254721Semaste    }
569254721Semaste    return error;
570254721Semaste}
571254721Semaste
572288943Sdim#if defined (__APPLE__)
573288943Sdim// Darwin kernels only can read/write <= INT_MAX bytes
574288943Sdim#define MAX_READ_SIZE INT_MAX
575288943Sdim#define MAX_WRITE_SIZE INT_MAX
576288943Sdim#endif
577288943Sdim
578254721SemasteError
579254721SemasteFile::Read (void *buf, size_t &num_bytes)
580254721Semaste{
581254721Semaste    Error error;
582288943Sdim
583288943Sdim#if defined (MAX_READ_SIZE)
584288943Sdim    if (num_bytes > MAX_READ_SIZE)
585288943Sdim    {
586288943Sdim        uint8_t *p = (uint8_t *)buf;
587288943Sdim        size_t bytes_left = num_bytes;
588288943Sdim        // Init the num_bytes read to zero
589288943Sdim        num_bytes = 0;
590288943Sdim
591288943Sdim        while (bytes_left > 0)
592288943Sdim        {
593288943Sdim            size_t curr_num_bytes;
594288943Sdim            if (bytes_left > MAX_READ_SIZE)
595288943Sdim                curr_num_bytes = MAX_READ_SIZE;
596288943Sdim            else
597288943Sdim                curr_num_bytes = bytes_left;
598288943Sdim
599288943Sdim            error = Read (p + num_bytes, curr_num_bytes);
600288943Sdim
601288943Sdim            // Update how many bytes were read
602288943Sdim            num_bytes += curr_num_bytes;
603288943Sdim            if (bytes_left < curr_num_bytes)
604288943Sdim                bytes_left = 0;
605288943Sdim            else
606288943Sdim                bytes_left -= curr_num_bytes;
607288943Sdim
608288943Sdim            if (error.Fail())
609288943Sdim                break;
610288943Sdim        }
611288943Sdim        return error;
612288943Sdim    }
613288943Sdim#endif
614288943Sdim
615254721Semaste    ssize_t bytes_read = -1;
616254721Semaste    if (DescriptorIsValid())
617254721Semaste    {
618254721Semaste        do
619254721Semaste        {
620254721Semaste            bytes_read = ::read (m_descriptor, buf, num_bytes);
621254721Semaste        } while (bytes_read < 0 && errno == EINTR);
622254721Semaste
623254721Semaste        if (bytes_read == -1)
624254721Semaste        {
625254721Semaste            error.SetErrorToErrno();
626254721Semaste            num_bytes = 0;
627254721Semaste        }
628254721Semaste        else
629254721Semaste            num_bytes = bytes_read;
630254721Semaste    }
631254721Semaste    else if (StreamIsValid())
632254721Semaste    {
633254721Semaste        bytes_read = ::fread (buf, 1, num_bytes, m_stream);
634254721Semaste
635254721Semaste        if (bytes_read == 0)
636254721Semaste        {
637254721Semaste            if (::feof(m_stream))
638254721Semaste                error.SetErrorString ("feof");
639254721Semaste            else if (::ferror (m_stream))
640254721Semaste                error.SetErrorString ("ferror");
641254721Semaste            num_bytes = 0;
642254721Semaste        }
643254721Semaste        else
644254721Semaste            num_bytes = bytes_read;
645254721Semaste    }
646254721Semaste    else
647254721Semaste    {
648254721Semaste        num_bytes = 0;
649254721Semaste        error.SetErrorString("invalid file handle");
650254721Semaste    }
651254721Semaste    return error;
652254721Semaste}
653254721Semaste
654254721SemasteError
655254721SemasteFile::Write (const void *buf, size_t &num_bytes)
656254721Semaste{
657254721Semaste    Error error;
658288943Sdim
659288943Sdim#if defined (MAX_WRITE_SIZE)
660288943Sdim    if (num_bytes > MAX_WRITE_SIZE)
661288943Sdim    {
662288943Sdim        const uint8_t *p = (const uint8_t *)buf;
663288943Sdim        size_t bytes_left = num_bytes;
664288943Sdim        // Init the num_bytes written to zero
665288943Sdim        num_bytes = 0;
666288943Sdim
667288943Sdim        while (bytes_left > 0)
668288943Sdim        {
669288943Sdim            size_t curr_num_bytes;
670288943Sdim            if (bytes_left > MAX_WRITE_SIZE)
671288943Sdim                curr_num_bytes = MAX_WRITE_SIZE;
672288943Sdim            else
673288943Sdim                curr_num_bytes = bytes_left;
674288943Sdim
675288943Sdim            error = Write (p + num_bytes, curr_num_bytes);
676288943Sdim
677288943Sdim            // Update how many bytes were read
678288943Sdim            num_bytes += curr_num_bytes;
679288943Sdim            if (bytes_left < curr_num_bytes)
680288943Sdim                bytes_left = 0;
681288943Sdim            else
682288943Sdim                bytes_left -= curr_num_bytes;
683288943Sdim
684288943Sdim            if (error.Fail())
685288943Sdim                break;
686288943Sdim        }
687288943Sdim        return error;
688288943Sdim    }
689288943Sdim#endif
690288943Sdim
691254721Semaste    ssize_t bytes_written = -1;
692254721Semaste    if (DescriptorIsValid())
693254721Semaste    {
694254721Semaste        do
695254721Semaste        {
696254721Semaste            bytes_written = ::write (m_descriptor, buf, num_bytes);
697254721Semaste        } while (bytes_written < 0 && errno == EINTR);
698254721Semaste
699254721Semaste        if (bytes_written == -1)
700254721Semaste        {
701254721Semaste            error.SetErrorToErrno();
702254721Semaste            num_bytes = 0;
703254721Semaste        }
704254721Semaste        else
705254721Semaste            num_bytes = bytes_written;
706254721Semaste    }
707254721Semaste    else if (StreamIsValid())
708254721Semaste    {
709254721Semaste        bytes_written = ::fwrite (buf, 1, num_bytes, m_stream);
710254721Semaste
711254721Semaste        if (bytes_written == 0)
712254721Semaste        {
713254721Semaste            if (::feof(m_stream))
714254721Semaste                error.SetErrorString ("feof");
715254721Semaste            else if (::ferror (m_stream))
716254721Semaste                error.SetErrorString ("ferror");
717254721Semaste            num_bytes = 0;
718254721Semaste        }
719254721Semaste        else
720254721Semaste            num_bytes = bytes_written;
721254721Semaste
722254721Semaste    }
723254721Semaste    else
724254721Semaste    {
725254721Semaste        num_bytes = 0;
726254721Semaste        error.SetErrorString("invalid file handle");
727254721Semaste    }
728276479Sdim
729254721Semaste    return error;
730254721Semaste}
731254721Semaste
732254721Semaste
733254721SemasteError
734254721SemasteFile::Read (void *buf, size_t &num_bytes, off_t &offset)
735254721Semaste{
736288943Sdim    Error error;
737288943Sdim
738288943Sdim#if defined (MAX_READ_SIZE)
739288943Sdim    if (num_bytes > MAX_READ_SIZE)
740288943Sdim    {
741288943Sdim        uint8_t *p = (uint8_t *)buf;
742288943Sdim        size_t bytes_left = num_bytes;
743288943Sdim        // Init the num_bytes read to zero
744288943Sdim        num_bytes = 0;
745288943Sdim
746288943Sdim        while (bytes_left > 0)
747288943Sdim        {
748288943Sdim            size_t curr_num_bytes;
749288943Sdim            if (bytes_left > MAX_READ_SIZE)
750288943Sdim                curr_num_bytes = MAX_READ_SIZE;
751288943Sdim            else
752288943Sdim                curr_num_bytes = bytes_left;
753288943Sdim
754288943Sdim            error = Read (p + num_bytes, curr_num_bytes, offset);
755288943Sdim
756288943Sdim            // Update how many bytes were read
757288943Sdim            num_bytes += curr_num_bytes;
758288943Sdim            if (bytes_left < curr_num_bytes)
759288943Sdim                bytes_left = 0;
760288943Sdim            else
761288943Sdim                bytes_left -= curr_num_bytes;
762288943Sdim
763288943Sdim            if (error.Fail())
764288943Sdim                break;
765288943Sdim        }
766288943Sdim        return error;
767288943Sdim    }
768288943Sdim#endif
769288943Sdim
770258054Semaste#ifndef _WIN32
771254721Semaste    int fd = GetDescriptor();
772254721Semaste    if (fd != kInvalidDescriptor)
773254721Semaste    {
774254721Semaste        ssize_t bytes_read = -1;
775254721Semaste        do
776254721Semaste        {
777254721Semaste            bytes_read = ::pread (fd, buf, num_bytes, offset);
778254721Semaste        } while (bytes_read < 0 && errno == EINTR);
779254721Semaste
780254721Semaste        if (bytes_read < 0)
781254721Semaste        {
782254721Semaste            num_bytes = 0;
783254721Semaste            error.SetErrorToErrno();
784254721Semaste        }
785254721Semaste        else
786254721Semaste        {
787254721Semaste            offset += bytes_read;
788254721Semaste            num_bytes = bytes_read;
789254721Semaste        }
790254721Semaste    }
791254721Semaste    else
792254721Semaste    {
793254721Semaste        num_bytes = 0;
794254721Semaste        error.SetErrorString("invalid file handle");
795254721Semaste    }
796258054Semaste#else
797258054Semaste    long cur = ::lseek(m_descriptor, 0, SEEK_CUR);
798258054Semaste    SeekFromStart(offset);
799288943Sdim    error = Read(buf, num_bytes);
800258054Semaste    if (!error.Fail())
801258054Semaste        SeekFromStart(cur);
802288943Sdim#endif
803258054Semaste    return error;
804254721Semaste}
805254721Semaste
806254721SemasteError
807254721SemasteFile::Read (size_t &num_bytes, off_t &offset, bool null_terminate, DataBufferSP &data_buffer_sp)
808254721Semaste{
809254721Semaste    Error error;
810254721Semaste
811254721Semaste    if (num_bytes > 0)
812254721Semaste    {
813254721Semaste        int fd = GetDescriptor();
814254721Semaste        if (fd != kInvalidDescriptor)
815254721Semaste        {
816254721Semaste            struct stat file_stats;
817254721Semaste            if (::fstat (fd, &file_stats) == 0)
818254721Semaste            {
819254721Semaste                if (file_stats.st_size > offset)
820254721Semaste                {
821254721Semaste                    const size_t bytes_left = file_stats.st_size - offset;
822254721Semaste                    if (num_bytes > bytes_left)
823254721Semaste                        num_bytes = bytes_left;
824254721Semaste
825288943Sdim                    size_t num_bytes_plus_nul_char = num_bytes + (null_terminate ? 1 : 0);
826254721Semaste                    std::unique_ptr<DataBufferHeap> data_heap_ap;
827288943Sdim                    data_heap_ap.reset(new DataBufferHeap());
828288943Sdim                    data_heap_ap->SetByteSize(num_bytes_plus_nul_char);
829254721Semaste
830254721Semaste                    if (data_heap_ap.get())
831254721Semaste                    {
832254721Semaste                        error = Read (data_heap_ap->GetBytes(), num_bytes, offset);
833254721Semaste                        if (error.Success())
834254721Semaste                        {
835254721Semaste                            // Make sure we read exactly what we asked for and if we got
836254721Semaste                            // less, adjust the array
837288943Sdim                            if (num_bytes_plus_nul_char < data_heap_ap->GetByteSize())
838288943Sdim                                data_heap_ap->SetByteSize(num_bytes_plus_nul_char);
839254721Semaste                            data_buffer_sp.reset(data_heap_ap.release());
840254721Semaste                            return error;
841254721Semaste                        }
842254721Semaste                    }
843254721Semaste                }
844254721Semaste                else
845254721Semaste                    error.SetErrorString("file is empty");
846254721Semaste            }
847254721Semaste            else
848254721Semaste                error.SetErrorToErrno();
849254721Semaste        }
850254721Semaste        else
851254721Semaste            error.SetErrorString("invalid file handle");
852254721Semaste    }
853254721Semaste    else
854254721Semaste        error.SetErrorString("invalid file handle");
855254721Semaste
856254721Semaste    num_bytes = 0;
857254721Semaste    data_buffer_sp.reset();
858254721Semaste    return error;
859254721Semaste}
860254721Semaste
861254721SemasteError
862254721SemasteFile::Write (const void *buf, size_t &num_bytes, off_t &offset)
863254721Semaste{
864254721Semaste    Error error;
865288943Sdim
866288943Sdim#if defined (MAX_WRITE_SIZE)
867288943Sdim    if (num_bytes > MAX_WRITE_SIZE)
868288943Sdim    {
869288943Sdim        const uint8_t *p = (const uint8_t *)buf;
870288943Sdim        size_t bytes_left = num_bytes;
871288943Sdim        // Init the num_bytes written to zero
872288943Sdim        num_bytes = 0;
873288943Sdim
874288943Sdim        while (bytes_left > 0)
875288943Sdim        {
876288943Sdim            size_t curr_num_bytes;
877288943Sdim            if (bytes_left > MAX_WRITE_SIZE)
878288943Sdim                curr_num_bytes = MAX_WRITE_SIZE;
879288943Sdim            else
880288943Sdim                curr_num_bytes = bytes_left;
881288943Sdim
882288943Sdim            error = Write (p + num_bytes, curr_num_bytes, offset);
883288943Sdim
884288943Sdim            // Update how many bytes were read
885288943Sdim            num_bytes += curr_num_bytes;
886288943Sdim            if (bytes_left < curr_num_bytes)
887288943Sdim                bytes_left = 0;
888288943Sdim            else
889288943Sdim                bytes_left -= curr_num_bytes;
890288943Sdim
891288943Sdim            if (error.Fail())
892288943Sdim                break;
893288943Sdim        }
894288943Sdim        return error;
895288943Sdim    }
896288943Sdim#endif
897288943Sdim
898254721Semaste    int fd = GetDescriptor();
899254721Semaste    if (fd != kInvalidDescriptor)
900254721Semaste    {
901258054Semaste#ifndef _WIN32
902254721Semaste        ssize_t bytes_written = -1;
903254721Semaste        do
904254721Semaste        {
905254721Semaste            bytes_written = ::pwrite (m_descriptor, buf, num_bytes, offset);
906254721Semaste        } while (bytes_written < 0 && errno == EINTR);
907254721Semaste
908254721Semaste        if (bytes_written < 0)
909254721Semaste        {
910254721Semaste            num_bytes = 0;
911254721Semaste            error.SetErrorToErrno();
912254721Semaste        }
913254721Semaste        else
914254721Semaste        {
915254721Semaste            offset += bytes_written;
916254721Semaste            num_bytes = bytes_written;
917254721Semaste        }
918258054Semaste#else
919258054Semaste        long cur = ::lseek(m_descriptor, 0, SEEK_CUR);
920258054Semaste        error = Write(buf, num_bytes);
921258054Semaste        long after = ::lseek(m_descriptor, 0, SEEK_CUR);
922258054Semaste
923258054Semaste        if (!error.Fail())
924258054Semaste            SeekFromStart(cur);
925258054Semaste
926258054Semaste        offset = after;
927258054Semaste#endif
928254721Semaste    }
929254721Semaste    else
930254721Semaste    {
931254721Semaste        num_bytes = 0;
932254721Semaste        error.SetErrorString("invalid file handle");
933254721Semaste    }
934254721Semaste    return error;
935254721Semaste}
936254721Semaste
937254721Semaste//------------------------------------------------------------------
938254721Semaste// Print some formatted output to the stream.
939254721Semaste//------------------------------------------------------------------
940254721Semastesize_t
941254721SemasteFile::Printf (const char *format, ...)
942254721Semaste{
943254721Semaste    va_list args;
944254721Semaste    va_start (args, format);
945254721Semaste    size_t result = PrintfVarArg (format, args);
946254721Semaste    va_end (args);
947254721Semaste    return result;
948254721Semaste}
949254721Semaste
950254721Semaste//------------------------------------------------------------------
951254721Semaste// Print some formatted output to the stream.
952254721Semaste//------------------------------------------------------------------
953254721Semastesize_t
954254721SemasteFile::PrintfVarArg (const char *format, va_list args)
955254721Semaste{
956254721Semaste    size_t result = 0;
957254721Semaste    if (DescriptorIsValid())
958254721Semaste    {
959254721Semaste        char *s = NULL;
960254721Semaste        result = vasprintf(&s, format, args);
961254721Semaste        if (s != NULL)
962254721Semaste        {
963254721Semaste            if (result > 0)
964254721Semaste            {
965254721Semaste                size_t s_len = result;
966254721Semaste                Write (s, s_len);
967254721Semaste                result = s_len;
968254721Semaste            }
969254721Semaste            free (s);
970254721Semaste        }
971254721Semaste    }
972254721Semaste    else if (StreamIsValid())
973254721Semaste    {
974254721Semaste        result = ::vfprintf (m_stream, format, args);
975254721Semaste    }
976254721Semaste    return result;
977254721Semaste}
978258054Semaste
979258054Semastemode_t
980258054SemasteFile::ConvertOpenOptionsForPOSIXOpen (uint32_t open_options)
981258054Semaste{
982258054Semaste    mode_t mode = 0;
983258054Semaste    if (open_options & eOpenOptionRead && open_options & eOpenOptionWrite)
984258054Semaste        mode |= O_RDWR;
985258054Semaste    else if (open_options & eOpenOptionWrite)
986258054Semaste        mode |= O_WRONLY;
987258054Semaste
988258054Semaste    if (open_options & eOpenOptionAppend)
989258054Semaste        mode |= O_APPEND;
990258054Semaste
991258054Semaste    if (open_options & eOpenOptionTruncate)
992258054Semaste        mode |= O_TRUNC;
993258054Semaste
994258054Semaste    if (open_options & eOpenOptionNonBlocking)
995258054Semaste        mode |= O_NONBLOCK;
996258054Semaste
997258054Semaste    if (open_options & eOpenOptionCanCreateNewOnly)
998258054Semaste        mode |= O_CREAT | O_EXCL;
999258054Semaste    else if (open_options & eOpenOptionCanCreate)
1000258054Semaste        mode |= O_CREAT;
1001258054Semaste
1002258054Semaste    return mode;
1003258054Semaste}
1004262528Semaste
1005262528Semastevoid
1006262528SemasteFile::CalculateInteractiveAndTerminal ()
1007262528Semaste{
1008262528Semaste    const int fd = GetDescriptor();
1009262528Semaste    if (fd >= 0)
1010262528Semaste    {
1011262528Semaste        m_is_interactive = eLazyBoolNo;
1012262528Semaste        m_is_real_terminal = eLazyBoolNo;
1013309124Sdim#if defined(_WIN32)
1014276479Sdim        if (_isatty(fd))
1015276479Sdim        {
1016276479Sdim            m_is_interactive = eLazyBoolYes;
1017276479Sdim            m_is_real_terminal = eLazyBoolYes;
1018276479Sdim        }
1019276479Sdim#else
1020262528Semaste        if (isatty(fd))
1021262528Semaste        {
1022262528Semaste            m_is_interactive = eLazyBoolYes;
1023262528Semaste            struct winsize window_size;
1024262528Semaste            if (::ioctl (fd, TIOCGWINSZ, &window_size) == 0)
1025262528Semaste            {
1026262528Semaste                if (window_size.ws_col > 0)
1027296417Sdim                {
1028262528Semaste                    m_is_real_terminal = eLazyBoolYes;
1029296417Sdim                    if (llvm::sys::Process::FileDescriptorHasColors(fd))
1030296417Sdim                        m_supports_colors = eLazyBoolYes;
1031296417Sdim                }
1032262528Semaste            }
1033262528Semaste        }
1034262528Semaste#endif
1035262528Semaste    }
1036262528Semaste}
1037262528Semaste
1038262528Semastebool
1039262528SemasteFile::GetIsInteractive ()
1040262528Semaste{
1041262528Semaste    if (m_is_interactive == eLazyBoolCalculate)
1042262528Semaste        CalculateInteractiveAndTerminal ();
1043262528Semaste    return m_is_interactive == eLazyBoolYes;
1044262528Semaste}
1045262528Semaste
1046262528Semastebool
1047262528SemasteFile::GetIsRealTerminal ()
1048262528Semaste{
1049262528Semaste    if (m_is_real_terminal == eLazyBoolCalculate)
1050262528Semaste        CalculateInteractiveAndTerminal();
1051262528Semaste    return m_is_real_terminal == eLazyBoolYes;
1052262528Semaste}
1053262528Semaste
1054296417Sdimbool
1055296417SdimFile::GetIsTerminalWithColors ()
1056296417Sdim{
1057296417Sdim    if (m_supports_colors == eLazyBoolCalculate)
1058296417Sdim        CalculateInteractiveAndTerminal();
1059296417Sdim    return m_supports_colors == eLazyBoolYes;
1060296417Sdim}
1061296417Sdim
1062