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);
68 // save the verifier in the map, and set it when
69 // the media number is first attached
70 _verifiers[media_nr] = verifier;
74 void MediaSetAccess::releaseFile( const OnMediaLocation & on_media_file )
76 releaseFile( on_media_file.filename(), on_media_file.medianr() );
79 void MediaSetAccess::releaseFile( const Pathname & file, unsigned media_nr)
81 media::MediaManager media_mgr;
82 media::MediaAccessId media;
84 media = getMediaAccessId( media_nr);
85 DBG << "Going to release file " << file
86 << " from media number " << media_nr << endl;
88 if ( ! media_mgr.isAttached(media) )
89 return; //disattached media is free
91 media_mgr.releaseFile (media, file);
94 void MediaSetAccess::dirInfo( filesystem::DirContent &retlist, const Pathname &dirname,
95 bool dots, unsigned media_nr )
97 media::MediaManager media_mgr;
98 media::MediaAccessId media;
99 media = getMediaAccessId(media_nr);
101 // try to attach the media
102 if ( ! media_mgr.isAttached(media) )
103 media_mgr.attach(media);
105 media_mgr.dirInfo(media, retlist, dirname, dots);
108 struct ProvideFileOperation
111 void operator()( media::MediaAccessId media, const Pathname &file )
113 media::MediaManager media_mgr;
114 media_mgr.provideFile(media, file);
115 result = media_mgr.localPath(media, file);
119 struct ProvideDirTreeOperation
122 void operator()( media::MediaAccessId media, const Pathname &file )
124 media::MediaManager media_mgr;
125 media_mgr.provideDirTree(media, file);
126 result = media_mgr.localPath(media, file);
130 struct ProvideDirOperation
133 void operator()( media::MediaAccessId media, const Pathname &file )
135 media::MediaManager media_mgr;
136 media_mgr.provideDir(media, file);
137 result = media_mgr.localPath(media, file);
141 struct ProvideFileExistenceOperation
144 ProvideFileExistenceOperation()
148 void operator()( media::MediaAccessId media, const Pathname &file )
150 media::MediaManager media_mgr;
151 result = media_mgr.doesFileExist(media, file);
157 Pathname MediaSetAccess::provideFile( const OnMediaLocation & resource, ProvideFileOptions options, const Pathname &deltafile )
159 ProvideFileOperation op;
160 provide( boost::ref(op), resource, options, deltafile );
164 Pathname MediaSetAccess::provideFile(const Pathname & file, unsigned media_nr, ProvideFileOptions options )
166 OnMediaLocation resource;
167 ProvideFileOperation op;
168 resource.setLocation(file, media_nr);
169 provide( boost::ref(op), resource, options, Pathname() );
173 bool MediaSetAccess::doesFileExist(const Pathname & file, unsigned media_nr )
175 ProvideFileExistenceOperation op;
176 OnMediaLocation resource;
177 resource.setLocation(file, media_nr);
178 provide( boost::ref(op), resource, PROVIDE_DEFAULT, Pathname());
182 void MediaSetAccess::provide( ProvideOperation op,
183 const OnMediaLocation &resource,
184 ProvideFileOptions options,
185 const Pathname &deltafile )
187 Pathname file(resource.filename());
188 unsigned media_nr(resource.medianr());
190 callback::SendReport<media::MediaChangeReport> report;
191 media::MediaManager media_mgr;
193 media::MediaAccessId media;
197 // get the mediaId, but don't try to attach it here
198 media = getMediaAccessId( media_nr);
199 bool deltafileset = false;
203 DBG << "Going to try to provide " << (resource.optional() ? "optional" : "") << " file " << file
204 << " from media number " << media_nr << endl;
205 // try to attach the media
206 if ( ! media_mgr.isAttached(media) )
207 media_mgr.attach(media);
208 media_mgr.setDeltafile(media, deltafile);
211 media_mgr.setDeltafile(media, Pathname());
214 catch ( media::MediaException & excp )
218 media_mgr.setDeltafile(media, Pathname());
219 media::MediaChangeReport::Action user = media::MediaChangeReport::ABORT;
220 unsigned int devindex = 0;
221 vector<string> devices;
222 media_mgr.getDetectedDevices(media, devices, devindex);
226 if (user != media::MediaChangeReport::EJECT) // no use in calling this again
228 DBG << "Media couldn't provide file " << file << " , releasing." << endl;
231 media_mgr.release(media);
233 catch (const Exception & excpt_r)
235 ZYPP_CAUGHT(excpt_r);
236 MIL << "Failed to release media " << media << endl;
241 media::MediaChangeReport::Error reason = media::MediaChangeReport::INVALID;
243 if( typeid(excp) == typeid( media::MediaFileNotFoundException ) ||
244 typeid(excp) == typeid( media::MediaNotAFileException ) )
246 reason = media::MediaChangeReport::NOT_FOUND;
248 else if( typeid(excp) == typeid( media::MediaNotDesiredException) ||
249 typeid(excp) == typeid( media::MediaNotAttachedException) )
251 reason = media::MediaChangeReport::WRONG;
253 else if( typeid(excp) == typeid( media::MediaTimeoutException) ||
254 typeid(excp) == typeid( media::MediaTemporaryProblemException))
256 reason = media::MediaChangeReport::IO_SOFT;
259 // Propagate the original error if _no_ callback receiver is connected, or
260 // non_interactive mode (for optional files) is used (except for wrong media).
261 if ( ! callback::SendReport<media::MediaChangeReport>::connected()
262 || (( options & PROVIDE_NON_INTERACTIVE ) && reason != media::MediaChangeReport::WRONG ) )
264 MIL << "Can't provide file. Non-Interactive mode." << endl;
269 // release all media before requesting another (#336881)
270 media_mgr.releaseAll();
272 user = report->requestMedia (
277 excp.asUserHistory(),
283 MIL << "ProvideFile exception caught, callback answer: " << user << endl;
285 if( user == media::MediaChangeReport::ABORT )
287 DBG << "Aborting" << endl;
288 AbortRequestException aexcp("Aborting requested by user");
289 aexcp.remember(excp);
292 else if ( user == media::MediaChangeReport::IGNORE )
294 DBG << "Skipping" << endl;
295 SkipRequestException nexcp("User-requested skipping of a file");
296 nexcp.remember(excp);
299 else if ( user == media::MediaChangeReport::EJECT )
301 DBG << "Eject: try to release" << endl;
304 media_mgr.releaseAll();
305 media_mgr.release (media, devindex < devices.size() ? devices[devindex] : "");
307 catch ( const Exception & e)
312 else if ( user == media::MediaChangeReport::RETRY ||
313 user == media::MediaChangeReport::CHANGE_URL )
316 DBG << "Going to try again" << endl;
317 // invalidate current media access id
318 media_mgr.close(media);
319 _medias.erase(media_nr);
321 // not attaching, media set will do that for us
322 // this could generate uncaught exception (#158620)
327 DBG << "Don't know, let's ABORT" << endl;
328 ZYPP_RETHROW ( excp );
330 } while( user == media::MediaChangeReport::EJECT );
333 // retry or change URL
337 Pathname MediaSetAccess::provideDir(const Pathname & dir,
340 ProvideFileOptions options )
342 OnMediaLocation resource;
343 resource.setLocation(dir, media_nr);
346 ProvideDirTreeOperation op;
347 provide( boost::ref(op), resource, options, Pathname());
350 ProvideDirOperation op;
351 provide( boost::ref(op), resource, options, Pathname());
355 media::MediaAccessId MediaSetAccess::getMediaAccessId (media::MediaNr medianr)
357 if ( _medias.find( medianr ) != _medias.end() )
359 return _medias[medianr];
362 Url url( medianr > 1 ? rewriteUrl( _url, medianr ) : _url );
363 media::MediaManager media_mgr;
364 media::MediaAccessId id = media_mgr.open( url, _prefAttachPoint );
365 _medias[medianr] = id;
369 if ( _verifiers.find(medianr) != _verifiers.end() )
371 // a verifier is set for this media
372 // FIXME check the case where the verifier exists
373 // but we have no access id for the media
374 media_mgr.delVerifier( id );
375 media_mgr.addVerifier( id, _verifiers[medianr] );
376 // remove any saved verifier for this media
377 _verifiers.erase( medianr );
380 catch ( const Exception &e )
383 WAR << "Verifier not found" << endl;
390 Url MediaSetAccess::rewriteUrl (const Url & url_r, const media::MediaNr medianr)
392 std::string scheme = url_r.getScheme();
393 if (scheme == "cd" || scheme == "dvd")
396 DBG << "Rewriting url " << url_r << endl;
400 // TODO the iso parameter will not be required in the future, this
401 // code has to be adapted together with the MediaISO change.
402 // maybe some MediaISOURL interface should be used.
403 std::string isofile = url_r.getQueryParam("iso");
404 str::regex e("^(.*)(cd|dvd|media)[0-9]+\\.iso$", str::regex::icase);
407 if(str::regex_match(isofile, what, e))
410 isofile = what[1] + what[2] + str::numstring(medianr) + ".iso";
411 url.setQueryParam("iso", isofile);
412 DBG << "Url rewrite result: " << url << endl;
418 std::string pathname = url_r.getPathName();
419 str::regex e("^(.*)(cd|dvd|media)[0-9]+(/)?$", str::regex::icase);
421 if(str::regex_match(pathname, what, e))
424 pathname = what[1] + what[2] + str::numstring(medianr) + what[3];
425 url.setPathName(pathname);
426 DBG << "Url rewrite result: " << url << endl;
433 void MediaSetAccess::release()
435 DBG << "Releasing all media IDs held by this MediaSetAccess" << endl;
436 media::MediaManager manager;
437 for (MediaMap::const_iterator m = _medias.begin(); m != _medias.end(); ++m)
438 manager.release(m->second, "");
441 std::ostream & MediaSetAccess::dumpOn( std::ostream & str ) const
443 str << "MediaSetAccess (URL='" << _url << "', attach_point_hint='" << _prefAttachPoint << "')";
447 /////////////////////////////////////////////////////////////////
449 ///////////////////////////////////////////////////////////////////