src/File.cpp
changeset 0 31a43d94cc26
child 2 851de24ecb61
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/File.cpp	Sun Sep 20 15:14:12 2009 -0700
     1.3 @@ -0,0 +1,214 @@
     1.4 +/*
     1.5 + *  File.cpp
     1.6 + *  Ottoman
     1.7 + *
     1.8 + *  Created by Jens Alfke on 8/20/09.
     1.9 + *  Copyright 2009 Jens Alfke. All rights reserved.
    1.10 + *  BSD-Licensed: See the file "LICENSE.txt" for details.
    1.11 + */
    1.12 +
    1.13 +#include "File.h"
    1.14 +#include "MemoryMap.h"
    1.15 +
    1.16 +#include <assert.h>
    1.17 +#include <errno.h>
    1.18 +#include <fcntl.h>
    1.19 +#include <stdio.h>
    1.20 +#include <sys/stat.h>
    1.21 +#include <sys/uio.h>
    1.22 +#include <unistd.h>
    1.23 +
    1.24 +namespace Mooseyard {
    1.25 +    
    1.26 +    File::File (const char *filename, bool writeable, bool create)  throw(Error)
    1.27 +        :_fd(_check( ::open(filename, writeable ?(create ?O_RDWR|O_CREAT :O_RDWR) :O_RDONLY, 0644) )),
    1.28 +         _memoryMap(NULL),
    1.29 +         _locked(0)
    1.30 +    { }
    1.31 +
    1.32 +    File::File (const char *filename, int oflag)  throw(Error)
    1.33 +        :_fd(_check( ::open(filename, oflag, 0644) )),
    1.34 +         _memoryMap(NULL),
    1.35 +         _locked( (oflag | O_EXLOCK) ?1 :0)
    1.36 +    { }
    1.37 +
    1.38 +    File::~File() {
    1.39 +        delete _memoryMap;
    1.40 +        _unlock();
    1.41 +        ::close(_fd);
    1.42 +    }
    1.43 +    
    1.44 +    
    1.45 +    off_t File::length() const  throw(Error) {
    1.46 +        struct stat s;
    1.47 +        _check( ::fstat(_fd,&s) );
    1.48 +        return s.st_size;
    1.49 +    }
    1.50 +     
    1.51 +    void File::setLength (off_t length)  throw(Error) {
    1.52 +        _check( ftruncate(_fd,length) );
    1.53 +    }
    1.54 +
    1.55 +    off_t File::position() const  throw(Error) {
    1.56 +        return _check( lseek(_fd,0,SEEK_CUR) );
    1.57 +    }
    1.58 +    
    1.59 +    void File::setPosition (off_t pos)  throw(Error) {
    1.60 +        _check( lseek(_fd,pos,SEEK_SET) );
    1.61 +    }
    1.62 +    
    1.63 +    off_t File::setPositionToEnd (off_t bytesBefore)  throw(Error) {
    1.64 +        return _check( lseek(_fd,-bytesBefore,SEEK_END) );
    1.65 +    }
    1.66 +    
    1.67 +    void File::read (void *dst, size_t size)  throw(Error) {
    1.68 +        _checkRead( ::read(_fd, dst, size), size );
    1.69 +    }
    1.70 +    
    1.71 +    size_t File::write (const void *src, size_t size)  throw(Error) {
    1.72 +        return _check( ::write(_fd, src, size) );
    1.73 +    }
    1.74 +    
    1.75 +    
    1.76 +    void File::readFrom (off_t where, void *dst, size_t size)  throw(Error) {
    1.77 +        _checkRead( ::pread(_fd, dst, size, where), size );
    1.78 +    }
    1.79 +    
    1.80 +    void File::writeTo (off_t where, const void *src, size_t size)  throw(Error) {
    1.81 +        _check( ::pwrite(_fd, src, size, where) );
    1.82 +    }
    1.83 +    
    1.84 +    size_t File::writeMultiple (Blob blobs[], int count) throw(Error) {
    1.85 +        struct iovec vec[count];
    1.86 +        for (int i=0; i<count; i++) {
    1.87 +            vec[i].iov_base = (void*) blobs[i].bytes;
    1.88 +            vec[i].iov_len = blobs[i].length;
    1.89 +        }
    1.90 +        return _check( ::writev(_fd, vec, count) );
    1.91 +    }
    1.92 +    
    1.93 +    size_t File::writePadding (int alignment) {
    1.94 +        off_t pad = alignment - (position() & (alignment-1));
    1.95 +        if (pad == alignment)
    1.96 +            return 0;
    1.97 +        uint8_t zero[pad];
    1.98 +        memset(zero, 0, pad);
    1.99 +        return write(zero, pad);
   1.100 +    }
   1.101 +    
   1.102 +    
   1.103 +    void File::flush()  throw(Error) {
   1.104 +        _check( ::fsync(_fd) );
   1.105 +    }
   1.106 +    
   1.107 +    void File::flushDisk()  throw(Error) {
   1.108 +        _check( ::fcntl(_fd,F_FULLFSYNC) );
   1.109 +    }
   1.110 +    
   1.111 +    bool File::hasPath (const char *path) const  throw(Error) {
   1.112 +        struct stat myStat, pathStat;
   1.113 +        _check( ::fstat(_fd, &myStat) );
   1.114 +        if ( ::stat(path, &pathStat) != 0 ) {
   1.115 +            if (errno == ENOENT)
   1.116 +                return false;
   1.117 +            _check(errno);
   1.118 +        }
   1.119 +        // Compare my inode number with that of the file at path:
   1.120 +        return myStat.st_ino == pathStat.st_ino;
   1.121 +    }
   1.122 +    
   1.123 +    
   1.124 +    void File::unlink (const char *filename)  throw(Error) {
   1.125 +        _check( ::unlink(filename) );
   1.126 +    }
   1.127 +    
   1.128 +    void File::rename (const char *srcFilename, const char *dstFilename)  throw(Error) {
   1.129 +        _check( ::rename(srcFilename, dstFilename) );
   1.130 +    }
   1.131 +
   1.132 +    
   1.133 +#pragma mark -
   1.134 +#pragma mark UTILITIES:
   1.135 +    
   1.136 +    int File::_check (int result)  throw(Error) {
   1.137 +        if (result >= 0)
   1.138 +            return result;
   1.139 +        //printf("*** File::_check: Error %i: %s\n", errno, strerror(errno));
   1.140 +        throw Error(errno, strerror(errno));
   1.141 +    }
   1.142 +    
   1.143 +    void File::_checkRead (ssize_t result, size_t expectedSize)  throw(Error) {
   1.144 +        if ((size_t)result < expectedSize) {
   1.145 +            if (result < 0)
   1.146 +                throw Error(errno, strerror(errno));
   1.147 +            else
   1.148 +                throw Error(kEOF, "unexpected EOF");
   1.149 +        }
   1.150 +    }
   1.151 +    
   1.152 +    File::Error::Error(const char *m)
   1.153 +        :code(ERANGE), 
   1.154 +         message(m) 
   1.155 +    { }
   1.156 +    
   1.157 +    
   1.158 +#pragma mark -
   1.159 +#pragma mark LOCKS:
   1.160 +    
   1.161 +    bool File::_lock (bool block) {
   1.162 +        if (_locked) {
   1.163 +            _locked++;
   1.164 +        } else {
   1.165 +            int mode = LOCK_EX;
   1.166 +            if (block)
   1.167 +                mode |= LOCK_NB;
   1.168 +            if (::flock(_fd, mode) == 0)
   1.169 +                _locked = 1;
   1.170 +            else if (errno != EWOULDBLOCK)          // may be returned in LOCK_UN mode
   1.171 +                _check(-1);
   1.172 +        }
   1.173 +        return _locked > 0;
   1.174 +    }
   1.175 +    
   1.176 +    void File::_unlock() {
   1.177 +        if (_locked > 0) {
   1.178 +            _locked--;
   1.179 +            ::flock(_fd, LOCK_UN);
   1.180 +        }
   1.181 +    }
   1.182 +    
   1.183 +    File::Lock::Lock (File *file, bool block)  throw(Error)
   1.184 +        :_file(file),
   1.185 +         _locked( _file->_lock(block) )
   1.186 +    { }
   1.187 +    
   1.188 +    File::Lock::~Lock() {
   1.189 +        if (_locked)
   1.190 +            _file->_unlock();
   1.191 +    }
   1.192 +    
   1.193 +    bool File::Lock::retry() {
   1.194 +        if (!_locked)
   1.195 +            _locked = _file->_lock(false);
   1.196 +        return _locked;
   1.197 +    }
   1.198 +    
   1.199 +    
   1.200 +#pragma mark -
   1.201 +#pragma mark MEMORY MAP:
   1.202 +    
   1.203 +    MemoryMap* File::map() {
   1.204 +        if (!_memoryMap)
   1.205 +            _memoryMap = new MemoryMap(this);
   1.206 +        return _memoryMap;
   1.207 +    }
   1.208 +    
   1.209 +    void File::mapRegion (off_t position, size_t length) {
   1.210 +        return map()->mapRegion(position,length);
   1.211 +    }
   1.212 +    
   1.213 +    const void* File::mappedPosition (off_t position) const {
   1.214 +        return map()->mappedPosition(position);
   1.215 +    }
   1.216 +
   1.217 +}