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 +}