- Fixed repo::provideFile to throw on error.
[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/Logger.h"
18 #include "zypp/repo/RepoProvideFile.h"
19 #include "zypp/ZYppCallbacks.h"
20 #include "zypp/MediaSetAccess.h"
21
22 using std::endl;
23 using std::set;
24
25 ///////////////////////////////////////////////////////////////////
26 namespace zypp
27 { /////////////////////////////////////////////////////////////////
28   ///////////////////////////////////////////////////////////////////
29   namespace repo
30   { /////////////////////////////////////////////////////////////////
31
32     ///////////////////////////////////////////////////////////////////
33     //
34     //  provideFile
35     //
36     ///////////////////////////////////////////////////////////////////
37
38     ///////////////////////////////////////////////////////////////////
39     namespace
40     { /////////////////////////////////////////////////////////////////
41
42       /** Hack to extract progress information from source::DownloadFileReport.
43        * We redirect the static report triggered from Repository::provideFile
44        * to feed the ProvideFilePolicy callbacks.
45       */
46       struct DownloadFileReportHack : public callback::ReceiveReport<repo::RepoReport>
47       {
48         virtual bool progress( int value )
49         {
50           if ( _redirect )
51             return _redirect( value );
52           return true;
53         }
54         function<bool ( int )> _redirect;
55       };
56
57       /** ManagedFile Dispose functor.
58        * The Pathname argument is ignored, as Repository::releaseFile expects the filename
59        * relative to the medias root (i.e. same args as to provideFile).
60       */
61       struct RepoReleaseFile
62       {
63         RepoReleaseFile( Repository repo_r, const Pathname & location_r, unsigned mediaNr_r )
64           : _repo( repo_r ), _location( location_r ), _medianr( mediaNr_r )
65         {}
66
67         void operator()( const Pathname & /*UNUSED*/ )
68         {
69           //_repo.releaseFile( _location, _medianr );
70         }
71
72         Repository _repo;
73         Pathname   _location;
74         unsigned   _medianr;
75       };
76
77       /////////////////////////////////////////////////////////////////
78     } // namespace
79     ///////////////////////////////////////////////////////////////////
80
81     ManagedFile provideFile( Repository repo_r,
82                              const OnMediaLocation & loc_r,
83                              const ProvideFilePolicy & policy_r )
84     {
85       MIL << "provideFile " << loc_r << endl;
86       // Arrange DownloadFileReportHack to recieve the source::DownloadFileReport
87       // and redirect download progress triggers to call the ProvideFilePolicy
88       // callback.
89       DownloadFileReportHack dumb;
90       dumb._redirect = bind( mem_fun_ref( &ProvideFilePolicy::progress ),
91                              ref( policy_r ), _1 );
92       callback::TempConnect<repo::RepoReport> temp( dumb );
93
94       Url url;
95       RepoInfo info = repo_r.info();
96       set<Url> urls = info.baseUrls();
97       if ( urls.empty() )
98         ZYPP_THROW(Exception(_("No url in repository.")));
99
100       for ( RepoInfo::urls_const_iterator it = urls.begin();
101             it != urls.end();
102             ++it )
103       {
104         url = *it;
105         try
106         {
107
108           MediaSetAccess access(url);
109
110           ManagedFile ret( access.provideFile(loc_r),
111                           RepoReleaseFile( repo_r, loc_r.filename(), loc_r.medianr() ) );
112
113           if ( loc_r.checksum().empty() )
114           {
115             // no checksum in metadata
116             WAR << "No checksum in metadata " << loc_r << endl;
117           }
118           else
119           {
120             std::ifstream input( ret->asString().c_str() );
121             CheckSum retChecksum( loc_r.checksum().type(), input );
122             input.close();
123
124             if ( loc_r.checksum() != retChecksum )
125             {
126               // failed integity check
127               std::ostringstream err;
128               err << "File " << ret << " fails integrity check. Expected: [" << loc_r.checksum() << "] Got: [";
129               if ( retChecksum.empty() )
130                 err << "Failed to compute checksum";
131               else
132                 err << retChecksum;
133               err << "]";
134
135               if ( policy_r.failOnChecksumError() )
136                 ZYPP_THROW( Exception( err.str() ) );
137               else
138                 WAR << "NO failOnChecksumError: " << err.str() << endl;
139             }
140           }
141
142           MIL << "provideFile at " << ret << endl;
143           return ret;
144         }
145         catch ( const Exception &e )
146         {
147           ZYPP_CAUGHT( e );
148           WAR << "Trying next url" << endl;
149           continue;
150         }
151       } // iteration over urls
152
153       ZYPP_THROW(Exception(_("No more urls in repository.")));
154       return ManagedFile(); // not reached
155     }
156
157     /////////////////////////////////////////////////////////////////
158   } // namespace repo
159   ///////////////////////////////////////////////////////////////////
160   /////////////////////////////////////////////////////////////////
161 } // namespace zypp
162 ///////////////////////////////////////////////////////////////////