1263367Semaste//===-- 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>
16269024Semaste#include <stdio.h>
17254721Semaste#include <sys/stat.h>
18254721Semaste
19263363Semaste#ifdef _WIN32
20263363Semaste#include "lldb/Host/windows/windows.h"
21269024Semaste#else
22269024Semaste#include <sys/ioctl.h>
23263363Semaste#endif
24263363Semaste
25254721Semaste#include "lldb/Core/DataBufferHeap.h"
26254721Semaste#include "lldb/Core/Error.h"
27254721Semaste#include "lldb/Host/Config.h"
28254721Semaste#include "lldb/Host/FileSpec.h"
29254721Semaste
30254721Semasteusing namespace lldb;
31254721Semasteusing namespace lldb_private;
32254721Semaste
33254721Semastestatic const char *
34254721SemasteGetStreamOpenModeFromOptions (uint32_t options)
35254721Semaste{
36254721Semaste    if (options & File::eOpenOptionAppend)
37254721Semaste    {
38254721Semaste        if (options & File::eOpenOptionRead)
39254721Semaste        {
40254721Semaste            if (options & File::eOpenOptionCanCreateNewOnly)
41254721Semaste                return "a+x";
42254721Semaste            else
43254721Semaste                return "a+";
44254721Semaste        }
45254721Semaste        else if (options & File::eOpenOptionWrite)
46254721Semaste        {
47254721Semaste            if (options & File::eOpenOptionCanCreateNewOnly)
48254721Semaste                return "ax";
49254721Semaste            else
50254721Semaste                return "a";
51254721Semaste        }
52254721Semaste    }
53254721Semaste    else if (options & File::eOpenOptionRead && options & File::eOpenOptionWrite)
54254721Semaste    {
55254721Semaste        if (options & File::eOpenOptionCanCreate)
56254721Semaste        {
57254721Semaste            if (options & File::eOpenOptionCanCreateNewOnly)
58254721Semaste                return "w+x";
59254721Semaste            else
60254721Semaste                return "w+";
61254721Semaste        }
62254721Semaste        else
63254721Semaste            return "r+";
64254721Semaste    }
65254721Semaste    else if (options & File::eOpenOptionRead)
66254721Semaste    {
67254721Semaste        return "r";
68254721Semaste    }
69254721Semaste    else if (options & File::eOpenOptionWrite)
70254721Semaste    {
71254721Semaste        return "w";
72254721Semaste    }
73254721Semaste    return NULL;
74254721Semaste}
75254721Semaste
76254721Semasteint File::kInvalidDescriptor = -1;
77254721SemasteFILE * File::kInvalidStream = NULL;
78254721Semaste
79254721SemasteFile::File(const char *path, uint32_t options, uint32_t permissions) :
80254721Semaste    m_descriptor (kInvalidDescriptor),
81254721Semaste    m_stream (kInvalidStream),
82269024Semaste    m_options (),
83269024Semaste    m_own_stream (false),
84269024Semaste    m_own_descriptor (false),
85269024Semaste    m_is_interactive (eLazyBoolCalculate),
86269024Semaste    m_is_real_terminal (eLazyBoolCalculate)
87254721Semaste{
88254721Semaste    Open (path, options, permissions);
89254721Semaste}
90254721Semaste
91263363SemasteFile::File (const FileSpec& filespec,
92263363Semaste            uint32_t options,
93263363Semaste            uint32_t permissions) :
94263363Semaste    m_descriptor (kInvalidDescriptor),
95263363Semaste    m_stream (kInvalidStream),
96263363Semaste    m_options (0),
97269024Semaste    m_own_stream (false),
98269024Semaste    m_own_descriptor (false),
99269024Semaste    m_is_interactive (eLazyBoolCalculate),
100269024Semaste    m_is_real_terminal (eLazyBoolCalculate)
101269024Semaste
102263363Semaste{
103263363Semaste    if (filespec)
104263363Semaste    {
105263363Semaste        Open (filespec.GetPath().c_str(), options, permissions);
106263363Semaste    }
107263363Semaste}
108263363Semaste
109254721SemasteFile::File (const File &rhs) :
110254721Semaste    m_descriptor (kInvalidDescriptor),
111254721Semaste    m_stream (kInvalidStream),
112254721Semaste    m_options (0),
113269024Semaste    m_own_stream (false),
114269024Semaste    m_own_descriptor (false),
115269024Semaste    m_is_interactive (eLazyBoolCalculate),
116269024Semaste    m_is_real_terminal (eLazyBoolCalculate)
117254721Semaste{
118254721Semaste    Duplicate (rhs);
119254721Semaste}
120254721Semaste
121254721Semaste
122254721SemasteFile &
123254721SemasteFile::operator = (const File &rhs)
124254721Semaste{
125254721Semaste    if (this != &rhs)
126254721Semaste        Duplicate (rhs);
127254721Semaste    return *this;
128254721Semaste}
129254721Semaste
130254721SemasteFile::~File()
131254721Semaste{
132254721Semaste    Close ();
133254721Semaste}
134254721Semaste
135254721Semaste
136254721Semasteint
137254721SemasteFile::GetDescriptor() const
138254721Semaste{
139254721Semaste    if (DescriptorIsValid())
140254721Semaste        return m_descriptor;
141254721Semaste
142254721Semaste    // Don't open the file descriptor if we don't need to, just get it from the
143254721Semaste    // stream if we have one.
144254721Semaste    if (StreamIsValid())
145254721Semaste        return fileno (m_stream);
146254721Semaste
147254721Semaste    // Invalid descriptor and invalid stream, return invalid descriptor.
148254721Semaste    return kInvalidDescriptor;
149254721Semaste}
150254721Semaste
151254721Semastevoid
152254721SemasteFile::SetDescriptor (int fd, bool transfer_ownership)
153254721Semaste{
154254721Semaste    if (IsValid())
155254721Semaste        Close();
156254721Semaste    m_descriptor = fd;
157269024Semaste    m_own_descriptor = transfer_ownership;
158254721Semaste}
159254721Semaste
160254721Semaste
161254721SemasteFILE *
162254721SemasteFile::GetStream ()
163254721Semaste{
164254721Semaste    if (!StreamIsValid())
165254721Semaste    {
166254721Semaste        if (DescriptorIsValid())
167254721Semaste        {
168254721Semaste            const char *mode = GetStreamOpenModeFromOptions (m_options);
169254721Semaste            if (mode)
170254721Semaste            {
171269024Semaste                if (!m_own_descriptor)
172269024Semaste                {
173269024Semaste                    // We must duplicate the file descriptor if we don't own it because
174269024Semaste                    // when you call fdopen, the stream will own the fd
175269024Semaste#ifdef _WIN32
176269024Semaste                    m_descriptor = ::_dup(GetDescriptor());
177269024Semaste#else
178269024Semaste                    m_descriptor = ::fcntl(GetDescriptor(), F_DUPFD);
179269024Semaste#endif
180269024Semaste                    m_own_descriptor = true;
181269024Semaste                }
182269024Semaste
183254721Semaste                do
184254721Semaste                {
185254721Semaste                    m_stream = ::fdopen (m_descriptor, mode);
186254721Semaste                } while (m_stream == NULL && errno == EINTR);
187269024Semaste
188269024Semaste                // If we got a stream, then we own the stream and should no
189269024Semaste                // longer own the descriptor because fclose() will close it for us
190269024Semaste
191269024Semaste                if (m_stream)
192269024Semaste                {
193269024Semaste                    m_own_stream = true;
194269024Semaste                    m_own_descriptor = false;
195269024Semaste                }
196254721Semaste            }
197254721Semaste        }
198254721Semaste    }
199254721Semaste    return m_stream;
200254721Semaste}
201254721Semaste
202254721Semaste
203254721Semastevoid
204254721SemasteFile::SetStream (FILE *fh, bool transfer_ownership)
205254721Semaste{
206254721Semaste    if (IsValid())
207254721Semaste        Close();
208254721Semaste    m_stream = fh;
209269024Semaste    m_own_stream = transfer_ownership;
210254721Semaste}
211254721Semaste
212254721SemasteError
213254721SemasteFile::Duplicate (const File &rhs)
214254721Semaste{
215254721Semaste    Error error;
216254721Semaste    if (IsValid ())
217254721Semaste        Close();
218254721Semaste
219254721Semaste    if (rhs.DescriptorIsValid())
220254721Semaste    {
221263363Semaste#ifdef _WIN32
222263363Semaste        m_descriptor = ::_dup(rhs.GetDescriptor());
223263363Semaste#else
224254721Semaste        m_descriptor = ::fcntl(rhs.GetDescriptor(), F_DUPFD);
225263363Semaste#endif
226254721Semaste        if (!DescriptorIsValid())
227254721Semaste            error.SetErrorToErrno();
228254721Semaste        else
229254721Semaste        {
230254721Semaste            m_options = rhs.m_options;
231269024Semaste            m_own_descriptor = true;
232254721Semaste        }
233254721Semaste    }
234254721Semaste    else
235254721Semaste    {
236254721Semaste        error.SetErrorString ("invalid file to duplicate");
237254721Semaste    }
238254721Semaste    return error;
239254721Semaste}
240254721Semaste
241254721SemasteError
242254721SemasteFile::Open (const char *path, uint32_t options, uint32_t permissions)
243254721Semaste{
244254721Semaste    Error error;
245254721Semaste    if (IsValid())
246254721Semaste        Close ();
247254721Semaste
248254721Semaste    int oflag = 0;
249254721Semaste    const bool read = options & eOpenOptionRead;
250254721Semaste    const bool write = options & eOpenOptionWrite;
251254721Semaste    if (write)
252254721Semaste    {
253254721Semaste        if (read)
254254721Semaste            oflag |= O_RDWR;
255254721Semaste        else
256254721Semaste            oflag |= O_WRONLY;
257254721Semaste
258254721Semaste        if (options & eOpenOptionAppend)
259254721Semaste            oflag |= O_APPEND;
260254721Semaste
261254721Semaste        if (options & eOpenOptionTruncate)
262254721Semaste            oflag |= O_TRUNC;
263254721Semaste
264254721Semaste        if (options & eOpenOptionCanCreate)
265254721Semaste            oflag |= O_CREAT;
266254721Semaste
267254721Semaste        if (options & eOpenOptionCanCreateNewOnly)
268254721Semaste            oflag |= O_CREAT | O_EXCL;
269254721Semaste    }
270254721Semaste    else if (read)
271254721Semaste    {
272254721Semaste        oflag |= O_RDONLY;
273263367Semaste
274263367Semaste#ifndef _WIN32
275263367Semaste        if (options & eOpenoptionDontFollowSymlinks)
276263367Semaste            oflag |= O_NOFOLLOW;
277263367Semaste#endif
278254721Semaste    }
279254721Semaste
280263363Semaste#ifndef _WIN32
281254721Semaste    if (options & eOpenOptionNonBlocking)
282254721Semaste        oflag |= O_NONBLOCK;
283263363Semaste#else
284263363Semaste    oflag |= O_BINARY;
285263363Semaste#endif
286254721Semaste
287254721Semaste    mode_t mode = 0;
288254721Semaste    if (oflag & O_CREAT)
289254721Semaste    {
290263367Semaste        if (permissions & lldb::eFilePermissionsUserRead)     mode |= S_IRUSR;
291263367Semaste        if (permissions & lldb::eFilePermissionsUserWrite)    mode |= S_IWUSR;
292263367Semaste        if (permissions & lldb::eFilePermissionsUserExecute)  mode |= S_IXUSR;
293263367Semaste        if (permissions & lldb::eFilePermissionsGroupRead)    mode |= S_IRGRP;
294263367Semaste        if (permissions & lldb::eFilePermissionsGroupWrite)   mode |= S_IWGRP;
295263367Semaste        if (permissions & lldb::eFilePermissionsGroupExecute) mode |= S_IXGRP;
296263367Semaste        if (permissions & lldb::eFilePermissionsWorldRead)    mode |= S_IROTH;
297263367Semaste        if (permissions & lldb::eFilePermissionsWorldWrite)   mode |= S_IWOTH;
298263367Semaste        if (permissions & lldb::eFilePermissionsWorldExecute) mode |= S_IXOTH;
299254721Semaste    }
300254721Semaste
301254721Semaste    do
302254721Semaste    {
303254721Semaste        m_descriptor = ::open(path, oflag, mode);
304254721Semaste    } while (m_descriptor < 0 && errno == EINTR);
305254721Semaste
306254721Semaste    if (!DescriptorIsValid())
307254721Semaste        error.SetErrorToErrno();
308254721Semaste    else
309269024Semaste    {
310269024Semaste        m_own_descriptor = true;
311269024Semaste        m_options = options;
312269024Semaste    }
313254721Semaste
314254721Semaste    return error;
315254721Semaste}
316254721Semaste
317263363Semasteuint32_t
318263363SemasteFile::GetPermissions (const char *path, Error &error)
319263363Semaste{
320263363Semaste    if (path && path[0])
321263363Semaste    {
322263363Semaste        struct stat file_stats;
323263363Semaste        if (::stat (path, &file_stats) == -1)
324263363Semaste            error.SetErrorToErrno();
325263363Semaste        else
326263363Semaste        {
327263363Semaste            error.Clear();
328263367Semaste            return file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
329263363Semaste        }
330263363Semaste    }
331263363Semaste    else
332263363Semaste    {
333263363Semaste        if (path)
334263363Semaste            error.SetErrorString ("invalid path");
335263363Semaste        else
336263363Semaste            error.SetErrorString ("empty path");
337263363Semaste    }
338263363Semaste    return 0;
339263363Semaste}
340263363Semaste
341263363Semasteuint32_t
342263363SemasteFile::GetPermissions(Error &error) const
343263363Semaste{
344263363Semaste    int fd = GetDescriptor();
345263363Semaste    if (fd != kInvalidDescriptor)
346263363Semaste    {
347263363Semaste        struct stat file_stats;
348263363Semaste        if (::fstat (fd, &file_stats) == -1)
349263363Semaste            error.SetErrorToErrno();
350263363Semaste        else
351263363Semaste        {
352263363Semaste            error.Clear();
353263367Semaste            return file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
354263363Semaste        }
355263363Semaste    }
356263363Semaste    else
357263363Semaste    {
358263363Semaste        error.SetErrorString ("invalid file descriptor");
359263363Semaste    }
360263363Semaste    return 0;
361263363Semaste}
362263363Semaste
363263363Semaste
364254721SemasteError
365254721SemasteFile::Close ()
366254721Semaste{
367254721Semaste    Error error;
368269024Semaste    if (StreamIsValid() && m_own_stream)
369254721Semaste    {
370269024Semaste        if (::fclose (m_stream) == EOF)
371269024Semaste            error.SetErrorToErrno();
372254721Semaste    }
373269024Semaste
374269024Semaste    if (DescriptorIsValid() && m_own_descriptor)
375269024Semaste    {
376269024Semaste        if (::close (m_descriptor) != 0)
377269024Semaste            error.SetErrorToErrno();
378269024Semaste    }
379269024Semaste    m_descriptor = kInvalidDescriptor;
380269024Semaste    m_stream = kInvalidStream;
381269024Semaste    m_options = 0;
382269024Semaste    m_own_stream = false;
383269024Semaste    m_own_descriptor = false;
384269024Semaste    m_is_interactive = eLazyBoolCalculate;
385269024Semaste    m_is_real_terminal = eLazyBoolCalculate;
386254721Semaste    return error;
387254721Semaste}
388254721Semaste
389254721Semaste
390254721SemasteError
391254721SemasteFile::GetFileSpec (FileSpec &file_spec) const
392254721Semaste{
393254721Semaste    Error error;
394254721Semaste#ifdef LLDB_CONFIG_FCNTL_GETPATH_SUPPORTED
395254721Semaste    if (IsValid ())
396254721Semaste    {
397254721Semaste        char path[PATH_MAX];
398254721Semaste        if (::fcntl(GetDescriptor(), F_GETPATH, path) == -1)
399254721Semaste            error.SetErrorToErrno();
400254721Semaste        else
401254721Semaste            file_spec.SetFile (path, false);
402254721Semaste    }
403254721Semaste    else
404254721Semaste    {
405254721Semaste        error.SetErrorString("invalid file handle");
406254721Semaste    }
407254721Semaste#elif defined(__linux__)
408254721Semaste    char proc[64];
409254721Semaste    char path[PATH_MAX];
410254721Semaste    if (::snprintf(proc, sizeof(proc), "/proc/self/fd/%d", GetDescriptor()) < 0)
411254721Semaste        error.SetErrorString ("cannot resolve file descriptor");
412254721Semaste    else
413254721Semaste    {
414254721Semaste        ssize_t len;
415254721Semaste        if ((len = ::readlink(proc, path, sizeof(path) - 1)) == -1)
416254721Semaste            error.SetErrorToErrno();
417254721Semaste        else
418254721Semaste        {
419254721Semaste            path[len] = '\0';
420254721Semaste            file_spec.SetFile (path, false);
421254721Semaste        }
422254721Semaste    }
423254721Semaste#else
424254721Semaste    error.SetErrorString ("File::GetFileSpec is not supported on this platform");
425254721Semaste#endif
426254721Semaste
427254721Semaste    if (error.Fail())
428254721Semaste        file_spec.Clear();
429254721Semaste    return error;
430254721Semaste}
431254721Semaste
432254721Semasteoff_t
433254721SemasteFile::SeekFromStart (off_t offset, Error *error_ptr)
434254721Semaste{
435254721Semaste    off_t result = 0;
436254721Semaste    if (DescriptorIsValid())
437254721Semaste    {
438254721Semaste        result = ::lseek (m_descriptor, offset, SEEK_SET);
439254721Semaste
440254721Semaste        if (error_ptr)
441254721Semaste        {
442254721Semaste            if (result == -1)
443254721Semaste                error_ptr->SetErrorToErrno();
444254721Semaste            else
445254721Semaste                error_ptr->Clear();
446254721Semaste        }
447254721Semaste    }
448254721Semaste    else if (StreamIsValid ())
449254721Semaste    {
450254721Semaste        result = ::fseek(m_stream, offset, SEEK_SET);
451254721Semaste
452254721Semaste        if (error_ptr)
453254721Semaste        {
454254721Semaste            if (result == -1)
455254721Semaste                error_ptr->SetErrorToErrno();
456254721Semaste            else
457254721Semaste                error_ptr->Clear();
458254721Semaste        }
459254721Semaste    }
460254721Semaste    else if (error_ptr)
461254721Semaste    {
462254721Semaste        error_ptr->SetErrorString("invalid file handle");
463254721Semaste    }
464254721Semaste    return result;
465254721Semaste}
466254721Semaste
467254721Semasteoff_t
468254721SemasteFile::SeekFromCurrent (off_t offset,  Error *error_ptr)
469254721Semaste{
470254721Semaste    off_t result = -1;
471254721Semaste    if (DescriptorIsValid())
472254721Semaste    {
473254721Semaste        result = ::lseek (m_descriptor, offset, SEEK_CUR);
474254721Semaste
475254721Semaste        if (error_ptr)
476254721Semaste        {
477254721Semaste            if (result == -1)
478254721Semaste                error_ptr->SetErrorToErrno();
479254721Semaste            else
480254721Semaste                error_ptr->Clear();
481254721Semaste        }
482254721Semaste    }
483254721Semaste    else if (StreamIsValid ())
484254721Semaste    {
485254721Semaste        result = ::fseek(m_stream, offset, SEEK_CUR);
486254721Semaste
487254721Semaste        if (error_ptr)
488254721Semaste        {
489254721Semaste            if (result == -1)
490254721Semaste                error_ptr->SetErrorToErrno();
491254721Semaste            else
492254721Semaste                error_ptr->Clear();
493254721Semaste        }
494254721Semaste    }
495254721Semaste    else if (error_ptr)
496254721Semaste    {
497254721Semaste        error_ptr->SetErrorString("invalid file handle");
498254721Semaste    }
499254721Semaste    return result;
500254721Semaste}
501254721Semaste
502254721Semasteoff_t
503254721SemasteFile::SeekFromEnd (off_t offset, Error *error_ptr)
504254721Semaste{
505254721Semaste    off_t result = -1;
506254721Semaste    if (DescriptorIsValid())
507254721Semaste    {
508254721Semaste        result = ::lseek (m_descriptor, offset, SEEK_END);
509254721Semaste
510254721Semaste        if (error_ptr)
511254721Semaste        {
512254721Semaste            if (result == -1)
513254721Semaste                error_ptr->SetErrorToErrno();
514254721Semaste            else
515254721Semaste                error_ptr->Clear();
516254721Semaste        }
517254721Semaste    }
518254721Semaste    else if (StreamIsValid ())
519254721Semaste    {
520254721Semaste        result = ::fseek(m_stream, offset, SEEK_END);
521254721Semaste
522254721Semaste        if (error_ptr)
523254721Semaste        {
524254721Semaste            if (result == -1)
525254721Semaste                error_ptr->SetErrorToErrno();
526254721Semaste            else
527254721Semaste                error_ptr->Clear();
528254721Semaste        }
529254721Semaste    }
530254721Semaste    else if (error_ptr)
531254721Semaste    {
532254721Semaste        error_ptr->SetErrorString("invalid file handle");
533254721Semaste    }
534254721Semaste    return result;
535254721Semaste}
536254721Semaste
537254721SemasteError
538254721SemasteFile::Flush ()
539254721Semaste{
540254721Semaste    Error error;
541254721Semaste    if (StreamIsValid())
542254721Semaste    {
543254721Semaste        int err = 0;
544254721Semaste        do
545254721Semaste        {
546254721Semaste            err = ::fflush (m_stream);
547254721Semaste        } while (err == EOF && errno == EINTR);
548254721Semaste
549254721Semaste        if (err == EOF)
550254721Semaste            error.SetErrorToErrno();
551254721Semaste    }
552254721Semaste    else if (!DescriptorIsValid())
553254721Semaste    {
554254721Semaste        error.SetErrorString("invalid file handle");
555254721Semaste    }
556254721Semaste    return error;
557254721Semaste}
558254721Semaste
559254721Semaste
560254721SemasteError
561254721SemasteFile::Sync ()
562254721Semaste{
563254721Semaste    Error error;
564254721Semaste    if (DescriptorIsValid())
565254721Semaste    {
566263363Semaste#ifdef _WIN32
567263363Semaste        int err = FlushFileBuffers((HANDLE)_get_osfhandle(m_descriptor));
568263363Semaste        if (err == 0)
569263363Semaste            error.SetErrorToGenericError();
570263363Semaste#else
571254721Semaste        int err = 0;
572254721Semaste        do
573254721Semaste        {
574254721Semaste            err = ::fsync (m_descriptor);
575254721Semaste        } while (err == -1 && errno == EINTR);
576254721Semaste
577254721Semaste        if (err == -1)
578254721Semaste            error.SetErrorToErrno();
579263363Semaste#endif
580254721Semaste    }
581254721Semaste    else
582254721Semaste    {
583254721Semaste        error.SetErrorString("invalid file handle");
584254721Semaste    }
585254721Semaste    return error;
586254721Semaste}
587254721Semaste
588254721SemasteError
589254721SemasteFile::Read (void *buf, size_t &num_bytes)
590254721Semaste{
591254721Semaste    Error error;
592254721Semaste    ssize_t bytes_read = -1;
593254721Semaste    if (DescriptorIsValid())
594254721Semaste    {
595254721Semaste        do
596254721Semaste        {
597254721Semaste            bytes_read = ::read (m_descriptor, buf, num_bytes);
598254721Semaste        } while (bytes_read < 0 && errno == EINTR);
599254721Semaste
600254721Semaste        if (bytes_read == -1)
601254721Semaste        {
602254721Semaste            error.SetErrorToErrno();
603254721Semaste            num_bytes = 0;
604254721Semaste        }
605254721Semaste        else
606254721Semaste            num_bytes = bytes_read;
607254721Semaste    }
608254721Semaste    else if (StreamIsValid())
609254721Semaste    {
610254721Semaste        bytes_read = ::fread (buf, 1, num_bytes, m_stream);
611254721Semaste
612254721Semaste        if (bytes_read == 0)
613254721Semaste        {
614254721Semaste            if (::feof(m_stream))
615254721Semaste                error.SetErrorString ("feof");
616254721Semaste            else if (::ferror (m_stream))
617254721Semaste                error.SetErrorString ("ferror");
618254721Semaste            num_bytes = 0;
619254721Semaste        }
620254721Semaste        else
621254721Semaste            num_bytes = bytes_read;
622254721Semaste    }
623254721Semaste    else
624254721Semaste    {
625254721Semaste        num_bytes = 0;
626254721Semaste        error.SetErrorString("invalid file handle");
627254721Semaste    }
628254721Semaste    return error;
629254721Semaste}
630254721Semaste
631254721SemasteError
632254721SemasteFile::Write (const void *buf, size_t &num_bytes)
633254721Semaste{
634254721Semaste    Error error;
635254721Semaste    ssize_t bytes_written = -1;
636254721Semaste    if (DescriptorIsValid())
637254721Semaste    {
638254721Semaste        do
639254721Semaste        {
640254721Semaste            bytes_written = ::write (m_descriptor, buf, num_bytes);
641254721Semaste        } while (bytes_written < 0 && errno == EINTR);
642254721Semaste
643254721Semaste        if (bytes_written == -1)
644254721Semaste        {
645254721Semaste            error.SetErrorToErrno();
646254721Semaste            num_bytes = 0;
647254721Semaste        }
648254721Semaste        else
649254721Semaste            num_bytes = bytes_written;
650254721Semaste    }
651254721Semaste    else if (StreamIsValid())
652254721Semaste    {
653254721Semaste        bytes_written = ::fwrite (buf, 1, num_bytes, m_stream);
654254721Semaste
655254721Semaste        if (bytes_written == 0)
656254721Semaste        {
657254721Semaste            if (::feof(m_stream))
658254721Semaste                error.SetErrorString ("feof");
659254721Semaste            else if (::ferror (m_stream))
660254721Semaste                error.SetErrorString ("ferror");
661254721Semaste            num_bytes = 0;
662254721Semaste        }
663254721Semaste        else
664254721Semaste            num_bytes = bytes_written;
665254721Semaste
666254721Semaste    }
667254721Semaste    else
668254721Semaste    {
669254721Semaste        num_bytes = 0;
670254721Semaste        error.SetErrorString("invalid file handle");
671254721Semaste    }
672254721Semaste    return error;
673254721Semaste}
674254721Semaste
675254721Semaste
676254721SemasteError
677254721SemasteFile::Read (void *buf, size_t &num_bytes, off_t &offset)
678254721Semaste{
679263363Semaste#ifndef _WIN32
680254721Semaste    Error error;
681254721Semaste    int fd = GetDescriptor();
682254721Semaste    if (fd != kInvalidDescriptor)
683254721Semaste    {
684254721Semaste        ssize_t bytes_read = -1;
685254721Semaste        do
686254721Semaste        {
687254721Semaste            bytes_read = ::pread (fd, buf, num_bytes, offset);
688254721Semaste        } while (bytes_read < 0 && errno == EINTR);
689254721Semaste
690254721Semaste        if (bytes_read < 0)
691254721Semaste        {
692254721Semaste            num_bytes = 0;
693254721Semaste            error.SetErrorToErrno();
694254721Semaste        }
695254721Semaste        else
696254721Semaste        {
697254721Semaste            offset += bytes_read;
698254721Semaste            num_bytes = bytes_read;
699254721Semaste        }
700254721Semaste    }
701254721Semaste    else
702254721Semaste    {
703254721Semaste        num_bytes = 0;
704254721Semaste        error.SetErrorString("invalid file handle");
705254721Semaste    }
706254721Semaste    return error;
707263363Semaste#else
708263363Semaste    long cur = ::lseek(m_descriptor, 0, SEEK_CUR);
709263363Semaste    SeekFromStart(offset);
710263363Semaste    Error error = Read(buf, num_bytes);
711263363Semaste    if (!error.Fail())
712263363Semaste        SeekFromStart(cur);
713263363Semaste    return error;
714263363Semaste#endif
715254721Semaste}
716254721Semaste
717254721SemasteError
718254721SemasteFile::Read (size_t &num_bytes, off_t &offset, bool null_terminate, DataBufferSP &data_buffer_sp)
719254721Semaste{
720254721Semaste    Error error;
721254721Semaste
722254721Semaste    if (num_bytes > 0)
723254721Semaste    {
724254721Semaste        int fd = GetDescriptor();
725254721Semaste        if (fd != kInvalidDescriptor)
726254721Semaste        {
727254721Semaste            struct stat file_stats;
728254721Semaste            if (::fstat (fd, &file_stats) == 0)
729254721Semaste            {
730254721Semaste                if (file_stats.st_size > offset)
731254721Semaste                {
732254721Semaste                    const size_t bytes_left = file_stats.st_size - offset;
733254721Semaste                    if (num_bytes > bytes_left)
734254721Semaste                        num_bytes = bytes_left;
735254721Semaste
736254721Semaste                    std::unique_ptr<DataBufferHeap> data_heap_ap;
737254721Semaste                    data_heap_ap.reset(new DataBufferHeap(num_bytes + (null_terminate ? 1 : 0), '\0'));
738254721Semaste
739254721Semaste                    if (data_heap_ap.get())
740254721Semaste                    {
741254721Semaste                        error = Read (data_heap_ap->GetBytes(), num_bytes, offset);
742254721Semaste                        if (error.Success())
743254721Semaste                        {
744254721Semaste                            // Make sure we read exactly what we asked for and if we got
745254721Semaste                            // less, adjust the array
746254721Semaste                            if (num_bytes < data_heap_ap->GetByteSize())
747254721Semaste                                data_heap_ap->SetByteSize(num_bytes);
748254721Semaste                            data_buffer_sp.reset(data_heap_ap.release());
749254721Semaste                            return error;
750254721Semaste                        }
751254721Semaste                    }
752254721Semaste                }
753254721Semaste                else
754254721Semaste                    error.SetErrorString("file is empty");
755254721Semaste            }
756254721Semaste            else
757254721Semaste                error.SetErrorToErrno();
758254721Semaste        }
759254721Semaste        else
760254721Semaste            error.SetErrorString("invalid file handle");
761254721Semaste    }
762254721Semaste    else
763254721Semaste        error.SetErrorString("invalid file handle");
764254721Semaste
765254721Semaste    num_bytes = 0;
766254721Semaste    data_buffer_sp.reset();
767254721Semaste    return error;
768254721Semaste}
769254721Semaste
770254721SemasteError
771254721SemasteFile::Write (const void *buf, size_t &num_bytes, off_t &offset)
772254721Semaste{
773254721Semaste    Error error;
774254721Semaste    int fd = GetDescriptor();
775254721Semaste    if (fd != kInvalidDescriptor)
776254721Semaste    {
777263363Semaste#ifndef _WIN32
778254721Semaste        ssize_t bytes_written = -1;
779254721Semaste        do
780254721Semaste        {
781254721Semaste            bytes_written = ::pwrite (m_descriptor, buf, num_bytes, offset);
782254721Semaste        } while (bytes_written < 0 && errno == EINTR);
783254721Semaste
784254721Semaste        if (bytes_written < 0)
785254721Semaste        {
786254721Semaste            num_bytes = 0;
787254721Semaste            error.SetErrorToErrno();
788254721Semaste        }
789254721Semaste        else
790254721Semaste        {
791254721Semaste            offset += bytes_written;
792254721Semaste            num_bytes = bytes_written;
793254721Semaste        }
794263363Semaste#else
795263363Semaste        long cur = ::lseek(m_descriptor, 0, SEEK_CUR);
796263363Semaste        error = Write(buf, num_bytes);
797263363Semaste        long after = ::lseek(m_descriptor, 0, SEEK_CUR);
798263363Semaste
799263363Semaste        if (!error.Fail())
800263363Semaste            SeekFromStart(cur);
801263363Semaste
802263363Semaste        ssize_t bytes_written = after - cur;
803263363Semaste        offset = after;
804263363Semaste#endif
805254721Semaste    }
806254721Semaste    else
807254721Semaste    {
808254721Semaste        num_bytes = 0;
809254721Semaste        error.SetErrorString("invalid file handle");
810254721Semaste    }
811254721Semaste    return error;
812254721Semaste}
813254721Semaste
814254721Semaste//------------------------------------------------------------------
815254721Semaste// Print some formatted output to the stream.
816254721Semaste//------------------------------------------------------------------
817254721Semastesize_t
818254721SemasteFile::Printf (const char *format, ...)
819254721Semaste{
820254721Semaste    va_list args;
821254721Semaste    va_start (args, format);
822254721Semaste    size_t result = PrintfVarArg (format, args);
823254721Semaste    va_end (args);
824254721Semaste    return result;
825254721Semaste}
826254721Semaste
827254721Semaste//------------------------------------------------------------------
828254721Semaste// Print some formatted output to the stream.
829254721Semaste//------------------------------------------------------------------
830254721Semastesize_t
831254721SemasteFile::PrintfVarArg (const char *format, va_list args)
832254721Semaste{
833254721Semaste    size_t result = 0;
834254721Semaste    if (DescriptorIsValid())
835254721Semaste    {
836254721Semaste        char *s = NULL;
837254721Semaste        result = vasprintf(&s, format, args);
838254721Semaste        if (s != NULL)
839254721Semaste        {
840254721Semaste            if (result > 0)
841254721Semaste            {
842254721Semaste                size_t s_len = result;
843254721Semaste                Write (s, s_len);
844254721Semaste                result = s_len;
845254721Semaste            }
846254721Semaste            free (s);
847254721Semaste        }
848254721Semaste    }
849254721Semaste    else if (StreamIsValid())
850254721Semaste    {
851254721Semaste        result = ::vfprintf (m_stream, format, args);
852254721Semaste    }
853254721Semaste    return result;
854254721Semaste}
855263363Semaste
856263363Semastemode_t
857263363SemasteFile::ConvertOpenOptionsForPOSIXOpen (uint32_t open_options)
858263363Semaste{
859263363Semaste    mode_t mode = 0;
860263363Semaste    if (open_options & eOpenOptionRead && open_options & eOpenOptionWrite)
861263363Semaste        mode |= O_RDWR;
862263363Semaste    else if (open_options & eOpenOptionWrite)
863263363Semaste        mode |= O_WRONLY;
864263363Semaste
865263363Semaste    if (open_options & eOpenOptionAppend)
866263363Semaste        mode |= O_APPEND;
867263363Semaste
868263363Semaste    if (open_options & eOpenOptionTruncate)
869263363Semaste        mode |= O_TRUNC;
870263363Semaste
871263363Semaste    if (open_options & eOpenOptionNonBlocking)
872263363Semaste        mode |= O_NONBLOCK;
873263363Semaste
874263363Semaste    if (open_options & eOpenOptionCanCreateNewOnly)
875263363Semaste        mode |= O_CREAT | O_EXCL;
876263363Semaste    else if (open_options & eOpenOptionCanCreate)
877263363Semaste        mode |= O_CREAT;
878263363Semaste
879263363Semaste    return mode;
880263363Semaste}
881269024Semaste
882269024Semastevoid
883269024SemasteFile::CalculateInteractiveAndTerminal ()
884269024Semaste{
885269024Semaste    const int fd = GetDescriptor();
886269024Semaste    if (fd >= 0)
887269024Semaste    {
888269024Semaste        m_is_interactive = eLazyBoolNo;
889269024Semaste        m_is_real_terminal = eLazyBoolNo;
890269024Semaste#ifndef _MSC_VER
891269024Semaste        if (isatty(fd))
892269024Semaste        {
893269024Semaste            m_is_interactive = eLazyBoolYes;
894269024Semaste            struct winsize window_size;
895269024Semaste            if (::ioctl (fd, TIOCGWINSZ, &window_size) == 0)
896269024Semaste            {
897269024Semaste                if (window_size.ws_col > 0)
898269024Semaste                    m_is_real_terminal = eLazyBoolYes;
899269024Semaste            }
900269024Semaste        }
901269024Semaste#endif
902269024Semaste    }
903269024Semaste}
904269024Semaste
905269024Semastebool
906269024SemasteFile::GetIsInteractive ()
907269024Semaste{
908269024Semaste    if (m_is_interactive == eLazyBoolCalculate)
909269024Semaste        CalculateInteractiveAndTerminal ();
910269024Semaste    return m_is_interactive == eLazyBoolYes;
911269024Semaste}
912269024Semaste
913269024Semastebool
914269024SemasteFile::GetIsRealTerminal ()
915269024Semaste{
916269024Semaste    if (m_is_real_terminal == eLazyBoolCalculate)
917269024Semaste        CalculateInteractiveAndTerminal();
918269024Semaste    return m_is_real_terminal == eLazyBoolYes;
919269024Semaste}
920269024Semaste
921