libzypp  17.27.0
MediaSetAccess.cc
Go to the documentation of this file.
1 /*---------------------------------------------------------------------\
2 | ____ _ __ __ ___ |
3 | |__ / \ / / . \ . \ |
4 | / / \ V /| _/ _/ |
5 | / /__ | | | | | | |
6 | /_____||_| |_| |_| |
7 | |
8 \---------------------------------------------------------------------*/
9 
10 #include <iostream>
11 #include <fstream>
12 
13 #include <zypp/base/LogTools.h>
14 #include <zypp/base/Regex.h>
17 #include <zypp/ZYppCallbacks.h>
18 #include <zypp/MediaSetAccess.h>
19 #include <zypp/PathInfo.h>
20 #include <zypp/TmpPath.h>
21 //#include <zypp/source/MediaSetAccessReportReceivers.h>
22 
23 #undef ZYPP_BASE_LOGGER_LOGGROUP
24 #define ZYPP_BASE_LOGGER_LOGGROUP "zypp::fetcher"
25 
26 using std::endl;
27 
29 namespace zypp
30 {
31 
33 
35 
37  const Pathname & prefered_attach_point)
38  : _url(url)
39  , _prefAttachPoint(prefered_attach_point)
40  {}
41 
42  MediaSetAccess::MediaSetAccess(const std::string & label_r,
43  const Url &url,
44  const Pathname & prefered_attach_point)
45  : _url(url)
46  , _prefAttachPoint(prefered_attach_point)
47  , _label( label_r )
48  {}
49 
51  {
52  try
53  {
54  media::MediaManager manager;
55  for ( const auto & mm : _medias )
56  manager.close( mm.second );
57  }
58  catch(...) {} // don't let exception escape a dtor.
59  }
60 
61 
63  {
64  if (_medias.find(media_nr) != _medias.end())
65  {
66  // the media already exists, set theverifier
67  media::MediaAccessId id = _medias[media_nr];
68  media::MediaManager media_mgr;
69  media_mgr.addVerifier( id, verifier );
70  // remove any saved verifier for this media
71  _verifiers.erase(media_nr);
72  }
73  else
74  {
75  // save the verifier in the map, and set it when
76  // the media number is first attached
77  _verifiers[media_nr] = verifier;
78  }
79  }
80 
81  void MediaSetAccess::releaseFile( const OnMediaLocation & on_media_file )
82  {
83  releaseFile( on_media_file.filename(), on_media_file.medianr() );
84  }
85 
86  void MediaSetAccess::releaseFile( const Pathname & file, unsigned media_nr)
87  {
88  media::MediaManager media_mgr;
90 
91  media = getMediaAccessId( media_nr);
92  DBG << "Going to release file " << file
93  << " from media number " << media_nr << endl;
94 
95  if ( ! media_mgr.isAttached(media) )
96  return; //disattached media is free
97 
98  media_mgr.releaseFile (media, file);
99  }
100 
102  bool dots, unsigned media_nr )
103  {
104  media::MediaManager media_mgr;
105  media::MediaAccessId media;
106  media = getMediaAccessId(media_nr);
107 
108  // try to attach the media
109  if ( ! media_mgr.isAttached(media) )
110  media_mgr.attach(media);
111 
112  media_mgr.dirInfo(media, retlist, dirname, dots);
113  }
114 
116  {
119  {
120  media::MediaManager media_mgr;
121  media_mgr.provideFile( media, file );
122  result = media_mgr.localPath( media, file.filename() );
123  }
124  };
125 
127  {
130  {
131  const auto &fName = file.filename();
132  media::MediaManager media_mgr;
133  media_mgr.provideDirTree( media, fName );
134  result = media_mgr.localPath( media, fName );
135  }
136  };
137 
139  {
142  {
143  const auto &fName = file.filename();
144  media::MediaManager media_mgr;
145  media_mgr.provideDir( media, fName );
146  result = media_mgr.localPath( media, fName );
147  }
148  };
149 
151  {
152  bool result;
154  : result(false)
155  {}
156 
158  {
159  const auto &fName = file.filename();
160  media::MediaManager media_mgr;
161  result = media_mgr.doesFileExist( media, fName );
162  }
163  };
164 
165  Pathname MediaSetAccess::provideFile( const OnMediaLocation &resource, ProvideFileOptions options )
166  {
168  provide( boost::ref(op), resource, options );
169  return op.result;
170  }
171 
172  Pathname MediaSetAccess::provideFile( const OnMediaLocation & resource, ProvideFileOptions options, const Pathname &deltafile )
173  {
174  return provideFile( OnMediaLocation( resource ).setDeltafile( deltafile ), options );
175  }
176 
177  Pathname MediaSetAccess::provideFile(const Pathname & file, unsigned media_nr, ProvideFileOptions options )
178  {
179  return provideFile( OnMediaLocation( file, media_nr ), options );
180  }
181 
182  Pathname MediaSetAccess::provideOptionalFile( const Pathname & file, unsigned media_nr )
183  {
184  try
185  {
186  if ( doesFileExist( file, media_nr ) )
187  return provideFile( OnMediaLocation( file, media_nr ), PROVIDE_NON_INTERACTIVE );
188  }
189  catch ( const media::MediaFileNotFoundException & excpt_r )
190  { ZYPP_CAUGHT( excpt_r ); }
191  catch ( const media::MediaForbiddenException & excpt_r )
192  { ZYPP_CAUGHT( excpt_r ); }
193  catch ( const media::MediaNotAFileException & excpt_r )
194  { ZYPP_CAUGHT( excpt_r ); }
195  return Pathname();
196  }
197 
198  ManagedFile MediaSetAccess::provideFileFromUrl(const Url &file_url, ProvideFileOptions options)
199  {
200  Url url(file_url);
201  Pathname path(url.getPathName());
202 
203  url.setPathName ("/");
204  MediaSetAccess access(url);
205 
207 
208  Pathname file = access.provideFile( OnMediaLocation(path, 1), options );
209 
210  //prevent the file from being deleted when MediaSetAccess gets out of scope
211  if ( filesystem::hardlinkCopy(file, tmpFile) != 0 )
212  ZYPP_THROW(Exception("Can't copy file from " + file.asString() + " to " + tmpFile->asString() ));
213 
214  return tmpFile;
215  }
216 
218  {
219  try
220  {
221  return provideFileFromUrl( file_url, PROVIDE_NON_INTERACTIVE );
222  }
223  catch ( const media::MediaFileNotFoundException & excpt_r )
224  { ZYPP_CAUGHT( excpt_r ); }
225  catch ( const media::MediaNotAFileException & excpt_r )
226  { ZYPP_CAUGHT( excpt_r ); }
227  return ManagedFile();
228  }
229 
230  bool MediaSetAccess::doesFileExist(const Pathname & file, unsigned media_nr )
231  {
233  OnMediaLocation resource(file, media_nr);
234  provide( boost::ref(op), resource, PROVIDE_DEFAULT );
235  return op.result;
236  }
237 
238  void MediaSetAccess::precacheFiles(const std::vector<OnMediaLocation> &files)
239  {
240  media::MediaManager media_mgr;
241 
242  for ( const auto &resource : files ) {
243  Pathname file(resource.filename());
244  unsigned media_nr(resource.medianr());
245  media::MediaAccessId media = getMediaAccessId( media_nr );
246 
247  if ( !media_mgr.isOpen( media ) ) {
248  MIL << "Skipping precache of file " << resource.filename() << " media is not open";
249  continue;
250  }
251 
252  if ( ! media_mgr.isAttached(media) )
253  media_mgr.attach(media);
254 
255  media_mgr.precacheFiles( media, { resource } );
256  }
257  }
258 
260  const OnMediaLocation &resource,
261  ProvideFileOptions options )
262  {
263  const auto &file(resource.filename());
264  unsigned media_nr(resource.medianr());
265 
267  media::MediaManager media_mgr;
268 
269  media::MediaAccessId media;
270 
271  do
272  {
273  // get the mediaId, but don't try to attach it here
274  media = getMediaAccessId( media_nr);
275 
276  try
277  {
278  DBG << "Going to try to provide " << (resource.optional() ? "optional" : "") << " file " << file
279  << " from media number " << media_nr << endl;
280  // try to attach the media
281  if ( ! media_mgr.isAttached(media) )
282  media_mgr.attach(media);
283  op(media, resource);
284  break;
285  }
286  catch ( media::MediaException & excp )
287  {
288  ZYPP_CAUGHT(excp);
290  unsigned int devindex = 0;
291  std::vector<std::string> devices;
292  media_mgr.getDetectedDevices(media, devices, devindex);
293 
294  do
295  {
296  if (user != media::MediaChangeReport::EJECT) // no use in calling this again
297  {
298  DBG << "Media couldn't provide file " << file << " , releasing." << endl;
299  try
300  {
301  media_mgr.release(media);
302  }
303  catch (const Exception & excpt_r)
304  {
305  ZYPP_CAUGHT(excpt_r);
306  MIL << "Failed to release media " << media << endl;
307  }
308  }
309 
310  // set up the reason
312 
313  if( typeid(excp) == typeid( media::MediaFileNotFoundException ) ||
314  typeid(excp) == typeid( media::MediaNotAFileException ) )
315  {
317  }
318  else if( typeid(excp) == typeid( media::MediaNotDesiredException) ||
319  typeid(excp) == typeid( media::MediaNotAttachedException) )
320  {
322  }
323  else if( typeid(excp) == typeid( media::MediaTimeoutException) ||
324  typeid(excp) == typeid( media::MediaTemporaryProblemException))
325  {
327  }
328 
329  // Propagate the original error if _no_ callback receiver is connected, or
330  // non_interactive mode (for optional files) is used (except for wrong media).
332  || (( options & PROVIDE_NON_INTERACTIVE ) && reason != media::MediaChangeReport::WRONG ) )
333  {
334  MIL << "Can't provide file. Non-Interactive mode." << endl;
335  ZYPP_RETHROW(excp);
336  }
337  else
338  {
339  // release all media before requesting another (#336881)
340  media_mgr.releaseAll();
341 
342  user = report->requestMedia (
343  _url,
344  media_nr,
345  _label,
346  reason,
347  excp.asUserHistory(),
348  devices,
349  devindex
350  );
351  }
352 
353  MIL << "ProvideFile exception caught, callback answer: " << user << endl;
354 
355  if( user == media::MediaChangeReport::ABORT )
356  {
357  DBG << "Aborting" << endl;
358  AbortRequestException aexcp("Aborting requested by user");
359  aexcp.remember(excp);
360  ZYPP_THROW(aexcp);
361  }
362  else if ( user == media::MediaChangeReport::IGNORE )
363  {
364  DBG << "Skipping" << endl;
365  SkipRequestException nexcp("User-requested skipping of a file");
366  nexcp.remember(excp);
367  ZYPP_THROW(nexcp);
368  }
369  else if ( user == media::MediaChangeReport::EJECT )
370  {
371  DBG << "Eject: try to release" << endl;
372  try
373  {
374  media_mgr.releaseAll();
375  media_mgr.release (media, devindex < devices.size() ? devices[devindex] : "");
376  }
377  catch ( const Exception & e)
378  {
379  ZYPP_CAUGHT(e);
380  }
381  }
382  else if ( user == media::MediaChangeReport::RETRY ||
384  {
385  // retry
386  DBG << "Going to try again" << endl;
387  // invalidate current media access id
388  media_mgr.close(media);
389  _medias.erase(media_nr);
390 
391  // not attaching, media set will do that for us
392  // this could generate uncaught exception (#158620)
393  break;
394  }
395  else
396  {
397  DBG << "Don't know, let's ABORT" << endl;
398  ZYPP_RETHROW ( excp );
399  }
400  } while( user == media::MediaChangeReport::EJECT );
401  }
402 
403  // retry or change URL
404  } while( true );
405  }
406 
408  bool recursive,
409  unsigned media_nr,
410  ProvideFileOptions options )
411  {
412  OnMediaLocation resource(dir, media_nr);
413  if ( recursive )
414  {
416  provide( boost::ref(op), resource, options );
417  return op.result;
418  }
420  provide( boost::ref(op), resource, options );
421  return op.result;
422  }
423 
425  {
426  if ( _medias.find( medianr ) != _medias.end() )
427  {
428  return _medias[medianr];
429  }
430 
431  Url url( medianr > 1 ? rewriteUrl( _url, medianr ) : _url );
432  media::MediaManager media_mgr;
433  media::MediaAccessId id = media_mgr.open( url, _prefAttachPoint );
434  _medias[medianr] = id;
435 
436  try
437  {
438  if ( _verifiers.find(medianr) != _verifiers.end() )
439  {
440  // a verifier is set for this media
441  // FIXME check the case where the verifier exists
442  // but we have no access id for the media
443  media_mgr.delVerifier( id );
444  media_mgr.addVerifier( id, _verifiers[medianr] );
445  // remove any saved verifier for this media
446  _verifiers.erase( medianr );
447  }
448  }
449  catch ( const Exception &e )
450  {
451  ZYPP_CAUGHT(e);
452  WAR << "Verifier not found" << endl;
453  }
454 
455  return id;
456  }
457 
458 
459  Url MediaSetAccess::rewriteUrl (const Url & url_r, const media::MediaNr medianr)
460  {
461  std::string scheme = url_r.getScheme();
462  if (scheme == "cd" || scheme == "dvd")
463  return url_r;
464 
465  DBG << "Rewriting url " << url_r << endl;
466 
467  if( scheme == "iso")
468  {
469  // TODO the iso parameter will not be required in the future, this
470  // code has to be adapted together with the MediaISO change.
471  // maybe some MediaISOURL interface should be used.
472  std::string isofile = url_r.getQueryParam("iso");
473  str::regex e("^(.*)(cd|dvd|media)[0-9]+\\.iso$", str::regex::icase);
474 
475  str::smatch what;
476  if(str::regex_match(isofile, what, e))
477  {
478  Url url( url_r);
479  isofile = what[1] + what[2] + str::numstring(medianr) + ".iso";
480  url.setQueryParam("iso", isofile);
481  DBG << "Url rewrite result: " << url << endl;
482  return url;
483  }
484  }
485  else
486  {
487  std::string pathname = url_r.getPathName();
488  str::regex e("^(.*)(cd|dvd|media)[0-9]+(/)?$", str::regex::icase);
489  str::smatch what;
490  if(str::regex_match(pathname, what, e))
491  {
492  Url url( url_r);
493  pathname = what[1] + what[2] + str::numstring(medianr) + what[3];
494  url.setPathName(pathname);
495  DBG << "Url rewrite result: " << url << endl;
496  return url;
497  }
498  }
499  return url_r;
500  }
501 
503  {
504  DBG << "Releasing all media IDs held by this MediaSetAccess" << endl;
505  media::MediaManager manager;
506  for (MediaMap::const_iterator m = _medias.begin(); m != _medias.end(); ++m)
507  manager.release(m->second, "");
508  }
509 
510  std::ostream & MediaSetAccess::dumpOn( std::ostream & str ) const
511  {
512  str << "MediaSetAccess (URL='" << _url << "', attach_point_hint='" << _prefAttachPoint << "')";
513  return str;
514  }
515 
517 } // namespace zypp
MediaVerifierRef verifier
Pathname deltafile
Reference counted access to a Tp object calling a custom Dispose function when the last AutoDispose h...
Definition: AutoDispose.h:93
Base class for Exception.
Definition: Exception.h:146
std::string asUserHistory() const
A single (multiline) string composed of asUserString and historyAsString.
Definition: Exception.cc:91
Media access layer responsible for handling files distributed on a set of media with media change and...
VerifierMap _verifiers
Mapping between media number and corespondent verifier.
media::MediaAccessId getMediaAccessId(media::MediaNr medianr)
Pathname provideDir(const Pathname &dir, bool recursive, unsigned media_nr=1, ProvideFileOptions options=PROVIDE_DEFAULT)
Provides direcotry dir from media number media_nr.
MediaMap _medias
Mapping between media number and Media Access ID.
virtual std::ostream & dumpOn(std::ostream &str) const
Overload to realize std::ostream & operator<<.
void precacheFiles(const std::vector< OnMediaLocation > &files)
Tries to fetch the given files and precaches them.
function< void(media::MediaAccessId, const OnMediaLocation &)> ProvideOperation
static ManagedFile provideFileFromUrl(const Url &file_url, ProvideFileOptions options=PROVIDE_DEFAULT)
Provides file from url.
@ PROVIDE_DEFAULT
The user is not asked anything, and the error exception is just propagated.
Pathname provideFile(const OnMediaLocation &resource, ProvideFileOptions options=PROVIDE_DEFAULT)
Provides a file from a media location.
Pathname provideOptionalFile(const Pathname &file, unsigned media_nr=1)
Provides an optional file from media media_nr.
static ManagedFile provideOptionalFileFromUrl(const Url &file_url)
Provides an optional file from url.
void setVerifier(unsigned media_nr, media::MediaVerifierRef verifier)
Sets a MediaVerifier verifier for given media number.
bool doesFileExist(const Pathname &file, unsigned media_nr=1)
Checks if a file exists on the specified media, with user callbacks.
void dirInfo(filesystem::DirContent &retlist, const Pathname &dirname, bool dots=true, unsigned media_nr=1)
Fills retlist with directory information.
MediaSetAccess(const Url &url, const Pathname &prefered_attach_point="")
Creates a callback enabled media access for specified url.
void release()
Release all attached media of this set.
Pathname _prefAttachPoint
Prefered mount point.
static Url rewriteUrl(const Url &url_r, const media::MediaNr medianr)
Replaces media number in specified url with given medianr.
void provide(ProvideOperation op, const OnMediaLocation &resource, ProvideFileOptions options)
Url _url
Media or media set URL.
void releaseFile(const OnMediaLocation &resource)
Release file from media.
Describes a resource file located on a medium.
bool optional() const
Whether this is an optional resource.
const Pathname & filename() const
The path to the resource on the medium.
unsigned medianr() const
The media number the resource is located on.
Url manipulation class.
Definition: Url.h:92
std::string getScheme() const
Returns the scheme name of the URL.
Definition: Url.cc:528
std::string getPathName(EEncoding eflag=zypp::url::E_DECODED) const
Returns the path name from the URL.
Definition: Url.cc:599
std::string getQueryParam(const std::string &param, EEncoding eflag=zypp::url::E_DECODED) const
Return the value for the specified query parameter.
Definition: Url.cc:655
void setPathName(const std::string &path, EEncoding eflag=zypp::url::E_DECODED)
Set the path name.
Definition: Url.cc:759
void setQueryParam(const std::string &param, const std::string &value)
Set or add value for the specified query parameter.
Definition: Url.cc:833
const std::string & asString() const
String representation.
Definition: Pathname.h:91
static ManagedFile asManagedFile()
Create a temporary file and convert it to a automatically cleaned up ManagedFile.
Definition: TmpPath.cc:230
Just inherits Exception to separate media exceptions.
Manages access to the 'physical' media, e.g CDROM drives, Disk volumes, directory trees,...
Definition: MediaManager.h:454
MediaAccessId open(const Url &url, const Pathname &preferred_attach_point="")
Opens the media access for specified with the url.
void delVerifier(MediaAccessId accessId)
Remove verifier for specified media id.
void releaseFile(MediaAccessId accessId, const Pathname &filename) const
FIXME: see MediaAccess class.
void releaseAll()
Release all attached media.
void attach(MediaAccessId accessId)
Attach the media using the concrete handler (checks all devices).
bool isOpen(MediaAccessId accessId) const
Query if the media access is open / exists.
void dirInfo(MediaAccessId accessId, std::list< std::string > &retlist, const Pathname &dirname, bool dots=true) const
FIXME: see MediaAccess class.
void close(MediaAccessId accessId)
Close the media access with specified id.
ZYPP_DEPRECATED void provideFile(MediaAccessId accessId, const Pathname &filename, const ByteCount &expectedFileSize) const
void release(MediaAccessId accessId, const std::string &ejectDev="")
Release the attached media and optionally eject.
void precacheFiles(MediaAccessId accessId, const std::vector< OnMediaLocation > &files)
Tries to fetch the given files and precaches them.
bool isAttached(MediaAccessId accessId) const
Check if media is attached or not.
bool doesFileExist(MediaAccessId accessId, const Pathname &filename) const
FIXME: see MediaAccess class.
void provideDir(MediaAccessId accessId, const Pathname &dirname) const
FIXME: see MediaAccess class.
Pathname localPath(MediaAccessId accessId, const Pathname &pathname) const
Shortcut for 'localRoot() + pathname', but returns an empty pathname if media is not attached.
void provideDirTree(MediaAccessId accessId, const Pathname &dirname) const
FIXME: see MediaAccess class.
void addVerifier(MediaAccessId accessId, const MediaVerifierRef &verifier)
Add verifier implementation for the specified media id.
void getDetectedDevices(MediaAccessId accessId, std::vector< std::string > &devices, unsigned int &index) const
Fill in a vector of detected ejectable devices and the index of the currently attached device within ...
Regular expression.
Definition: Regex.h:95
@ icase
Do not differentiate case.
Definition: Regex.h:99
Regular expression match result.
Definition: Regex.h:168
String related utilities and Regular expression matching.
int hardlinkCopy(const Pathname &oldpath, const Pathname &newpath)
Create newpath as hardlink or copy of oldpath.
Definition: PathInfo.cc:823
std::list< DirEntry > DirContent
Returned by readdir.
Definition: PathInfo.h:514
unsigned int MediaNr
Definition: MediaManager.h:30
unsigned int MediaAccessId
Media manager access Id type.
Definition: MediaSource.h:29
std::string numstring(char n, int w=0)
Definition: String.h:289
bool regex_match(const std::string &s, smatch &matches, const regex &regex)
\relates regex \ingroup ZYPP_STR_REGEX \relates regex \ingroup ZYPP_STR_REGEX
Definition: Regex.h:70
Easy-to use interface to the ZYPP dependency resolver.
Definition: CodePitfalls.doc:2
AutoDispose< const Pathname > ManagedFile
A Pathname plus associated cleanup code to be executed when path is no longer needed.
Definition: ManagedFile.h:27
IMPL_PTR_TYPE(Application)
void operator()(media::MediaAccessId media, const OnMediaLocation &file)
void operator()(media::MediaAccessId media, const OnMediaLocation &file)
void operator()(media::MediaAccessId media, const OnMediaLocation &file)
void operator()(media::MediaAccessId media, const OnMediaLocation &file)
Wrapper for const correct access via Smart pointer types.
Definition: PtrTypes.h:286
@ IO_SOFT
IO error which can happen on worse connection like timeout exceed.
#define ZYPP_RETHROW(EXCPT)
Drops a logline and rethrows, updating the CodeLocation.
Definition: Exception.h:400
#define ZYPP_CAUGHT(EXCPT)
Drops a logline telling the Exception was caught (in order to handle it).
Definition: Exception.h:396
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
Definition: Exception.h:392
#define DBG
Definition: Logger.h:95
#define MIL
Definition: Logger.h:96
#define WAR
Definition: Logger.h:97