MediaManager::attachDesiredMedia() added to support multiple drives
[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/ZYppCallbacks.h"
15 #include "zypp/MediaSetAccess.h"
16 #include "zypp/PathInfo.h"
17 //#include "zypp/source/MediaSetAccessReportReceivers.h"
18
19 using namespace std;
20
21 ///////////////////////////////////////////////////////////////////
22 namespace zypp
23 { /////////////////////////////////////////////////////////////////
24 ///////////////////////////////////////////////////////////////////
25
26   ChecksumFileChecker::ChecksumFileChecker( const CheckSum &checksum )
27     : _checksum(checksum)
28   {
29   }
30
31   bool ChecksumFileChecker::operator()( const Pathname &file )
32   {
33     // FIXME probably this funcionality should be in CheckSum itself
34     CheckSum real_checksum( _checksum.type(), filesystem::checksum( file, _checksum.type() ));
35     if ( real_checksum == _checksum )
36     {
37       return true;
38     }
39     else
40     {
41       ERR << "Got " << real_checksum << ", expected " << _checksum << std::endl;
42       return false;
43     }
44   }
45
46   bool NullFileChecker::operator()(const Pathname &file )
47   {
48     return true;
49   }
50
51
52   MediaSetAccess::MediaSetAccess(  const Url &url, const Pathname &path )
53       : _url(url),
54         _path(path)
55   {
56     MIL << "initializing.." << std::endl;
57     //std::vector<media::MediaVerifierRef> single_media;
58     //single_media[0] = media::MediaVerifierRef(new media::NoVerifier());
59     //_verifiers = single_media;
60   }
61
62
63   MediaSetAccess::~MediaSetAccess()
64   {
65   }
66
67
68   void MediaSetAccess::setVerifier( unsigned media_nr, media::MediaVerifierRef verifier )
69   {
70     if (_medias.find(media_nr) != _medias.end())
71     {
72       // the media already exists, set theverifier
73       media::MediaAccessId id = _medias[media_nr];
74       media::MediaManager media_mgr;
75       media_mgr.addVerifier( id, verifier );
76       // remove any saved verifier for this media
77       _verifiers.erase(media_nr);
78       //if (! noattach && ! media_mgr.isAttached(id))
79       //media_mgr.attach(id);
80     }
81     else
82     {
83       // save the verifier in the map, and set it when
84       // the media number is first attached
85       _verifiers[media_nr] = verifier;
86     }
87   }
88
89 //       callback::SendReport<source::DownloadFileReport> report;
90 //       DownloadProgressFileReceiver download_report( report );
91 //       SourceFactory source_factory;
92 //       Url file_url( url().asString() + file_r.asString() );
93 //       report->start( source_factory.createFrom(this), file_url );
94 //       callback::TempConnect<media::DownloadProgressReport> tmp_download( download_report );
95 //       Pathname file = provideJustFile( file_r, media_nr, cached, checkonly );
96 //       report->finish( file_url, source::DownloadFileReport::NO_ERROR, "" );
97 //       return file;
98
99
100   Pathname MediaSetAccess::provideFile( const OnMediaLocation & on_media_file )
101   {
102     return provideFile( on_media_file.filename(), on_media_file.medianr() );
103   }
104
105
106   Pathname MediaSetAccess::provideFile(const Pathname & file, unsigned media_nr )
107   {
108     return provideFileInternal( file, media_nr, false, false);
109   }
110
111
112   Pathname  MediaSetAccess::provideFile(const Pathname & file, unsigned media_nr, FileChecker checker )
113   {
114     Pathname p = provideFileInternal( file, media_nr, false, false);
115     
116     if ( ! checker(p) )
117     {
118       ZYPP_THROW(Exception("Error checker"));
119     }
120     return p;
121   }
122
123
124   Pathname MediaSetAccess::provideFileInternal(const Pathname & file, unsigned media_nr, bool cached, bool checkonly )
125   {
126     callback::SendReport<media::MediaChangeReport> report;
127     media::MediaManager media_mgr;
128     // get the mediaId, but don't try to attach it here
129     media::MediaAccessId media = getMediaAccessId( media_nr);
130
131     do
132     {
133       try
134       {
135         DBG << "Going to try to provide file " << file
136             << " from media number " << media_nr << endl;        
137         // try to attach the media
138         if ( ! media_mgr.isAttached(media) )
139           media_mgr.attachDesiredMedia(media);
140         media_mgr.provideFile (media, file, false, false);
141         break;
142       }
143       catch ( Exception & excp )
144       {
145         ZYPP_CAUGHT(excp);
146         media::MediaChangeReport::Action user;
147         do
148         {
149           DBG << "Media couldn't provide file " << file << " , releasing." << endl;
150           try
151           {
152             media_mgr.release (media, false);
153           }
154           catch (const Exception & excpt_r)
155           {
156               ZYPP_CAUGHT(excpt_r);
157               MIL << "Failed to release media " << media << endl;
158           }
159           
160           /*MIL << "Releasing all _medias of all sources" << endl;
161           try
162           {
163             //zypp::SourceManager::sourceManager()->releaseAllSources();
164           }
165           catch (const zypp::Exception& excpt_r)
166           {
167               ZYPP_CAUGHT(excpt_r);
168               ERR << "Failed to release all sources" << endl;
169           }*/
170
171           // set up the reason
172           media::MediaChangeReport::Error reason = media::MediaChangeReport::INVALID;
173           
174           if( typeid(excp) == typeid( media::MediaFileNotFoundException )  ||
175               typeid(excp) == typeid( media::MediaNotAFileException ) )
176           {
177             reason = media::MediaChangeReport::NOT_FOUND;
178           }
179           else if( typeid(excp) == typeid( media::MediaNotDesiredException)  ||
180               typeid(excp) == typeid( media::MediaNotAttachedException) )
181           {
182             reason = media::MediaChangeReport::WRONG;
183           }
184
185           user  = checkonly ? media::MediaChangeReport::ABORT :
186             report->requestMedia (
187               Source_Ref::noSource,
188               media_nr,
189               reason,
190               excp.asUserString()
191             );
192
193           DBG << "ProvideFile exception caught, callback answer: " << user << endl;
194
195           if( user == media::MediaChangeReport::ABORT )
196           {
197             DBG << "Aborting" << endl;
198             ZYPP_RETHROW ( excp );
199           }
200           else if ( user == media::MediaChangeReport::IGNORE )
201           {
202             DBG << "Skipping" << endl;
203             ZYPP_THROW ( source::SkipRequestedException("User-requested skipping of a file") );
204           }
205           else if ( user == media::MediaChangeReport::EJECT )
206           {
207             DBG << "Eject: try to release" << endl;
208             try
209             {
210               //zypp::SourceManager::sourceManager()->releaseAllSources();
211             }
212             catch (const zypp::Exception& excpt_r)
213             {
214               ZYPP_CAUGHT(excpt_r);
215               ERR << "Failed to release all sources" << endl;
216             }
217             media_mgr.release (media, true); // one more release needed for eject
218             // FIXME: this will not work, probably
219           }
220           else if ( user == media::MediaChangeReport::RETRY  ||
221             user == media::MediaChangeReport::CHANGE_URL )
222           {
223             // retry
224             DBG << "Going to try again" << endl;
225
226             // not attaching, media set will do that for us
227             // this could generate uncaught exception (#158620)
228             break;
229           }
230           else
231           {
232             DBG << "Don't know, let's ABORT" << endl;
233             ZYPP_RETHROW ( excp );
234           }
235         } while( user == media::MediaChangeReport::EJECT );
236       }
237
238       // retry or change URL
239     } while( true );
240
241     return media_mgr.localPath( media, file );
242   }
243
244   media::MediaAccessId MediaSetAccess::getMediaAccessId (media::MediaNr medianr)
245   {
246     media::MediaManager media_mgr;
247
248     if (_medias.find(medianr) != _medias.end())
249     {
250       media::MediaAccessId id = _medias[medianr];
251       //if (! noattach && ! media_mgr.isAttached(id))
252       //media_mgr.attach(id);
253       return id;
254     }
255     Url url;
256     url = rewriteUrl (_url, medianr);
257     media::MediaAccessId id = media_mgr.open(url, _path);
258     _medias[medianr] = id;
259
260     try
261     {
262       if (_verifiers.find(medianr) != _verifiers.end())
263       {
264         // a verifier is set for this media
265         // FIXME check the case where the verifier exists
266         // but we have no access id for the media
267         media::MediaAccessId id = _medias[medianr];
268         media::MediaManager media_mgr;
269         media_mgr.delVerifier(id);
270         media_mgr.addVerifier( id, _verifiers[medianr] );
271         // remove any saved verifier for this media
272         _verifiers.erase(medianr);
273       }
274     }
275     catch ( const Exception &e )
276     {
277       ZYPP_CAUGHT(e);
278       WAR << "Verifier not found" << endl;
279     }
280     
281     return id;
282   }
283
284
285   Url MediaSetAccess::rewriteUrl (const Url & url_r, const media::MediaNr medianr)
286   {
287     std::string scheme = url_r.getScheme();
288     if (scheme == "cd" || scheme == "dvd")
289       return url_r;
290
291     DBG << "Rewriting url " << url_r << endl;
292
293     if( scheme == "iso")
294     {
295       // TODO the iso parameter will not be required in the future, this
296       // code has to be adapted together with the MediaISO change.
297       // maybe some MediaISOURL interface should be used.
298       std::string isofile = url_r.getQueryParam("iso");
299       boost::regex e("^(.*(cd|dvd))([0-9]+)(\\.iso)$", boost::regex::icase);
300       boost::smatch what;
301       if(boost::regex_match(isofile, what, e, boost::match_extra))
302       {
303         Url url( url_r);
304         isofile = what[1] + str::numstring(medianr) + what[4];
305         url.setQueryParam("iso", isofile);
306         DBG << "Url rewrite result: " << url << endl;
307         return url;
308       }
309     }
310     else
311     {
312       std::string pathname = url_r.getPathName();
313       boost::regex e("^(.*(cd|dvd))([0-9]+)(/?)$", boost::regex::icase);
314       boost::smatch what;
315       if(boost::regex_match(pathname, what, e, boost::match_extra))
316       {
317         Url url( url_r);
318         pathname = what[1] + str::numstring(medianr) + what[4];
319         url.setPathName(pathname);
320         DBG << "Url rewrite result: " << url << endl;
321         return url;
322       }
323     }
324     return url_r;
325   }
326
327   std::ostream & MediaSetAccess::dumpOn( std::ostream & str ) const
328   {
329     str << "MediaSetAccess (URL='" << _url << "', path='" << _path << "')";
330     return str;
331   }
332
333 //     media::MediaVerifierRef MediaSetAccess::verifier(unsigned media_nr)
334 //     { return media::MediaVerifierRef(new media::NoVerifier()); }
335
336 /////////////////////////////////////////////////////////////////
337 } // namespace zypp
338 ///////////////////////////////////////////////////////////////////