Vault  4.1
vdirectiofilestream.cpp
Go to the documentation of this file.
00001 /*
00002 Copyright c1997-2014 Trygve Isaacson. All rights reserved.
00003 This file is part of the Code Vault version 4.1
00004 http://www.bombaydigital.com/
00005 License: MIT. See LICENSE.md in the Vault top level directory.
00006 */
00007 
00010 #include "vdirectiofilestream.h"
00011 #include "vtypes_internal.h"
00012 
00013 #include "vexception.h"
00014 
00015 VDirectIOFileStream::VDirectIOFileStream()
00016     : VAbstractFileStream()
00017     , mFile(-1)
00018     , mCloseOnDestruct(true)
00019     {
00020 }
00021 
00022 VDirectIOFileStream::VDirectIOFileStream(const VFSNode& node)
00023     : VAbstractFileStream(node)
00024     , mFile(-1)
00025     , mCloseOnDestruct(true)
00026     {
00027 }
00028 
00029 VDirectIOFileStream::VDirectIOFileStream(int fd, bool closeOnDestruct)
00030     : VAbstractFileStream()
00031     , mFile(fd)
00032     , mCloseOnDestruct(closeOnDestruct)
00033     {
00034 }
00035 
00036 VDirectIOFileStream::~VDirectIOFileStream() {
00037     if (mCloseOnDestruct) {
00038         VDirectIOFileStream::close();
00039     }
00040 }
00041 
00042 void VDirectIOFileStream::setFile(int fd, bool closeOnDestruct) {
00043     mFile = fd;
00044     mCloseOnDestruct = closeOnDestruct;
00045 }
00046 
00047 void VDirectIOFileStream::openReadOnly() {
00048     mFile = VFileSystem::open(mNode.getPath(), READ_ONLY_MODE);
00049 
00050     this->_throwIfOpenFailed("VDirectIOFileStream::openReadOnly", mNode.getPath());
00051 }
00052 
00053 void VDirectIOFileStream::openReadWrite() {
00054     /*
00055     The semantics of ::fopen() and ::open() run counter to the normal desire
00056     to open a file r/w and have it created if it doesn't exist. For example,
00057     mode "r" does not create the file. Mode "w" does. So instead, we check for
00058     existence first, and then open it exactly the way we intend.
00059     */
00060 
00061     mFile = VFileSystem::open(mNode.getPath(), mNode.exists() ? READWRITE_MODE : WRITE_CREATE_MODE);
00062 
00063     this->_throwIfOpenFailed("VDirectIOFileStream::openReadWrite", mNode.getPath());
00064 }
00065 
00066 void VDirectIOFileStream::openWrite() {
00067     mFile = VFileSystem::open(mNode.getPath(), WRITE_CREATE_MODE);
00068 
00069     this->_throwIfOpenFailed("VDirectIOFileStream::openWrite", mNode.getPath());
00070 }
00071 
00072 bool VDirectIOFileStream::isOpen() const {
00073     return (mFile != -1);
00074 }
00075 
00076 void VDirectIOFileStream::close() {
00077     if (this->isOpen()) {
00078         (void) VFileSystem::close(mFile);
00079         mFile = -1;
00080     }
00081 }
00082 
00083 Vs64 VDirectIOFileStream::read(Vu8* targetBuffer, Vs64 numBytesToRead) {
00084     /*
00085     Most of the work here is to deal with the fact that we are providing
00086     a SInt64 count in our API, but the underlying OS API may only
00087     allow a size_t count. So we may have to read in a loop until the
00088     requested number of bytes is read or EOF is reached. In the typical
00089     case, of course, we only go through the loop once.
00090     */
00091 
00092     bool    needsSizeConversion = VStream::needSizeConversion(numBytesToRead);
00093     Vs64    numBytesRemaining = numBytesToRead;
00094     Vs64    numBytesRead = 0;
00095     size_t  requestCount;
00096     size_t  actualCount;
00097 
00098     // FIXME: If needsSizeConversion is false, just do a read w/o the excess baggage here.
00099     // Also, we can set it to false if the actual size fits in 31 bits, as in VStream::copyMemory.
00100     do {
00101         if (needsSizeConversion) {
00102             requestCount = static_cast<size_t>(V_MIN((CONST_S64(0x7FFFFFFF)), numBytesRemaining));
00103         } else {
00104             requestCount = static_cast<size_t>(numBytesRemaining);
00105         }
00106 
00107         actualCount = static_cast<size_t>(VFileSystem::read(mFile, targetBuffer + numBytesRead, requestCount));
00108 
00109         numBytesRead += actualCount;
00110         numBytesRemaining -= actualCount;
00111 
00112     } while ((actualCount == requestCount) && (numBytesRemaining > 0));
00113 
00114     return numBytesRead;
00115 }
00116 
00117 Vs64 VDirectIOFileStream::write(const Vu8* buffer, Vs64 numBytesToWrite) {
00118     /*
00119     Most of the work here is to deal with the fact that we are providing
00120     a SInt64 count in our API, but the underlying OS API may only
00121     allow a size_t count. So we may have to write in a loop until the
00122     requested number of bytes is written. In the typical
00123     case, of course, we only go through the loop once.
00124     */
00125 
00126     bool    needsSizeConversion = VStream::needSizeConversion(numBytesToWrite);
00127     Vs64    numBytesRemaining = numBytesToWrite;
00128     Vs64    numBytesWritten = 0;
00129     size_t  requestCount;
00130     size_t  actualCount;
00131 
00132     // FIXME: If needsSizeConversion is false, just do a write w/o the excess baggage here.
00133     // Also, we can set it to false if the actual size fits in 31 bits, as in VStream::copyMemory.
00134     do {
00135         if (needsSizeConversion) {
00136             requestCount = static_cast<size_t>(V_MIN((static_cast<Vs64>(LONG_MAX)), numBytesRemaining));
00137         } else {
00138             requestCount = static_cast<size_t>(numBytesRemaining);
00139         }
00140 
00141         actualCount = static_cast<size_t>(VFileSystem::write(mFile, buffer + numBytesWritten, requestCount));
00142 
00143         numBytesWritten += actualCount;
00144         numBytesRemaining -= actualCount;
00145 
00146     } while ((actualCount == requestCount) && (numBytesRemaining > 0));
00147 
00148     if (numBytesWritten != numBytesToWrite) {
00149         VString    path;
00150         mNode.getPath(path);
00151 
00152         throw VException(VSystemError(), VSTRING_FORMAT("VDirectIOFileStream::write to '%s' only wrote " VSTRING_FORMATTER_S64 " of " VSTRING_FORMATTER_S64 " requested bytes.", path.chars(), numBytesWritten, numBytesToWrite));
00153     }
00154 
00155     return numBytesWritten;
00156 }
00157 
00158 void VDirectIOFileStream::flush() {
00159     // Unbuffered file writes have no flush mechanism since they are not buffered.
00160 }
00161 
00162 bool VDirectIOFileStream::skip(Vs64 numBytesToSkip) {
00163     /*
00164     Most of the work here is to deal with the fact that we are providing
00165     a SInt64 count in our API, but the underlying OS API may only
00166     allow a long count. So we may have to seek in a loop until the
00167     requested offset is seeked. In the typical case, of course, we only go
00168     through the loop once.
00169     */
00170 
00171     bool success;
00172     bool needsSizeConversion = VStream::needSizeConversion(numBytesToSkip);
00173     Vs64 numBytesRemaining = numBytesToSkip;
00174     Vs64 requestCount;
00175 
00176     // FIXME: If needsSizeConversion is false, just do a seek w/o the excess baggage here.
00177     // Also, we can set it to false if the actual size fits in 31 bits, as in VStream::copyMemory.
00178     // FIXME: This calls VDirectIOFileStream::seek below, which is not as savvy as this--should it be?
00179     do {
00180         if (needsSizeConversion) {
00181             requestCount = V_MIN((static_cast<Vs64>(LONG_MAX)), numBytesRemaining);
00182         } else {
00183             requestCount = numBytesRemaining;
00184         }
00185 
00186         success = this->seek(requestCount, SEEK_CUR);
00187 
00188         numBytesRemaining -= requestCount;
00189 
00190     } while (success && (numBytesRemaining > 0));
00191 
00192     return success;
00193 }
00194 
00195 bool VDirectIOFileStream::seek(Vs64 offset, int whence) {
00196     // FIXME: need to deal with Vs64-to-off_t conversion
00197     return (VFileSystem::lseek(mFile, static_cast<off_t>(offset), whence) == 0);
00198 }
00199 
00200 Vs64 VDirectIOFileStream::getIOOffset() const {
00201     return VFileSystem::lseek(mFile, static_cast<off_t>(0), SEEK_CUR);
00202 }
00203 
00204 Vs64 VDirectIOFileStream::available() const {
00205     Vs64 currentOffset = this->getIOOffset();
00206     Vs64 eofOffset;
00207 
00208     // const_cast: WORKAROUND. Save/restore state.
00209     const_cast<VDirectIOFileStream*>(this)->seek(0, SEEK_END);
00210     eofOffset = this->getIOOffset();
00211     const_cast<VDirectIOFileStream*>(this)->seek(currentOffset, SEEK_SET);    // restore original position
00212 
00213     return eofOffset - currentOffset;
00214 }
00215 

Copyright ©1997-2014 Trygve Isaacson. All rights reserved. This documentation was generated with Doxygen.