libzypp
10.5.0
|
00001 /*---------------------------------------------------------------------\ 00002 | ____ _ __ __ ___ | 00003 | |__ / \ / / . \ . \ | 00004 | / / \ V /| _/ _/ | 00005 | / /__ | | | | | | | 00006 | /_____||_| |_| |_| | 00007 | | 00008 \---------------------------------------------------------------------*/ 00009 00010 #include <iostream> 00011 #include <fstream> 00012 00013 #include "zypp/base/LogTools.h" 00014 #include "zypp/base/Regex.h" 00015 #include "zypp/base/UserRequestException.h" 00016 #include "zypp/ZYppCallbacks.h" 00017 #include "zypp/MediaSetAccess.h" 00018 #include "zypp/PathInfo.h" 00019 //#include "zypp/source/MediaSetAccessReportReceivers.h" 00020 00021 using namespace std; 00022 00024 namespace zypp 00025 { 00026 00027 IMPL_PTR_TYPE(MediaSetAccess); 00028 00030 00031 MediaSetAccess::MediaSetAccess(const Url &url, 00032 const Pathname & prefered_attach_point) 00033 : _url(url) 00034 , _prefAttachPoint(prefered_attach_point) 00035 {} 00036 00037 MediaSetAccess::MediaSetAccess(const std::string & label_r, 00038 const Url &url, 00039 const Pathname & prefered_attach_point) 00040 : _url(url) 00041 , _prefAttachPoint(prefered_attach_point) 00042 , _label( label_r ) 00043 {} 00044 00045 MediaSetAccess::~MediaSetAccess() 00046 { 00047 try 00048 { 00049 release(); 00050 } 00051 catch(...) {} // don't let exception escape a dtor. 00052 } 00053 00054 00055 void MediaSetAccess::setVerifier( unsigned media_nr, media::MediaVerifierRef verifier ) 00056 { 00057 if (_medias.find(media_nr) != _medias.end()) 00058 { 00059 // the media already exists, set theverifier 00060 media::MediaAccessId id = _medias[media_nr]; 00061 media::MediaManager media_mgr; 00062 media_mgr.addVerifier( id, verifier ); 00063 // remove any saved verifier for this media 00064 _verifiers.erase(media_nr); 00065 } 00066 else 00067 { 00068 // save the verifier in the map, and set it when 00069 // the media number is first attached 00070 _verifiers[media_nr] = verifier; 00071 } 00072 } 00073 00074 void MediaSetAccess::releaseFile( const OnMediaLocation & on_media_file ) 00075 { 00076 releaseFile( on_media_file.filename(), on_media_file.medianr() ); 00077 } 00078 00079 void MediaSetAccess::releaseFile( const Pathname & file, unsigned media_nr) 00080 { 00081 media::MediaManager media_mgr; 00082 media::MediaAccessId media; 00083 00084 media = getMediaAccessId( media_nr); 00085 DBG << "Going to release file " << file 00086 << " from media number " << media_nr << endl; 00087 00088 if ( ! media_mgr.isAttached(media) ) 00089 return; //disattached media is free 00090 00091 media_mgr.releaseFile (media, file); 00092 } 00093 00094 void MediaSetAccess::dirInfo( filesystem::DirContent &retlist, const Pathname &dirname, 00095 bool dots, unsigned media_nr ) 00096 { 00097 media::MediaManager media_mgr; 00098 media::MediaAccessId media; 00099 media = getMediaAccessId(media_nr); 00100 00101 // try to attach the media 00102 if ( ! media_mgr.isAttached(media) ) 00103 media_mgr.attach(media); 00104 00105 media_mgr.dirInfo(media, retlist, dirname, dots); 00106 } 00107 00108 struct ProvideFileOperation 00109 { 00110 Pathname result; 00111 void operator()( media::MediaAccessId media, const Pathname &file ) 00112 { 00113 media::MediaManager media_mgr; 00114 media_mgr.provideFile(media, file); 00115 result = media_mgr.localPath(media, file); 00116 } 00117 }; 00118 00119 struct ProvideDirTreeOperation 00120 { 00121 Pathname result; 00122 void operator()( media::MediaAccessId media, const Pathname &file ) 00123 { 00124 media::MediaManager media_mgr; 00125 media_mgr.provideDirTree(media, file); 00126 result = media_mgr.localPath(media, file); 00127 } 00128 }; 00129 00130 struct ProvideDirOperation 00131 { 00132 Pathname result; 00133 void operator()( media::MediaAccessId media, const Pathname &file ) 00134 { 00135 media::MediaManager media_mgr; 00136 media_mgr.provideDir(media, file); 00137 result = media_mgr.localPath(media, file); 00138 } 00139 }; 00140 00141 struct ProvideFileExistenceOperation 00142 { 00143 bool result; 00144 ProvideFileExistenceOperation() 00145 : result(false) 00146 {} 00147 00148 void operator()( media::MediaAccessId media, const Pathname &file ) 00149 { 00150 media::MediaManager media_mgr; 00151 result = media_mgr.doesFileExist(media, file); 00152 } 00153 }; 00154 00155 00156 00157 Pathname MediaSetAccess::provideFile( const OnMediaLocation & resource, ProvideFileOptions options, const Pathname &deltafile ) 00158 { 00159 ProvideFileOperation op; 00160 provide( boost::ref(op), resource, options, deltafile ); 00161 return op.result; 00162 } 00163 00164 Pathname MediaSetAccess::provideFile(const Pathname & file, unsigned media_nr, ProvideFileOptions options ) 00165 { 00166 OnMediaLocation resource; 00167 ProvideFileOperation op; 00168 resource.setLocation(file, media_nr); 00169 provide( boost::ref(op), resource, options, Pathname() ); 00170 return op.result; 00171 } 00172 00173 bool MediaSetAccess::doesFileExist(const Pathname & file, unsigned media_nr ) 00174 { 00175 ProvideFileExistenceOperation op; 00176 OnMediaLocation resource; 00177 resource.setLocation(file, media_nr); 00178 provide( boost::ref(op), resource, PROVIDE_DEFAULT, Pathname()); 00179 return op.result; 00180 } 00181 00182 void MediaSetAccess::provide( ProvideOperation op, 00183 const OnMediaLocation &resource, 00184 ProvideFileOptions options, 00185 const Pathname &deltafile ) 00186 { 00187 Pathname file(resource.filename()); 00188 unsigned media_nr(resource.medianr()); 00189 00190 callback::SendReport<media::MediaChangeReport> report; 00191 media::MediaManager media_mgr; 00192 00193 media::MediaAccessId media; 00194 00195 do 00196 { 00197 // get the mediaId, but don't try to attach it here 00198 media = getMediaAccessId( media_nr); 00199 bool deltafileset = false; 00200 00201 try 00202 { 00203 DBG << "Going to try to provide " << (resource.optional() ? "optional" : "") << " file " << file 00204 << " from media number " << media_nr << endl; 00205 // try to attach the media 00206 if ( ! media_mgr.isAttached(media) ) 00207 media_mgr.attach(media); 00208 media_mgr.setDeltafile(media, deltafile); 00209 deltafileset = true; 00210 op(media, file); 00211 media_mgr.setDeltafile(media, Pathname()); 00212 break; 00213 } 00214 catch ( media::MediaException & excp ) 00215 { 00216 ZYPP_CAUGHT(excp); 00217 if (deltafileset) 00218 media_mgr.setDeltafile(media, Pathname()); 00219 media::MediaChangeReport::Action user = media::MediaChangeReport::ABORT; 00220 unsigned int devindex = 0; 00221 vector<string> devices; 00222 media_mgr.getDetectedDevices(media, devices, devindex); 00223 00224 do 00225 { 00226 if (user != media::MediaChangeReport::EJECT) // no use in calling this again 00227 { 00228 DBG << "Media couldn't provide file " << file << " , releasing." << endl; 00229 try 00230 { 00231 media_mgr.release(media); 00232 } 00233 catch (const Exception & excpt_r) 00234 { 00235 ZYPP_CAUGHT(excpt_r); 00236 MIL << "Failed to release media " << media << endl; 00237 } 00238 } 00239 00240 // set up the reason 00241 media::MediaChangeReport::Error reason = media::MediaChangeReport::INVALID; 00242 00243 if( typeid(excp) == typeid( media::MediaFileNotFoundException ) || 00244 typeid(excp) == typeid( media::MediaNotAFileException ) ) 00245 { 00246 reason = media::MediaChangeReport::NOT_FOUND; 00247 } 00248 else if( typeid(excp) == typeid( media::MediaNotDesiredException) || 00249 typeid(excp) == typeid( media::MediaNotAttachedException) ) 00250 { 00251 reason = media::MediaChangeReport::WRONG; 00252 } 00253 else if( typeid(excp) == typeid( media::MediaTimeoutException) || 00254 typeid(excp) == typeid( media::MediaTemporaryProblemException)) 00255 { 00256 reason = media::MediaChangeReport::IO_SOFT; 00257 } 00258 00259 // non interactive only bother the user if wrong medium is in the drive 00260 // otherwise propagate the error 00261 if ( ( options & PROVIDE_NON_INTERACTIVE ) && reason != media::MediaChangeReport::WRONG) 00262 { 00263 MIL << "Can't provide file. Non-Interactive mode." << endl; 00264 ZYPP_RETHROW(excp); 00265 } 00266 else 00267 { 00268 // release all media before requesting another (#336881) 00269 media_mgr.releaseAll(); 00270 00271 user = report->requestMedia ( 00272 _url, 00273 media_nr, 00274 _label, 00275 reason, 00276 excp.asUserString(), 00277 devices, 00278 devindex 00279 ); 00280 } 00281 00282 MIL << "ProvideFile exception caught, callback answer: " << user << endl; 00283 00284 if( user == media::MediaChangeReport::ABORT ) 00285 { 00286 DBG << "Aborting" << endl; 00287 ZYPP_RETHROW ( excp ); 00288 } 00289 else if ( user == media::MediaChangeReport::IGNORE ) 00290 { 00291 DBG << "Skipping" << endl; 00292 SkipRequestException nexcp("User-requested skipping of a file"); 00293 nexcp.remember(excp); 00294 ZYPP_THROW(nexcp); 00295 } 00296 else if ( user == media::MediaChangeReport::EJECT ) 00297 { 00298 DBG << "Eject: try to release" << endl; 00299 media_mgr.releaseAll(); 00300 // eject 00301 media_mgr.release (media, 00302 devindex < devices.size() ? devices[devindex] : ""); 00303 } 00304 else if ( user == media::MediaChangeReport::RETRY || 00305 user == media::MediaChangeReport::CHANGE_URL ) 00306 { 00307 // retry 00308 DBG << "Going to try again" << endl; 00309 // invalidate current media access id 00310 media_mgr.close(media); 00311 _medias.erase(media_nr); 00312 00313 // not attaching, media set will do that for us 00314 // this could generate uncaught exception (#158620) 00315 break; 00316 } 00317 else 00318 { 00319 DBG << "Don't know, let's ABORT" << endl; 00320 ZYPP_RETHROW ( excp ); 00321 } 00322 } while( user == media::MediaChangeReport::EJECT ); 00323 } 00324 00325 // retry or change URL 00326 } while( true ); 00327 } 00328 00329 Pathname MediaSetAccess::provideDir(const Pathname & dir, 00330 bool recursive, 00331 unsigned media_nr, 00332 ProvideFileOptions options ) 00333 { 00334 OnMediaLocation resource; 00335 resource.setLocation(dir, media_nr); 00336 if ( recursive ) 00337 { 00338 ProvideDirTreeOperation op; 00339 provide( boost::ref(op), resource, options, Pathname()); 00340 return op.result; 00341 } 00342 ProvideDirOperation op; 00343 provide( boost::ref(op), resource, options, Pathname()); 00344 return op.result; 00345 } 00346 00347 media::MediaAccessId MediaSetAccess::getMediaAccessId (media::MediaNr medianr) 00348 { 00349 media::MediaManager media_mgr; 00350 00351 if (_medias.find(medianr) != _medias.end()) 00352 { 00353 media::MediaAccessId id = _medias[medianr]; 00354 return id; 00355 } 00356 Url url; 00357 url = rewriteUrl (_url, medianr); 00358 media::MediaAccessId id = media_mgr.open(url, _prefAttachPoint); 00359 _medias[medianr] = id; 00360 00361 try 00362 { 00363 if (_verifiers.find(medianr) != _verifiers.end()) 00364 { 00365 // a verifier is set for this media 00366 // FIXME check the case where the verifier exists 00367 // but we have no access id for the media 00368 media::MediaAccessId id = _medias[medianr]; 00369 media::MediaManager media_mgr; 00370 media_mgr.delVerifier(id); 00371 media_mgr.addVerifier( id, _verifiers[medianr] ); 00372 // remove any saved verifier for this media 00373 _verifiers.erase(medianr); 00374 } 00375 } 00376 catch ( const Exception &e ) 00377 { 00378 ZYPP_CAUGHT(e); 00379 WAR << "Verifier not found" << endl; 00380 } 00381 00382 return id; 00383 } 00384 00385 00386 Url MediaSetAccess::rewriteUrl (const Url & url_r, const media::MediaNr medianr) 00387 { 00388 std::string scheme = url_r.getScheme(); 00389 if (scheme == "cd" || scheme == "dvd") 00390 return url_r; 00391 00392 DBG << "Rewriting url " << url_r << endl; 00393 00394 if( scheme == "iso") 00395 { 00396 // TODO the iso parameter will not be required in the future, this 00397 // code has to be adapted together with the MediaISO change. 00398 // maybe some MediaISOURL interface should be used. 00399 std::string isofile = url_r.getQueryParam("iso"); 00400 str::regex e("^(.*)(cd|dvd|media)[0-9]+\\.iso$", str::regex::icase); 00401 00402 str::smatch what; 00403 if(str::regex_match(isofile, what, e)) 00404 { 00405 Url url( url_r); 00406 isofile = what[1] + what[2] + str::numstring(medianr) + ".iso"; 00407 url.setQueryParam("iso", isofile); 00408 DBG << "Url rewrite result: " << url << endl; 00409 return url; 00410 } 00411 } 00412 else 00413 { 00414 std::string pathname = url_r.getPathName(); 00415 str::regex e("^(.*)(cd|dvd|media)[0-9]+(/)?$", str::regex::icase); 00416 str::smatch what; 00417 if(str::regex_match(pathname, what, e)) 00418 { 00419 Url url( url_r); 00420 pathname = what[1] + what[2] + str::numstring(medianr) + what[3]; 00421 url.setPathName(pathname); 00422 DBG << "Url rewrite result: " << url << endl; 00423 return url; 00424 } 00425 } 00426 return url_r; 00427 } 00428 00429 void MediaSetAccess::release() 00430 { 00431 DBG << "Releasing all media IDs held by this MediaSetAccess" << endl; 00432 media::MediaManager manager; 00433 for (MediaMap::const_iterator m = _medias.begin(); m != _medias.end(); ++m) 00434 manager.release(m->second, ""); 00435 } 00436 00437 std::ostream & MediaSetAccess::dumpOn( std::ostream & str ) const 00438 { 00439 str << "MediaSetAccess (URL='" << _url << "', attach_point_hint='" << _prefAttachPoint << "')"; 00440 return str; 00441 } 00442 00444 } // namespace zypp