src/File.cpp
author Jens Alfke <jens@mooseyard.com>
Sun Sep 20 21:25:47 2009 -0700 (2009-09-20)
changeset 2 851de24ecb61
parent 0 31a43d94cc26
child 8 21a6c17f4e3e
permissions -rw-r--r--
Added library target, changed some build settings, and fixed 64-to-32-bit conversion warnings.
     1 /*
     2  *  File.cpp
     3  *  Ottoman
     4  *
     5  *  Created by Jens Alfke on 8/20/09.
     6  *  Copyright 2009 Jens Alfke. All rights reserved.
     7  *  BSD-Licensed: See the file "LICENSE.txt" for details.
     8  */
     9 
    10 #include "File.h"
    11 #include "MemoryMap.h"
    12 
    13 #include <assert.h>
    14 #include <errno.h>
    15 #include <fcntl.h>
    16 #include <stdio.h>
    17 #include <sys/stat.h>
    18 #include <sys/uio.h>
    19 #include <unistd.h>
    20 
    21 namespace Mooseyard {
    22     
    23     File::File (const char *filename, bool writeable, bool create)  throw(Error)
    24         :_fd(_check( ::open(filename, writeable ?(create ?O_RDWR|O_CREAT :O_RDWR) :O_RDONLY, 0644) )),
    25          _memoryMap(NULL),
    26          _locked(0)
    27     { }
    28 
    29     File::File (const char *filename, int oflag)  throw(Error)
    30         :_fd(_check( ::open(filename, oflag, 0644) )),
    31          _memoryMap(NULL),
    32          _locked( (oflag | O_EXLOCK) ?1 :0)
    33     { }
    34 
    35     File::~File() {
    36         delete _memoryMap;
    37         _unlock();
    38         ::close(_fd);
    39     }
    40     
    41     
    42     off_t File::length() const  throw(Error) {
    43         struct stat s;
    44         _check( ::fstat(_fd,&s) );
    45         return s.st_size;
    46     }
    47      
    48     void File::setLength (off_t length)  throw(Error) {
    49         _check( ftruncate(_fd,length) );
    50     }
    51 
    52     off_t File::position() const  throw(Error) {
    53         return _check( lseek(_fd,0,SEEK_CUR) );
    54     }
    55     
    56     void File::setPosition (off_t pos)  throw(Error) {
    57         _check( lseek(_fd,pos,SEEK_SET) );
    58     }
    59     
    60     off_t File::setPositionToEnd (off_t bytesBefore)  throw(Error) {
    61         return _check( lseek(_fd,-bytesBefore,SEEK_END) );
    62     }
    63     
    64     void File::read (void *dst, size_t size)  throw(Error) {
    65         _checkRead( ::read(_fd, dst, size), size );
    66     }
    67     
    68     size_t File::write (const void *src, size_t size)  throw(Error) {
    69         return _check( ::write(_fd, src, size) );
    70     }
    71     
    72     
    73     void File::readFrom (off_t where, void *dst, size_t size)  throw(Error) {
    74         _checkRead( ::pread(_fd, dst, size, where), size );
    75     }
    76     
    77     void File::writeTo (off_t where, const void *src, size_t size)  throw(Error) {
    78         _check( ::pwrite(_fd, src, size, where) );
    79     }
    80     
    81     size_t File::writeMultiple (Blob blobs[], int count) throw(Error) {
    82         struct iovec vec[count];
    83         for (int i=0; i<count; i++) {
    84             vec[i].iov_base = (void*) blobs[i].bytes;
    85             vec[i].iov_len = blobs[i].length;
    86         }
    87         return _check( ::writev(_fd, vec, count) );
    88     }
    89     
    90     size_t File::writePadding (int alignment) {
    91         int pad = alignment - (int)(position() & (alignment-1));
    92         if (pad == alignment)
    93             return 0;
    94         uint8_t zero[pad];
    95         memset(zero, 0, pad);
    96         return write(zero, pad);
    97     }
    98     
    99     
   100     void File::flush()  throw(Error) {
   101         _check( ::fsync(_fd) );
   102     }
   103     
   104     void File::flushDisk()  throw(Error) {
   105         _check( ::fcntl(_fd,F_FULLFSYNC) );
   106     }
   107     
   108     bool File::hasPath (const char *path) const  throw(Error) {
   109         struct stat myStat, pathStat;
   110         _check( ::fstat(_fd, &myStat) );
   111         if ( ::stat(path, &pathStat) != 0 ) {
   112             if (errno == ENOENT)
   113                 return false;
   114             _check(errno);
   115         }
   116         // Compare my inode number with that of the file at path:
   117         return myStat.st_ino == pathStat.st_ino;
   118     }
   119     
   120     
   121     void File::unlink (const char *filename)  throw(Error) {
   122         _check( ::unlink(filename) );
   123     }
   124     
   125     void File::rename (const char *srcFilename, const char *dstFilename)  throw(Error) {
   126         _check( ::rename(srcFilename, dstFilename) );
   127     }
   128 
   129     
   130 #pragma mark -
   131 #pragma mark UTILITIES:
   132     
   133     int File::_check (int result)  throw(Error) {
   134         if (result >= 0)
   135             return result;
   136         //printf("*** File::_check: Error %i: %s\n", errno, strerror(errno));
   137         throw Error(errno, strerror(errno));
   138     }
   139     
   140     void File::_checkRead (ssize_t result, size_t expectedSize)  throw(Error) {
   141         if ((size_t)result < expectedSize) {
   142             if (result < 0)
   143                 throw Error(errno, strerror(errno));
   144             else
   145                 throw Error(kEOF, "unexpected EOF");
   146         }
   147     }
   148     
   149     File::Error::Error(const char *m)
   150         :code(ERANGE), 
   151          message(m) 
   152     { }
   153     
   154     
   155 #pragma mark -
   156 #pragma mark LOCKS:
   157     
   158     bool File::_lock (bool block) {
   159         if (_locked) {
   160             _locked++;
   161         } else {
   162             int mode = LOCK_EX;
   163             if (block)
   164                 mode |= LOCK_NB;
   165             if (::flock(_fd, mode) == 0)
   166                 _locked = 1;
   167             else if (errno != EWOULDBLOCK)          // may be returned in LOCK_UN mode
   168                 _check(-1);
   169         }
   170         return _locked > 0;
   171     }
   172     
   173     void File::_unlock() {
   174         if (_locked > 0) {
   175             _locked--;
   176             ::flock(_fd, LOCK_UN);
   177         }
   178     }
   179     
   180     File::Lock::Lock (File *file, bool block)  throw(Error)
   181         :_file(file),
   182          _locked( _file->_lock(block) )
   183     { }
   184     
   185     File::Lock::~Lock() {
   186         if (_locked)
   187             _file->_unlock();
   188     }
   189     
   190     bool File::Lock::retry() {
   191         if (!_locked)
   192             _locked = _file->_lock(false);
   193         return _locked;
   194     }
   195     
   196     
   197 #pragma mark -
   198 #pragma mark MEMORY MAP:
   199     
   200     MemoryMap* File::map() {
   201         if (!_memoryMap)
   202             _memoryMap = new MemoryMap(this);
   203         return _memoryMap;
   204     }
   205     
   206     void File::mapRegion (off_t position, size_t length) {
   207         return map()->mapRegion(position,length);
   208     }
   209     
   210     const void* File::mappedPosition (off_t position) const {
   211         return map()->mappedPosition(position);
   212     }
   213 
   214 }