libzypp  17.14.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"
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"
21 
22 using namespace std;
23 
25 namespace zypp
26 {
27 
29 
31 
32  MediaSetAccess::MediaSetAccess(const Url &url,
33  const Pathname & prefered_attach_point)
34  : _url(url)
35  , _prefAttachPoint(prefered_attach_point)
36  {}
37 
38  MediaSetAccess::MediaSetAccess(const std::string & label_r,
39  const Url &url,
40  const Pathname & prefered_attach_point)
41  : _url(url)
42  , _prefAttachPoint(prefered_attach_point)
43  , _label( label_r )
44  {}
45 
47  {
48  try
49  {
50  media::MediaManager manager;
51  for ( const auto & mm : _medias )
52  manager.close( mm.second );
53  }
54  catch(...) {} // don't let exception escape a dtor.
55  }
56 
57 
59  {
60  if (_medias.find(media_nr) != _medias.end())
61  {
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);
68  }
69  else
70  {
71  // save the verifier in the map, and set it when
72  // the media number is first attached
73  _verifiers[media_nr] = verifier;
74  }
75  }
76 
77  void MediaSetAccess::releaseFile( const OnMediaLocation & on_media_file )
78  {
79  releaseFile( on_media_file.filename(), on_media_file.medianr() );
80  }
81 
82  void MediaSetAccess::releaseFile( const Pathname & file, unsigned media_nr)
83  {
84  media::MediaManager media_mgr;
86 
87  media = getMediaAccessId( media_nr);
88  DBG << "Going to release file " << file
89  << " from media number " << media_nr << endl;
90 
91  if ( ! media_mgr.isAttached(media) )
92  return; //disattached media is free
93 
94  media_mgr.releaseFile (media, file);
95  }
96 
98  bool dots, unsigned media_nr )
99  {
100  media::MediaManager media_mgr;
101  media::MediaAccessId media;
102  media = getMediaAccessId(media_nr);
103 
104  // try to attach the media
105  if ( ! media_mgr.isAttached(media) )
106  media_mgr.attach(media);
107 
108  media_mgr.dirInfo(media, retlist, dirname, dots);
109  }
110 
112  {
115  void operator()( media::MediaAccessId media, const Pathname &file )
116  {
117  media::MediaManager media_mgr;
118  media_mgr.provideFile(media, file, expectedFileSize);
119  result = media_mgr.localPath(media, file);
120  }
121  };
122 
124  {
126  void operator()( media::MediaAccessId media, const Pathname &file )
127  {
128  media::MediaManager media_mgr;
129  media_mgr.provideDirTree(media, file);
130  result = media_mgr.localPath(media, file);
131  }
132  };
133 
135  {
137  void operator()( media::MediaAccessId media, const Pathname &file )
138  {
139  media::MediaManager media_mgr;
140  media_mgr.provideDir(media, file);
141  result = media_mgr.localPath(media, file);
142  }
143  };
144 
146  {
147  bool result;
149  : result(false)
150  {}
151 
152  void operator()( media::MediaAccessId media, const Pathname &file )
153  {
154  media::MediaManager media_mgr;
155  result = media_mgr.doesFileExist(media, file);
156  }
157  };
158 
159 
160 
161  Pathname MediaSetAccess::provideFile( const OnMediaLocation & resource, ProvideFileOptions options, const Pathname &deltafile )
162  {
164  op.expectedFileSize = resource.downloadSize();
165  provide( boost::ref(op), resource, options, deltafile );
166  return op.result;
167  }
168 
169  Pathname MediaSetAccess::provideFile(const Pathname & file, unsigned media_nr, ProvideFileOptions options )
170  {
171  OnMediaLocation resource;
173  resource.setLocation(file, media_nr);
174  provide( boost::ref(op), resource, options, Pathname() );
175  return op.result;
176  }
177 
178  Pathname MediaSetAccess::provideOptionalFile( const Pathname & file, unsigned media_nr )
179  {
180  try
181  {
182  if ( doesFileExist( file, media_nr ) )
183  return provideFile( file, media_nr, PROVIDE_NON_INTERACTIVE );
184  }
185  catch ( const media::MediaFileNotFoundException & excpt_r )
186  { ZYPP_CAUGHT( excpt_r ); }
187  catch ( const media::MediaNotAFileException & excpt_r )
188  { ZYPP_CAUGHT( excpt_r ); }
189  return Pathname();
190  }
191 
192  ManagedFile MediaSetAccess::provideFileFromUrl(const Url &file_url, ProvideFileOptions options)
193  {
194  Url url(file_url);
195  Pathname path(url.getPathName());
196  url.setPathName ("/");
197  MediaSetAccess access(url);
198 
200 
201  Pathname file = access.provideFile(path, 1, options);
202 
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() ));
206 
207  return tmpFile;
208  }
209 
211  {
212  try
213  {
214  return provideFileFromUrl( file_url, PROVIDE_NON_INTERACTIVE );
215  }
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();
221  }
222 
223  bool MediaSetAccess::doesFileExist(const Pathname & file, unsigned media_nr )
224  {
226  OnMediaLocation resource;
227  resource.setLocation(file, media_nr);
228  provide( boost::ref(op), resource, PROVIDE_DEFAULT, Pathname());
229  return op.result;
230  }
231 
233  const OnMediaLocation &resource,
234  ProvideFileOptions options,
235  const Pathname &deltafile )
236  {
237  Pathname file(resource.filename());
238  unsigned media_nr(resource.medianr());
239 
241  media::MediaManager media_mgr;
242 
243  media::MediaAccessId media;
244 
245  do
246  {
247  // get the mediaId, but don't try to attach it here
248  media = getMediaAccessId( media_nr);
249  bool deltafileset = false;
250 
251  try
252  {
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);
259  deltafileset = true;
260  op(media, file);
261  media_mgr.setDeltafile(media, Pathname());
262  break;
263  }
264  catch ( media::MediaException & excp )
265  {
266  ZYPP_CAUGHT(excp);
267  if (deltafileset)
268  media_mgr.setDeltafile(media, Pathname());
270  unsigned int devindex = 0;
271  vector<string> devices;
272  media_mgr.getDetectedDevices(media, devices, devindex);
273 
274  do
275  {
276  if (user != media::MediaChangeReport::EJECT) // no use in calling this again
277  {
278  DBG << "Media couldn't provide file " << file << " , releasing." << endl;
279  try
280  {
281  media_mgr.release(media);
282  }
283  catch (const Exception & excpt_r)
284  {
285  ZYPP_CAUGHT(excpt_r);
286  MIL << "Failed to release media " << media << endl;
287  }
288  }
289 
290  // set up the reason
292 
293  if( typeid(excp) == typeid( media::MediaFileNotFoundException ) ||
294  typeid(excp) == typeid( media::MediaNotAFileException ) )
295  {
297  }
298  else if( typeid(excp) == typeid( media::MediaNotDesiredException) ||
299  typeid(excp) == typeid( media::MediaNotAttachedException) )
300  {
302  }
303  else if( typeid(excp) == typeid( media::MediaTimeoutException) ||
304  typeid(excp) == typeid( media::MediaTemporaryProblemException))
305  {
307  }
308 
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).
312  || (( options & PROVIDE_NON_INTERACTIVE ) && reason != media::MediaChangeReport::WRONG ) )
313  {
314  MIL << "Can't provide file. Non-Interactive mode." << endl;
315  ZYPP_RETHROW(excp);
316  }
317  else
318  {
319  // release all media before requesting another (#336881)
320  media_mgr.releaseAll();
321 
322  user = report->requestMedia (
323  _url,
324  media_nr,
325  _label,
326  reason,
327  excp.asUserHistory(),
328  devices,
329  devindex
330  );
331  }
332 
333  MIL << "ProvideFile exception caught, callback answer: " << user << endl;
334 
335  if( user == media::MediaChangeReport::ABORT )
336  {
337  DBG << "Aborting" << endl;
338  AbortRequestException aexcp("Aborting requested by user");
339  aexcp.remember(excp);
340  ZYPP_THROW(aexcp);
341  }
342  else if ( user == media::MediaChangeReport::IGNORE )
343  {
344  DBG << "Skipping" << endl;
345  SkipRequestException nexcp("User-requested skipping of a file");
346  nexcp.remember(excp);
347  ZYPP_THROW(nexcp);
348  }
349  else if ( user == media::MediaChangeReport::EJECT )
350  {
351  DBG << "Eject: try to release" << endl;
352  try
353  {
354  media_mgr.releaseAll();
355  media_mgr.release (media, devindex < devices.size() ? devices[devindex] : "");
356  }
357  catch ( const Exception & e)
358  {
359  ZYPP_CAUGHT(e);
360  }
361  }
362  else if ( user == media::MediaChangeReport::RETRY ||
364  {
365  // retry
366  DBG << "Going to try again" << endl;
367  // invalidate current media access id
368  media_mgr.close(media);
369  _medias.erase(media_nr);
370 
371  // not attaching, media set will do that for us
372  // this could generate uncaught exception (#158620)
373  break;
374  }
375  else
376  {
377  DBG << "Don't know, let's ABORT" << endl;
378  ZYPP_RETHROW ( excp );
379  }
380  } while( user == media::MediaChangeReport::EJECT );
381  }
382 
383  // retry or change URL
384  } while( true );
385  }
386 
388  bool recursive,
389  unsigned media_nr,
390  ProvideFileOptions options )
391  {
392  OnMediaLocation resource;
393  resource.setLocation(dir, media_nr);
394  if ( recursive )
395  {
397  provide( boost::ref(op), resource, options, Pathname());
398  return op.result;
399  }
401  provide( boost::ref(op), resource, options, Pathname());
402  return op.result;
403  }
404 
406  {
407  if ( _medias.find( medianr ) != _medias.end() )
408  {
409  return _medias[medianr];
410  }
411 
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;
416 
417  try
418  {
419  if ( _verifiers.find(medianr) != _verifiers.end() )
420  {
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 );
428  }
429  }
430  catch ( const Exception &e )
431  {
432  ZYPP_CAUGHT(e);
433  WAR << "Verifier not found" << endl;
434  }
435 
436  return id;
437  }
438 
439 
440  Url MediaSetAccess::rewriteUrl (const Url & url_r, const media::MediaNr medianr)
441  {
442  std::string scheme = url_r.getScheme();
443  if (scheme == "cd" || scheme == "dvd")
444  return url_r;
445 
446  DBG << "Rewriting url " << url_r << endl;
447 
448  if( scheme == "iso")
449  {
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);
455 
456  str::smatch what;
457  if(str::regex_match(isofile, what, e))
458  {
459  Url url( url_r);
460  isofile = what[1] + what[2] + str::numstring(medianr) + ".iso";
461  url.setQueryParam("iso", isofile);
462  DBG << "Url rewrite result: " << url << endl;
463  return url;
464  }
465  }
466  else
467  {
468  std::string pathname = url_r.getPathName();
469  str::regex e("^(.*)(cd|dvd|media)[0-9]+(/)?$", str::regex::icase);
470  str::smatch what;
471  if(str::regex_match(pathname, what, e))
472  {
473  Url url( url_r);
474  pathname = what[1] + what[2] + str::numstring(medianr) + what[3];
475  url.setPathName(pathname);
476  DBG << "Url rewrite result: " << url << endl;
477  return url;
478  }
479  }
480  return url_r;
481  }
482 
484  {
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, "");
489  }
490 
491  std::ostream & MediaSetAccess::dumpOn( std::ostream & str ) const
492  {
493  str << "MediaSetAccess (URL='" << _url << "', attach_point_hint='" << _prefAttachPoint << "')";
494  return str;
495  }
496 
498 } // 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:528
#define MIL
Definition: Logger.h:79
void provide(ProvideOperation op, const OnMediaLocation &resource, ProvideFileOptions options, const Pathname &deltafile)
void provideDirTree(MediaAccessId accessId, const Pathname &dirname) const
FIXME: see MediaAccess class.
void setDeltafile(MediaAccessId accessId, const Pathname &filename) const
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
Definition: Exception.h:392
Describes a path on a certain media amongs as the information required to download it,...
Regular expression.
Definition: Regex.h:86
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.
Store and operate with byte count.
Definition: ByteCount.h:30
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.
const ByteCount & downloadSize() const
The size of the resource on the server.
virtual std::ostream & dumpOn(std::ostream &str) const
Overload to realize std::ostream & operator<<.
IO error which can happen on worse connection like timeout exceed.
String related utilities and Regular expression matching.
bool doesFileExist(const Pathname &file, unsigned media_nr=1)
Checks if a file exists on the specified media, with user callbacks.
Definition: Arch.h:344
AutoDispose< const Pathname > ManagedFile
A Pathname plus associated cleanup code to be executed when path is no longer needed.
Definition: ManagedFile.h:27
Url url
Definition: MediaCurl.cc:180
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.
void provideFile(MediaAccessId accessId, const Pathname &filename, const ByteCount &expectedFileSize) const
Provide provide file denoted by relative path below of the 'attach point' of the specified media and ...
const bool optional() const
whether this is an optional resource.
unsigned int MediaAccessId
Media manager access Id type.
Definition: MediaSource.h:29
void operator()(media::MediaAccessId media, const Pathname &file)
Pathname localPath(MediaAccessId accessId, const Pathname &pathname) const
Shortcut for 'localRoot() + pathname', but returns an empty pathname if media is not attached.
void releaseFile(const OnMediaLocation &resource)
Release file from media.
unsigned medianr() const
media number where the resource is located.
void release(MediaAccessId accessId, const std::string &ejectDev="")
Release the attached media and optionally eject.
#define ZYPP_RETHROW(EXCPT)
Drops a logline and rethrows, updating the CodeLocation.
Definition: Exception.h:400
Do not differentiate case.
Definition: Regex.h:91
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
const std::string & asString() const
String representation.
Definition: Pathname.h:90
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:91
#define WAR
Definition: Logger.h:80
std::list< DirEntry > DirContent
Returned by readdir.
Definition: PathInfo.h:547
int hardlinkCopy(const Pathname &oldpath, const Pathname &newpath)
Create newpath as hardlink or copy of oldpath.
Definition: PathInfo.cc:836
void addVerifier(MediaAccessId accessId, const MediaVerifierRef &verifier)
Add verifier implementation for the specified media id.
void operator()(media::MediaAccessId media, const Pathname &file)
std::string numstring(char n, int w=0)
Definition: String.h:288
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).
function< void(media::MediaAccessId, const Pathname &)> ProvideOperation
#define ZYPP_CAUGHT(EXCPT)
Drops a logline telling the Exception was caught (in order to handle it).
Definition: Exception.h:396
const Pathname & filename() const
The path to the resource relatve to the url and path.
Regular expression match result.
Definition: Regex.h:145
Manages access to the 'physical' media, e.g CDROM drives, Disk volumes, directory trees,...
Definition: MediaManager.h:470
Base class for Exception.
Definition: Exception.h:145
void operator()(media::MediaAccessId media, const Pathname &file)
void setVerifier(unsigned media_nr, media::MediaVerifierRef verifier)
Sets a MediaVerifier verifier for given media number.
callback::SendReport< DownloadProgressReport > * report
Definition: MediaCurl.cc:184
std::string getPathName(EEncoding eflag=zypp::url::E_DECODED) const
Returns the path name from the URL.
Definition: Url.cc:599
MediaVerifierRef verifier
Wrapper for const correct access via Smart pointer types.
Definition: PtrTypes.h:285
media::MediaAccessId getMediaAccessId(media::MediaNr medianr)
Reference counted access to a Tp object calling a custom Dispose function when the last AutoDispose h...
Definition: AutoDispose.h:92
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
bool isAttached(MediaAccessId accessId) const
Check if media is attached or not.
void operator()(media::MediaAccessId media, const Pathname &file)
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 ...
Easy-to use interface to the ZYPP dependency resolver.
Definition: CodePitfalls.doc:1
Pathname provideFile(const OnMediaLocation &resource, ProvideFileOptions options=PROVIDE_DEFAULT, const Pathname &deltafile=Pathname())
Provides a file from a media location.
MediaSetAccess(const Url &url, const Pathname &prefered_attach_point="")
Creates a callback enabled media access for specified url.
MediaAccessId open(const Url &url, const Pathname &preferred_attach_point="")
Opens the media access for specified with the url.
VerifierMap _verifiers
Mapping between media number and corespondent verifier.
Url manipulation class.
Definition: Url.h:87
void delVerifier(MediaAccessId accessId)
Remove verifier for specified media id.
void releaseFile(MediaAccessId accessId, const Pathname &filename) const
FIXME: see MediaAccess class.
OnMediaLocation & setLocation(const Pathname &val_r, unsigned mediaNumber_r=1)
Set filename and media number (defaults to 1).
#define IMPL_PTR_TYPE(NAME)
unsigned int MediaNr
Definition: MediaManager.h:40
void close(MediaAccessId accessId)
Close the media access with specified id.
#define DBG
Definition: Logger.h:78
static ManagedFile asManagedFile()
Create a temporary file and convert it to a automatically cleaned up ManagedFile.
Definition: TmpPath.cc:230
The user is not asked anything, and the error exception is just propagated.