File.cpp revision 258884
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>
16254721Semaste#include <sys/stat.h>
17254721Semaste
18258054Semaste#ifdef _WIN32
19258054Semaste#include "lldb/Host/windows/windows.h"
20258054Semaste#endif
21258054Semaste
22254721Semaste#include "lldb/Core/DataBufferHeap.h"
23254721Semaste#include "lldb/Core/Error.h"
24254721Semaste#include "lldb/Host/Config.h"
25254721Semaste#include "lldb/Host/FileSpec.h"
26254721Semaste
27254721Semasteusing namespace lldb;
28254721Semasteusing namespace lldb_private;
29254721Semaste
30254721Semastestatic const char *
31254721SemasteGetStreamOpenModeFromOptions (uint32_t options)
32254721Semaste{
33254721Semaste    if (options & File::eOpenOptionAppend)
34254721Semaste    {
35254721Semaste        if (options & File::eOpenOptionRead)
36254721Semaste        {
37254721Semaste            if (options & File::eOpenOptionCanCreateNewOnly)
38254721Semaste                return "a+x";
39254721Semaste            else
40254721Semaste                return "a+";
41254721Semaste        }
42254721Semaste        else if (options & File::eOpenOptionWrite)
43254721Semaste        {
44254721Semaste            if (options & File::eOpenOptionCanCreateNewOnly)
45254721Semaste                return "ax";
46254721Semaste            else
47254721Semaste                return "a";
48254721Semaste        }
49254721Semaste    }
50254721Semaste    else if (options & File::eOpenOptionRead && options & File::eOpenOptionWrite)
51254721Semaste    {
52254721Semaste        if (options & File::eOpenOptionCanCreate)
53254721Semaste        {
54254721Semaste            if (options & File::eOpenOptionCanCreateNewOnly)
55254721Semaste                return "w+x";
56254721Semaste            else
57254721Semaste                return "w+";
58254721Semaste        }
59254721Semaste        else
60254721Semaste            return "r+";
61254721Semaste    }
62254721Semaste    else if (options & File::eOpenOptionRead)
63254721Semaste    {
64254721Semaste        return "r";
65254721Semaste    }
66254721Semaste    else if (options & File::eOpenOptionWrite)
67254721Semaste    {
68254721Semaste        return "w";
69254721Semaste    }
70254721Semaste    return NULL;
71254721Semaste}
72254721Semaste
73254721Semasteint File::kInvalidDescriptor = -1;
74254721SemasteFILE * File::kInvalidStream = NULL;
75254721Semaste
76254721SemasteFile::File(const char *path, uint32_t options, uint32_t permissions) :
77254721Semaste    m_descriptor (kInvalidDescriptor),
78254721Semaste    m_stream (kInvalidStream),
79254721Semaste    m_options (0),
80254721Semaste    m_owned (false)
81254721Semaste{
82254721Semaste    Open (path, options, permissions);
83254721Semaste}
84254721Semaste
85258054SemasteFile::File (const FileSpec& filespec,
86258054Semaste            uint32_t options,
87258054Semaste            uint32_t permissions) :
88258054Semaste    m_descriptor (kInvalidDescriptor),
89258054Semaste    m_stream (kInvalidStream),
90258054Semaste    m_options (0),
91258054Semaste    m_owned (false)
92258054Semaste{
93258054Semaste    if (filespec)
94258054Semaste    {
95258054Semaste        Open (filespec.GetPath().c_str(), options, permissions);
96258054Semaste    }
97258054Semaste}
98258054Semaste
99254721SemasteFile::File (const File &rhs) :
100254721Semaste    m_descriptor (kInvalidDescriptor),
101254721Semaste    m_stream (kInvalidStream),
102254721Semaste    m_options (0),
103254721Semaste    m_owned (false)
104254721Semaste{
105254721Semaste    Duplicate (rhs);
106254721Semaste}
107254721Semaste
108254721Semaste
109254721SemasteFile &
110254721SemasteFile::operator = (const File &rhs)
111254721Semaste{
112254721Semaste    if (this != &rhs)
113254721Semaste        Duplicate (rhs);
114254721Semaste    return *this;
115254721Semaste}
116254721Semaste
117254721SemasteFile::~File()
118254721Semaste{
119254721Semaste    Close ();
120254721Semaste}
121254721Semaste
122254721Semaste
123254721Semasteint
124254721SemasteFile::GetDescriptor() const
125254721Semaste{
126254721Semaste    if (DescriptorIsValid())
127254721Semaste        return m_descriptor;
128254721Semaste
129254721Semaste    // Don't open the file descriptor if we don't need to, just get it from the
130254721Semaste    // stream if we have one.
131254721Semaste    if (StreamIsValid())
132254721Semaste        return fileno (m_stream);
133254721Semaste
134254721Semaste    // Invalid descriptor and invalid stream, return invalid descriptor.
135254721Semaste    return kInvalidDescriptor;
136254721Semaste}
137254721Semaste
138254721Semastevoid
139254721SemasteFile::SetDescriptor (int fd, bool transfer_ownership)
140254721Semaste{
141254721Semaste    if (IsValid())
142254721Semaste        Close();
143254721Semaste    m_descriptor = fd;
144254721Semaste    m_owned = transfer_ownership;
145254721Semaste}
146254721Semaste
147254721Semaste
148254721SemasteFILE *
149254721SemasteFile::GetStream ()
150254721Semaste{
151254721Semaste    if (!StreamIsValid())
152254721Semaste    {
153254721Semaste        if (DescriptorIsValid())
154254721Semaste        {
155254721Semaste            const char *mode = GetStreamOpenModeFromOptions (m_options);
156254721Semaste            if (mode)
157254721Semaste            {
158254721Semaste                do
159254721Semaste                {
160254721Semaste                    m_stream = ::fdopen (m_descriptor, mode);
161254721Semaste                } while (m_stream == NULL && errno == EINTR);
162254721Semaste            }
163254721Semaste        }
164254721Semaste    }
165254721Semaste    return m_stream;
166254721Semaste}
167254721Semaste
168254721Semaste
169254721Semastevoid
170254721SemasteFile::SetStream (FILE *fh, bool transfer_ownership)
171254721Semaste{
172254721Semaste    if (IsValid())
173254721Semaste        Close();
174254721Semaste    m_stream = fh;
175254721Semaste    m_owned = transfer_ownership;
176254721Semaste}
177254721Semaste
178254721SemasteError
179254721SemasteFile::Duplicate (const File &rhs)
180254721Semaste{
181254721Semaste    Error error;
182254721Semaste    if (IsValid ())
183254721Semaste        Close();
184254721Semaste
185254721Semaste    if (rhs.DescriptorIsValid())
186254721Semaste    {
187258054Semaste#ifdef _WIN32
188258054Semaste        m_descriptor = ::_dup(rhs.GetDescriptor());
189258054Semaste#else
190254721Semaste        m_descriptor = ::fcntl(rhs.GetDescriptor(), F_DUPFD);
191258054Semaste#endif
192254721Semaste        if (!DescriptorIsValid())
193254721Semaste            error.SetErrorToErrno();
194254721Semaste        else
195254721Semaste        {
196254721Semaste            m_options = rhs.m_options;
197254721Semaste            m_owned = true;
198254721Semaste        }
199254721Semaste    }
200254721Semaste    else
201254721Semaste    {
202254721Semaste        error.SetErrorString ("invalid file to duplicate");
203254721Semaste    }
204254721Semaste    return error;
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
241258884Semaste        if (options & eOpenoptionDontFollowSymlinks)
242258884Semaste            oflag |= O_NOFOLLOW;
243258884Semaste#endif
244254721Semaste    }
245254721Semaste
246258054Semaste#ifndef _WIN32
247254721Semaste    if (options & eOpenOptionNonBlocking)
248254721Semaste        oflag |= O_NONBLOCK;
249258054Semaste#else
250258054Semaste    oflag |= O_BINARY;
251258054Semaste#endif
252254721Semaste
253254721Semaste    mode_t mode = 0;
254254721Semaste    if (oflag & O_CREAT)
255254721Semaste    {
256258884Semaste        if (permissions & lldb::eFilePermissionsUserRead)     mode |= S_IRUSR;
257258884Semaste        if (permissions & lldb::eFilePermissionsUserWrite)    mode |= S_IWUSR;
258258884Semaste        if (permissions & lldb::eFilePermissionsUserExecute)  mode |= S_IXUSR;
259258884Semaste        if (permissions & lldb::eFilePermissionsGroupRead)    mode |= S_IRGRP;
260258884Semaste        if (permissions & lldb::eFilePermissionsGroupWrite)   mode |= S_IWGRP;
261258884Semaste        if (permissions & lldb::eFilePermissionsGroupExecute) mode |= S_IXGRP;
262258884Semaste        if (permissions & lldb::eFilePermissionsWorldRead)    mode |= S_IROTH;
263258884Semaste        if (permissions & lldb::eFilePermissionsWorldWrite)   mode |= S_IWOTH;
264258884Semaste        if (permissions & lldb::eFilePermissionsWorldExecute) mode |= S_IXOTH;
265254721Semaste    }
266254721Semaste
267254721Semaste    do
268254721Semaste    {
269254721Semaste        m_descriptor = ::open(path, oflag, mode);
270254721Semaste    } while (m_descriptor < 0 && errno == EINTR);
271254721Semaste
272254721Semaste    if (!DescriptorIsValid())
273254721Semaste        error.SetErrorToErrno();
274254721Semaste    else
275254721Semaste        m_owned = true;
276254721Semaste
277254721Semaste    return error;
278254721Semaste}
279254721Semaste
280258054Semasteuint32_t
281258054SemasteFile::GetPermissions (const char *path, Error &error)
282258054Semaste{
283258054Semaste    if (path && path[0])
284258054Semaste    {
285258054Semaste        struct stat file_stats;
286258054Semaste        if (::stat (path, &file_stats) == -1)
287258054Semaste            error.SetErrorToErrno();
288258054Semaste        else
289258054Semaste        {
290258054Semaste            error.Clear();
291258884Semaste            return file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
292258054Semaste        }
293258054Semaste    }
294258054Semaste    else
295258054Semaste    {
296258054Semaste        if (path)
297258054Semaste            error.SetErrorString ("invalid path");
298258054Semaste        else
299258054Semaste            error.SetErrorString ("empty path");
300258054Semaste    }
301258054Semaste    return 0;
302258054Semaste}
303258054Semaste
304258054Semasteuint32_t
305258054SemasteFile::GetPermissions(Error &error) const
306258054Semaste{
307258054Semaste    int fd = GetDescriptor();
308258054Semaste    if (fd != kInvalidDescriptor)
309258054Semaste    {
310258054Semaste        struct stat file_stats;
311258054Semaste        if (::fstat (fd, &file_stats) == -1)
312258054Semaste            error.SetErrorToErrno();
313258054Semaste        else
314258054Semaste        {
315258054Semaste            error.Clear();
316258884Semaste            return file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
317258054Semaste        }
318258054Semaste    }
319258054Semaste    else
320258054Semaste    {
321258054Semaste        error.SetErrorString ("invalid file descriptor");
322258054Semaste    }
323258054Semaste    return 0;
324258054Semaste}
325258054Semaste
326258054Semaste
327254721SemasteError
328254721SemasteFile::Close ()
329254721Semaste{
330254721Semaste    Error error;
331254721Semaste    if (IsValid ())
332254721Semaste    {
333254721Semaste        if (m_owned)
334254721Semaste        {
335254721Semaste            if (StreamIsValid())
336254721Semaste            {
337254721Semaste                if (::fclose (m_stream) == EOF)
338254721Semaste                    error.SetErrorToErrno();
339254721Semaste            }
340254721Semaste
341254721Semaste            if (DescriptorIsValid())
342254721Semaste            {
343254721Semaste                if (::close (m_descriptor) != 0)
344254721Semaste                    error.SetErrorToErrno();
345254721Semaste            }
346254721Semaste        }
347254721Semaste        m_descriptor = kInvalidDescriptor;
348254721Semaste        m_stream = kInvalidStream;
349254721Semaste        m_options = 0;
350254721Semaste        m_owned = false;
351254721Semaste    }
352254721Semaste    return error;
353254721Semaste}
354254721Semaste
355254721Semaste
356254721SemasteError
357254721SemasteFile::GetFileSpec (FileSpec &file_spec) const
358254721Semaste{
359254721Semaste    Error error;
360254721Semaste#ifdef LLDB_CONFIG_FCNTL_GETPATH_SUPPORTED
361254721Semaste    if (IsValid ())
362254721Semaste    {
363254721Semaste        char path[PATH_MAX];
364254721Semaste        if (::fcntl(GetDescriptor(), F_GETPATH, path) == -1)
365254721Semaste            error.SetErrorToErrno();
366254721Semaste        else
367254721Semaste            file_spec.SetFile (path, false);
368254721Semaste    }
369254721Semaste    else
370254721Semaste    {
371254721Semaste        error.SetErrorString("invalid file handle");
372254721Semaste    }
373254721Semaste#elif defined(__linux__)
374254721Semaste    char proc[64];
375254721Semaste    char path[PATH_MAX];
376254721Semaste    if (::snprintf(proc, sizeof(proc), "/proc/self/fd/%d", GetDescriptor()) < 0)
377254721Semaste        error.SetErrorString ("cannot resolve file descriptor");
378254721Semaste    else
379254721Semaste    {
380254721Semaste        ssize_t len;
381254721Semaste        if ((len = ::readlink(proc, path, sizeof(path) - 1)) == -1)
382254721Semaste            error.SetErrorToErrno();
383254721Semaste        else
384254721Semaste        {
385254721Semaste            path[len] = '\0';
386254721Semaste            file_spec.SetFile (path, false);
387254721Semaste        }
388254721Semaste    }
389254721Semaste#else
390254721Semaste    error.SetErrorString ("File::GetFileSpec is not supported on this platform");
391254721Semaste#endif
392254721Semaste
393254721Semaste    if (error.Fail())
394254721Semaste        file_spec.Clear();
395254721Semaste    return error;
396254721Semaste}
397254721Semaste
398254721Semasteoff_t
399254721SemasteFile::SeekFromStart (off_t offset, Error *error_ptr)
400254721Semaste{
401254721Semaste    off_t result = 0;
402254721Semaste    if (DescriptorIsValid())
403254721Semaste    {
404254721Semaste        result = ::lseek (m_descriptor, offset, SEEK_SET);
405254721Semaste
406254721Semaste        if (error_ptr)
407254721Semaste        {
408254721Semaste            if (result == -1)
409254721Semaste                error_ptr->SetErrorToErrno();
410254721Semaste            else
411254721Semaste                error_ptr->Clear();
412254721Semaste        }
413254721Semaste    }
414254721Semaste    else if (StreamIsValid ())
415254721Semaste    {
416254721Semaste        result = ::fseek(m_stream, offset, SEEK_SET);
417254721Semaste
418254721Semaste        if (error_ptr)
419254721Semaste        {
420254721Semaste            if (result == -1)
421254721Semaste                error_ptr->SetErrorToErrno();
422254721Semaste            else
423254721Semaste                error_ptr->Clear();
424254721Semaste        }
425254721Semaste    }
426254721Semaste    else if (error_ptr)
427254721Semaste    {
428254721Semaste        error_ptr->SetErrorString("invalid file handle");
429254721Semaste    }
430254721Semaste    return result;
431254721Semaste}
432254721Semaste
433254721Semasteoff_t
434254721SemasteFile::SeekFromCurrent (off_t offset,  Error *error_ptr)
435254721Semaste{
436254721Semaste    off_t result = -1;
437254721Semaste    if (DescriptorIsValid())
438254721Semaste    {
439254721Semaste        result = ::lseek (m_descriptor, offset, SEEK_CUR);
440254721Semaste
441254721Semaste        if (error_ptr)
442254721Semaste        {
443254721Semaste            if (result == -1)
444254721Semaste                error_ptr->SetErrorToErrno();
445254721Semaste            else
446254721Semaste                error_ptr->Clear();
447254721Semaste        }
448254721Semaste    }
449254721Semaste    else if (StreamIsValid ())
450254721Semaste    {
451254721Semaste        result = ::fseek(m_stream, offset, SEEK_CUR);
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 (error_ptr)
462254721Semaste    {
463254721Semaste        error_ptr->SetErrorString("invalid file handle");
464254721Semaste    }
465254721Semaste    return result;
466254721Semaste}
467254721Semaste
468254721Semasteoff_t
469254721SemasteFile::SeekFromEnd (off_t offset, Error *error_ptr)
470254721Semaste{
471254721Semaste    off_t result = -1;
472254721Semaste    if (DescriptorIsValid())
473254721Semaste    {
474254721Semaste        result = ::lseek (m_descriptor, offset, SEEK_END);
475254721Semaste
476254721Semaste        if (error_ptr)
477254721Semaste        {
478254721Semaste            if (result == -1)
479254721Semaste                error_ptr->SetErrorToErrno();
480254721Semaste            else
481254721Semaste                error_ptr->Clear();
482254721Semaste        }
483254721Semaste    }
484254721Semaste    else if (StreamIsValid ())
485254721Semaste    {
486254721Semaste        result = ::fseek(m_stream, offset, SEEK_END);
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 (error_ptr)
497254721Semaste    {
498254721Semaste        error_ptr->SetErrorString("invalid file handle");
499254721Semaste    }
500254721Semaste    return result;
501254721Semaste}
502254721Semaste
503254721SemasteError
504254721SemasteFile::Flush ()
505254721Semaste{
506254721Semaste    Error error;
507254721Semaste    if (StreamIsValid())
508254721Semaste    {
509254721Semaste        int err = 0;
510254721Semaste        do
511254721Semaste        {
512254721Semaste            err = ::fflush (m_stream);
513254721Semaste        } while (err == EOF && errno == EINTR);
514254721Semaste
515254721Semaste        if (err == EOF)
516254721Semaste            error.SetErrorToErrno();
517254721Semaste    }
518254721Semaste    else if (!DescriptorIsValid())
519254721Semaste    {
520254721Semaste        error.SetErrorString("invalid file handle");
521254721Semaste    }
522254721Semaste    return error;
523254721Semaste}
524254721Semaste
525254721Semaste
526254721SemasteError
527254721SemasteFile::Sync ()
528254721Semaste{
529254721Semaste    Error error;
530254721Semaste    if (DescriptorIsValid())
531254721Semaste    {
532258054Semaste#ifdef _WIN32
533258054Semaste        int err = FlushFileBuffers((HANDLE)_get_osfhandle(m_descriptor));
534258054Semaste        if (err == 0)
535258054Semaste            error.SetErrorToGenericError();
536258054Semaste#else
537254721Semaste        int err = 0;
538254721Semaste        do
539254721Semaste        {
540254721Semaste            err = ::fsync (m_descriptor);
541254721Semaste        } while (err == -1 && errno == EINTR);
542254721Semaste
543254721Semaste        if (err == -1)
544254721Semaste            error.SetErrorToErrno();
545258054Semaste#endif
546254721Semaste    }
547254721Semaste    else
548254721Semaste    {
549254721Semaste        error.SetErrorString("invalid file handle");
550254721Semaste    }
551254721Semaste    return error;
552254721Semaste}
553254721Semaste
554254721SemasteError
555254721SemasteFile::Read (void *buf, size_t &num_bytes)
556254721Semaste{
557254721Semaste    Error error;
558254721Semaste    ssize_t bytes_read = -1;
559254721Semaste    if (DescriptorIsValid())
560254721Semaste    {
561254721Semaste        do
562254721Semaste        {
563254721Semaste            bytes_read = ::read (m_descriptor, buf, num_bytes);
564254721Semaste        } while (bytes_read < 0 && errno == EINTR);
565254721Semaste
566254721Semaste        if (bytes_read == -1)
567254721Semaste        {
568254721Semaste            error.SetErrorToErrno();
569254721Semaste            num_bytes = 0;
570254721Semaste        }
571254721Semaste        else
572254721Semaste            num_bytes = bytes_read;
573254721Semaste    }
574254721Semaste    else if (StreamIsValid())
575254721Semaste    {
576254721Semaste        bytes_read = ::fread (buf, 1, num_bytes, m_stream);
577254721Semaste
578254721Semaste        if (bytes_read == 0)
579254721Semaste        {
580254721Semaste            if (::feof(m_stream))
581254721Semaste                error.SetErrorString ("feof");
582254721Semaste            else if (::ferror (m_stream))
583254721Semaste                error.SetErrorString ("ferror");
584254721Semaste            num_bytes = 0;
585254721Semaste        }
586254721Semaste        else
587254721Semaste            num_bytes = bytes_read;
588254721Semaste    }
589254721Semaste    else
590254721Semaste    {
591254721Semaste        num_bytes = 0;
592254721Semaste        error.SetErrorString("invalid file handle");
593254721Semaste    }
594254721Semaste    return error;
595254721Semaste}
596254721Semaste
597254721SemasteError
598254721SemasteFile::Write (const void *buf, size_t &num_bytes)
599254721Semaste{
600254721Semaste    Error error;
601254721Semaste    ssize_t bytes_written = -1;
602254721Semaste    if (DescriptorIsValid())
603254721Semaste    {
604254721Semaste        do
605254721Semaste        {
606254721Semaste            bytes_written = ::write (m_descriptor, buf, num_bytes);
607254721Semaste        } while (bytes_written < 0 && errno == EINTR);
608254721Semaste
609254721Semaste        if (bytes_written == -1)
610254721Semaste        {
611254721Semaste            error.SetErrorToErrno();
612254721Semaste            num_bytes = 0;
613254721Semaste        }
614254721Semaste        else
615254721Semaste            num_bytes = bytes_written;
616254721Semaste    }
617254721Semaste    else if (StreamIsValid())
618254721Semaste    {
619254721Semaste        bytes_written = ::fwrite (buf, 1, num_bytes, m_stream);
620254721Semaste
621254721Semaste        if (bytes_written == 0)
622254721Semaste        {
623254721Semaste            if (::feof(m_stream))
624254721Semaste                error.SetErrorString ("feof");
625254721Semaste            else if (::ferror (m_stream))
626254721Semaste                error.SetErrorString ("ferror");
627254721Semaste            num_bytes = 0;
628254721Semaste        }
629254721Semaste        else
630254721Semaste            num_bytes = bytes_written;
631254721Semaste
632254721Semaste    }
633254721Semaste    else
634254721Semaste    {
635254721Semaste        num_bytes = 0;
636254721Semaste        error.SetErrorString("invalid file handle");
637254721Semaste    }
638254721Semaste    return error;
639254721Semaste}
640254721Semaste
641254721Semaste
642254721SemasteError
643254721SemasteFile::Read (void *buf, size_t &num_bytes, off_t &offset)
644254721Semaste{
645258054Semaste#ifndef _WIN32
646254721Semaste    Error error;
647254721Semaste    int fd = GetDescriptor();
648254721Semaste    if (fd != kInvalidDescriptor)
649254721Semaste    {
650254721Semaste        ssize_t bytes_read = -1;
651254721Semaste        do
652254721Semaste        {
653254721Semaste            bytes_read = ::pread (fd, buf, num_bytes, offset);
654254721Semaste        } while (bytes_read < 0 && errno == EINTR);
655254721Semaste
656254721Semaste        if (bytes_read < 0)
657254721Semaste        {
658254721Semaste            num_bytes = 0;
659254721Semaste            error.SetErrorToErrno();
660254721Semaste        }
661254721Semaste        else
662254721Semaste        {
663254721Semaste            offset += bytes_read;
664254721Semaste            num_bytes = bytes_read;
665254721Semaste        }
666254721Semaste    }
667254721Semaste    else
668254721Semaste    {
669254721Semaste        num_bytes = 0;
670254721Semaste        error.SetErrorString("invalid file handle");
671254721Semaste    }
672254721Semaste    return error;
673258054Semaste#else
674258054Semaste    long cur = ::lseek(m_descriptor, 0, SEEK_CUR);
675258054Semaste    SeekFromStart(offset);
676258054Semaste    Error error = Read(buf, num_bytes);
677258054Semaste    if (!error.Fail())
678258054Semaste        SeekFromStart(cur);
679258054Semaste    return error;
680258054Semaste#endif
681254721Semaste}
682254721Semaste
683254721SemasteError
684254721SemasteFile::Read (size_t &num_bytes, off_t &offset, bool null_terminate, DataBufferSP &data_buffer_sp)
685254721Semaste{
686254721Semaste    Error error;
687254721Semaste
688254721Semaste    if (num_bytes > 0)
689254721Semaste    {
690254721Semaste        int fd = GetDescriptor();
691254721Semaste        if (fd != kInvalidDescriptor)
692254721Semaste        {
693254721Semaste            struct stat file_stats;
694254721Semaste            if (::fstat (fd, &file_stats) == 0)
695254721Semaste            {
696254721Semaste                if (file_stats.st_size > offset)
697254721Semaste                {
698254721Semaste                    const size_t bytes_left = file_stats.st_size - offset;
699254721Semaste                    if (num_bytes > bytes_left)
700254721Semaste                        num_bytes = bytes_left;
701254721Semaste
702254721Semaste                    std::unique_ptr<DataBufferHeap> data_heap_ap;
703254721Semaste                    data_heap_ap.reset(new DataBufferHeap(num_bytes + (null_terminate ? 1 : 0), '\0'));
704254721Semaste
705254721Semaste                    if (data_heap_ap.get())
706254721Semaste                    {
707254721Semaste                        error = Read (data_heap_ap->GetBytes(), num_bytes, offset);
708254721Semaste                        if (error.Success())
709254721Semaste                        {
710254721Semaste                            // Make sure we read exactly what we asked for and if we got
711254721Semaste                            // less, adjust the array
712254721Semaste                            if (num_bytes < data_heap_ap->GetByteSize())
713254721Semaste                                data_heap_ap->SetByteSize(num_bytes);
714254721Semaste                            data_buffer_sp.reset(data_heap_ap.release());
715254721Semaste                            return error;
716254721Semaste                        }
717254721Semaste                    }
718254721Semaste                }
719254721Semaste                else
720254721Semaste                    error.SetErrorString("file is empty");
721254721Semaste            }
722254721Semaste            else
723254721Semaste                error.SetErrorToErrno();
724254721Semaste        }
725254721Semaste        else
726254721Semaste            error.SetErrorString("invalid file handle");
727254721Semaste    }
728254721Semaste    else
729254721Semaste        error.SetErrorString("invalid file handle");
730254721Semaste
731254721Semaste    num_bytes = 0;
732254721Semaste    data_buffer_sp.reset();
733254721Semaste    return error;
734254721Semaste}
735254721Semaste
736254721SemasteError
737254721SemasteFile::Write (const void *buf, size_t &num_bytes, off_t &offset)
738254721Semaste{
739254721Semaste    Error error;
740254721Semaste    int fd = GetDescriptor();
741254721Semaste    if (fd != kInvalidDescriptor)
742254721Semaste    {
743258054Semaste#ifndef _WIN32
744254721Semaste        ssize_t bytes_written = -1;
745254721Semaste        do
746254721Semaste        {
747254721Semaste            bytes_written = ::pwrite (m_descriptor, buf, num_bytes, offset);
748254721Semaste        } while (bytes_written < 0 && errno == EINTR);
749254721Semaste
750254721Semaste        if (bytes_written < 0)
751254721Semaste        {
752254721Semaste            num_bytes = 0;
753254721Semaste            error.SetErrorToErrno();
754254721Semaste        }
755254721Semaste        else
756254721Semaste        {
757254721Semaste            offset += bytes_written;
758254721Semaste            num_bytes = bytes_written;
759254721Semaste        }
760258054Semaste#else
761258054Semaste        long cur = ::lseek(m_descriptor, 0, SEEK_CUR);
762258054Semaste        error = Write(buf, num_bytes);
763258054Semaste        long after = ::lseek(m_descriptor, 0, SEEK_CUR);
764258054Semaste
765258054Semaste        if (!error.Fail())
766258054Semaste            SeekFromStart(cur);
767258054Semaste
768258054Semaste        ssize_t bytes_written = after - cur;
769258054Semaste        offset = after;
770258054Semaste#endif
771254721Semaste    }
772254721Semaste    else
773254721Semaste    {
774254721Semaste        num_bytes = 0;
775254721Semaste        error.SetErrorString("invalid file handle");
776254721Semaste    }
777254721Semaste    return error;
778254721Semaste}
779254721Semaste
780254721Semaste//------------------------------------------------------------------
781254721Semaste// Print some formatted output to the stream.
782254721Semaste//------------------------------------------------------------------
783254721Semastesize_t
784254721SemasteFile::Printf (const char *format, ...)
785254721Semaste{
786254721Semaste    va_list args;
787254721Semaste    va_start (args, format);
788254721Semaste    size_t result = PrintfVarArg (format, args);
789254721Semaste    va_end (args);
790254721Semaste    return result;
791254721Semaste}
792254721Semaste
793254721Semaste//------------------------------------------------------------------
794254721Semaste// Print some formatted output to the stream.
795254721Semaste//------------------------------------------------------------------
796254721Semastesize_t
797254721SemasteFile::PrintfVarArg (const char *format, va_list args)
798254721Semaste{
799254721Semaste    size_t result = 0;
800254721Semaste    if (DescriptorIsValid())
801254721Semaste    {
802254721Semaste        char *s = NULL;
803254721Semaste        result = vasprintf(&s, format, args);
804254721Semaste        if (s != NULL)
805254721Semaste        {
806254721Semaste            if (result > 0)
807254721Semaste            {
808254721Semaste                size_t s_len = result;
809254721Semaste                Write (s, s_len);
810254721Semaste                result = s_len;
811254721Semaste            }
812254721Semaste            free (s);
813254721Semaste        }
814254721Semaste    }
815254721Semaste    else if (StreamIsValid())
816254721Semaste    {
817254721Semaste        result = ::vfprintf (m_stream, format, args);
818254721Semaste    }
819254721Semaste    return result;
820254721Semaste}
821258054Semaste
822258054Semastemode_t
823258054SemasteFile::ConvertOpenOptionsForPOSIXOpen (uint32_t open_options)
824258054Semaste{
825258054Semaste    mode_t mode = 0;
826258054Semaste    if (open_options & eOpenOptionRead && open_options & eOpenOptionWrite)
827258054Semaste        mode |= O_RDWR;
828258054Semaste    else if (open_options & eOpenOptionWrite)
829258054Semaste        mode |= O_WRONLY;
830258054Semaste
831258054Semaste    if (open_options & eOpenOptionAppend)
832258054Semaste        mode |= O_APPEND;
833258054Semaste
834258054Semaste    if (open_options & eOpenOptionTruncate)
835258054Semaste        mode |= O_TRUNC;
836258054Semaste
837258054Semaste    if (open_options & eOpenOptionNonBlocking)
838258054Semaste        mode |= O_NONBLOCK;
839258054Semaste
840258054Semaste    if (open_options & eOpenOptionCanCreateNewOnly)
841258054Semaste        mode |= O_CREAT | O_EXCL;
842258054Semaste    else if (open_options & eOpenOptionCanCreate)
843258054Semaste        mode |= O_CREAT;
844258054Semaste
845258054Semaste    return mode;
846258054Semaste}
847