File.cpp revision 296417
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#include <sys/stat.h>
18254721Semaste
19258054Semaste#ifdef _WIN32
20258054Semaste#include "lldb/Host/windows/windows.h"
21262528Semaste#else
22262528Semaste#include <sys/ioctl.h>
23258054Semaste#endif
24258054Semaste
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"
32254721Semaste
33254721Semasteusing namespace lldb;
34254721Semasteusing namespace lldb_private;
35254721Semaste
36254721Semastestatic const char *
37254721SemasteGetStreamOpenModeFromOptions (uint32_t options)
38254721Semaste{
39254721Semaste    if (options & File::eOpenOptionAppend)
40254721Semaste    {
41254721Semaste        if (options & File::eOpenOptionRead)
42254721Semaste        {
43254721Semaste            if (options & File::eOpenOptionCanCreateNewOnly)
44254721Semaste                return "a+x";
45254721Semaste            else
46254721Semaste                return "a+";
47254721Semaste        }
48254721Semaste        else if (options & File::eOpenOptionWrite)
49254721Semaste        {
50254721Semaste            if (options & File::eOpenOptionCanCreateNewOnly)
51254721Semaste                return "ax";
52254721Semaste            else
53254721Semaste                return "a";
54254721Semaste        }
55254721Semaste    }
56254721Semaste    else if (options & File::eOpenOptionRead && options & File::eOpenOptionWrite)
57254721Semaste    {
58254721Semaste        if (options & File::eOpenOptionCanCreate)
59254721Semaste        {
60254721Semaste            if (options & File::eOpenOptionCanCreateNewOnly)
61254721Semaste                return "w+x";
62254721Semaste            else
63254721Semaste                return "w+";
64254721Semaste        }
65254721Semaste        else
66254721Semaste            return "r+";
67254721Semaste    }
68254721Semaste    else if (options & File::eOpenOptionRead)
69254721Semaste    {
70254721Semaste        return "r";
71254721Semaste    }
72254721Semaste    else if (options & File::eOpenOptionWrite)
73254721Semaste    {
74254721Semaste        return "w";
75254721Semaste    }
76254721Semaste    return NULL;
77254721Semaste}
78254721Semaste
79254721Semasteint File::kInvalidDescriptor = -1;
80254721SemasteFILE * File::kInvalidStream = NULL;
81254721Semaste
82254721SemasteFile::File(const char *path, uint32_t options, uint32_t permissions) :
83276479Sdim    IOObject(eFDTypeFile, false),
84254721Semaste    m_descriptor (kInvalidDescriptor),
85254721Semaste    m_stream (kInvalidStream),
86262528Semaste    m_options (),
87262528Semaste    m_own_stream (false),
88262528Semaste    m_is_interactive (eLazyBoolCalculate),
89262528Semaste    m_is_real_terminal (eLazyBoolCalculate)
90254721Semaste{
91254721Semaste    Open (path, options, permissions);
92254721Semaste}
93254721Semaste
94258054SemasteFile::File (const FileSpec& filespec,
95258054Semaste            uint32_t options,
96258054Semaste            uint32_t permissions) :
97276479Sdim    IOObject(eFDTypeFile, false),
98258054Semaste    m_descriptor (kInvalidDescriptor),
99258054Semaste    m_stream (kInvalidStream),
100258054Semaste    m_options (0),
101262528Semaste    m_own_stream (false),
102262528Semaste    m_is_interactive (eLazyBoolCalculate),
103262528Semaste    m_is_real_terminal (eLazyBoolCalculate)
104262528Semaste
105258054Semaste{
106258054Semaste    if (filespec)
107258054Semaste    {
108258054Semaste        Open (filespec.GetPath().c_str(), options, permissions);
109258054Semaste    }
110258054Semaste}
111258054Semaste
112254721SemasteFile::File (const File &rhs) :
113276479Sdim    IOObject(eFDTypeFile, false),
114254721Semaste    m_descriptor (kInvalidDescriptor),
115254721Semaste    m_stream (kInvalidStream),
116254721Semaste    m_options (0),
117262528Semaste    m_own_stream (false),
118262528Semaste    m_is_interactive (eLazyBoolCalculate),
119262528Semaste    m_is_real_terminal (eLazyBoolCalculate)
120254721Semaste{
121254721Semaste    Duplicate (rhs);
122254721Semaste}
123254721Semaste
124254721Semaste
125254721SemasteFile &
126254721SemasteFile::operator = (const File &rhs)
127254721Semaste{
128254721Semaste    if (this != &rhs)
129254721Semaste        Duplicate (rhs);
130254721Semaste    return *this;
131254721Semaste}
132254721Semaste
133254721SemasteFile::~File()
134254721Semaste{
135254721Semaste    Close ();
136254721Semaste}
137254721Semaste
138254721Semaste
139254721Semasteint
140254721SemasteFile::GetDescriptor() const
141254721Semaste{
142254721Semaste    if (DescriptorIsValid())
143254721Semaste        return m_descriptor;
144254721Semaste
145254721Semaste    // Don't open the file descriptor if we don't need to, just get it from the
146254721Semaste    // stream if we have one.
147254721Semaste    if (StreamIsValid())
148296417Sdim    {
149296417Sdim#if defined(LLVM_ON_WIN32)
150296417Sdim        return _fileno(m_stream);
151296417Sdim#else
152296417Sdim        return fileno(m_stream);
153296417Sdim#endif
154296417Sdim    }
155254721Semaste
156254721Semaste    // Invalid descriptor and invalid stream, return invalid descriptor.
157254721Semaste    return kInvalidDescriptor;
158254721Semaste}
159254721Semaste
160276479SdimIOObject::WaitableHandle
161276479SdimFile::GetWaitableHandle()
162276479Sdim{
163276479Sdim    return m_descriptor;
164276479Sdim}
165276479Sdim
166276479Sdim
167254721Semastevoid
168254721SemasteFile::SetDescriptor (int fd, bool transfer_ownership)
169254721Semaste{
170254721Semaste    if (IsValid())
171254721Semaste        Close();
172254721Semaste    m_descriptor = fd;
173276479Sdim    m_should_close_fd = transfer_ownership;
174254721Semaste}
175254721Semaste
176254721Semaste
177254721SemasteFILE *
178254721SemasteFile::GetStream ()
179254721Semaste{
180254721Semaste    if (!StreamIsValid())
181254721Semaste    {
182254721Semaste        if (DescriptorIsValid())
183254721Semaste        {
184254721Semaste            const char *mode = GetStreamOpenModeFromOptions (m_options);
185254721Semaste            if (mode)
186254721Semaste            {
187276479Sdim                if (!m_should_close_fd)
188262528Semaste                {
189262528Semaste                    // We must duplicate the file descriptor if we don't own it because
190262528Semaste                    // when you call fdopen, the stream will own the fd
191262528Semaste#ifdef _WIN32
192262528Semaste                    m_descriptor = ::_dup(GetDescriptor());
193262528Semaste#else
194262528Semaste                    m_descriptor = ::fcntl(GetDescriptor(), F_DUPFD);
195262528Semaste#endif
196276479Sdim                    m_should_close_fd = true;
197262528Semaste                }
198262528Semaste
199254721Semaste                do
200254721Semaste                {
201254721Semaste                    m_stream = ::fdopen (m_descriptor, mode);
202254721Semaste                } while (m_stream == NULL && errno == EINTR);
203262528Semaste
204262528Semaste                // If we got a stream, then we own the stream and should no
205262528Semaste                // longer own the descriptor because fclose() will close it for us
206262528Semaste
207262528Semaste                if (m_stream)
208262528Semaste                {
209262528Semaste                    m_own_stream = true;
210276479Sdim                    m_should_close_fd = false;
211262528Semaste                }
212254721Semaste            }
213254721Semaste        }
214254721Semaste    }
215254721Semaste    return m_stream;
216254721Semaste}
217254721Semaste
218254721Semaste
219254721Semastevoid
220254721SemasteFile::SetStream (FILE *fh, bool transfer_ownership)
221254721Semaste{
222254721Semaste    if (IsValid())
223254721Semaste        Close();
224254721Semaste    m_stream = fh;
225262528Semaste    m_own_stream = transfer_ownership;
226254721Semaste}
227254721Semaste
228254721SemasteError
229254721SemasteFile::Duplicate (const File &rhs)
230254721Semaste{
231254721Semaste    Error error;
232254721Semaste    if (IsValid ())
233254721Semaste        Close();
234254721Semaste
235254721Semaste    if (rhs.DescriptorIsValid())
236254721Semaste    {
237258054Semaste#ifdef _WIN32
238258054Semaste        m_descriptor = ::_dup(rhs.GetDescriptor());
239258054Semaste#else
240254721Semaste        m_descriptor = ::fcntl(rhs.GetDescriptor(), F_DUPFD);
241258054Semaste#endif
242254721Semaste        if (!DescriptorIsValid())
243254721Semaste            error.SetErrorToErrno();
244254721Semaste        else
245254721Semaste        {
246254721Semaste            m_options = rhs.m_options;
247276479Sdim            m_should_close_fd = true;
248254721Semaste        }
249254721Semaste    }
250254721Semaste    else
251254721Semaste    {
252254721Semaste        error.SetErrorString ("invalid file to duplicate");
253254721Semaste    }
254254721Semaste    return error;
255254721Semaste}
256254721Semaste
257254721SemasteError
258254721SemasteFile::Open (const char *path, uint32_t options, uint32_t permissions)
259254721Semaste{
260254721Semaste    Error error;
261254721Semaste    if (IsValid())
262254721Semaste        Close ();
263254721Semaste
264254721Semaste    int oflag = 0;
265254721Semaste    const bool read = options & eOpenOptionRead;
266254721Semaste    const bool write = options & eOpenOptionWrite;
267254721Semaste    if (write)
268254721Semaste    {
269254721Semaste        if (read)
270254721Semaste            oflag |= O_RDWR;
271254721Semaste        else
272254721Semaste            oflag |= O_WRONLY;
273254721Semaste
274254721Semaste        if (options & eOpenOptionAppend)
275254721Semaste            oflag |= O_APPEND;
276254721Semaste
277254721Semaste        if (options & eOpenOptionTruncate)
278254721Semaste            oflag |= O_TRUNC;
279254721Semaste
280254721Semaste        if (options & eOpenOptionCanCreate)
281254721Semaste            oflag |= O_CREAT;
282254721Semaste
283254721Semaste        if (options & eOpenOptionCanCreateNewOnly)
284254721Semaste            oflag |= O_CREAT | O_EXCL;
285254721Semaste    }
286254721Semaste    else if (read)
287254721Semaste    {
288254721Semaste        oflag |= O_RDONLY;
289258884Semaste
290258884Semaste#ifndef _WIN32
291258884Semaste        if (options & eOpenoptionDontFollowSymlinks)
292258884Semaste            oflag |= O_NOFOLLOW;
293258884Semaste#endif
294254721Semaste    }
295254721Semaste
296258054Semaste#ifndef _WIN32
297254721Semaste    if (options & eOpenOptionNonBlocking)
298254721Semaste        oflag |= O_NONBLOCK;
299288943Sdim    if (options & eOpenOptionCloseOnExec)
300288943Sdim        oflag |= O_CLOEXEC;
301258054Semaste#else
302258054Semaste    oflag |= O_BINARY;
303258054Semaste#endif
304254721Semaste
305254721Semaste    mode_t mode = 0;
306254721Semaste    if (oflag & O_CREAT)
307254721Semaste    {
308258884Semaste        if (permissions & lldb::eFilePermissionsUserRead)     mode |= S_IRUSR;
309258884Semaste        if (permissions & lldb::eFilePermissionsUserWrite)    mode |= S_IWUSR;
310258884Semaste        if (permissions & lldb::eFilePermissionsUserExecute)  mode |= S_IXUSR;
311258884Semaste        if (permissions & lldb::eFilePermissionsGroupRead)    mode |= S_IRGRP;
312258884Semaste        if (permissions & lldb::eFilePermissionsGroupWrite)   mode |= S_IWGRP;
313258884Semaste        if (permissions & lldb::eFilePermissionsGroupExecute) mode |= S_IXGRP;
314258884Semaste        if (permissions & lldb::eFilePermissionsWorldRead)    mode |= S_IROTH;
315258884Semaste        if (permissions & lldb::eFilePermissionsWorldWrite)   mode |= S_IWOTH;
316258884Semaste        if (permissions & lldb::eFilePermissionsWorldExecute) mode |= S_IXOTH;
317254721Semaste    }
318254721Semaste
319254721Semaste    do
320254721Semaste    {
321254721Semaste        m_descriptor = ::open(path, oflag, mode);
322254721Semaste    } while (m_descriptor < 0 && errno == EINTR);
323254721Semaste
324254721Semaste    if (!DescriptorIsValid())
325254721Semaste        error.SetErrorToErrno();
326254721Semaste    else
327262528Semaste    {
328276479Sdim        m_should_close_fd = true;
329262528Semaste        m_options = options;
330262528Semaste    }
331254721Semaste
332254721Semaste    return error;
333254721Semaste}
334254721Semaste
335258054Semasteuint32_t
336288943SdimFile::GetPermissions(const FileSpec &file_spec, Error &error)
337258054Semaste{
338288943Sdim    if (file_spec)
339258054Semaste    {
340258054Semaste        struct stat file_stats;
341288943Sdim        if (::stat(file_spec.GetCString(), &file_stats) == -1)
342258054Semaste            error.SetErrorToErrno();
343258054Semaste        else
344258054Semaste        {
345258054Semaste            error.Clear();
346258884Semaste            return file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
347258054Semaste        }
348258054Semaste    }
349258054Semaste    else
350288943Sdim        error.SetErrorString ("empty file spec");
351258054Semaste    return 0;
352258054Semaste}
353258054Semaste
354258054Semasteuint32_t
355258054SemasteFile::GetPermissions(Error &error) const
356258054Semaste{
357258054Semaste    int fd = GetDescriptor();
358258054Semaste    if (fd != kInvalidDescriptor)
359258054Semaste    {
360258054Semaste        struct stat file_stats;
361258054Semaste        if (::fstat (fd, &file_stats) == -1)
362258054Semaste            error.SetErrorToErrno();
363258054Semaste        else
364258054Semaste        {
365258054Semaste            error.Clear();
366258884Semaste            return file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
367258054Semaste        }
368258054Semaste    }
369258054Semaste    else
370258054Semaste    {
371258054Semaste        error.SetErrorString ("invalid file descriptor");
372258054Semaste    }
373258054Semaste    return 0;
374258054Semaste}
375258054Semaste
376258054Semaste
377254721SemasteError
378254721SemasteFile::Close ()
379254721Semaste{
380254721Semaste    Error error;
381262528Semaste    if (StreamIsValid() && m_own_stream)
382254721Semaste    {
383262528Semaste        if (::fclose (m_stream) == EOF)
384262528Semaste            error.SetErrorToErrno();
385254721Semaste    }
386262528Semaste
387276479Sdim    if (DescriptorIsValid() && m_should_close_fd)
388262528Semaste    {
389262528Semaste        if (::close (m_descriptor) != 0)
390262528Semaste            error.SetErrorToErrno();
391262528Semaste    }
392262528Semaste    m_descriptor = kInvalidDescriptor;
393262528Semaste    m_stream = kInvalidStream;
394262528Semaste    m_options = 0;
395262528Semaste    m_own_stream = false;
396276479Sdim    m_should_close_fd = false;
397262528Semaste    m_is_interactive = eLazyBoolCalculate;
398262528Semaste    m_is_real_terminal = eLazyBoolCalculate;
399254721Semaste    return error;
400254721Semaste}
401254721Semaste
402254721Semaste
403254721SemasteError
404254721SemasteFile::GetFileSpec (FileSpec &file_spec) const
405254721Semaste{
406254721Semaste    Error error;
407254721Semaste#ifdef LLDB_CONFIG_FCNTL_GETPATH_SUPPORTED
408254721Semaste    if (IsValid ())
409254721Semaste    {
410254721Semaste        char path[PATH_MAX];
411254721Semaste        if (::fcntl(GetDescriptor(), F_GETPATH, path) == -1)
412254721Semaste            error.SetErrorToErrno();
413254721Semaste        else
414254721Semaste            file_spec.SetFile (path, false);
415254721Semaste    }
416254721Semaste    else
417254721Semaste    {
418254721Semaste        error.SetErrorString("invalid file handle");
419254721Semaste    }
420254721Semaste#elif defined(__linux__)
421254721Semaste    char proc[64];
422254721Semaste    char path[PATH_MAX];
423254721Semaste    if (::snprintf(proc, sizeof(proc), "/proc/self/fd/%d", GetDescriptor()) < 0)
424254721Semaste        error.SetErrorString ("cannot resolve file descriptor");
425254721Semaste    else
426254721Semaste    {
427254721Semaste        ssize_t len;
428254721Semaste        if ((len = ::readlink(proc, path, sizeof(path) - 1)) == -1)
429254721Semaste            error.SetErrorToErrno();
430254721Semaste        else
431254721Semaste        {
432254721Semaste            path[len] = '\0';
433254721Semaste            file_spec.SetFile (path, false);
434254721Semaste        }
435254721Semaste    }
436254721Semaste#else
437254721Semaste    error.SetErrorString ("File::GetFileSpec is not supported on this platform");
438254721Semaste#endif
439254721Semaste
440254721Semaste    if (error.Fail())
441254721Semaste        file_spec.Clear();
442254721Semaste    return error;
443254721Semaste}
444254721Semaste
445254721Semasteoff_t
446254721SemasteFile::SeekFromStart (off_t offset, Error *error_ptr)
447254721Semaste{
448254721Semaste    off_t result = 0;
449254721Semaste    if (DescriptorIsValid())
450254721Semaste    {
451254721Semaste        result = ::lseek (m_descriptor, offset, SEEK_SET);
452254721Semaste
453254721Semaste        if (error_ptr)
454254721Semaste        {
455254721Semaste            if (result == -1)
456254721Semaste                error_ptr->SetErrorToErrno();
457254721Semaste            else
458254721Semaste                error_ptr->Clear();
459254721Semaste        }
460254721Semaste    }
461254721Semaste    else if (StreamIsValid ())
462254721Semaste    {
463254721Semaste        result = ::fseek(m_stream, offset, SEEK_SET);
464254721Semaste
465254721Semaste        if (error_ptr)
466254721Semaste        {
467254721Semaste            if (result == -1)
468254721Semaste                error_ptr->SetErrorToErrno();
469254721Semaste            else
470254721Semaste                error_ptr->Clear();
471254721Semaste        }
472254721Semaste    }
473254721Semaste    else if (error_ptr)
474254721Semaste    {
475254721Semaste        error_ptr->SetErrorString("invalid file handle");
476254721Semaste    }
477254721Semaste    return result;
478254721Semaste}
479254721Semaste
480254721Semasteoff_t
481254721SemasteFile::SeekFromCurrent (off_t offset,  Error *error_ptr)
482254721Semaste{
483254721Semaste    off_t result = -1;
484254721Semaste    if (DescriptorIsValid())
485254721Semaste    {
486254721Semaste        result = ::lseek (m_descriptor, offset, SEEK_CUR);
487254721Semaste
488254721Semaste        if (error_ptr)
489254721Semaste        {
490254721Semaste            if (result == -1)
491254721Semaste                error_ptr->SetErrorToErrno();
492254721Semaste            else
493254721Semaste                error_ptr->Clear();
494254721Semaste        }
495254721Semaste    }
496254721Semaste    else if (StreamIsValid ())
497254721Semaste    {
498254721Semaste        result = ::fseek(m_stream, offset, SEEK_CUR);
499254721Semaste
500254721Semaste        if (error_ptr)
501254721Semaste        {
502254721Semaste            if (result == -1)
503254721Semaste                error_ptr->SetErrorToErrno();
504254721Semaste            else
505254721Semaste                error_ptr->Clear();
506254721Semaste        }
507254721Semaste    }
508254721Semaste    else if (error_ptr)
509254721Semaste    {
510254721Semaste        error_ptr->SetErrorString("invalid file handle");
511254721Semaste    }
512254721Semaste    return result;
513254721Semaste}
514254721Semaste
515254721Semasteoff_t
516254721SemasteFile::SeekFromEnd (off_t offset, Error *error_ptr)
517254721Semaste{
518254721Semaste    off_t result = -1;
519254721Semaste    if (DescriptorIsValid())
520254721Semaste    {
521254721Semaste        result = ::lseek (m_descriptor, offset, SEEK_END);
522254721Semaste
523254721Semaste        if (error_ptr)
524254721Semaste        {
525254721Semaste            if (result == -1)
526254721Semaste                error_ptr->SetErrorToErrno();
527254721Semaste            else
528254721Semaste                error_ptr->Clear();
529254721Semaste        }
530254721Semaste    }
531254721Semaste    else if (StreamIsValid ())
532254721Semaste    {
533254721Semaste        result = ::fseek(m_stream, offset, SEEK_END);
534254721Semaste
535254721Semaste        if (error_ptr)
536254721Semaste        {
537254721Semaste            if (result == -1)
538254721Semaste                error_ptr->SetErrorToErrno();
539254721Semaste            else
540254721Semaste                error_ptr->Clear();
541254721Semaste        }
542254721Semaste    }
543254721Semaste    else if (error_ptr)
544254721Semaste    {
545254721Semaste        error_ptr->SetErrorString("invalid file handle");
546254721Semaste    }
547254721Semaste    return result;
548254721Semaste}
549254721Semaste
550254721SemasteError
551254721SemasteFile::Flush ()
552254721Semaste{
553254721Semaste    Error error;
554254721Semaste    if (StreamIsValid())
555254721Semaste    {
556254721Semaste        int err = 0;
557254721Semaste        do
558254721Semaste        {
559254721Semaste            err = ::fflush (m_stream);
560254721Semaste        } while (err == EOF && errno == EINTR);
561254721Semaste
562254721Semaste        if (err == EOF)
563254721Semaste            error.SetErrorToErrno();
564254721Semaste    }
565254721Semaste    else if (!DescriptorIsValid())
566254721Semaste    {
567254721Semaste        error.SetErrorString("invalid file handle");
568254721Semaste    }
569254721Semaste    return error;
570254721Semaste}
571254721Semaste
572254721Semaste
573254721SemasteError
574254721SemasteFile::Sync ()
575254721Semaste{
576254721Semaste    Error error;
577254721Semaste    if (DescriptorIsValid())
578254721Semaste    {
579258054Semaste#ifdef _WIN32
580258054Semaste        int err = FlushFileBuffers((HANDLE)_get_osfhandle(m_descriptor));
581258054Semaste        if (err == 0)
582258054Semaste            error.SetErrorToGenericError();
583258054Semaste#else
584254721Semaste        int err = 0;
585254721Semaste        do
586254721Semaste        {
587254721Semaste            err = ::fsync (m_descriptor);
588254721Semaste        } while (err == -1 && errno == EINTR);
589254721Semaste
590254721Semaste        if (err == -1)
591254721Semaste            error.SetErrorToErrno();
592258054Semaste#endif
593254721Semaste    }
594254721Semaste    else
595254721Semaste    {
596254721Semaste        error.SetErrorString("invalid file handle");
597254721Semaste    }
598254721Semaste    return error;
599254721Semaste}
600254721Semaste
601288943Sdim#if defined (__APPLE__)
602288943Sdim// Darwin kernels only can read/write <= INT_MAX bytes
603288943Sdim#define MAX_READ_SIZE INT_MAX
604288943Sdim#define MAX_WRITE_SIZE INT_MAX
605288943Sdim#endif
606288943Sdim
607254721SemasteError
608254721SemasteFile::Read (void *buf, size_t &num_bytes)
609254721Semaste{
610254721Semaste    Error error;
611288943Sdim
612288943Sdim#if defined (MAX_READ_SIZE)
613288943Sdim    if (num_bytes > MAX_READ_SIZE)
614288943Sdim    {
615288943Sdim        uint8_t *p = (uint8_t *)buf;
616288943Sdim        size_t bytes_left = num_bytes;
617288943Sdim        // Init the num_bytes read to zero
618288943Sdim        num_bytes = 0;
619288943Sdim
620288943Sdim        while (bytes_left > 0)
621288943Sdim        {
622288943Sdim            size_t curr_num_bytes;
623288943Sdim            if (bytes_left > MAX_READ_SIZE)
624288943Sdim                curr_num_bytes = MAX_READ_SIZE;
625288943Sdim            else
626288943Sdim                curr_num_bytes = bytes_left;
627288943Sdim
628288943Sdim            error = Read (p + num_bytes, curr_num_bytes);
629288943Sdim
630288943Sdim            // Update how many bytes were read
631288943Sdim            num_bytes += curr_num_bytes;
632288943Sdim            if (bytes_left < curr_num_bytes)
633288943Sdim                bytes_left = 0;
634288943Sdim            else
635288943Sdim                bytes_left -= curr_num_bytes;
636288943Sdim
637288943Sdim            if (error.Fail())
638288943Sdim                break;
639288943Sdim        }
640288943Sdim        return error;
641288943Sdim    }
642288943Sdim#endif
643288943Sdim
644254721Semaste    ssize_t bytes_read = -1;
645254721Semaste    if (DescriptorIsValid())
646254721Semaste    {
647254721Semaste        do
648254721Semaste        {
649254721Semaste            bytes_read = ::read (m_descriptor, buf, num_bytes);
650254721Semaste        } while (bytes_read < 0 && errno == EINTR);
651254721Semaste
652254721Semaste        if (bytes_read == -1)
653254721Semaste        {
654254721Semaste            error.SetErrorToErrno();
655254721Semaste            num_bytes = 0;
656254721Semaste        }
657254721Semaste        else
658254721Semaste            num_bytes = bytes_read;
659254721Semaste    }
660254721Semaste    else if (StreamIsValid())
661254721Semaste    {
662254721Semaste        bytes_read = ::fread (buf, 1, num_bytes, m_stream);
663254721Semaste
664254721Semaste        if (bytes_read == 0)
665254721Semaste        {
666254721Semaste            if (::feof(m_stream))
667254721Semaste                error.SetErrorString ("feof");
668254721Semaste            else if (::ferror (m_stream))
669254721Semaste                error.SetErrorString ("ferror");
670254721Semaste            num_bytes = 0;
671254721Semaste        }
672254721Semaste        else
673254721Semaste            num_bytes = bytes_read;
674254721Semaste    }
675254721Semaste    else
676254721Semaste    {
677254721Semaste        num_bytes = 0;
678254721Semaste        error.SetErrorString("invalid file handle");
679254721Semaste    }
680254721Semaste    return error;
681254721Semaste}
682254721Semaste
683254721SemasteError
684254721SemasteFile::Write (const void *buf, size_t &num_bytes)
685254721Semaste{
686254721Semaste    Error error;
687288943Sdim
688288943Sdim#if defined (MAX_WRITE_SIZE)
689288943Sdim    if (num_bytes > MAX_WRITE_SIZE)
690288943Sdim    {
691288943Sdim        const uint8_t *p = (const uint8_t *)buf;
692288943Sdim        size_t bytes_left = num_bytes;
693288943Sdim        // Init the num_bytes written to zero
694288943Sdim        num_bytes = 0;
695288943Sdim
696288943Sdim        while (bytes_left > 0)
697288943Sdim        {
698288943Sdim            size_t curr_num_bytes;
699288943Sdim            if (bytes_left > MAX_WRITE_SIZE)
700288943Sdim                curr_num_bytes = MAX_WRITE_SIZE;
701288943Sdim            else
702288943Sdim                curr_num_bytes = bytes_left;
703288943Sdim
704288943Sdim            error = Write (p + num_bytes, curr_num_bytes);
705288943Sdim
706288943Sdim            // Update how many bytes were read
707288943Sdim            num_bytes += curr_num_bytes;
708288943Sdim            if (bytes_left < curr_num_bytes)
709288943Sdim                bytes_left = 0;
710288943Sdim            else
711288943Sdim                bytes_left -= curr_num_bytes;
712288943Sdim
713288943Sdim            if (error.Fail())
714288943Sdim                break;
715288943Sdim        }
716288943Sdim        return error;
717288943Sdim    }
718288943Sdim#endif
719288943Sdim
720254721Semaste    ssize_t bytes_written = -1;
721254721Semaste    if (DescriptorIsValid())
722254721Semaste    {
723254721Semaste        do
724254721Semaste        {
725254721Semaste            bytes_written = ::write (m_descriptor, buf, num_bytes);
726254721Semaste        } while (bytes_written < 0 && errno == EINTR);
727254721Semaste
728254721Semaste        if (bytes_written == -1)
729254721Semaste        {
730254721Semaste            error.SetErrorToErrno();
731254721Semaste            num_bytes = 0;
732254721Semaste        }
733254721Semaste        else
734254721Semaste            num_bytes = bytes_written;
735254721Semaste    }
736254721Semaste    else if (StreamIsValid())
737254721Semaste    {
738254721Semaste        bytes_written = ::fwrite (buf, 1, num_bytes, m_stream);
739254721Semaste
740254721Semaste        if (bytes_written == 0)
741254721Semaste        {
742254721Semaste            if (::feof(m_stream))
743254721Semaste                error.SetErrorString ("feof");
744254721Semaste            else if (::ferror (m_stream))
745254721Semaste                error.SetErrorString ("ferror");
746254721Semaste            num_bytes = 0;
747254721Semaste        }
748254721Semaste        else
749254721Semaste            num_bytes = bytes_written;
750254721Semaste
751254721Semaste    }
752254721Semaste    else
753254721Semaste    {
754254721Semaste        num_bytes = 0;
755254721Semaste        error.SetErrorString("invalid file handle");
756254721Semaste    }
757276479Sdim
758254721Semaste    return error;
759254721Semaste}
760254721Semaste
761254721Semaste
762254721SemasteError
763254721SemasteFile::Read (void *buf, size_t &num_bytes, off_t &offset)
764254721Semaste{
765288943Sdim    Error error;
766288943Sdim
767288943Sdim#if defined (MAX_READ_SIZE)
768288943Sdim    if (num_bytes > MAX_READ_SIZE)
769288943Sdim    {
770288943Sdim        uint8_t *p = (uint8_t *)buf;
771288943Sdim        size_t bytes_left = num_bytes;
772288943Sdim        // Init the num_bytes read to zero
773288943Sdim        num_bytes = 0;
774288943Sdim
775288943Sdim        while (bytes_left > 0)
776288943Sdim        {
777288943Sdim            size_t curr_num_bytes;
778288943Sdim            if (bytes_left > MAX_READ_SIZE)
779288943Sdim                curr_num_bytes = MAX_READ_SIZE;
780288943Sdim            else
781288943Sdim                curr_num_bytes = bytes_left;
782288943Sdim
783288943Sdim            error = Read (p + num_bytes, curr_num_bytes, offset);
784288943Sdim
785288943Sdim            // Update how many bytes were read
786288943Sdim            num_bytes += curr_num_bytes;
787288943Sdim            if (bytes_left < curr_num_bytes)
788288943Sdim                bytes_left = 0;
789288943Sdim            else
790288943Sdim                bytes_left -= curr_num_bytes;
791288943Sdim
792288943Sdim            if (error.Fail())
793288943Sdim                break;
794288943Sdim        }
795288943Sdim        return error;
796288943Sdim    }
797288943Sdim#endif
798288943Sdim
799258054Semaste#ifndef _WIN32
800254721Semaste    int fd = GetDescriptor();
801254721Semaste    if (fd != kInvalidDescriptor)
802254721Semaste    {
803254721Semaste        ssize_t bytes_read = -1;
804254721Semaste        do
805254721Semaste        {
806254721Semaste            bytes_read = ::pread (fd, buf, num_bytes, offset);
807254721Semaste        } while (bytes_read < 0 && errno == EINTR);
808254721Semaste
809254721Semaste        if (bytes_read < 0)
810254721Semaste        {
811254721Semaste            num_bytes = 0;
812254721Semaste            error.SetErrorToErrno();
813254721Semaste        }
814254721Semaste        else
815254721Semaste        {
816254721Semaste            offset += bytes_read;
817254721Semaste            num_bytes = bytes_read;
818254721Semaste        }
819254721Semaste    }
820254721Semaste    else
821254721Semaste    {
822254721Semaste        num_bytes = 0;
823254721Semaste        error.SetErrorString("invalid file handle");
824254721Semaste    }
825258054Semaste#else
826258054Semaste    long cur = ::lseek(m_descriptor, 0, SEEK_CUR);
827258054Semaste    SeekFromStart(offset);
828288943Sdim    error = Read(buf, num_bytes);
829258054Semaste    if (!error.Fail())
830258054Semaste        SeekFromStart(cur);
831288943Sdim#endif
832258054Semaste    return error;
833254721Semaste}
834254721Semaste
835254721SemasteError
836254721SemasteFile::Read (size_t &num_bytes, off_t &offset, bool null_terminate, DataBufferSP &data_buffer_sp)
837254721Semaste{
838254721Semaste    Error error;
839254721Semaste
840254721Semaste    if (num_bytes > 0)
841254721Semaste    {
842254721Semaste        int fd = GetDescriptor();
843254721Semaste        if (fd != kInvalidDescriptor)
844254721Semaste        {
845254721Semaste            struct stat file_stats;
846254721Semaste            if (::fstat (fd, &file_stats) == 0)
847254721Semaste            {
848254721Semaste                if (file_stats.st_size > offset)
849254721Semaste                {
850254721Semaste                    const size_t bytes_left = file_stats.st_size - offset;
851254721Semaste                    if (num_bytes > bytes_left)
852254721Semaste                        num_bytes = bytes_left;
853254721Semaste
854288943Sdim                    size_t num_bytes_plus_nul_char = num_bytes + (null_terminate ? 1 : 0);
855254721Semaste                    std::unique_ptr<DataBufferHeap> data_heap_ap;
856288943Sdim                    data_heap_ap.reset(new DataBufferHeap());
857288943Sdim                    data_heap_ap->SetByteSize(num_bytes_plus_nul_char);
858254721Semaste
859254721Semaste                    if (data_heap_ap.get())
860254721Semaste                    {
861254721Semaste                        error = Read (data_heap_ap->GetBytes(), num_bytes, offset);
862254721Semaste                        if (error.Success())
863254721Semaste                        {
864254721Semaste                            // Make sure we read exactly what we asked for and if we got
865254721Semaste                            // less, adjust the array
866288943Sdim                            if (num_bytes_plus_nul_char < data_heap_ap->GetByteSize())
867288943Sdim                                data_heap_ap->SetByteSize(num_bytes_plus_nul_char);
868254721Semaste                            data_buffer_sp.reset(data_heap_ap.release());
869254721Semaste                            return error;
870254721Semaste                        }
871254721Semaste                    }
872254721Semaste                }
873254721Semaste                else
874254721Semaste                    error.SetErrorString("file is empty");
875254721Semaste            }
876254721Semaste            else
877254721Semaste                error.SetErrorToErrno();
878254721Semaste        }
879254721Semaste        else
880254721Semaste            error.SetErrorString("invalid file handle");
881254721Semaste    }
882254721Semaste    else
883254721Semaste        error.SetErrorString("invalid file handle");
884254721Semaste
885254721Semaste    num_bytes = 0;
886254721Semaste    data_buffer_sp.reset();
887254721Semaste    return error;
888254721Semaste}
889254721Semaste
890254721SemasteError
891254721SemasteFile::Write (const void *buf, size_t &num_bytes, off_t &offset)
892254721Semaste{
893254721Semaste    Error error;
894288943Sdim
895288943Sdim#if defined (MAX_WRITE_SIZE)
896288943Sdim    if (num_bytes > MAX_WRITE_SIZE)
897288943Sdim    {
898288943Sdim        const uint8_t *p = (const uint8_t *)buf;
899288943Sdim        size_t bytes_left = num_bytes;
900288943Sdim        // Init the num_bytes written to zero
901288943Sdim        num_bytes = 0;
902288943Sdim
903288943Sdim        while (bytes_left > 0)
904288943Sdim        {
905288943Sdim            size_t curr_num_bytes;
906288943Sdim            if (bytes_left > MAX_WRITE_SIZE)
907288943Sdim                curr_num_bytes = MAX_WRITE_SIZE;
908288943Sdim            else
909288943Sdim                curr_num_bytes = bytes_left;
910288943Sdim
911288943Sdim            error = Write (p + num_bytes, curr_num_bytes, offset);
912288943Sdim
913288943Sdim            // Update how many bytes were read
914288943Sdim            num_bytes += curr_num_bytes;
915288943Sdim            if (bytes_left < curr_num_bytes)
916288943Sdim                bytes_left = 0;
917288943Sdim            else
918288943Sdim                bytes_left -= curr_num_bytes;
919288943Sdim
920288943Sdim            if (error.Fail())
921288943Sdim                break;
922288943Sdim        }
923288943Sdim        return error;
924288943Sdim    }
925288943Sdim#endif
926288943Sdim
927254721Semaste    int fd = GetDescriptor();
928254721Semaste    if (fd != kInvalidDescriptor)
929254721Semaste    {
930258054Semaste#ifndef _WIN32
931254721Semaste        ssize_t bytes_written = -1;
932254721Semaste        do
933254721Semaste        {
934254721Semaste            bytes_written = ::pwrite (m_descriptor, buf, num_bytes, offset);
935254721Semaste        } while (bytes_written < 0 && errno == EINTR);
936254721Semaste
937254721Semaste        if (bytes_written < 0)
938254721Semaste        {
939254721Semaste            num_bytes = 0;
940254721Semaste            error.SetErrorToErrno();
941254721Semaste        }
942254721Semaste        else
943254721Semaste        {
944254721Semaste            offset += bytes_written;
945254721Semaste            num_bytes = bytes_written;
946254721Semaste        }
947258054Semaste#else
948258054Semaste        long cur = ::lseek(m_descriptor, 0, SEEK_CUR);
949258054Semaste        error = Write(buf, num_bytes);
950258054Semaste        long after = ::lseek(m_descriptor, 0, SEEK_CUR);
951258054Semaste
952258054Semaste        if (!error.Fail())
953258054Semaste            SeekFromStart(cur);
954258054Semaste
955258054Semaste        offset = after;
956258054Semaste#endif
957254721Semaste    }
958254721Semaste    else
959254721Semaste    {
960254721Semaste        num_bytes = 0;
961254721Semaste        error.SetErrorString("invalid file handle");
962254721Semaste    }
963254721Semaste    return error;
964254721Semaste}
965254721Semaste
966254721Semaste//------------------------------------------------------------------
967254721Semaste// Print some formatted output to the stream.
968254721Semaste//------------------------------------------------------------------
969254721Semastesize_t
970254721SemasteFile::Printf (const char *format, ...)
971254721Semaste{
972254721Semaste    va_list args;
973254721Semaste    va_start (args, format);
974254721Semaste    size_t result = PrintfVarArg (format, args);
975254721Semaste    va_end (args);
976254721Semaste    return result;
977254721Semaste}
978254721Semaste
979254721Semaste//------------------------------------------------------------------
980254721Semaste// Print some formatted output to the stream.
981254721Semaste//------------------------------------------------------------------
982254721Semastesize_t
983254721SemasteFile::PrintfVarArg (const char *format, va_list args)
984254721Semaste{
985254721Semaste    size_t result = 0;
986254721Semaste    if (DescriptorIsValid())
987254721Semaste    {
988254721Semaste        char *s = NULL;
989254721Semaste        result = vasprintf(&s, format, args);
990254721Semaste        if (s != NULL)
991254721Semaste        {
992254721Semaste            if (result > 0)
993254721Semaste            {
994254721Semaste                size_t s_len = result;
995254721Semaste                Write (s, s_len);
996254721Semaste                result = s_len;
997254721Semaste            }
998254721Semaste            free (s);
999254721Semaste        }
1000254721Semaste    }
1001254721Semaste    else if (StreamIsValid())
1002254721Semaste    {
1003254721Semaste        result = ::vfprintf (m_stream, format, args);
1004254721Semaste    }
1005254721Semaste    return result;
1006254721Semaste}
1007258054Semaste
1008258054Semastemode_t
1009258054SemasteFile::ConvertOpenOptionsForPOSIXOpen (uint32_t open_options)
1010258054Semaste{
1011258054Semaste    mode_t mode = 0;
1012258054Semaste    if (open_options & eOpenOptionRead && open_options & eOpenOptionWrite)
1013258054Semaste        mode |= O_RDWR;
1014258054Semaste    else if (open_options & eOpenOptionWrite)
1015258054Semaste        mode |= O_WRONLY;
1016258054Semaste
1017258054Semaste    if (open_options & eOpenOptionAppend)
1018258054Semaste        mode |= O_APPEND;
1019258054Semaste
1020258054Semaste    if (open_options & eOpenOptionTruncate)
1021258054Semaste        mode |= O_TRUNC;
1022258054Semaste
1023258054Semaste    if (open_options & eOpenOptionNonBlocking)
1024258054Semaste        mode |= O_NONBLOCK;
1025258054Semaste
1026258054Semaste    if (open_options & eOpenOptionCanCreateNewOnly)
1027258054Semaste        mode |= O_CREAT | O_EXCL;
1028258054Semaste    else if (open_options & eOpenOptionCanCreate)
1029258054Semaste        mode |= O_CREAT;
1030258054Semaste
1031258054Semaste    return mode;
1032258054Semaste}
1033262528Semaste
1034262528Semastevoid
1035262528SemasteFile::CalculateInteractiveAndTerminal ()
1036262528Semaste{
1037262528Semaste    const int fd = GetDescriptor();
1038262528Semaste    if (fd >= 0)
1039262528Semaste    {
1040262528Semaste        m_is_interactive = eLazyBoolNo;
1041262528Semaste        m_is_real_terminal = eLazyBoolNo;
1042280031Sdim#if (defined(_WIN32) || defined(__ANDROID_NDK__))
1043276479Sdim        if (_isatty(fd))
1044276479Sdim        {
1045276479Sdim            m_is_interactive = eLazyBoolYes;
1046276479Sdim            m_is_real_terminal = eLazyBoolYes;
1047276479Sdim        }
1048276479Sdim#else
1049262528Semaste        if (isatty(fd))
1050262528Semaste        {
1051262528Semaste            m_is_interactive = eLazyBoolYes;
1052262528Semaste            struct winsize window_size;
1053262528Semaste            if (::ioctl (fd, TIOCGWINSZ, &window_size) == 0)
1054262528Semaste            {
1055262528Semaste                if (window_size.ws_col > 0)
1056296417Sdim                {
1057262528Semaste                    m_is_real_terminal = eLazyBoolYes;
1058296417Sdim                    if (llvm::sys::Process::FileDescriptorHasColors(fd))
1059296417Sdim                        m_supports_colors = eLazyBoolYes;
1060296417Sdim                }
1061262528Semaste            }
1062262528Semaste        }
1063262528Semaste#endif
1064262528Semaste    }
1065262528Semaste}
1066262528Semaste
1067262528Semastebool
1068262528SemasteFile::GetIsInteractive ()
1069262528Semaste{
1070262528Semaste    if (m_is_interactive == eLazyBoolCalculate)
1071262528Semaste        CalculateInteractiveAndTerminal ();
1072262528Semaste    return m_is_interactive == eLazyBoolYes;
1073262528Semaste}
1074262528Semaste
1075262528Semastebool
1076262528SemasteFile::GetIsRealTerminal ()
1077262528Semaste{
1078262528Semaste    if (m_is_real_terminal == eLazyBoolCalculate)
1079262528Semaste        CalculateInteractiveAndTerminal();
1080262528Semaste    return m_is_real_terminal == eLazyBoolYes;
1081262528Semaste}
1082262528Semaste
1083296417Sdimbool
1084296417SdimFile::GetIsTerminalWithColors ()
1085296417Sdim{
1086296417Sdim    if (m_supports_colors == eLazyBoolCalculate)
1087296417Sdim        CalculateInteractiveAndTerminal();
1088296417Sdim    return m_supports_colors == eLazyBoolYes;
1089296417Sdim}
1090296417Sdim
1091