libzypp  17.8.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  release();
51  }
52  catch(...) {} // don't let exception escape a dtor.
53  }
54 
55 
57  {
58  if (_medias.find(media_nr) != _medias.end())
59  {
60  // the media already exists, set theverifier
61  media::MediaAccessId id = _medias[media_nr];
62  media::MediaManager media_mgr;
63  media_mgr.addVerifier( id, verifier );
64  // remove any saved verifier for this media
65  _verifiers.erase(media_nr);
66  }
67  else
68  {
69  // save the verifier in the map, and set it when
70  // the media number is first attached
71  _verifiers[media_nr] = verifier;
72  }
73  }
74 
75  void MediaSetAccess::releaseFile( const OnMediaLocation & on_media_file )
76  {
77  releaseFile( on_media_file.filename(), on_media_file.medianr() );
78  }
79 
80  void MediaSetAccess::releaseFile( const Pathname & file, unsigned media_nr)
81  {
82  media::MediaManager media_mgr;
84 
85  media = getMediaAccessId( media_nr);
86  DBG << "Going to release file " << file
87  << " from media number " << media_nr << endl;
88 
89  if ( ! media_mgr.isAttached(media) )
90  return; //disattached media is free
91 
92  media_mgr.releaseFile (media, file);
93  }
94 
96  bool dots, unsigned media_nr )
97  {
98  media::MediaManager media_mgr;
100  media = getMediaAccessId(media_nr);
101 
102  // try to attach the media
103  if ( ! media_mgr.isAttached(media) )
104  media_mgr.attach(media);
105 
106  media_mgr.dirInfo(media, retlist, dirname, dots);
107  }
108 
110  {
113  void operator()( media::MediaAccessId media, const Pathname &file )
114  {
115  media::MediaManager media_mgr;
116  media_mgr.provideFile(media, file, expectedFileSize);
117  result = media_mgr.localPath(media, file);
118  }
119  };
120 
122  {
124  void operator()( media::MediaAccessId media, const Pathname &file )
125  {
126  media::MediaManager media_mgr;
127  media_mgr.provideDirTree(media, file);
128  result = media_mgr.localPath(media, file);
129  }
130  };
131 
133  {
135  void operator()( media::MediaAccessId media, const Pathname &file )
136  {
137  media::MediaManager media_mgr;
138  media_mgr.provideDir(media, file);
139  result = media_mgr.localPath(media, file);
140  }
141  };
142 
144  {
145  bool result;
147  : result(false)
148  {}
149 
150  void operator()( media::MediaAccessId media, const Pathname &file )
151  {
152  media::MediaManager media_mgr;
153  result = media_mgr.doesFileExist(media, file);
154  }
155  };
156 
157 
158 
159  Pathname MediaSetAccess::provideFile( const OnMediaLocation & resource, ProvideFileOptions options, const Pathname &deltafile )
160  {
162  op.expectedFileSize = resource.downloadSize();
163  provide( boost::ref(op), resource, options, deltafile );
164  return op.result;
165  }
166 
167  Pathname MediaSetAccess::provideFile(const Pathname & file, unsigned media_nr, ProvideFileOptions options )
168  {
169  OnMediaLocation resource;
171  resource.setLocation(file, media_nr);
172  provide( boost::ref(op), resource, options, Pathname() );
173  return op.result;
174  }
175 
176  Pathname MediaSetAccess::provideOptionalFile( const Pathname & file, unsigned media_nr )
177  {
178  try
179  {
180  if ( doesFileExist( file, media_nr ) )
181  return provideFile( file, media_nr, PROVIDE_NON_INTERACTIVE );
182  }
183  catch ( const media::MediaFileNotFoundException & excpt_r )
184  { ZYPP_CAUGHT( excpt_r ); }
185  catch ( const media::MediaNotAFileException & excpt_r )
186  { ZYPP_CAUGHT( excpt_r ); }
187  return Pathname();
188  }
189 
190  ManagedFile MediaSetAccess::provideFileFromUrl(const Url &file_url, ProvideFileOptions options)
191  {
192  Url url(file_url);
193  Pathname path(url.getPathName());
194  url.setPathName ("/");
195  MediaSetAccess access(url);
196 
198 
199  Pathname file = access.provideFile(path, 1, options);
200 
201  //prevent the file from being deleted when MediaSetAccess gets out of scope
202  if ( filesystem::hardlinkCopy(file, tmpFile) != 0 )
203  ZYPP_THROW(Exception("Can't copy file from " + file.asString() + " to " + tmpFile->asString() ));
204 
205  return tmpFile;
206  }
207 
209  {
210  try
211  {
212  return provideFileFromUrl( file_url, PROVIDE_NON_INTERACTIVE );
213  }
214  catch ( const media::MediaFileNotFoundException & excpt_r )
215  { ZYPP_CAUGHT( excpt_r ); }
216  catch ( const media::MediaNotAFileException & excpt_r )
217  { ZYPP_CAUGHT( excpt_r ); }
218  return ManagedFile();
219  }
220 
221  bool MediaSetAccess::doesFileExist(const Pathname & file, unsigned media_nr )
222  {
224  OnMediaLocation resource;
225  resource.setLocation(file, media_nr);
226  provide( boost::ref(op), resource, PROVIDE_DEFAULT, Pathname());
227  return op.result;
228  }
229 
231  const OnMediaLocation &resource,
232  ProvideFileOptions options,
233  const Pathname &deltafile )
234  {
235  Pathname file(resource.filename());
236  unsigned media_nr(resource.medianr());
237 
239  media::MediaManager media_mgr;
240 
241  media::MediaAccessId media;
242 
243  do
244  {
245  // get the mediaId, but don't try to attach it here
246  media = getMediaAccessId( media_nr);
247  bool deltafileset = false;
248 
249  try
250  {
251  DBG << "Going to try to provide " << (resource.optional() ? "optional" : "") << " file " << file
252  << " from media number " << media_nr << endl;
253  // try to attach the media
254  if ( ! media_mgr.isAttached(media) )
255  media_mgr.attach(media);
256  media_mgr.setDeltafile(media, deltafile);
257  deltafileset = true;
258  op(media, file);
259  media_mgr.setDeltafile(media, Pathname());
260  break;
261  }
262  catch ( media::MediaException & excp )
263  {
264  ZYPP_CAUGHT(excp);
265  if (deltafileset)
266  media_mgr.setDeltafile(media, Pathname());
268  unsigned int devindex = 0;
269  vector<string> devices;
270  media_mgr.getDetectedDevices(media, devices, devindex);
271 
272  do
273  {
274  if (user != media::MediaChangeReport::EJECT) // no use in calling this again
275  {
276  DBG << "Media couldn't provide file " << file << " , releasing." << endl;
277  try
278  {
279  media_mgr.release(media);
280  }
281  catch (const Exception & excpt_r)
282  {
283  ZYPP_CAUGHT(excpt_r);
284  MIL << "Failed to release media " << media << endl;
285  }
286  }
287 
288  // set up the reason
290 
291  if( typeid(excp) == typeid( media::MediaFileNotFoundException ) ||
292  typeid(excp) == typeid( media::MediaNotAFileException ) )
293  {
295  }
296  else if( typeid(excp) == typeid( media::MediaNotDesiredException) ||
297  typeid(excp) == typeid( media::MediaNotAttachedException) )
298  {
300  }
301  else if( typeid(excp) == typeid( media::MediaTimeoutException) ||
302  typeid(excp) == typeid( media::MediaTemporaryProblemException))
303  {
305  }
306 
307  // Propagate the original error if _no_ callback receiver is connected, or
308  // non_interactive mode (for optional files) is used (except for wrong media).
310  || (( options & PROVIDE_NON_INTERACTIVE ) && reason != media::MediaChangeReport::WRONG ) )
311  {
312  MIL << "Can't provide file. Non-Interactive mode." << endl;
313  ZYPP_RETHROW(excp);
314  }
315  else
316  {
317  // release all media before requesting another (#336881)
318  media_mgr.releaseAll();
319 
320  user = report->requestMedia (
321  _url,
322  media_nr,
323  _label,
324  reason,
325  excp.asUserHistory(),
326  devices,
327  devindex
328  );
329  }
330 
331  MIL << "ProvideFile exception caught, callback answer: " << user << endl;
332 
333  if( user == media::MediaChangeReport::ABORT )
334  {
335  DBG << "Aborting" << endl;
336  AbortRequestException aexcp("Aborting requested by user");
337  aexcp.remember(excp);
338  ZYPP_THROW(aexcp);
339  }
340  else if ( user == media::MediaChangeReport::IGNORE )
341  {
342  DBG << "Skipping" << endl;
343  SkipRequestException nexcp("User-requested skipping of a file");
344  nexcp.remember(excp);
345  ZYPP_THROW(nexcp);
346  }
347  else if ( user == media::MediaChangeReport::EJECT )
348  {
349  DBG << "Eject: try to release" << endl;
350  try
351  {
352  media_mgr.releaseAll();
353  media_mgr.release (media, devindex < devices.size() ? devices[devindex] : "");
354  }
355  catch ( const Exception & e)
356  {
357  ZYPP_CAUGHT(e);
358  }
359  }
360  else if ( user == media::MediaChangeReport::RETRY ||
362  {
363  // retry
364  DBG << "Going to try again" << endl;
365  // invalidate current media access id
366  media_mgr.close(media);
367  _medias.erase(media_nr);
368 
369  // not attaching, media set will do that for us
370  // this could generate uncaught exception (#158620)
371  break;
372  }
373  else
374  {
375  DBG << "Don't know, let's ABORT" << endl;
376  ZYPP_RETHROW ( excp );
377  }
378  } while( user == media::MediaChangeReport::EJECT );
379  }
380 
381  // retry or change URL
382  } while( true );
383  }
384 
386  bool recursive,
387  unsigned media_nr,
388  ProvideFileOptions options )
389  {
390  OnMediaLocation resource;
391  resource.setLocation(dir, media_nr);
392  if ( recursive )
393  {
395  provide( boost::ref(op), resource, options, Pathname());
396  return op.result;
397  }
399  provide( boost::ref(op), resource, options, Pathname());
400  return op.result;
401  }
402 
404  {
405  if ( _medias.find( medianr ) != _medias.end() )
406  {
407  return _medias[medianr];
408  }
409 
410  Url url( medianr > 1 ? rewriteUrl( _url, medianr ) : _url );
411  media::MediaManager media_mgr;
412  media::MediaAccessId id = media_mgr.open( url, _prefAttachPoint );
413  _medias[medianr] = id;
414 
415  try
416  {
417  if ( _verifiers.find(medianr) != _verifiers.end() )
418  {
419  // a verifier is set for this media
420  // FIXME check the case where the verifier exists
421  // but we have no access id for the media
422  media_mgr.delVerifier( id );
423  media_mgr.addVerifier( id, _verifiers[medianr] );
424  // remove any saved verifier for this media
425  _verifiers.erase( medianr );
426  }
427  }
428  catch ( const Exception &e )
429  {
430  ZYPP_CAUGHT(e);
431  WAR << "Verifier not found" << endl;
432  }
433 
434  return id;
435  }
436 
437 
438  Url MediaSetAccess::rewriteUrl (const Url & url_r, const media::MediaNr medianr)
439  {
440  std::string scheme = url_r.getScheme();
441  if (scheme == "cd" || scheme == "dvd")
442  return url_r;
443 
444  DBG << "Rewriting url " << url_r << endl;
445 
446  if( scheme == "iso")
447  {
448  // TODO the iso parameter will not be required in the future, this
449  // code has to be adapted together with the MediaISO change.
450  // maybe some MediaISOURL interface should be used.
451  std::string isofile = url_r.getQueryParam("iso");
452  str::regex e("^(.*)(cd|dvd|media)[0-9]+\\.iso$", str::regex::icase);
453 
454  str::smatch what;
455  if(str::regex_match(isofile, what, e))
456  {
457  Url url( url_r);
458  isofile = what[1] + what[2] + str::numstring(medianr) + ".iso";
459  url.setQueryParam("iso", isofile);
460  DBG << "Url rewrite result: " << url << endl;
461  return url;
462  }
463  }
464  else
465  {
466  std::string pathname = url_r.getPathName();
467  str::regex e("^(.*)(cd|dvd|media)[0-9]+(/)?$", str::regex::icase);
468  str::smatch what;
469  if(str::regex_match(pathname, what, e))
470  {
471  Url url( url_r);
472  pathname = what[1] + what[2] + str::numstring(medianr) + what[3];
473  url.setPathName(pathname);
474  DBG << "Url rewrite result: " << url << endl;
475  return url;
476  }
477  }
478  return url_r;
479  }
480 
482  {
483  DBG << "Releasing all media IDs held by this MediaSetAccess" << endl;
484  media::MediaManager manager;
485  for (MediaMap::const_iterator m = _medias.begin(); m != _medias.end(); ++m)
486  manager.release(m->second, "");
487  }
488 
489  std::ostream & MediaSetAccess::dumpOn( std::ostream & str ) const
490  {
491  str << "MediaSetAccess (URL='" << _url << "', attach_point_hint='" << _prefAttachPoint << "')";
492  return str;
493  }
494 
496 } // 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:527
#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:199
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 &#39;attach point&#39; 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 &#39;localRoot() + pathname&#39;, 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:654
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 &#39;physical&#39; media, e.g CDROM drives, Disk volumes, directory trees...
Definition: MediaManager.h:473
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:203
std::string getPathName(EEncoding eflag=zypp::url::E_DECODED) const
Returns the path name from the URL.
Definition: Url.cc:598
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)
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 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.