libzypp
10.5.0
|
00001 /*---------------------------------------------------------------------\ 00002 | | 00003 | __ __ ____ _____ ____ | 00004 | \ \ / /_ _/ ___|_ _|___ \ | 00005 | \ V / _` \___ \ | | __) | | 00006 | | | (_| |___) || | / __/ | 00007 | |_|\__,_|____/ |_| |_____| | 00008 | | 00009 | core system | 00010 | (C) SuSE Linux Products GmbH | 00011 \----------------------------------------------------------------------/ 00012 00013 File: GzStream.cc 00014 00015 Author: Michael Andres <ma@suse.de> 00016 Maintainer: Michael Andres <ma@suse.de> 00017 00018 Purpose: Streams reading and writing gzip files. 00019 00020 /-*/ 00021 00022 #include <cerrno> 00023 #include <iostream> 00024 #include <zypp/base/LogControl.h> 00025 #include <zypp/base/LogTools.h> 00026 using std::endl; 00027 00028 #include "zypp/base/GzStream.h" 00029 00030 #include <sys/types.h> 00031 #include <sys/stat.h> 00032 #include <fcntl.h> 00033 00035 namespace zypp 00036 { 00037 00038 namespace gzstream_detail 00039 { 00040 00041 00043 // 00044 // CLASS NAME : ZlibError 00045 // 00047 00049 // 00050 // METHOD NAME : ZlibError::strerror 00051 // METHOD TYPE : std::string 00052 // 00053 std::string 00054 ZlibError::strerror() const 00055 { 00056 std::string ret = ( _zError ? ::zError( _zError ) : "OK" ); 00057 if ( _zError == Z_ERRNO ) 00058 ret += std::string("(") + ::strerror( _errno ) + ")"; 00059 return ret; 00060 } 00061 00063 // 00064 // CLASS NAME : fgzstreambuf 00065 // 00067 00069 // 00070 // METHOD NAME : fgzstreambuf::open 00071 // METHOD TYPE : fgzstreambuf * 00072 // 00073 fgzstreambuf * 00074 fgzstreambuf::open( const char * name_r, std::ios_base::openmode mode_r ) 00075 { 00076 fgzstreambuf * ret = NULL; 00077 if ( ! isOpen() ) 00078 { 00079 // we expect gzdopen to handle errors of ::open 00080 if ( mode_r == std::ios_base::in ) 00081 { 00082 _fd = ::open( name_r, O_RDONLY | O_CLOEXEC ); 00083 _file = gzdopen( _fd, "rb" ); 00084 } 00085 else if ( mode_r == std::ios_base::out ) 00086 { 00087 _fd = ::open( name_r, O_WRONLY|O_CREAT|O_CLOEXEC, 0666 ); 00088 _file = gzdopen( _fd, "wb" ); 00089 } 00090 // else: not supported 00091 00092 if ( isOpen() ) 00093 { 00094 // Store mode and initialize the internal buffer. 00095 _mode = mode_r; 00096 if ( inReadMode() ) 00097 { 00098 setp( NULL, NULL ); 00099 setg( &(_buffer[0]), &(_buffer[0]), &(_buffer[0]) ); 00100 } 00101 else 00102 { 00103 setp( &(_buffer[0]), &(_buffer[_buffer.size()-1]) ); 00104 setg( NULL, NULL, NULL ); 00105 } 00106 ret = this; 00107 } 00108 else 00109 setZError(); 00110 } 00111 return ret; 00112 } 00113 00115 // 00116 // METHOD NAME : fgzstreambuf::close 00117 // METHOD TYPE : fgzstreambuf * 00118 // 00119 fgzstreambuf * 00120 fgzstreambuf::close() 00121 { 00122 fgzstreambuf * ret = NULL; 00123 if ( isOpen() ) 00124 { 00125 bool failed = false; 00126 if ( sync() != 0 ) 00127 failed = true; 00128 // it also closes _fd, fine 00129 int r = gzclose( _file ); 00130 if ( r != Z_OK ) 00131 { 00132 failed = true; 00133 // DONT call setZError() here, as _file is no longer valid 00134 _error._zError = r; 00135 _error._errno = errno; 00136 } 00137 00138 // Reset everything 00139 _fd = -1; 00140 _file = NULL; 00141 _mode = std::ios_base::openmode(0); 00142 setp( NULL, NULL ); 00143 setg( NULL, NULL, NULL ); 00144 if ( ! failed ) 00145 ret = this; 00146 } 00147 return ret; 00148 } 00149 00151 // 00152 // METHOD NAME : fgzstreambuf::sync 00153 // METHOD TYPE : int 00154 // 00155 int 00156 fgzstreambuf::sync() 00157 { 00158 int ret = 0; 00159 if ( pbase() < pptr() ) { 00160 const int_type res = overflow(); 00161 if ( traits_type::eq_int_type( res, traits_type::eof() ) ) 00162 ret = -1; 00163 } 00164 return ret; 00165 } 00166 00168 // 00169 // METHOD NAME : fgzstreambuf::overflow 00170 // METHOD TYPE : fgzstreambuf::int_type 00171 // 00172 fgzstreambuf::int_type 00173 fgzstreambuf::overflow( int_type c ) 00174 { 00175 int_type ret = traits_type::eof(); 00176 if ( inWriteMode() ) 00177 { 00178 if ( ! traits_type::eq_int_type( c, traits_type::eof() ) ) 00179 { 00180 *pptr() = traits_type::to_char_type( c ); 00181 pbump(1); 00182 } 00183 if ( pbase() <= pptr() ) 00184 { 00185 if ( zWriteFrom( pbase(), pptr() - pbase() ) ) 00186 { 00187 setp( &(_buffer[0]), &(_buffer[_buffer.size()-1]) ); 00188 ret = traits_type::not_eof( c ); 00189 } 00190 // else: error writing the file 00191 } 00192 } 00193 return ret; 00194 } 00195 00197 // 00198 // METHOD NAME : fgzstreambuf::underflow 00199 // METHOD TYPE : fgzstreambuf::int_type 00200 // 00201 fgzstreambuf::int_type 00202 fgzstreambuf::underflow() 00203 { 00204 int_type ret = traits_type::eof(); 00205 if ( inReadMode() ) 00206 { 00207 if ( gptr() < egptr() ) 00208 return traits_type::to_int_type( *gptr() ); 00209 00210 const std::streamsize got = zReadTo( &(_buffer[0]), _buffer.size() ); 00211 if ( got > 0 ) 00212 { 00213 setg( &(_buffer[0]), &(_buffer[0]), &(_buffer[got]) ); 00214 ret = traits_type::to_int_type( *gptr() ); 00215 } 00216 else if ( got == 0 ) 00217 { 00218 // EOF 00219 setg( &(_buffer[0]), &(_buffer[0]), &(_buffer[0]) ); 00220 } 00221 // else: error reading the file 00222 } 00223 return ret; 00224 } 00225 00227 // 00228 // METHOD NAME : fgzstreambuf::zReadTo 00229 // METHOD TYPE : std::streamsize 00230 // 00231 std::streamsize 00232 fgzstreambuf::zReadTo( char * buffer_r, std::streamsize maxcount_r ) 00233 { 00234 int read = gzread( _file, buffer_r, maxcount_r ); 00235 if ( read < 0 ) 00236 setZError(); 00237 return read; 00238 } 00239 00241 // 00242 // METHOD NAME : fgzstreambuf::zWriteFrom 00243 // METHOD TYPE : bool 00244 // 00245 bool 00246 fgzstreambuf::zWriteFrom( const char * buffer_r, std::streamsize count_r ) 00247 { 00248 int written = 0; 00249 if ( count_r ) 00250 { 00251 if ( (written = gzwrite( _file, buffer_r, count_r )) == 0 ) 00252 setZError(); 00253 } 00254 return( written == count_r ); 00255 } 00256 00258 // 00259 // METHOD NAME : fgzstreambuf::zSeekTo 00260 // METHOD TYPE : fgzstreambuf::pos_type 00261 // 00262 fgzstreambuf::pos_type 00263 fgzstreambuf::zSeekTo( off_type off_r, std::ios_base::seekdir way_r ) 00264 { 00265 z_off_t ret = gzseek( _file, off_r, way_r ); 00266 if ( ret == -1 ) 00267 setZError(); 00268 return ret; 00269 } 00270 00272 // 00273 // METHOD NAME : fgzstreambuf::zTell 00274 // METHOD TYPE : fgzstreambuf::pos_type 00275 // 00276 fgzstreambuf::pos_type 00277 fgzstreambuf::zTell() 00278 { 00279 z_off_t ret = gztell( _file ); 00280 if ( ret == -1 ) 00281 setZError(); 00282 return ret; 00283 } 00284 00286 // 00287 // METHOD NAME : fgzstreambuf::seekTo 00288 // METHOD TYPE : fgzstreambuf::pos_type 00289 // 00290 fgzstreambuf::pos_type 00291 fgzstreambuf::seekTo( off_type off_r, std::ios_base::seekdir way_r ) 00292 { 00293 pos_type ret = pos_type(off_type(-1)); 00294 if ( isOpen() ) 00295 { 00296 if ( inWriteMode() ) 00297 { 00298 if ( sync() == 0 ) 00299 ret = zSeekTo( off_r, way_r ); 00300 } 00301 else 00302 { 00303 off_type zegptr = zTell(); 00304 if ( zegptr != off_type(-1) ) 00305 { 00306 if ( way_r == std::ios_base::end ) 00307 { 00308 // Invalidate buffer and seek. 00309 // XXX improve by transformation into ios_base::beg 00310 // to see whether we stay inside the buffer. 00311 setg( &(_buffer[0]), &(_buffer[0]), &(_buffer[0]) ); 00312 ret = zSeekTo( off_r, way_r ); 00313 } 00314 else 00315 { 00316 // Transform into ios_base::beg and seek. 00317 off_type zeback = zegptr - ( egptr() - eback() ); 00318 off_type zgptr = zegptr - ( egptr() - gptr() ); 00319 off_type zngptr = off_r; 00320 if ( way_r == std::ios_base::cur ) 00321 { 00322 zngptr += zgptr; 00323 way_r = std::ios_base::beg; 00324 } 00325 00326 if ( way_r == std::ios_base::beg ) 00327 { 00328 if ( zeback <= zngptr && zngptr <= zegptr ) 00329 { 00330 // Still inside buffer, adjust gptr and 00331 // calculate new position. 00332 setg( eback(), 00333 eback() + (zngptr-zeback), 00334 egptr() ); 00335 ret = pos_type(zngptr); 00336 } 00337 else 00338 { 00339 // Invalidate buffer and seek. 00340 setg( &(_buffer[0]), &(_buffer[0]), &(_buffer[0]) ); 00341 ret = zSeekTo( off_r, way_r ); 00342 } 00343 } 00344 } 00345 } 00346 } 00347 } 00348 return ret; 00349 } 00350 00351 fgzstreambuf::pos_type 00352 fgzstreambuf::compressed_tell() const 00353 { 00354 off_t pos = lseek (_fd, 0, SEEK_CUR); 00355 // hopefully the conversion is ok 00356 return pos; 00357 } 00358 00360 } // namespace gzstream_detail 00363 } // namespace zypp 00365