ISIS Core Library 0.7.2 (api 3.0.0)

/scr/tee1/isis/lib/Core/DataStorage/fileptr.cpp

Go to the documentation of this file.
00001 //
00002 //  fileptr.cpp
00003 //  isis
00004 //
00005 //  Created by Enrico Reimer on 08.08.11.
00006 //  Copyright 2011 __MyCompanyName__. All rights reserved.
00007 //
00008 
00009 #include "fileptr.hpp"
00010 
00011 #ifdef WIN32
00012 #else
00013 #include <sys/mman.h>
00014 #endif
00015 
00016 #include <iostream>
00017 #include <fcntl.h>
00018 #include <unistd.h>
00019 #include <boost/mpl/for_each.hpp>
00020 #include "../CoreUtils/singletons.hpp"
00021 
00022 // we need that, because boost::mpl::for_each will instantiate all types - and this needs the output stream operations
00023 #include <boost/date_time/gregorian/gregorian.hpp>
00024 #include <boost/date_time/posix_time/posix_time.hpp>
00025 #include <utime.h>
00026 
00027 namespace isis
00028 {
00029 namespace data
00030 {
00031 
00032 void FilePtr::Closer::operator()( void *p )
00033 {
00034     LOG( Debug, info ) << "Unmapping and closing " << util::MSubject( filename.file_string() ) << " it was mapped at " << p;
00035 
00036     bool unmapped = false;
00037 #ifdef WIN32
00038     unmapped = UnmapViewOfFile( p );
00039 #else
00040     unmapped = !munmap( p, len );
00041 #endif
00042     LOG_IF( !unmapped, Runtime, warning )
00043             << "Unmapping of " << util::MSubject( filename.file_string() )
00044             << " failed, the error was: " << util::MSubject( util::getLastSystemError() );
00045 
00046 #ifdef __APPLE__
00047 
00048     if( write && futimes( file, NULL ) != 0 ) {
00049         LOG( Runtime, warning )
00050                 << "Setting access time of " << util::MSubject( filename.file_string() )
00051                 << " failed, the error was: " << util::MSubject( strerror( errno ) );
00052     }
00053 
00054 #elif WIN32
00055 
00056     if( write ) {
00057         FILETIME ft;
00058         SYSTEMTIME st;
00059 
00060         GetSystemTime( &st );
00061         bool ok = SystemTimeToFileTime( &st, &ft ) && SetFileTime( file, NULL, ( LPFILETIME ) NULL, &ft );
00062         LOG_IF( !ok, Runtime, warning )
00063                 << "Setting access time of " << util::MSubject( filename.file_string() )
00064                 << " failed, the error was: " << util::MSubject( util::getLastSystemError() );
00065     }
00066 
00067 #endif
00068 
00069 #ifdef WIN32
00070 
00071     if( !( CloseHandle( mmaph ) && CloseHandle( file ) ) ) {
00072 #else
00073 
00074     if( ::close( file ) != 0 ) {
00075 #endif
00076         LOG( Runtime, warning )
00077                 << "Closing of " << util::MSubject( filename.file_string() )
00078                 << " failed, the error was: " << util::MSubject( strerror( errno ) );
00079     }
00080 }
00081 
00082 FilePtr::GeneratorMap::GeneratorMap()
00083 {
00084     boost::mpl::for_each<util::_internal::types>( proc( this ) );
00085     assert( !empty() );
00086 }
00087 
00088 
00089 bool FilePtr::map( FILE_HANDLE file, size_t len, bool write, const boost::filesystem::path &filename )
00090 {
00091     void *ptr = NULL;
00092     FILE_HANDLE mmaph = 0;
00093 #ifdef WIN32 //mmap is broken on windows - workaround stolen from http://crupp.de/2007/11/14/howto-port-unix-mmap-to-win32/
00094     mmaph = CreateFileMapping( file, 0, write ? PAGE_READWRITE : PAGE_WRITECOPY, 0, 0, NULL );
00095 
00096     if( mmaph ) {
00097         ptr = MapViewOfFile( mmaph, write ? FILE_MAP_WRITE : FILE_MAP_COPY, 0, 0, 0 );
00098     }
00099 
00100 #else
00101     ptr = mmap( 0, len, PROT_WRITE | PROT_READ, write ? MAP_SHARED : MAP_PRIVATE , file, 0 ); // yes we say PROT_WRITE here also if the file is opened ro - its for the mapping, not for the file
00102 #endif
00103 
00104     if( ptr == NULL ) {
00105         LOG( Debug, error ) << "Failed to map " << util::MSubject( filename.file_string() ) << ", error was " << util::getLastSystemError();
00106         return false;
00107     } else {
00108         const Closer cl = {file, mmaph, len, filename, write};
00109         writing = write;
00110         static_cast<ValueArray<uint8_t>&>( *this ) = ValueArray<uint8_t>( static_cast<uint8_t * const>( ptr ), len, cl );
00111         return true;
00112     }
00113 }
00114 
00115 size_t FilePtr::checkSize( bool write, FILE_HANDLE file, const boost::filesystem::path &filename, size_t size )
00116 {
00117     const boost::uintmax_t currSize = boost::filesystem::file_size( filename );
00118 
00119     if( write ) { // if we're writing
00120         assert( size > 0 );
00121 
00122         if( size > currSize ) { // and the file is shorter than requested, resize it
00123 #ifdef WIN32
00124             DWORD dwPtr = SetFilePointer( file, size, NULL, FILE_BEGIN );
00125 
00126             if ( dwPtr != INVALID_SET_FILE_POINTER ) {
00127                 if( SetEndOfFile( file ) /*&& SetFileValidData(file, size)*/ ) {
00128                     return GetFileSize( file, NULL );
00129                 }
00130             }
00131 
00132             LOG( Runtime, error )
00133                     << "Failed to resize " << util::MSubject( filename.file_string() )
00134                     << " to the requested size " << size << ", the error was: " << util::MSubject( util::getLastSystemError() );
00135             return 0; // fail
00136 #else
00137             const int err = ftruncate( file, size ) ? errno : 0;
00138 
00139             if( err ) { // could not resize the file => fail
00140                 LOG( Runtime, error )
00141                         << "Failed to resize " << util::MSubject( filename.file_string() )
00142                         << " to the requested size " << size << ", the error was: " << util::MSubject( strerror( err ) );
00143                 return 0; // fail
00144             } else
00145                 return size; // ok now the file has the right size
00146 
00147 #endif
00148         } else
00149             return size; // no resizing needed
00150     } else { // if we're reading
00151         if( size == 0 ) {
00152             if ( std::numeric_limits<size_t>::max() < currSize ) {
00153                 LOG( Runtime, error ) << "Sorry cannot map files larger than " << std::numeric_limits<size_t>::max()
00154                                       << " bytes on this platform";
00155                 return 0;
00156             } else
00157                 return currSize; // automatically select size of the file
00158         } else if( size <= currSize )
00159             return size; // keep the requested size (will fit into the file)
00160         else { // size will not fit into the file (and we cannot resize) => fail
00161             LOG( Runtime, error ) << "The requested size for readonly mapping of " << util::MSubject( filename.file_string() )
00162                                   << " is greater than the filesize (" << currSize << ").";
00163             return 0; // fail
00164         }
00165     }
00166 }
00167 
00168 FilePtr::FilePtr(): m_good( false ) {}
00169 
00170 
00171 FilePtr::FilePtr( const boost::filesystem::path &filename, size_t len, bool write ): m_good( false )
00172 {
00173 #ifdef WIN32
00174     const FILE_HANDLE invalid = INVALID_HANDLE_VALUE;
00175     const int oflag = write ?
00176                       GENERIC_READ | GENERIC_WRITE :
00177                       GENERIC_READ; //open file readonly
00178     const FILE_HANDLE file =
00179         CreateFile( filename.file_string().c_str(), oflag, write ? 0 : FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
00180 #else
00181     const FILE_HANDLE invalid = -1;
00182     const int oflag = write ?
00183                       O_CREAT | O_RDWR : //create file if its not there
00184                       O_RDONLY; //open file readonly
00185     const FILE_HANDLE file =
00186         open( filename.file_string().c_str(), oflag, 0666 );
00187 #endif
00188 
00189     if( file == invalid ) {
00190         LOG( Runtime, error ) << "Failed to open " << util::MSubject( filename.file_string() )
00191                               << ", the error was: " << util::getLastSystemError();
00192         return;
00193     }
00194 
00195     const size_t map_size = checkSize( write, file, filename, len ); // get the mapping size
00196 
00197     if( map_size ) {
00198         m_good = map( file, map_size, write, filename ); //and do the mapping
00199         LOG( Debug, info ) << "Mapped " << map_size << " bytes of " << util::MSubject( filename.file_string() ) << " at " << getRawAddress().get();
00200     }
00201 
00202     // from here on the pointer will be set if mapping succeded
00203 }
00204 
00205 bool FilePtr::good() {return m_good;}
00206 
00207 void FilePtr::release()
00208 {
00209     static_cast<boost::shared_ptr<uint8_t>&>( *this ).reset();
00210     m_good = false;
00211 }
00212 
00213 ValueArrayReference FilePtr::atByID( short unsigned int ID, size_t offset, size_t len, bool swap_endianess )
00214 {
00215     LOG_IF( static_cast<boost::shared_ptr<uint8_t>&>( *this ).get() == 0, Debug, error )
00216             << "There is no mapped data for this FilePtr - I'm very likely gonna crash soon ..";
00217     GeneratorMap &map = util::Singletons::get<GeneratorMap, 0>();
00218     assert( !map.empty() );
00219     const generator_type gen = map[ID];
00220     assert( gen );
00221     return gen( *this, offset, len, swap_endianess );
00222 }
00223 
00224 
00225 }
00226 }