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