ISIS Core Library 0.7.2 (api 3.0.0)
|
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 }