1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
13 #include "zypp/base/LogTools.h"
14 #include "zypp/base/Regex.h"
15 #include "zypp/base/UserRequestException.h"
16 #include "zypp/ZYppCallbacks.h"
17 #include "zypp/MediaSetAccess.h"
18 #include "zypp/PathInfo.h"
19 //#include "zypp/source/MediaSetAccessReportReceivers.h"
23 ///////////////////////////////////////////////////////////////////
25 { /////////////////////////////////////////////////////////////////
27 IMPL_PTR_TYPE(MediaSetAccess);
29 ///////////////////////////////////////////////////////////////////
31 MediaSetAccess::MediaSetAccess(const Url &url,
32 const Pathname & prefered_attach_point)
34 , _prefAttachPoint(prefered_attach_point)
37 MediaSetAccess::MediaSetAccess(const std::string & label_r,
39 const Pathname & prefered_attach_point)
41 , _prefAttachPoint(prefered_attach_point)
45 MediaSetAccess::~MediaSetAccess()
51 catch(...) {} // don't let exception escape a dtor.
55 void MediaSetAccess::setVerifier( unsigned media_nr, media::MediaVerifierRef verifier )
57 if (_medias.find(media_nr) != _medias.end())
59 // the media already exists, set theverifier
60 media::MediaAccessId id = _medias[media_nr];
61 media::MediaManager media_mgr;
62 media_mgr.addVerifier( id, verifier );
63 // remove any saved verifier for this media
64 _verifiers.erase(media_nr);
65 //if (! noattach && ! media_mgr.isAttached(id))
66 //media_mgr.attach(id);
70 // save the verifier in the map, and set it when
71 // the media number is first attached
72 _verifiers[media_nr] = verifier;
76 // callback::SendReport<source::DownloadFileReport> report;
77 // DownloadProgressFileReceiver download_report( report );
78 // SourceFactory source_factory;
79 // Url file_url( url().asString() + file_r.asString() );
80 // report->start( source_factory.createFrom(this), file_url );
81 // callback::TempConnect<media::DownloadProgressReport> tmp_download( download_report );
82 // Pathname file = provideJustFile( file_r, media_nr, cached, checkonly );
83 // report->finish( file_url, source::DownloadFileReport::NO_ERROR, "" );
86 void MediaSetAccess::releaseFile( const OnMediaLocation & on_media_file )
88 releaseFile( on_media_file.filename(), on_media_file.medianr() );
91 void MediaSetAccess::releaseFile( const Pathname & file, unsigned media_nr)
93 media::MediaManager media_mgr;
94 media::MediaAccessId media;
96 media = getMediaAccessId( media_nr);
97 DBG << "Going to release file " << file
98 << " from media number " << media_nr << endl;
100 if ( ! media_mgr.isAttached(media) )
101 return; //disattached media is free
103 media_mgr.releaseFile (media, file);
106 void MediaSetAccess::dirInfo( filesystem::DirContent &retlist, const Pathname &dirname,
107 bool dots, unsigned media_nr )
109 media::MediaManager media_mgr;
110 media::MediaAccessId media;
111 media = getMediaAccessId(media_nr);
113 // try to attach the media
114 if ( ! media_mgr.isAttached(media) )
115 media_mgr.attachDesiredMedia(media);
117 media_mgr.dirInfo(media, retlist, dirname, dots);
120 Pathname MediaSetAccess::provideFile( const OnMediaLocation & on_media_file )
122 return provideFile( on_media_file.filename(), on_media_file.medianr() );
126 Pathname MediaSetAccess::provideFile(const Pathname & file, unsigned media_nr )
128 return provideFileInternal( file, media_nr, false, false);
131 Pathname MediaSetAccess::provideOptionalFile(const Pathname & file, unsigned media_nr )
133 return provideFileInternal( file, media_nr, false, true);
136 bool MediaSetAccess::doesFileExist(const Pathname & file, unsigned media_nr )
138 callback::SendReport<media::MediaChangeReport> report;
139 media::MediaManager media_mgr;
145 // get the mediaId, but don't try to attach it here
146 media::MediaAccessId media = getMediaAccessId( media_nr);
150 DBG << "Cheking if file " << file
151 << " from media number " << media_nr << " exists." << endl;
152 // try to attach the media
153 if ( ! media_mgr.isAttached(media) )
154 media_mgr.attachDesiredMedia(media);
155 exists = media_mgr.doesFileExist(media, file);
158 catch ( media::MediaException & excp )
161 media::MediaChangeReport::Action user;
164 DBG << "Media couldn't provide file " << file << " , releasing." << endl;
167 media_mgr.release (media);
169 catch (const Exception & excpt_r)
171 ZYPP_CAUGHT(excpt_r);
172 MIL << "Failed to release media " << media << endl;
176 media::MediaChangeReport::Error reason = media::MediaChangeReport::INVALID;
178 if( typeid(excp) == typeid( media::MediaFileNotFoundException ) ||
179 typeid(excp) == typeid( media::MediaNotAFileException ) )
181 reason = media::MediaChangeReport::NOT_FOUND;
183 else if( typeid(excp) == typeid( media::MediaNotDesiredException) ||
184 typeid(excp) == typeid( media::MediaNotAttachedException) )
186 reason = media::MediaChangeReport::WRONG;
188 else if( typeid(excp) == typeid( media::MediaTimeoutException))
190 reason = media::MediaChangeReport::IO_SOFT;
193 vector<string> devices;
194 unsigned int devindex;
195 media_mgr.getDetectedDevices(media, devices, devindex);
197 // release all media before requesting another (#336881)
198 media_mgr.releaseAll();
200 user = report->requestMedia (
209 MIL << "doesFileExist exception caught, callback answer: " << user << endl;
211 if( user == media::MediaChangeReport::ABORT )
213 DBG << "Aborting" << endl;
214 ZYPP_RETHROW ( excp );
216 else if ( user == media::MediaChangeReport::IGNORE )
218 DBG << "Skipping" << endl;
219 SkipRequestException nexcp("User-requested skipping of a file");
220 nexcp.remember(excp);
223 else if ( user == media::MediaChangeReport::EJECT )
225 DBG << "Eject: try to release" << endl;
226 media_mgr.releaseAll();
228 media_mgr.release (media,
229 devindex < devices.size() ? devices[devindex] : "");
231 else if ( user == media::MediaChangeReport::RETRY ||
232 user == media::MediaChangeReport::CHANGE_URL )
235 DBG << "Going to try again" << endl;
236 // invalidate current media access id
237 media_mgr.close(media);
238 _medias.erase(media_nr);
240 // not attaching, media set will do that for us
241 // this could generate uncaught exception (#158620)
246 DBG << "Don't know, let's ABORT" << endl;
247 ZYPP_RETHROW ( excp );
249 } while( user == media::MediaChangeReport::EJECT );
252 // retry or change URL
258 Pathname MediaSetAccess::provideFileInternal(const Pathname & file, unsigned media_nr, bool cached, bool checkonly )
260 callback::SendReport<media::MediaChangeReport> report;
261 media::MediaManager media_mgr;
263 media::MediaAccessId media;
267 // get the mediaId, but don't try to attach it here
268 media = getMediaAccessId( media_nr);
272 DBG << "Going to try to provide file " << file
273 << " from media number " << media_nr << endl;
274 // try to attach the media
275 if ( ! media_mgr.isAttached(media) )
276 media_mgr.attachDesiredMedia(media);
277 media_mgr.provideFile (media, file, false, false);
280 catch ( media::MediaException & excp )
283 media::MediaChangeReport::Action user = media::MediaChangeReport::ABORT;
284 unsigned int devindex = 0;
285 vector<string> devices;
286 media_mgr.getDetectedDevices(media, devices, devindex);
290 if (user != media::MediaChangeReport::EJECT) // no use in calling this again
292 DBG << "Media couldn't provide file " << file << " , releasing." << endl;
295 media_mgr.release(media);
297 catch (const Exception & excpt_r)
299 ZYPP_CAUGHT(excpt_r);
300 MIL << "Failed to release media " << media << endl;
305 media::MediaChangeReport::Error reason = media::MediaChangeReport::INVALID;
307 if( typeid(excp) == typeid( media::MediaFileNotFoundException ) ||
308 typeid(excp) == typeid( media::MediaNotAFileException ) )
310 reason = media::MediaChangeReport::NOT_FOUND;
312 else if( typeid(excp) == typeid( media::MediaNotDesiredException) ||
313 typeid(excp) == typeid( media::MediaNotAttachedException) )
315 reason = media::MediaChangeReport::WRONG;
318 // checkonly: only bother the user if wrong medium is in the drive
319 if (checkonly && reason != media::MediaChangeReport::WRONG)
323 // release all media before requesting another (#336881)
324 media_mgr.releaseAll();
326 user = report->requestMedia (
337 MIL << "ProvideFile exception caught, callback answer: " << user << endl;
339 if( user == media::MediaChangeReport::ABORT )
341 DBG << "Aborting" << endl;
344 ZYPP_RETHROW ( excp );
346 else if ( user == media::MediaChangeReport::IGNORE )
348 DBG << "Skipping" << endl;
351 SkipRequestException nexcp("User-requested skipping of a file");
352 nexcp.remember(excp);
355 else if ( user == media::MediaChangeReport::EJECT )
357 DBG << "Eject: try to release" << endl;
358 media_mgr.releaseAll();
360 media_mgr.release (media,
361 devindex < devices.size() ? devices[devindex] : "");
363 else if ( user == media::MediaChangeReport::RETRY ||
364 user == media::MediaChangeReport::CHANGE_URL )
367 DBG << "Going to try again" << endl;
368 // invalidate current media access id
369 media_mgr.close(media);
370 _medias.erase(media_nr);
372 // not attaching, media set will do that for us
373 // this could generate uncaught exception (#158620)
378 DBG << "Don't know, let's ABORT" << endl;
381 ZYPP_RETHROW ( excp );
383 } while( user == media::MediaChangeReport::EJECT );
386 // retry or change URL
389 return media_mgr.localPath( media, file );
393 Pathname MediaSetAccess::provideDir(const Pathname & dir,
397 callback::SendReport<media::MediaChangeReport> report;
398 media::MediaManager media_mgr;
399 media::MediaAccessId _media;
403 // get the mediaId, but don't try to attach it here
404 _media = getMediaAccessId(media_nr);
408 DBG << "Going to try provide direcotry " << dir
409 << (recursive ? " (recursively)" : "")
410 << " from media nr. " << media_nr << endl;
412 // try to attach the media
413 if (!media_mgr.isAttached(_media))
414 media_mgr.attachDesiredMedia(_media);
416 _media = getMediaAccessId(media_nr); // in case of redirect
419 media_mgr.provideDirTree(_media, dir);
421 media_mgr.provideDir(_media, dir);
423 break; // quit the retry loop
425 catch (media::MediaException & excp)
428 media::MediaChangeReport::Action user;
432 DBG << "Media couldn't provide dir " << dir << ", releasing." << endl;
435 media_mgr.release (_media);
437 catch (const Exception & excpt_r)
439 ZYPP_CAUGHT(excpt_r);
440 ERR << "Failed to release media " << _media << endl;
443 //MIL << "Releasing all medias of all sources" << endl;
446 //! \todo do we need replacement for this at all?
447 //zypp::SourceManager::sourceManager()->releaseAllSources();
449 catch (const zypp::Exception& excpt_r)
451 ZYPP_CAUGHT(excpt_r);
452 ERR << "Failed to release all sources" << endl;
456 media::MediaChangeReport::Error reason = media::MediaChangeReport::INVALID;
458 if (typeid(excp) == typeid(media::MediaFileNotFoundException)
459 || typeid(excp) == typeid(media::MediaNotAFileException))
461 reason = media::MediaChangeReport::NOT_FOUND;
463 else if (typeid(excp) == typeid( media::MediaNotDesiredException)
464 || typeid(excp) == typeid(media::MediaNotAttachedException))
466 reason = media::MediaChangeReport::WRONG;
469 vector<string> devices;
470 unsigned int devindex;
471 media_mgr.getDetectedDevices(_media, devices, devindex);
473 // release all media before requesting another (#336881)
474 media_mgr.releaseAll();
476 user = report->requestMedia(_url,
484 MIL << "ProvideDir exception caught, callback answer: " << user << endl;
486 if (user == media::MediaChangeReport::ABORT)
488 DBG << "Aborting" << endl;
489 ZYPP_RETHROW ( excp );
491 else if (user == media::MediaChangeReport::EJECT)
493 DBG << "Eject: try to release" << endl;
494 media_mgr.releaseAll();
496 media_mgr.release (_media,
497 devindex < devices.size() ? devices[devindex] : "");
499 else if (user == media::MediaChangeReport::RETRY ||
500 user == media::MediaChangeReport::CHANGE_URL)
503 DBG << "Going to try again" << endl;
504 // invalidate current media access id
505 media_mgr.close(_media);
506 _medias.erase(media_nr);
508 // not attaching, media set will do that for us
509 // this could generate uncaught exception (#158620)
515 DBG << "Don't know, let's ABORT" << endl;
520 while (user == media::MediaChangeReport::EJECT);
522 // retry or change URL
526 return media_mgr.localPath(_media, dir);
529 media::MediaAccessId MediaSetAccess::getMediaAccessId (media::MediaNr medianr)
531 media::MediaManager media_mgr;
533 if (_medias.find(medianr) != _medias.end())
535 media::MediaAccessId id = _medias[medianr];
536 //if (! noattach && ! media_mgr.isAttached(id))
537 //media_mgr.attach(id);
541 url = rewriteUrl (_url, medianr);
542 media::MediaAccessId id = media_mgr.open(url, _prefAttachPoint);
543 _medias[medianr] = id;
547 if (_verifiers.find(medianr) != _verifiers.end())
549 // a verifier is set for this media
550 // FIXME check the case where the verifier exists
551 // but we have no access id for the media
552 media::MediaAccessId id = _medias[medianr];
553 media::MediaManager media_mgr;
554 media_mgr.delVerifier(id);
555 media_mgr.addVerifier( id, _verifiers[medianr] );
556 // remove any saved verifier for this media
557 _verifiers.erase(medianr);
560 catch ( const Exception &e )
563 WAR << "Verifier not found" << endl;
570 Url MediaSetAccess::rewriteUrl (const Url & url_r, const media::MediaNr medianr)
572 std::string scheme = url_r.getScheme();
573 if (scheme == "cd" || scheme == "dvd")
576 DBG << "Rewriting url " << url_r << endl;
580 // TODO the iso parameter will not be required in the future, this
581 // code has to be adapted together with the MediaISO change.
582 // maybe some MediaISOURL interface should be used.
583 std::string isofile = url_r.getQueryParam("iso");
584 str::regex e("^(.*)(cd|dvd)[0-9]+\\.iso$", str::regex::icase);
587 if(str::regex_match(isofile, what, e))
590 isofile = what[1] + what[2] + str::numstring(medianr) + ".iso";
591 url.setQueryParam("iso", isofile);
592 DBG << "Url rewrite result: " << url << endl;
598 std::string pathname = url_r.getPathName();
599 str::regex e("^(.*)(cd|dvd)[0-9]+(/)?$", str::regex::icase);
601 if(str::regex_match(pathname, what, e))
604 pathname = what[1] + what[2] + str::numstring(medianr) + what[3];
605 url.setPathName(pathname);
606 DBG << "Url rewrite result: " << url << endl;
613 void MediaSetAccess::release()
615 DBG << "Releasing all media IDs held by this MediaSetAccess" << endl;
616 media::MediaManager manager;
617 for (MediaMap::const_iterator m = _medias.begin(); m != _medias.end(); ++m)
618 manager.release(m->second, "");
621 std::ostream & MediaSetAccess::dumpOn( std::ostream & str ) const
623 str << "MediaSetAccess (URL='" << _url << "', attach_point_hint='" << _prefAttachPoint << "')";
627 // media::MediaVerifierRef MediaSetAccess::verifier(unsigned media_nr)
628 // { return media::MediaVerifierRef(new media::NoVerifier()); }
630 /////////////////////////////////////////////////////////////////
632 ///////////////////////////////////////////////////////////////////