missing quote
[platform/upstream/libzypp.git] / zypp / repo / RepoProvideFile.cc
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file       zypp/source/RepoProvideFile.cc
10  *
11 */
12 #include <iostream>
13 #include <fstream>
14 #include <sstream>
15 #include <set>
16
17 #include "zypp/base/Gettext.h"
18 #include "zypp/base/Logger.h"
19 #include "zypp/base/String.h"
20 #include "zypp/base/UserRequestException.h"
21 #include "zypp/repo/RepoProvideFile.h"
22 #include "zypp/ZYppCallbacks.h"
23 #include "zypp/MediaSetAccess.h"
24 #include "zypp/ZConfig.h"
25 #include "zypp/repo/SUSEMediaVerifier.h"
26 #include "zypp/repo/RepoException.h"
27
28 #include "zypp/repo/SUSEMediaVerifier.h"
29 #include "zypp/repo/RepoException.h"
30
31 using std::endl;
32 using std::set;
33
34 ///////////////////////////////////////////////////////////////////
35 namespace zypp
36 { /////////////////////////////////////////////////////////////////
37   ///////////////////////////////////////////////////////////////////
38   namespace repo
39   { /////////////////////////////////////////////////////////////////
40
41     ///////////////////////////////////////////////////////////////////
42     //
43     //  provideFile
44     //
45     ///////////////////////////////////////////////////////////////////
46
47     ///////////////////////////////////////////////////////////////////
48     namespace
49     { /////////////////////////////////////////////////////////////////
50
51       /** Hack to extract progress information from source::DownloadFileReport.
52        * We redirect the static report triggered from Repository::provideFile
53        * to feed the ProvideFilePolicy callbacks.
54       */
55       struct DownloadFileReportHack : public callback::ReceiveReport<repo::RepoReport>
56       {
57         virtual bool progress( const ProgressData &progress )
58         {
59           if ( _redirect )
60             return _redirect( progress.val() );
61           return true;
62         }
63         function<bool ( int )> _redirect;
64       };
65
66       /////////////////////////////////////////////////////////////////
67     } // namespace
68     ///////////////////////////////////////////////////////////////////
69
70     ManagedFile provideFile( Repository repo_r,
71                              const OnMediaLocation & loc_r,
72                              const ProvideFilePolicy & policy_r )
73     {
74       RepoMediaAccess access;
75       return access.provideFile(repo_r, loc_r, policy_r );
76     }
77
78     class RepoMediaAccess::Impl
79     {
80     public:
81       Impl( const ProvideFilePolicy & defaultPolicy_r )
82         : _defaultPolicy( defaultPolicy_r )
83       {}
84
85       ~Impl()
86       {
87         std::map<Url, shared_ptr<MediaSetAccess> >::iterator it;
88         for ( it = _medias.begin();
89               it != _medias.end();
90               ++it )
91         {
92           it->second->release();
93         }
94       }
95
96       shared_ptr<MediaSetAccess> mediaAccessForUrl( const Url &url )
97       {
98         std::map<Url, shared_ptr<MediaSetAccess> >::const_iterator it;
99         it = _medias.find(url);
100         shared_ptr<MediaSetAccess> media;
101         if ( it != _medias.end() )
102         {
103           media = it->second;
104         }
105         else
106         {
107           media.reset( new MediaSetAccess(url) );
108           _medias[url] = media;
109         }
110         return media;
111       }
112
113       void setVerifierForRepo( Repository repo, shared_ptr<MediaSetAccess> media )
114       {
115         RepoInfo info = repo.info();
116         // set a verifier if the repository has it
117         Pathname mediafile = info.metadataPath() + "/media.1/media";
118         if ( ! mediafile.empty() )
119         {
120           if ( PathInfo(mediafile).isExist() )
121           {
122             std::map<shared_ptr<MediaSetAccess>, Repository>::const_iterator it;
123             it = _verifier.find(media);
124             if ( it != _verifier.end() )
125             {
126               if ( it->second == repo )
127               {
128                 // this media is already using this repo verifier
129                 return;
130               }
131             }
132
133             std::ifstream str(mediafile.asString().c_str());
134             std::string vendor;
135             std::string mediaid;
136             std::string buffer;
137             if ( str )
138             {
139               getline(str, vendor);
140               getline(str, mediaid);
141               getline(str, buffer);
142
143               unsigned media_nr = str::strtonum<unsigned>(buffer);
144               MIL << "Repository '" << info.alias() << "' has " << media_nr << " medias"<< endl;
145
146               for ( unsigned i=1; i <= media_nr; ++i )
147               {
148                 media::MediaVerifierRef verifier( new repo::SUSEMediaVerifier( vendor, mediaid, i ) );
149
150                 media->setVerifier( i, verifier);
151               }
152               _verifier[media] = repo;
153             }
154             else
155             {
156               ZYPP_THROW(RepoMetadataException(info));
157             }
158           }
159           else
160           {
161             WAR << "No media verifier for repo '" << info.alias() << "'" << endl;
162           }
163         }
164         else
165         {
166           MIL << "Unknown metadata path for repo '" << info.alias() << "'. Can't set media verifier."<< endl;
167         }
168       }
169
170       std::map<shared_ptr<MediaSetAccess>, Repository> _verifier;
171       std::map<Url, shared_ptr<MediaSetAccess> > _medias;
172       ProvideFilePolicy _defaultPolicy;
173     };
174
175
176
177     RepoMediaAccess::RepoMediaAccess( const ProvideFilePolicy & defaultPolicy_r )
178       : _impl( new Impl( defaultPolicy_r ) )
179     {}
180
181     RepoMediaAccess::~RepoMediaAccess()
182     {}
183
184     void RepoMediaAccess::setDefaultPolicy( const ProvideFilePolicy & policy_r )
185     { _impl->_defaultPolicy = policy_r; }
186
187     const ProvideFilePolicy & RepoMediaAccess::defaultPolicy() const
188     { return _impl->_defaultPolicy; }
189
190     ManagedFile RepoMediaAccess::provideFile( Repository repo_r,
191                                               const OnMediaLocation & loc_r,
192                                               const ProvideFilePolicy & policy_r )
193     {
194       MIL << "provideFile " << loc_r << endl;
195       // Arrange DownloadFileReportHack to recieve the source::DownloadFileReport
196       // and redirect download progress triggers to call the ProvideFilePolicy
197       // callback.
198       DownloadFileReportHack dumb;
199       dumb._redirect = bind( mem_fun_ref( &ProvideFilePolicy::progress ),
200                              ref( policy_r ), _1 );
201       callback::TempConnect<repo::RepoReport> temp( dumb );
202
203       Url url;
204       RepoInfo info = repo_r.info();
205       if ( info.baseUrlsEmpty() )
206         ZYPP_THROW(Exception(_("No url in repository.")));
207
208       for ( RepoInfo::urls_const_iterator it = info.baseUrlsBegin();
209             it != info.baseUrlsEnd();
210             ++it )
211       {
212         url = *it;
213         try
214         {
215           MIL << "Providing file of repo '" << info.alias()
216               << "' from " << url << endl;
217           shared_ptr<MediaSetAccess> access = _impl->mediaAccessForUrl(url);
218           _impl->setVerifierForRepo(repo_r, access);
219
220           ManagedFile ret( access->provideFile(loc_r) );
221
222           std::string scheme( url.getScheme() );
223           if ( scheme == "http" || scheme == "https" || scheme == "ftp" )
224           {
225             ret.setDispose( filesystem::unlink );
226           }
227
228           if ( loc_r.checksum().empty() )
229           {
230             // no checksum in metadata
231             WAR << "No checksum in metadata " << loc_r << endl;
232           }
233           else
234           {
235             std::ifstream input( ret->asString().c_str() );
236             CheckSum retChecksum( loc_r.checksum().type(), input );
237             input.close();
238
239             if ( loc_r.checksum() != retChecksum )
240             {
241               // failed integity check
242               std::ostringstream err;
243               err << "File " << ret << " fails integrity check. Expected: [" << loc_r.checksum() << "] Got: [";
244               if ( retChecksum.empty() )
245                 err << "Failed to compute checksum";
246               else
247                 err << retChecksum;
248               err << "]";
249
250               if ( policy_r.failOnChecksumError() )
251                 ZYPP_THROW( Exception( err.str() ) );
252               else
253                 WAR << "NO failOnChecksumError: " << err.str() << endl;
254             }
255           }
256
257           MIL << "provideFile at " << ret << endl;
258           return ret;
259         }
260         catch ( const SkipRequestException &e )
261         {
262           ZYPP_CAUGHT( e );
263           ZYPP_RETHROW(e);
264         }
265         catch ( const AbortRequestException &e )
266         {
267           ZYPP_CAUGHT( e );
268           ZYPP_RETHROW(e);
269         }
270         catch ( const Exception &e )
271         {
272           ZYPP_CAUGHT( e );
273           WAR << "Trying next url" << endl;
274           continue;
275         }
276       } // iteration over urls
277
278       ZYPP_THROW(Exception(str::form(_("Can't provide file %s from repository %s"),
279                                        loc_r.filename().c_str(),
280                                        info.alias().c_str() ) ) );
281
282       return ManagedFile(); // not reached
283     }
284
285     /////////////////////////////////////////////////////////////////
286   } // namespace repo
287   ///////////////////////////////////////////////////////////////////
288   /////////////////////////////////////////////////////////////////
289 } // namespace zypp
290 ///////////////////////////////////////////////////////////////////