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/TmpPath.h>
20 //#include <zypp/source/MediaSetAccessReportReceivers.h>
24 ///////////////////////////////////////////////////////////////////
26 { /////////////////////////////////////////////////////////////////
28 IMPL_PTR_TYPE(MediaSetAccess);
30 ///////////////////////////////////////////////////////////////////
32 MediaSetAccess::MediaSetAccess(const Url &url,
33 const Pathname & prefered_attach_point)
35 , _prefAttachPoint(prefered_attach_point)
38 MediaSetAccess::MediaSetAccess(const std::string & label_r,
40 const Pathname & prefered_attach_point)
42 , _prefAttachPoint(prefered_attach_point)
46 MediaSetAccess::~MediaSetAccess()
50 media::MediaManager manager;
51 for ( const auto & mm : _medias )
52 manager.close( mm.second );
54 catch(...) {} // don't let exception escape a dtor.
58 void MediaSetAccess::setVerifier( unsigned media_nr, media::MediaVerifierRef verifier )
60 if (_medias.find(media_nr) != _medias.end())
62 // the media already exists, set theverifier
63 media::MediaAccessId id = _medias[media_nr];
64 media::MediaManager media_mgr;
65 media_mgr.addVerifier( id, verifier );
66 // remove any saved verifier for this media
67 _verifiers.erase(media_nr);
71 // save the verifier in the map, and set it when
72 // the media number is first attached
73 _verifiers[media_nr] = verifier;
77 void MediaSetAccess::releaseFile( const OnMediaLocation & on_media_file )
79 releaseFile( on_media_file.filename(), on_media_file.medianr() );
82 void MediaSetAccess::releaseFile( const Pathname & file, unsigned media_nr)
84 media::MediaManager media_mgr;
85 media::MediaAccessId media;
87 media = getMediaAccessId( media_nr);
88 DBG << "Going to release file " << file
89 << " from media number " << media_nr << endl;
91 if ( ! media_mgr.isAttached(media) )
92 return; //disattached media is free
94 media_mgr.releaseFile (media, file);
97 void MediaSetAccess::dirInfo( filesystem::DirContent &retlist, const Pathname &dirname,
98 bool dots, unsigned media_nr )
100 media::MediaManager media_mgr;
101 media::MediaAccessId media;
102 media = getMediaAccessId(media_nr);
104 // try to attach the media
105 if ( ! media_mgr.isAttached(media) )
106 media_mgr.attach(media);
108 media_mgr.dirInfo(media, retlist, dirname, dots);
111 struct ProvideFileOperation
114 ByteCount expectedFileSize;
115 void operator()( media::MediaAccessId media, const Pathname &file )
117 media::MediaManager media_mgr;
118 media_mgr.provideFile(media, file, expectedFileSize);
119 result = media_mgr.localPath(media, file);
123 struct ProvideDirTreeOperation
126 void operator()( media::MediaAccessId media, const Pathname &file )
128 media::MediaManager media_mgr;
129 media_mgr.provideDirTree(media, file);
130 result = media_mgr.localPath(media, file);
134 struct ProvideDirOperation
137 void operator()( media::MediaAccessId media, const Pathname &file )
139 media::MediaManager media_mgr;
140 media_mgr.provideDir(media, file);
141 result = media_mgr.localPath(media, file);
145 struct ProvideFileExistenceOperation
148 ProvideFileExistenceOperation()
152 void operator()( media::MediaAccessId media, const Pathname &file )
154 media::MediaManager media_mgr;
155 result = media_mgr.doesFileExist(media, file);
161 Pathname MediaSetAccess::provideFile( const OnMediaLocation & resource, ProvideFileOptions options, const Pathname &deltafile )
163 ProvideFileOperation op;
164 op.expectedFileSize = resource.downloadSize();
165 provide( boost::ref(op), resource, options, deltafile );
169 Pathname MediaSetAccess::provideFile(const Pathname & file, unsigned media_nr, ProvideFileOptions options )
171 OnMediaLocation resource;
172 ProvideFileOperation op;
173 resource.setLocation(file, media_nr);
174 provide( boost::ref(op), resource, options, Pathname() );
178 Pathname MediaSetAccess::provideOptionalFile( const Pathname & file, unsigned media_nr )
182 if ( doesFileExist( file, media_nr ) )
183 return provideFile( file, media_nr, PROVIDE_NON_INTERACTIVE );
185 catch ( const media::MediaFileNotFoundException & excpt_r )
186 { ZYPP_CAUGHT( excpt_r ); }
187 catch ( const media::MediaNotAFileException & excpt_r )
188 { ZYPP_CAUGHT( excpt_r ); }
192 ManagedFile MediaSetAccess::provideFileFromUrl(const Url &file_url, ProvideFileOptions options)
195 Pathname path(url.getPathName());
196 url.setPathName ("/");
197 MediaSetAccess access(url);
199 ManagedFile tmpFile = filesystem::TmpFile::asManagedFile();
201 Pathname file = access.provideFile(path, 1, options);
203 //prevent the file from being deleted when MediaSetAccess gets out of scope
204 if ( filesystem::hardlinkCopy(file, tmpFile) != 0 )
205 ZYPP_THROW(Exception("Can't copy file from " + file.asString() + " to " + tmpFile->asString() ));
210 ManagedFile MediaSetAccess::provideOptionalFileFromUrl( const Url & file_url )
214 return provideFileFromUrl( file_url, PROVIDE_NON_INTERACTIVE );
216 catch ( const media::MediaFileNotFoundException & excpt_r )
217 { ZYPP_CAUGHT( excpt_r ); }
218 catch ( const media::MediaNotAFileException & excpt_r )
219 { ZYPP_CAUGHT( excpt_r ); }
220 return ManagedFile();
223 bool MediaSetAccess::doesFileExist(const Pathname & file, unsigned media_nr )
225 ProvideFileExistenceOperation op;
226 OnMediaLocation resource;
227 resource.setLocation(file, media_nr);
228 provide( boost::ref(op), resource, PROVIDE_DEFAULT, Pathname());
232 void MediaSetAccess::provide( ProvideOperation op,
233 const OnMediaLocation &resource,
234 ProvideFileOptions options,
235 const Pathname &deltafile )
237 Pathname file(resource.filename());
238 unsigned media_nr(resource.medianr());
240 callback::SendReport<media::MediaChangeReport> report;
241 media::MediaManager media_mgr;
243 media::MediaAccessId media;
247 // get the mediaId, but don't try to attach it here
248 media = getMediaAccessId( media_nr);
249 bool deltafileset = false;
253 DBG << "Going to try to provide " << (resource.optional() ? "optional" : "") << " file " << file
254 << " from media number " << media_nr << endl;
255 // try to attach the media
256 if ( ! media_mgr.isAttached(media) )
257 media_mgr.attach(media);
258 media_mgr.setDeltafile(media, deltafile);
261 media_mgr.setDeltafile(media, Pathname());
264 catch ( media::MediaException & excp )
268 media_mgr.setDeltafile(media, Pathname());
269 media::MediaChangeReport::Action user = media::MediaChangeReport::ABORT;
270 unsigned int devindex = 0;
271 std::vector<std::string> devices;
272 media_mgr.getDetectedDevices(media, devices, devindex);
276 if (user != media::MediaChangeReport::EJECT) // no use in calling this again
278 DBG << "Media couldn't provide file " << file << " , releasing." << endl;
281 media_mgr.release(media);
283 catch (const Exception & excpt_r)
285 ZYPP_CAUGHT(excpt_r);
286 MIL << "Failed to release media " << media << endl;
291 media::MediaChangeReport::Error reason = media::MediaChangeReport::INVALID;
293 if( typeid(excp) == typeid( media::MediaFileNotFoundException ) ||
294 typeid(excp) == typeid( media::MediaNotAFileException ) )
296 reason = media::MediaChangeReport::NOT_FOUND;
298 else if( typeid(excp) == typeid( media::MediaNotDesiredException) ||
299 typeid(excp) == typeid( media::MediaNotAttachedException) )
301 reason = media::MediaChangeReport::WRONG;
303 else if( typeid(excp) == typeid( media::MediaTimeoutException) ||
304 typeid(excp) == typeid( media::MediaTemporaryProblemException))
306 reason = media::MediaChangeReport::IO_SOFT;
309 // Propagate the original error if _no_ callback receiver is connected, or
310 // non_interactive mode (for optional files) is used (except for wrong media).
311 if ( ! callback::SendReport<media::MediaChangeReport>::connected()
312 || (( options & PROVIDE_NON_INTERACTIVE ) && reason != media::MediaChangeReport::WRONG ) )
314 MIL << "Can't provide file. Non-Interactive mode." << endl;
319 // release all media before requesting another (#336881)
320 media_mgr.releaseAll();
322 user = report->requestMedia (
327 excp.asUserHistory(),
333 MIL << "ProvideFile exception caught, callback answer: " << user << endl;
335 if( user == media::MediaChangeReport::ABORT )
337 DBG << "Aborting" << endl;
338 AbortRequestException aexcp("Aborting requested by user");
339 aexcp.remember(excp);
342 else if ( user == media::MediaChangeReport::IGNORE )
344 DBG << "Skipping" << endl;
345 SkipRequestException nexcp("User-requested skipping of a file");
346 nexcp.remember(excp);
349 else if ( user == media::MediaChangeReport::EJECT )
351 DBG << "Eject: try to release" << endl;
354 media_mgr.releaseAll();
355 media_mgr.release (media, devindex < devices.size() ? devices[devindex] : "");
357 catch ( const Exception & e)
362 else if ( user == media::MediaChangeReport::RETRY ||
363 user == media::MediaChangeReport::CHANGE_URL )
366 DBG << "Going to try again" << endl;
367 // invalidate current media access id
368 media_mgr.close(media);
369 _medias.erase(media_nr);
371 // not attaching, media set will do that for us
372 // this could generate uncaught exception (#158620)
377 DBG << "Don't know, let's ABORT" << endl;
378 ZYPP_RETHROW ( excp );
380 } while( user == media::MediaChangeReport::EJECT );
383 // retry or change URL
387 Pathname MediaSetAccess::provideDir(const Pathname & dir,
390 ProvideFileOptions options )
392 OnMediaLocation resource;
393 resource.setLocation(dir, media_nr);
396 ProvideDirTreeOperation op;
397 provide( boost::ref(op), resource, options, Pathname());
400 ProvideDirOperation op;
401 provide( boost::ref(op), resource, options, Pathname());
405 media::MediaAccessId MediaSetAccess::getMediaAccessId (media::MediaNr medianr)
407 if ( _medias.find( medianr ) != _medias.end() )
409 return _medias[medianr];
412 Url url( medianr > 1 ? rewriteUrl( _url, medianr ) : _url );
413 media::MediaManager media_mgr;
414 media::MediaAccessId id = media_mgr.open( url, _prefAttachPoint );
415 _medias[medianr] = id;
419 if ( _verifiers.find(medianr) != _verifiers.end() )
421 // a verifier is set for this media
422 // FIXME check the case where the verifier exists
423 // but we have no access id for the media
424 media_mgr.delVerifier( id );
425 media_mgr.addVerifier( id, _verifiers[medianr] );
426 // remove any saved verifier for this media
427 _verifiers.erase( medianr );
430 catch ( const Exception &e )
433 WAR << "Verifier not found" << endl;
440 Url MediaSetAccess::rewriteUrl (const Url & url_r, const media::MediaNr medianr)
442 std::string scheme = url_r.getScheme();
443 if (scheme == "cd" || scheme == "dvd")
446 DBG << "Rewriting url " << url_r << endl;
450 // TODO the iso parameter will not be required in the future, this
451 // code has to be adapted together with the MediaISO change.
452 // maybe some MediaISOURL interface should be used.
453 std::string isofile = url_r.getQueryParam("iso");
454 str::regex e("^(.*)(cd|dvd|media)[0-9]+\\.iso$", str::regex::icase);
457 if(str::regex_match(isofile, what, e))
460 isofile = what[1] + what[2] + str::numstring(medianr) + ".iso";
461 url.setQueryParam("iso", isofile);
462 DBG << "Url rewrite result: " << url << endl;
468 std::string pathname = url_r.getPathName();
469 str::regex e("^(.*)(cd|dvd|media)[0-9]+(/)?$", str::regex::icase);
471 if(str::regex_match(pathname, what, e))
474 pathname = what[1] + what[2] + str::numstring(medianr) + what[3];
475 url.setPathName(pathname);
476 DBG << "Url rewrite result: " << url << endl;
483 void MediaSetAccess::release()
485 DBG << "Releasing all media IDs held by this MediaSetAccess" << endl;
486 media::MediaManager manager;
487 for (MediaMap::const_iterator m = _medias.begin(); m != _medias.end(); ++m)
488 manager.release(m->second, "");
491 std::ostream & MediaSetAccess::dumpOn( std::ostream & str ) const
493 str << "MediaSetAccess (URL='" << _url << "', attach_point_hint='" << _prefAttachPoint << "')";
497 /////////////////////////////////////////////////////////////////
499 ///////////////////////////////////////////////////////////////////