019a7d0bf96eff27d65badb1f2b134a54230763c
[platform/upstream/libzypp.git] / zypp / MediaSetAccess.cc
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/UserRequestException.h"
15 #include "zypp/ZYppCallbacks.h"
16 #include "zypp/MediaSetAccess.h"
17 #include "zypp/PathInfo.h"
18 //#include "zypp/source/MediaSetAccessReportReceivers.h"
19
20 using namespace std;
21
22 ///////////////////////////////////////////////////////////////////
23 namespace zypp
24 { /////////////////////////////////////////////////////////////////
25
26 IMPL_PTR_TYPE(MediaSetAccess);
27
28 ///////////////////////////////////////////////////////////////////
29
30   MediaSetAccess::MediaSetAccess(const Url &url,
31                                  const Pathname & prefered_attach_point)
32       : _url(url),
33         _prefAttachPoint(prefered_attach_point)
34   {
35     MIL << "initializing.." << std::endl;
36     //std::vector<media::MediaVerifierRef> single_media;
37     //single_media[0] = media::MediaVerifierRef(new media::NoVerifier());
38     //_verifiers = single_media;
39   }
40
41
42   MediaSetAccess::~MediaSetAccess()
43   {
44     release();
45   }
46
47
48   void MediaSetAccess::setVerifier( unsigned media_nr, media::MediaVerifierRef verifier )
49   {
50     if (_medias.find(media_nr) != _medias.end())
51     {
52       // the media already exists, set theverifier
53       media::MediaAccessId id = _medias[media_nr];
54       media::MediaManager media_mgr;
55       media_mgr.addVerifier( id, verifier );
56       // remove any saved verifier for this media
57       _verifiers.erase(media_nr);
58       //if (! noattach && ! media_mgr.isAttached(id))
59       //media_mgr.attach(id);
60     }
61     else
62     {
63       // save the verifier in the map, and set it when
64       // the media number is first attached
65       _verifiers[media_nr] = verifier;
66     }
67   }
68
69 //       callback::SendReport<source::DownloadFileReport> report;
70 //       DownloadProgressFileReceiver download_report( report );
71 //       SourceFactory source_factory;
72 //       Url file_url( url().asString() + file_r.asString() );
73 //       report->start( source_factory.createFrom(this), file_url );
74 //       callback::TempConnect<media::DownloadProgressReport> tmp_download( download_report );
75 //       Pathname file = provideJustFile( file_r, media_nr, cached, checkonly );
76 //       report->finish( file_url, source::DownloadFileReport::NO_ERROR, "" );
77 //       return file;
78
79
80   Pathname MediaSetAccess::provideFile( const OnMediaLocation & on_media_file )
81   {
82     return provideFile( on_media_file.filename(), on_media_file.medianr() );
83   }
84
85
86   Pathname MediaSetAccess::provideFile(const Pathname & file, unsigned media_nr )
87   {
88     return provideFileInternal( file, media_nr, false, false);
89   }
90
91   bool MediaSetAccess::doesFileExist(const Pathname & file, unsigned media_nr )
92   {
93     callback::SendReport<media::MediaChangeReport> report;
94     media::MediaManager media_mgr;
95     // get the mediaId, but don't try to attach it here
96     media::MediaAccessId media = getMediaAccessId( media_nr);
97
98     bool exists = false;
99
100     do
101     {
102       try
103       {
104         DBG << "Cheking if file " << file
105             << " from media number " << media_nr << " exists." << endl;
106         // try to attach the media
107         if ( ! media_mgr.isAttached(media) )
108           media_mgr.attachDesiredMedia(media);
109         exists = media_mgr.doesFileExist(media, file);
110         break;
111       }
112       catch ( media::MediaException & excp )
113       {
114         ZYPP_CAUGHT(excp);
115         media::MediaChangeReport::Action user;
116         do
117         {
118           DBG << "Media couldn't provide file " << file << " , releasing." << endl;
119           try
120           {
121             media_mgr.release (media, false);
122           }
123           catch (const Exception & excpt_r)
124           {
125               ZYPP_CAUGHT(excpt_r);
126               MIL << "Failed to release media " << media << endl;
127           }
128
129           // set up the reason
130           media::MediaChangeReport::Error reason = media::MediaChangeReport::INVALID;
131
132           if( typeid(excp) == typeid( media::MediaFileNotFoundException )  ||
133               typeid(excp) == typeid( media::MediaNotAFileException ) )
134           {
135             reason = media::MediaChangeReport::NOT_FOUND;
136           }
137           else if( typeid(excp) == typeid( media::MediaNotDesiredException)  ||
138               typeid(excp) == typeid( media::MediaNotAttachedException) )
139           {
140             reason = media::MediaChangeReport::WRONG;
141           }
142
143           user  = media::MediaChangeReport::ABORT;
144           DBG << "doesFileExist exception caught, callback answer: " << user << endl;
145
146           if( user == media::MediaChangeReport::ABORT )
147           {
148             DBG << "Aborting" << endl;
149             ZYPP_RETHROW ( excp );
150           }
151           else if ( user == media::MediaChangeReport::IGNORE )
152           {
153             DBG << "Skipping" << endl;
154             ZYPP_THROW ( SkipRequestException("User-requested skipping of a file") );
155           }
156           else if ( user == media::MediaChangeReport::EJECT )
157           {
158             DBG << "Eject: try to release" << endl;
159             try
160             {
161               //zypp::SourceManager::sourceManager()->releaseAllSources();
162             }
163             catch (const zypp::Exception& excpt_r)
164             {
165               ZYPP_CAUGHT(excpt_r);
166               ERR << "Failed to release all sources" << endl;
167             }
168             media_mgr.release (media, true); // one more release needed for eject
169             // FIXME: this will not work, probably
170           }
171           else if ( user == media::MediaChangeReport::RETRY  ||
172             user == media::MediaChangeReport::CHANGE_URL )
173           {
174             // retry
175             DBG << "Going to try again" << endl;
176
177             // not attaching, media set will do that for us
178             // this could generate uncaught exception (#158620)
179             break;
180           }
181           else
182           {
183             DBG << "Don't know, let's ABORT" << endl;
184             ZYPP_RETHROW ( excp );
185           }
186         } while( user == media::MediaChangeReport::EJECT );
187       }
188
189       // retry or change URL
190     } while( true );
191
192     return exists;
193   }
194
195   Pathname MediaSetAccess::provideFileInternal(const Pathname & file, unsigned media_nr, bool cached, bool checkonly )
196   {
197     callback::SendReport<media::MediaChangeReport> report;
198     media::MediaManager media_mgr;
199     // get the mediaId, but don't try to attach it here
200     media::MediaAccessId media = getMediaAccessId( media_nr);
201
202     do
203     {
204       try
205       {
206         DBG << "Going to try to provide file " << file
207             << " from media number " << media_nr << endl;
208         // try to attach the media
209         if ( ! media_mgr.isAttached(media) )
210           media_mgr.attachDesiredMedia(media);
211         media_mgr.provideFile (media, file, false, false);
212         break;
213       }
214       catch ( media::MediaException & excp )
215       {
216         ZYPP_CAUGHT(excp);
217         media::MediaChangeReport::Action user;
218         do
219         {
220           DBG << "Media couldn't provide file " << file << " , releasing." << endl;
221           try
222           {
223             media_mgr.release (media, false);
224           }
225           catch (const Exception & excpt_r)
226           {
227               ZYPP_CAUGHT(excpt_r);
228               MIL << "Failed to release media " << media << endl;
229           }
230
231           // set up the reason
232           media::MediaChangeReport::Error reason = media::MediaChangeReport::INVALID;
233
234           if( typeid(excp) == typeid( media::MediaFileNotFoundException )  ||
235               typeid(excp) == typeid( media::MediaNotAFileException ) )
236           {
237             reason = media::MediaChangeReport::NOT_FOUND;
238           }
239           else if( typeid(excp) == typeid( media::MediaNotDesiredException)  ||
240               typeid(excp) == typeid( media::MediaNotAttachedException) )
241           {
242             reason = media::MediaChangeReport::WRONG;
243           }
244
245           // request media change, if the media is changeable and this is
246           // not just a check, otherwise just abort 
247           if (checkonly || !media_mgr.isChangeable(media))
248             user = media::MediaChangeReport::ABORT;
249           else
250             user = 
251               report->requestMedia (
252                 Repository::noRepository,
253                 media_nr,
254                 reason,
255                 excp.asUserString()
256               );
257
258           DBG << "ProvideFile exception caught, callback answer: " << user << endl;
259
260           if( user == media::MediaChangeReport::ABORT )
261           {
262             DBG << "Aborting" << endl;
263             ZYPP_RETHROW ( excp );
264           }
265           else if ( user == media::MediaChangeReport::IGNORE )
266           {
267             DBG << "Skipping" << endl;
268             ZYPP_THROW ( SkipRequestException("User-requested skipping of a file") );
269           }
270           else if ( user == media::MediaChangeReport::EJECT )
271           {
272             DBG << "Eject: try to release" << endl;
273             try
274             {
275               //zypp::SourceManager::sourceManager()->releaseAllSources();
276             }
277             catch (const zypp::Exception& excpt_r)
278             {
279               ZYPP_CAUGHT(excpt_r);
280               ERR << "Failed to release all sources" << endl;
281             }
282             media_mgr.release (media, true); // one more release needed for eject
283             // FIXME: this will not work, probably
284           }
285           else if ( user == media::MediaChangeReport::RETRY  ||
286             user == media::MediaChangeReport::CHANGE_URL )
287           {
288             // retry
289             DBG << "Going to try again" << endl;
290
291             // not attaching, media set will do that for us
292             // this could generate uncaught exception (#158620)
293             break;
294           }
295           else
296           {
297             DBG << "Don't know, let's ABORT" << endl;
298             ZYPP_RETHROW ( excp );
299           }
300         } while( user == media::MediaChangeReport::EJECT );
301       }
302
303       // retry or change URL
304     } while( true );
305
306     return media_mgr.localPath( media, file );
307   }
308
309
310   Pathname MediaSetAccess::provideDir(const Pathname & dir,
311                                       bool recursive,
312                                       unsigned media_nr)
313   {
314     callback::SendReport<media::MediaChangeReport> report;
315     media::MediaManager media_mgr;
316
317     // get the mediaId, but don't try to attach it here
318     media::MediaAccessId _media = getMediaAccessId(media_nr);
319     do
320     {
321       try
322       {
323         DBG << "Going to try provide direcotry " << dir
324             << (recursive ? " (recursively)" : "")
325             << " from media nr. " << media_nr << endl;
326
327         // try to attach the media
328         if (!media_mgr.isAttached(_media))
329           media_mgr.attachDesiredMedia(_media);
330
331         _media = getMediaAccessId(media_nr); // in case of redirect
332
333         if (recursive)
334           media_mgr.provideDirTree(_media, dir);
335         else
336           media_mgr.provideDir(_media, dir);
337
338         break; // quit the retry loop
339       }
340       catch (media::MediaException & excp)
341       {
342         ZYPP_CAUGHT(excp);
343         media::MediaChangeReport::Action user;
344
345         do
346         {
347           DBG << "Media couldn't provide dir " << dir << ", releasing." << endl;
348           try
349           {
350             media_mgr.release (_media, false);
351           }
352           catch (const Exception & excpt_r)
353           {
354             ZYPP_CAUGHT(excpt_r);
355             ERR << "Failed to release media " << _media << endl;
356           }
357
358           //MIL << "Releasing all medias of all sources" << endl;
359           try
360           {
361             //! \todo do we need replacement for this at all?
362             //zypp::SourceManager::sourceManager()->releaseAllSources();
363           }
364           catch (const zypp::Exception& excpt_r)
365           {
366             ZYPP_CAUGHT(excpt_r);
367             ERR << "Failed to release all sources" << endl;
368           }
369
370           // set up the reason
371           media::MediaChangeReport::Error reason = media::MediaChangeReport::INVALID;
372
373           if (typeid(excp) == typeid(media::MediaFileNotFoundException)
374               || typeid(excp) == typeid(media::MediaNotAFileException))
375           {
376             reason = media::MediaChangeReport::NOT_FOUND;
377           }
378           else if (typeid(excp) == typeid( media::MediaNotDesiredException)
379               || typeid(excp) == typeid(media::MediaNotAttachedException))
380           {
381             reason = media::MediaChangeReport::WRONG;
382           }
383
384
385           // request media change, if the media is changeable, otherwise just abort 
386           if (media_mgr.isChangeable(_media))
387             user =
388               report->requestMedia(
389                 Repository::noRepository,
390                 media_nr,
391                 reason,
392                 excp.asUserString()
393               );
394           else
395             user = media::MediaChangeReport::ABORT;
396
397           DBG << "ProvideFile exception caught, callback answer: " << user << endl;
398
399           if (user == media::MediaChangeReport::ABORT)
400           {
401             DBG << "Aborting" << endl;
402             ZYPP_RETHROW ( excp );
403           }
404           else if (user == media::MediaChangeReport::EJECT)
405           {
406             DBG << "Eject: try to release" << endl;
407             try
408             {
409               //! \todo do we need replacement for this at all?
410               // zypp::SourceManager::sourceManager()->releaseAllSources();
411             }
412             catch (const zypp::Exception& excpt_r)
413             {
414               ZYPP_CAUGHT(excpt_r);
415               ERR << "Failed to release all sources" << endl;
416             }
417             media_mgr.release (_media, true); // one more release needed for eject
418             // FIXME: this will not work, probably
419           }
420           else if (user == media::MediaChangeReport::RETRY ||
421               user == media::MediaChangeReport::CHANGE_URL)
422           {
423             // retry
424             DBG << "Going to try again" << endl;
425
426             // not attaching, media set will do that for us
427             // this could generate uncaught exception (#158620)
428
429             break;
430           }
431           else
432           {
433             DBG << "Don't know, let's ABORT" << endl;
434
435             ZYPP_RETHROW (excp);
436           }
437         }
438         while (user == media::MediaChangeReport::EJECT);
439       }
440       // retry or change URL
441     }
442     while (true);
443
444     return media_mgr.localPath(_media, dir);
445   }
446
447   media::MediaAccessId MediaSetAccess::getMediaAccessId (media::MediaNr medianr)
448   {
449     media::MediaManager media_mgr;
450
451     if (_medias.find(medianr) != _medias.end())
452     {
453       media::MediaAccessId id = _medias[medianr];
454       //if (! noattach && ! media_mgr.isAttached(id))
455       //media_mgr.attach(id);
456       return id;
457     }
458     Url url;
459     url = rewriteUrl (_url, medianr);
460     media::MediaAccessId id = media_mgr.open(url, _prefAttachPoint);
461     _medias[medianr] = id;
462
463     try
464     {
465       if (_verifiers.find(medianr) != _verifiers.end())
466       {
467         // a verifier is set for this media
468         // FIXME check the case where the verifier exists
469         // but we have no access id for the media
470         media::MediaAccessId id = _medias[medianr];
471         media::MediaManager media_mgr;
472         media_mgr.delVerifier(id);
473         media_mgr.addVerifier( id, _verifiers[medianr] );
474         // remove any saved verifier for this media
475         _verifiers.erase(medianr);
476       }
477     }
478     catch ( const Exception &e )
479     {
480       ZYPP_CAUGHT(e);
481       WAR << "Verifier not found" << endl;
482     }
483
484     return id;
485   }
486
487
488   Url MediaSetAccess::rewriteUrl (const Url & url_r, const media::MediaNr medianr)
489   {
490     std::string scheme = url_r.getScheme();
491     if (scheme == "cd" || scheme == "dvd")
492       return url_r;
493
494     DBG << "Rewriting url " << url_r << endl;
495
496     if( scheme == "iso")
497     {
498       // TODO the iso parameter will not be required in the future, this
499       // code has to be adapted together with the MediaISO change.
500       // maybe some MediaISOURL interface should be used.
501       std::string isofile = url_r.getQueryParam("iso");
502       boost::regex e("^(.*(cd|dvd))([0-9]+)(\\.iso)$", boost::regex::icase);
503       boost::smatch what;
504       if(boost::regex_match(isofile, what, e, boost::match_extra))
505       {
506         Url url( url_r);
507         isofile = what[1] + str::numstring(medianr) + what[4];
508         url.setQueryParam("iso", isofile);
509         DBG << "Url rewrite result: " << url << endl;
510         return url;
511       }
512     }
513     else
514     {
515       std::string pathname = url_r.getPathName();
516       boost::regex e("^(.*(cd|dvd))([0-9]+)(/?)$", boost::regex::icase);
517       boost::smatch what;
518       if(boost::regex_match(pathname, what, e, boost::match_extra))
519       {
520         Url url( url_r);
521         pathname = what[1] + str::numstring(medianr) + what[4];
522         url.setPathName(pathname);
523         DBG << "Url rewrite result: " << url << endl;
524         return url;
525       }
526     }
527     return url_r;
528   }
529
530   void MediaSetAccess::release()
531   {
532     DBG << "Releasing all media IDs held by this MediaSetAccess" << endl;
533     media::MediaManager manager;
534     for (MediaMap::const_iterator m = _medias.begin(); m != _medias.end(); ++m)
535       manager.release(m->second);
536   }
537
538   std::ostream & MediaSetAccess::dumpOn( std::ostream & str ) const
539   {
540     str << "MediaSetAccess (URL='" << _url << "', attach_point_hint='" << _prefAttachPoint << "')";
541     return str;
542   }
543
544 //     media::MediaVerifierRef MediaSetAccess::verifier(unsigned media_nr)
545 //     { return media::MediaVerifierRef(new media::NoVerifier()); }
546
547 /////////////////////////////////////////////////////////////////
548 } // namespace zypp
549 ///////////////////////////////////////////////////////////////////