IBR-DTNSuite
0.8
|
00001 /* 00002 * BLOB.cpp 00003 * 00004 * Created on: 15.12.2009 00005 * Author: morgenro 00006 */ 00007 00008 #include "ibrcommon/data/BLOB.h" 00009 #include "ibrcommon/thread/MutexLock.h" 00010 #include "ibrcommon/Exceptions.h" 00011 #include "ibrcommon/Logger.h" 00012 #include <stdio.h> 00013 #include <stdlib.h> 00014 #include <string.h> 00015 #include <cstring> 00016 #include <cerrno> 00017 00018 #ifdef __DEVELOPMENT_ASSERTIONS__ 00019 #include <cassert> 00020 #endif 00021 00022 namespace ibrcommon 00023 { 00024 // maximum of concurrent opened files 00025 ibrcommon::Semaphore BLOB::_filelimit(10); 00026 00027 // default BLOB provider - memory based; auto deletion enabled 00028 ibrcommon::BLOB::ProviderRef BLOB::provider(new ibrcommon::MemoryBLOBProvider(), true); 00029 00030 BLOB::BLOB() 00031 { } 00032 00033 BLOB::~BLOB() 00034 { 00035 } 00036 00037 std::ostream& BLOB::copy(std::ostream &output, std::istream &input, const size_t size, const size_t buffer_size) 00038 { 00039 // read payload 00040 char buffer[buffer_size]; 00041 size_t remain = size; 00042 00043 while (remain > 0) 00044 { 00045 // something bad happened, abort! 00046 if (input.bad()) 00047 { 00048 std::stringstream errmsg; errmsg << "input stream went bad [" << std::strerror(errno) << "]; " << (size-remain) << " of " << size << " bytes copied"; 00049 throw ibrcommon::IOException(errmsg.str()); 00050 } 00051 00052 // reached EOF too early 00053 if (input.eof()) 00054 { 00055 std::stringstream errmsg; errmsg << "input stream reached EOF [" << std::strerror(errno) << "]; " << (size-remain) << " of " << size << " bytes copied"; 00056 throw ibrcommon::IOException(errmsg.str()); 00057 } 00058 00059 // check if the destination stream is ok 00060 if (output.bad()) 00061 { 00062 std::stringstream errmsg; errmsg << "output stream went bad [" << std::strerror(errno) << "]; " << (size-remain) << " of " << size << " bytes copied"; 00063 throw ibrcommon::IOException(errmsg.str()); 00064 } 00065 00066 // retry if the read failed 00067 if (input.fail()) 00068 { 00069 IBRCOMMON_LOGGER(warning) << "input stream failed [" << std::strerror(errno) << "]; " << (size-remain) << " of " << size << " bytes copied" << IBRCOMMON_LOGGER_ENDL; 00070 input.clear(); 00071 } 00072 00073 // if the last write failed, then retry 00074 if (output.fail()) 00075 { 00076 IBRCOMMON_LOGGER(warning) << "output stream failed [" << std::strerror(errno) << "]; " << (size-remain) << " of " << size << " bytes copied" << IBRCOMMON_LOGGER_ENDL; 00077 output.clear(); 00078 } 00079 else 00080 { 00081 // read the full buffer size of less? 00082 if (remain > buffer_size) 00083 { 00084 input.read(buffer, buffer_size); 00085 } 00086 else 00087 { 00088 input.read(buffer, remain); 00089 } 00090 00091 // retry if the read failed 00092 if (input.fail()) continue; 00093 } 00094 00095 // write the bytes to the BLOB 00096 output.write(buffer, input.gcount()); 00097 00098 // shrink the remaining bytes by the red bytes 00099 remain -= input.gcount(); 00100 } 00101 00102 return output; 00103 } 00104 00105 ibrcommon::BLOB::Reference BLOB::create() 00106 { 00107 return ibrcommon::BLOB::provider.create(); 00108 } 00109 00110 ibrcommon::BLOB::Reference BLOB::open(const ibrcommon::File &f) 00111 { 00112 return ibrcommon::BLOB::Reference(new ibrcommon::FileBLOB(f)); 00113 } 00114 00115 void BLOB::changeProvider(BLOB::Provider *p, bool auto_delete) 00116 { 00117 ibrcommon::BLOB::provider.change(p, auto_delete); 00118 } 00119 00120 BLOB::Provider::~Provider() 00121 { }; 00122 00123 BLOB::ProviderRef::ProviderRef(Provider *provider, bool auto_delete) 00124 : _provider(provider), _auto_delete(auto_delete) 00125 { 00126 } 00127 00128 BLOB::ProviderRef::~ProviderRef() 00129 { 00130 if (_auto_delete) 00131 { 00132 delete _provider; 00133 } 00134 } 00135 00136 void BLOB::ProviderRef::change(BLOB::Provider *p, bool auto_delete) 00137 { 00138 if (_auto_delete) 00139 { 00140 delete _provider; 00141 } 00142 00143 _provider = p; 00144 _auto_delete = auto_delete; 00145 } 00146 00147 BLOB::Reference BLOB::ProviderRef::create() 00148 { 00149 return _provider->create(); 00150 } 00151 00152 MemoryBLOBProvider::MemoryBLOBProvider() 00153 { 00154 } 00155 00156 MemoryBLOBProvider::~MemoryBLOBProvider() 00157 { 00158 } 00159 00160 ibrcommon::BLOB::Reference MemoryBLOBProvider::create() 00161 { 00162 return StringBLOB::create(); 00163 } 00164 00165 FileBLOBProvider::FileBLOBProvider(const File &path) 00166 : _tmppath(path) 00167 { 00168 } 00169 00170 FileBLOBProvider::~FileBLOBProvider() 00171 { 00172 } 00173 00174 ibrcommon::BLOB::Reference FileBLOBProvider::create() 00175 { 00176 return ibrcommon::BLOB::Reference(new TmpFileBLOB(_tmppath)); 00177 } 00178 00179 BLOB::Reference::Reference(const Reference &ref) 00180 : _blob(ref._blob) 00181 { 00182 } 00183 00184 BLOB::Reference::~Reference() 00185 { 00186 } 00187 00188 BLOB::iostream BLOB::Reference::iostream() 00189 { 00190 return BLOB::iostream(*_blob); 00191 } 00192 00193 BLOB::Reference::Reference(BLOB *blob) 00194 : _blob(blob) 00195 { 00196 } 00197 00198 const BLOB& BLOB::Reference::operator*() const 00199 { 00200 return *_blob; 00201 } 00202 00203 BLOB::Reference MemoryBLOBProvider::StringBLOB::create() 00204 { 00205 BLOB::Reference ref(new MemoryBLOBProvider::StringBLOB()); 00206 return ref; 00207 } 00208 00209 void MemoryBLOBProvider::StringBLOB::clear() 00210 { 00211 _stringstream.str(""); 00212 } 00213 00214 MemoryBLOBProvider::StringBLOB::StringBLOB() 00215 : BLOB(), _stringstream() 00216 { 00217 00218 } 00219 00220 MemoryBLOBProvider::StringBLOB::~StringBLOB() 00221 { 00222 } 00223 00224 void MemoryBLOBProvider::StringBLOB::open() 00225 { 00226 // set pointer to the beginning of the stream and remove any error flags 00227 _stringstream.clear(); 00228 _stringstream.seekp(0); 00229 _stringstream.seekg(0); 00230 } 00231 00232 void MemoryBLOBProvider::StringBLOB::close() 00233 { 00234 } 00235 00236 size_t MemoryBLOBProvider::StringBLOB::__get_size() 00237 { 00238 // store current position 00239 size_t pos = _stringstream.tellg(); 00240 00241 _stringstream.seekg(0, std::ios_base::end); 00242 size_t size = _stringstream.tellg(); 00243 _stringstream.seekg(pos); 00244 00245 return size; 00246 } 00247 00248 void FileBLOB::clear() 00249 { 00250 throw ibrcommon::IOException("clear is not possible on a read only file"); 00251 } 00252 00253 FileBLOB::FileBLOB(const File &f) 00254 : ibrcommon::BLOB(), _filestream(), _file(f) 00255 { 00256 if (!f.exists()) 00257 { 00258 throw ibrcommon::FileNotExistsException(f); 00259 } 00260 } 00261 00262 FileBLOB::~FileBLOB() 00263 { 00264 } 00265 00266 void FileBLOB::open() 00267 { 00268 BLOB::_filelimit.wait(); 00269 00270 // open the file 00271 _filestream.open(_file.getPath().c_str(), ios::in|ios::binary); 00272 00273 if (!_filestream.is_open()) 00274 { 00275 throw ibrcommon::CanNotOpenFileException(_file); 00276 } 00277 } 00278 00279 void FileBLOB::close() 00280 { 00281 // close the file 00282 _filestream.close(); 00283 00284 BLOB::_filelimit.post(); 00285 } 00286 00287 size_t FileBLOB::__get_size() 00288 { 00289 return _file.size(); 00290 } 00291 00292 void FileBLOBProvider::TmpFileBLOB::clear() 00293 { 00294 // close the file 00295 _filestream.close(); 00296 00297 // open temporary file 00298 _filestream.open(_tmpfile.getPath().c_str(), ios::in | ios::out | ios::trunc | ios::binary ); 00299 00300 if (!_filestream.is_open()) 00301 { 00302 IBRCOMMON_LOGGER(error) << "can not open temporary file " << _tmpfile.getPath() << IBRCOMMON_LOGGER_ENDL; 00303 throw ibrcommon::CanNotOpenFileException(_tmpfile); 00304 } 00305 } 00306 00307 FileBLOBProvider::TmpFileBLOB::TmpFileBLOB(const File &tmppath) 00308 : BLOB(), _filestream() 00309 { 00310 // check if path is a directory 00311 if (!tmppath.isDirectory()) 00312 { 00313 throw ibrcommon::IOException("BLOB::tmppath not initialized or path is not a directory."); 00314 } 00315 00316 _tmpfile = ibrcommon::TemporaryFile(tmppath, "blob"); 00317 _tmpfile.update(); 00318 } 00319 00320 FileBLOBProvider::TmpFileBLOB::~TmpFileBLOB() 00321 { 00322 // delete the file if the last reference is destroyed 00323 _tmpfile.remove(); 00324 } 00325 00326 void FileBLOBProvider::TmpFileBLOB::open() 00327 { 00328 BLOB::_filelimit.wait(); 00329 00330 // open temporary file 00331 _filestream.open(_tmpfile.getPath().c_str(), ios::in | ios::out | ios::binary ); 00332 00333 if (!_filestream.is_open()) 00334 { 00335 IBRCOMMON_LOGGER(error) << "can not open temporary file " << _tmpfile.getPath() << IBRCOMMON_LOGGER_ENDL; 00336 throw ibrcommon::CanNotOpenFileException(_tmpfile); 00337 } 00338 } 00339 00340 void FileBLOBProvider::TmpFileBLOB::close() 00341 { 00342 // flush the filestream 00343 _filestream.flush(); 00344 00345 // close the file 00346 _filestream.close(); 00347 00348 BLOB::_filelimit.post(); 00349 } 00350 00351 size_t FileBLOBProvider::TmpFileBLOB::__get_size() 00352 { 00353 return _tmpfile.size(); 00354 } 00355 }