ignore
[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   MediaSetAccess::MediaSetAccess(  const Url &url, const Pathname &path )
52       : _url(url),
53         _path(path)
54   {
55     MIL << "initializing.." << std::endl;
56     //std::vector<media::MediaVerifierRef> single_media;
57     //single_media[0] = media::MediaVerifierRef(new media::NoVerifier());
58     //_verifiers = single_media;
59   }
60   
61   MediaSetAccess::~MediaSetAccess()
62   {
63   }
64
65   void MediaSetAccess::setVerifiers( const std::vector<media::MediaVerifierRef> &verifiers )
66   {
67     _verifiers = verifiers;
68   }
69
70 //       callback::SendReport<source::DownloadFileReport> report;
71 //       DownloadProgressFileReceiver download_report( report );
72 //       SourceFactory source_factory;
73 //       Url file_url( url().asString() + file_r.asString() );
74 //       report->start( source_factory.createFrom(this), file_url );
75 //       callback::TempConnect<media::DownloadProgressReport> tmp_download( download_report );
76 //       Pathname file = provideJustFile( file_r, media_nr, cached, checkonly );
77 //       report->finish( file_url, source::DownloadFileReport::NO_ERROR, "" );
78 //       return file;
79
80
81   void MediaSetAccess::providePossiblyCachedMetadataFile( const Pathname &file_to_download, unsigned medianr, const Pathname &destination, const Pathname &cached_file, const CheckSum &checksum )
82   {
83     Url file_url( _url.asString() + file_to_download.asString() );
84     // if we have a cached file and its the same
85     if ( PathInfo(cached_file).isExist() && (! checksum.empty()) && is_checksum( cached_file, checksum ) )
86     {
87       MIL << "file " << file_url << " found in previous cache. Using cached copy." << std::endl;
88       // checksum is already checked.
89       // we could later implement double failover and try to download if file copy fails.
90       if ( filesystem::copy(cached_file, destination) != 0 )
91         ZYPP_THROW(Exception("Can't copy " + cached_file.asString() + " to " + destination.asString()));
92     }
93     else
94     {
95       // we dont have it or its not the same, download it.
96       Pathname downloaded_file = provideFile( file_to_download, medianr, ChecksumFileChecker(checksum) );
97       
98       if ( filesystem::copy(downloaded_file, destination) != 0 )
99         ZYPP_THROW(Exception("Can't copy " + downloaded_file.asString() + " to " + destination.asString()));      
100     }
101   }
102
103   Pathname MediaSetAccess::provideFile(const Pathname & file, unsigned media_nr )
104   {
105     return provideFileInternal( file, media_nr, false, false);
106   }
107
108   Pathname  MediaSetAccess::provideFile(const Pathname & file, unsigned media_nr, FileChecker checker )
109   {
110     Pathname p = provideFileInternal( file, media_nr, false, false);
111     
112     if ( ! checker(p) )
113     {
114       ZYPP_THROW(Exception("Error checker"));
115     }
116     return p;
117   }
118
119   Pathname MediaSetAccess::provideFileInternal(const Pathname & file, unsigned media_nr, bool cached, bool checkonly )
120   {
121     callback::SendReport<media::MediaChangeReport> report;
122     media::MediaManager media_mgr;
123     // get the mediaId, but don't try to attach it here
124     media::MediaAccessId media = getMediaAccessId( media_nr);
125       
126     do
127     {
128       try
129       {
130         DBG << "Going to try provide file " << file << " from " << media_nr << endl;        
131         // try to attach the media
132         if ( ! media_mgr.isAttached(media) )
133         media_mgr.attach(media);
134         media_mgr.provideFile (media, file, false, false);
135         break;
136       }
137       catch ( Exception & excp )
138       {
139         ZYPP_CAUGHT(excp);
140         media::MediaChangeReport::Action user;
141         do
142         {
143           DBG << "Media couldn't provide file " << file << " , releasing." << endl;
144           try
145           {
146             media_mgr.release (media, false);
147           }
148           catch (const Exception & excpt_r)
149           {
150               ZYPP_CAUGHT(excpt_r);
151               MIL << "Failed to release media " << media << endl;
152           }
153           
154           MIL << "Releasing all medias of all sources" << endl;
155           try
156           {
157             //zypp::SourceManager::sourceManager()->releaseAllSources();
158           }
159           catch (const zypp::Exception& excpt_r)
160           {
161               ZYPP_CAUGHT(excpt_r);
162               ERR << "Failed to release all sources" << endl;
163           }
164
165           // set up the reason
166           media::MediaChangeReport::Error reason = media::MediaChangeReport::INVALID;
167           
168           if( typeid(excp) == typeid( media::MediaFileNotFoundException )  ||
169               typeid(excp) == typeid( media::MediaNotAFileException ) )
170           {
171             reason = media::MediaChangeReport::NOT_FOUND;
172           } 
173           else if( typeid(excp) == typeid( media::MediaNotDesiredException)  ||
174               typeid(excp) == typeid( media::MediaNotAttachedException) )
175           {
176             reason = media::MediaChangeReport::WRONG;
177           }
178
179           user  = checkonly ? media::MediaChangeReport::ABORT :
180             report->requestMedia (
181               Source_Ref::noSource,
182               media_nr,
183               reason,
184               excp.asUserString()
185             );
186
187           DBG << "ProvideFile exception caught, callback answer: " << user << endl;
188
189           if( user == media::MediaChangeReport::ABORT )
190           {
191             DBG << "Aborting" << endl;
192             ZYPP_RETHROW ( excp );
193           }
194           else if ( user == media::MediaChangeReport::IGNORE )
195           {
196             DBG << "Skipping" << endl;
197             ZYPP_THROW ( source::SkipRequestedException("User-requested skipping of a file") );
198           }
199           else if ( user == media::MediaChangeReport::EJECT )
200           {
201             DBG << "Eject: try to release" << endl;
202             try
203             {
204               //zypp::SourceManager::sourceManager()->releaseAllSources();
205             }
206             catch (const zypp::Exception& excpt_r)
207             {
208               ZYPP_CAUGHT(excpt_r);
209               ERR << "Failed to release all sources" << endl;
210             }
211             media_mgr.release (media, true); // one more release needed for eject
212             // FIXME: this will not work, probably
213           }
214           else if ( user == media::MediaChangeReport::RETRY  ||
215             user == media::MediaChangeReport::CHANGE_URL )
216           {
217             // retry
218             DBG << "Going to try again" << endl;
219
220             // not attaching, media set will do that for us
221             // this could generate uncaught exception (#158620)
222             break;
223           }
224           else
225           {
226             DBG << "Don't know, let's ABORT" << endl;
227             ZYPP_RETHROW ( excp );
228           }
229         } while( user == media::MediaChangeReport::EJECT );
230       }
231
232       // retry or change URL
233     } while( true );
234
235     return media_mgr.localPath( media, file );
236   }
237
238   media::MediaAccessId MediaSetAccess::getMediaAccessId (media::MediaNr medianr)
239   {
240     media::MediaManager media_mgr;
241
242     if (medias.find(medianr) != medias.end())
243     {
244       media::MediaAccessId id = medias[medianr];
245       //if (! noattach && ! media_mgr.isAttached(id))
246       //media_mgr.attach(id);
247       return id;
248     }
249     Url url;
250     url = rewriteUrl (_url, medianr);
251     media::MediaAccessId id = media_mgr.open(url, _path);
252     //try {
253     //  MIL << "Adding media verifier" << endl;
254     //  media_mgr.delVerifier(id);
255     //  media_mgr.addVerifier(id, _source.verifier(medianr));
256     //}
257     //catch (const Exception & excpt_r)
258     //{
259     //  ZYPP_CAUGHT(excpt_r);
260     //  WAR << "Verifier not found" << endl;
261     //}
262     medias[medianr] = id;
263     
264     //if (! noattach)
265     //  media_mgr.attach(id);
266
267     return id;
268   }
269
270   Url MediaSetAccess::rewriteUrl (const Url & url_r, const media::MediaNr medianr)
271   {
272     std::string scheme = url_r.getScheme();
273     if (scheme == "cd" || scheme == "dvd")
274     return url_r;
275
276     DBG << "Rewriting url " << url_r << endl;
277
278     if( scheme == "iso")
279     {
280       std::string isofile = url_r.getQueryParam("iso");
281       boost::regex e("^(.*(cd|dvd))([0-9]+)(\\.iso)$", boost::regex::icase);
282       boost::smatch what;
283       if(boost::regex_match(isofile, what, e, boost::match_extra))
284       {
285         Url url( url_r);
286         isofile = what[1] + str::numstring(medianr) + what[4];
287         url.setQueryParam("iso", isofile);
288         DBG << "Url rewrite result: " << url << endl;
289         return url;
290       }
291     }
292     else
293     {
294       std::string pathname = url_r.getPathName();
295       boost::regex e("^(.*(cd|dvd))([0-9]+)(/?)$", boost::regex::icase);
296       boost::smatch what;
297       if(boost::regex_match(pathname, what, e, boost::match_extra))
298       {
299         Url url( url_r);
300         pathname = what[1] + str::numstring(medianr) + what[4];
301         url.setPathName(pathname);
302         DBG << "Url rewrite result: " << url << endl;
303         return url;
304       }
305     }
306     return url_r;
307   }
308
309   std::ostream & MediaSetAccess::dumpOn( std::ostream & str ) const
310   {
311     return str;
312   }
313
314 //     media::MediaVerifierRef MediaSetAccess::verifier(unsigned media_nr)
315 //     { return media::MediaVerifierRef(new media::NoVerifier()); }
316
317   MediaVerifier::MediaVerifier(const std::string & vendor_r, const std::string & id_r, const media::MediaNr media_nr)
318     : _media_vendor(vendor_r)
319       , _media_id(id_r)
320       , _media_nr(media_nr)
321   {}
322
323   bool MediaVerifier::isDesiredMedia(const media::MediaAccessRef &ref)
324   {
325     if (_media_vendor.empty() || _media_id.empty())
326       return true;
327
328       Pathname media_file = "/media." + str::numstring(_media_nr) + "/media";
329       ref->provideFile (media_file);
330       media_file = ref->localPath(media_file);
331       std::ifstream str(media_file.asString().c_str());
332       std::string vendor;
333       std::string id;
334
335 #warning check the stream status
336       getline(str, vendor);
337       getline(str, id);
338
339       return (vendor == _media_vendor && id == _media_id );
340   }
341
342
343 /////////////////////////////////////////////////////////////////
344 } // namespace source
345 ///////////////////////////////////////////////////////////////////