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()
49 media::MediaManager manager;
50 for ( const auto & mm : _medias )
51 manager.close( mm.second );
53 catch(...) {} // don't let exception escape a dtor.
57 void MediaSetAccess::setVerifier( unsigned media_nr, media::MediaVerifierRef verifier )
59 if (_medias.find(media_nr) != _medias.end())
61 // the media already exists, set theverifier
62 media::MediaAccessId id = _medias[media_nr];
63 media::MediaManager media_mgr;
64 media_mgr.addVerifier( id, verifier );
65 // remove any saved verifier for this media
66 _verifiers.erase(media_nr);
70 // save the verifier in the map, and set it when
71 // the media number is first attached
72 _verifiers[media_nr] = verifier;
76 void MediaSetAccess::releaseFile( const OnMediaLocation & on_media_file )
78 releaseFile( on_media_file.filename(), on_media_file.medianr() );
81 void MediaSetAccess::releaseFile( const Pathname & file, unsigned media_nr)
83 media::MediaManager media_mgr;
84 media::MediaAccessId media;
86 media = getMediaAccessId( media_nr);
87 DBG << "Going to release file " << file
88 << " from media number " << media_nr << endl;
90 if ( ! media_mgr.isAttached(media) )
91 return; //disattached media is free
93 media_mgr.releaseFile (media, file);
96 void MediaSetAccess::dirInfo( filesystem::DirContent &retlist, const Pathname &dirname,
97 bool dots, unsigned media_nr )
99 media::MediaManager media_mgr;
100 media::MediaAccessId media;
101 media = getMediaAccessId(media_nr);
103 // try to attach the media
104 if ( ! media_mgr.isAttached(media) )
105 media_mgr.attach(media);
107 media_mgr.dirInfo(media, retlist, dirname, dots);
110 struct ProvideFileOperation
113 ByteCount expectedFileSize;
114 void operator()( media::MediaAccessId media, const Pathname &file )
116 media::MediaManager media_mgr;
117 media_mgr.provideFile(media, file, expectedFileSize);
118 result = media_mgr.localPath(media, file);
122 struct ProvideDirTreeOperation
125 void operator()( media::MediaAccessId media, const Pathname &file )
127 media::MediaManager media_mgr;
128 media_mgr.provideDirTree(media, file);
129 result = media_mgr.localPath(media, file);
133 struct ProvideDirOperation
136 void operator()( media::MediaAccessId media, const Pathname &file )
138 media::MediaManager media_mgr;
139 media_mgr.provideDir(media, file);
140 result = media_mgr.localPath(media, file);
144 struct ProvideFileExistenceOperation
147 ProvideFileExistenceOperation()
151 void operator()( media::MediaAccessId media, const Pathname &file )
153 media::MediaManager media_mgr;
154 result = media_mgr.doesFileExist(media, file);
160 Pathname MediaSetAccess::provideFile( const OnMediaLocation & resource, ProvideFileOptions options, const Pathname &deltafile )
162 ProvideFileOperation op;
163 op.expectedFileSize = resource.downloadSize();
164 provide( boost::ref(op), resource, options, deltafile );
168 Pathname MediaSetAccess::provideFile(const Pathname & file, unsigned media_nr, ProvideFileOptions options )
170 OnMediaLocation resource;
171 ProvideFileOperation op;
172 resource.setLocation(file, media_nr);
173 provide( boost::ref(op), resource, options, Pathname() );
177 bool MediaSetAccess::doesFileExist(const Pathname & file, unsigned media_nr )
179 ProvideFileExistenceOperation op;
180 OnMediaLocation resource;
181 resource.setLocation(file, media_nr);
182 provide( boost::ref(op), resource, PROVIDE_DEFAULT, Pathname());
186 void MediaSetAccess::provide( ProvideOperation op,
187 const OnMediaLocation &resource,
188 ProvideFileOptions options,
189 const Pathname &deltafile )
191 Pathname file(resource.filename());
192 unsigned media_nr(resource.medianr());
194 callback::SendReport<media::MediaChangeReport> report;
195 media::MediaManager media_mgr;
197 media::MediaAccessId media;
201 // get the mediaId, but don't try to attach it here
202 media = getMediaAccessId( media_nr);
203 bool deltafileset = false;
207 DBG << "Going to try to provide " << (resource.optional() ? "optional" : "") << " file " << file
208 << " from media number " << media_nr << endl;
209 // try to attach the media
210 if ( ! media_mgr.isAttached(media) )
211 media_mgr.attach(media);
212 media_mgr.setDeltafile(media, deltafile);
215 media_mgr.setDeltafile(media, Pathname());
218 catch ( media::MediaException & excp )
222 media_mgr.setDeltafile(media, Pathname());
223 media::MediaChangeReport::Action user = media::MediaChangeReport::ABORT;
224 unsigned int devindex = 0;
225 vector<string> devices;
226 media_mgr.getDetectedDevices(media, devices, devindex);
230 if (user != media::MediaChangeReport::EJECT) // no use in calling this again
232 DBG << "Media couldn't provide file " << file << " , releasing." << endl;
235 media_mgr.release(media);
237 catch (const Exception & excpt_r)
239 ZYPP_CAUGHT(excpt_r);
240 MIL << "Failed to release media " << media << endl;
245 media::MediaChangeReport::Error reason = media::MediaChangeReport::INVALID;
247 if( typeid(excp) == typeid( media::MediaFileNotFoundException ) ||
248 typeid(excp) == typeid( media::MediaNotAFileException ) )
250 reason = media::MediaChangeReport::NOT_FOUND;
252 else if( typeid(excp) == typeid( media::MediaNotDesiredException) ||
253 typeid(excp) == typeid( media::MediaNotAttachedException) )
255 reason = media::MediaChangeReport::WRONG;
257 else if( typeid(excp) == typeid( media::MediaTimeoutException) ||
258 typeid(excp) == typeid( media::MediaTemporaryProblemException))
260 reason = media::MediaChangeReport::IO_SOFT;
263 // Propagate the original error if _no_ callback receiver is connected, or
264 // non_interactive mode (for optional files) is used (except for wrong media).
265 if ( ! callback::SendReport<media::MediaChangeReport>::connected()
266 || (( options & PROVIDE_NON_INTERACTIVE ) && reason != media::MediaChangeReport::WRONG ) )
268 MIL << "Can't provide file. Non-Interactive mode." << endl;
273 // release all media before requesting another (#336881)
274 media_mgr.releaseAll();
276 user = report->requestMedia (
287 MIL << "ProvideFile exception caught, callback answer: " << user << endl;
289 if( user == media::MediaChangeReport::ABORT )
291 DBG << "Aborting" << endl;
292 AbortRequestException aexcp("Aborting requested by user");
293 aexcp.remember(excp);
296 else if ( user == media::MediaChangeReport::IGNORE )
298 DBG << "Skipping" << endl;
299 SkipRequestException nexcp("User-requested skipping of a file");
300 nexcp.remember(excp);
303 else if ( user == media::MediaChangeReport::EJECT )
305 DBG << "Eject: try to release" << endl;
308 media_mgr.releaseAll();
309 media_mgr.release (media, devindex < devices.size() ? devices[devindex] : "");
311 catch ( const Exception & e)
316 else if ( user == media::MediaChangeReport::RETRY ||
317 user == media::MediaChangeReport::CHANGE_URL )
320 DBG << "Going to try again" << endl;
321 // invalidate current media access id
322 media_mgr.close(media);
323 _medias.erase(media_nr);
325 // not attaching, media set will do that for us
326 // this could generate uncaught exception (#158620)
331 DBG << "Don't know, let's ABORT" << endl;
332 ZYPP_RETHROW ( excp );
334 } while( user == media::MediaChangeReport::EJECT );
337 // retry or change URL
341 Pathname MediaSetAccess::provideDir(const Pathname & dir,
344 ProvideFileOptions options )
346 OnMediaLocation resource;
347 resource.setLocation(dir, media_nr);
350 ProvideDirTreeOperation op;
351 provide( boost::ref(op), resource, options, Pathname());
354 ProvideDirOperation op;
355 provide( boost::ref(op), resource, options, Pathname());
359 media::MediaAccessId MediaSetAccess::getMediaAccessId (media::MediaNr medianr)
361 media::MediaManager media_mgr;
363 if (_medias.find(medianr) != _medias.end())
365 media::MediaAccessId id = _medias[medianr];
369 url = rewriteUrl (_url, medianr);
370 media::MediaAccessId id = media_mgr.open(url, _prefAttachPoint);
371 _medias[medianr] = id;
375 if (_verifiers.find(medianr) != _verifiers.end())
377 // a verifier is set for this media
378 // FIXME check the case where the verifier exists
379 // but we have no access id for the media
380 media::MediaAccessId id = _medias[medianr];
381 media::MediaManager media_mgr;
382 media_mgr.delVerifier(id);
383 media_mgr.addVerifier( id, _verifiers[medianr] );
384 // remove any saved verifier for this media
385 _verifiers.erase(medianr);
388 catch ( const Exception &e )
391 WAR << "Verifier not found" << endl;
398 Url MediaSetAccess::rewriteUrl (const Url & url_r, const media::MediaNr medianr)
400 std::string scheme = url_r.getScheme();
401 if (scheme == "cd" || scheme == "dvd")
404 DBG << "Rewriting url " << url_r << endl;
408 // TODO the iso parameter will not be required in the future, this
409 // code has to be adapted together with the MediaISO change.
410 // maybe some MediaISOURL interface should be used.
411 std::string isofile = url_r.getQueryParam("iso");
412 str::regex e("^(.*)(cd|dvd|media)[0-9]+\\.iso$", str::regex::icase);
415 if(str::regex_match(isofile, what, e))
418 isofile = what[1] + what[2] + str::numstring(medianr) + ".iso";
419 url.setQueryParam("iso", isofile);
420 DBG << "Url rewrite result: " << url << endl;
426 std::string pathname = url_r.getPathName();
427 str::regex e("^(.*)(cd|dvd|media)[0-9]+(/)?$", str::regex::icase);
429 if(str::regex_match(pathname, what, e))
432 pathname = what[1] + what[2] + str::numstring(medianr) + what[3];
433 url.setPathName(pathname);
434 DBG << "Url rewrite result: " << url << endl;
441 void MediaSetAccess::release()
443 DBG << "Releasing all media IDs held by this MediaSetAccess" << endl;
444 media::MediaManager manager;
445 for (MediaMap::const_iterator m = _medias.begin(); m != _medias.end(); ++m)
446 manager.release(m->second, "");
449 std::ostream & MediaSetAccess::dumpOn( std::ostream & str ) const
451 str << "MediaSetAccess (URL='" << _url << "', attach_point_hint='" << _prefAttachPoint << "')";
455 /////////////////////////////////////////////////////////////////
457 ///////////////////////////////////////////////////////////////////