- implement signature and checksum checker in
[platform/upstream/libzypp.git] / zypp / Fetcher.cc
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file       zypp/Fetcher.cc
10  *
11 */
12 #include <iostream>
13 #include <list>
14
15 #include "zypp/base/Logger.h"
16 #include "zypp/base/DefaultIntegral.h"
17 #include "zypp/ZYppFactory.h"
18 #include "zypp/Fetcher.h"
19 #include "zypp/KeyRing.h"
20
21 using namespace std;
22
23 ///////////////////////////////////////////////////////////////////
24 namespace zypp
25 { /////////////////////////////////////////////////////////////////
26
27   Fetcher::ChecksumFileChecker::ChecksumFileChecker( const CheckSum &checksum )
28     : _checksum(checksum)
29   {
30   }
31
32   bool Fetcher::ChecksumFileChecker::operator()( const Pathname &file )
33   {
34     callback::SendReport<DigestReport> report;
35     CheckSum real_checksum( _checksum.type(), filesystem::checksum( file, _checksum.type() ));
36     
37     if ( _checksum.empty() )
38     {
39       MIL << "File " <<  file << " has no checksum available." << std::endl;
40       if ( report->askUserToAcceptNoDigest(file) )
41       {
42         MIL << "User accepted " <<  file << " with no checksum." << std::endl;
43         return true;
44       }
45       else
46       {
47         return false;
48       }
49     }
50     else
51     {
52       if ( (real_checksum == _checksum) )
53       {
54         if ( report->askUserToAcceptWrongDigest( file, _checksum.checksum(), real_checksum.checksum() ) )
55         {
56           WAR << "User accepted " <<  file << " with WRONG CHECKSUM." << std::endl;
57           return true;
58         }
59         else
60         {
61           return false;
62         }
63       }
64       else
65       {
66         return true;
67       }
68     }
69   }
70
71   bool Fetcher::NullFileChecker::operator()(const Pathname &file )
72   {
73     return true;
74   }
75
76   bool Fetcher::CompositeFileChecker::operator()(const Pathname &file )
77   {
78     bool result = true;
79     for ( list<Fetcher::FileChecker>::iterator it = _checkers.begin(); it != _checkers.end(); ++it )
80     {
81       result = result && (*it)(file);
82     }
83     return result;
84   }
85   
86   void Fetcher::CompositeFileChecker::add( const FileChecker &checker )
87   {
88     _checkers.push_back(checker);
89   }
90
91   Fetcher::SignatureFileChecker::SignatureFileChecker( const Pathname &signature )
92     : _signature(signature)
93   {
94   }
95   
96   Fetcher::SignatureFileChecker::SignatureFileChecker()
97   {
98   }
99   
100   void Fetcher::SignatureFileChecker::addPublicKey( const Pathname &publickey )
101   {
102     ZYpp::Ptr z = getZYpp();
103     z->keyRing()->importKey(publickey, false);
104   }
105   
106   bool Fetcher::SignatureFileChecker::operator()(const Pathname &file )
107   {
108     ZYpp::Ptr z = getZYpp();
109     MIL << "checking " << file << " file vailidity using digital signature.." << endl;
110     bool valid = z->keyRing()->verifyFileSignatureWorkflow( file, string(), _signature);
111     return valid;
112   }
113   
114   /**
115    * Class to encapsulate the \ref OnMediaLocation object
116    * and the \ref Fetcher::FileChcker together
117    */
118   struct FetcherJob
119   {
120     FetcherJob( const OnMediaLocation &loc )
121       : location(loc)
122     {
123
124     }
125
126     OnMediaLocation location;
127     Fetcher::CompositeFileChecker checkers;
128   };
129
130   ///////////////////////////////////////////////////////////////////
131   //
132   //    CLASS NAME : Fetcher::Impl
133   //
134   /** Fetcher implementation. */
135   struct Fetcher::Impl
136   {
137
138   public:
139
140     void enqueue( const OnMediaLocation &resource, const Fetcher::FileChecker &checker  );
141     void enqueueDigested( const OnMediaLocation &resource, const Fetcher::FileChecker &checker );
142     void addCachePath( const Pathname &cache_dir );
143     void reset();
144     void start( const Pathname &dest_dir, MediaSetAccess &media );
145
146     /** Offer default Impl. */
147     static shared_ptr<Impl> nullimpl()
148     {
149       static shared_ptr<Impl> _nullimpl( new Impl );
150       return _nullimpl;
151     }
152
153   private:
154     friend Impl * rwcowClone<Impl>( const Impl * rhs );
155     /** clone for RWCOW_pointer */
156     Impl * clone() const
157     { return new Impl( *this ); }
158
159     std::list<FetcherJob> _resources;
160     std::list<Pathname> _caches;
161   };
162   ///////////////////////////////////////////////////////////////////
163
164
165   void Fetcher::Impl::enqueueDigested( const OnMediaLocation &resource, const FileChecker &checker )
166   {
167     CompositeFileChecker composite;
168     composite.add(ChecksumFileChecker(resource.checksum()));
169     composite.add(checker);
170     enqueue(resource, composite);
171   }
172   
173   void Fetcher::Impl::enqueue( const OnMediaLocation &resource, const FileChecker &checker )
174   {
175     FetcherJob job(resource);
176     job.checkers.add(checker);
177     _resources.push_back(resource);
178   }
179
180   void Fetcher::Impl::reset()
181   {
182     _resources.clear();
183     _caches.clear();
184   }
185   
186   void Fetcher::Impl::addCachePath( const Pathname &cache_dir )
187   {
188     _caches.push_back(cache_dir);
189   }
190   
191   void Fetcher::Impl::start( const Pathname &dest_dir, MediaSetAccess &media )
192   {
193     for ( list<FetcherJob>::const_iterator it_res = _resources.begin(); it_res != _resources.end(); ++it_res )
194     {
195       bool got_from_cache = false;
196       for ( list<Pathname>::const_iterator it_cache = _caches.begin(); it_cache != _caches.end(); ++it_cache )
197       {
198         // Pathinfos could be cached to avoid too many stats?
199         PathInfo info(*it_cache);
200         if ( info.isDir() )
201         {
202           // does the current file exists in the current cache?
203           Pathname cached_file = *it_cache + (*it_res).location.filename();
204           if ( PathInfo( cached_file ).isExist() )
205           {
206             // check the checksum
207             if ( is_checksum( cached_file, (*it_res).location.checksum() ) )
208             {
209               // cached
210               MIL << "file " << (*it_res).location.filename() << " found in previous cache. Using cached copy." << endl;
211               // checksum is already checked.
212               // we could later implement double failover and try to download if file copy fails.
213   
214               // replicate the complete path in the target directory
215               Pathname dest_full_path = dest_dir + (*it_res).location.filename();
216               if ( assert_dir( dest_full_path.dirname() ) != 0 )
217                 ZYPP_THROW( Exception("Can't create " + dest_full_path.dirname().asString()));
218   
219               if ( filesystem::copy(cached_file, dest_full_path ) != 0 )
220               { //copy_file2dir
221                 //ZYPP_THROW(SourceIOException("Can't copy " + cached_file.asString() + " to " + destination.asString()));
222                 ERR << "Can't copy " << cached_file + " to " + dest_dir << endl;
223                 // try next cache
224                 continue;
225               }
226   
227               got_from_cache = true;
228               break;
229             }
230           }
231           else
232           {
233             // File exists in cache but with a different checksum
234             // so just try next cache
235             continue;
236           }
237         }
238         else
239         {
240           // skip bad cache directory and try with next one
241           ERR << "Skipping cache : " << *it_cache << endl;
242           continue;
243         }
244       }
245   
246       if ( ! got_from_cache )
247       {
248         // try to get the file from the net
249         try
250         {
251           Pathname tmp_file = media.provideFile((*it_res).location);
252           Pathname dest_full_path = dest_dir + (*it_res).location.filename();
253           if ( assert_dir( dest_full_path.dirname() ) != 0 )
254                 ZYPP_THROW( Exception("Can't create " + dest_full_path.dirname().asString()));
255           if ( filesystem::copy(tmp_file, dest_full_path ) != 0 )
256           {
257             ZYPP_THROW( Exception("Can't copy " + tmp_file.asString() + " to " + dest_dir.asString()));
258           }
259         }
260         catch (const Exception & excpt_r)
261         {
262           ZYPP_CAUGHT(excpt_r);
263           ZYPP_THROW(Exception("Can't provide " + (*it_res).location.filename().asString() + " : " + excpt_r.msg() ));
264         }
265       }
266       else
267       {
268         // We got the file from cache
269         // continue with next file
270         continue;
271       }
272     }
273   }
274
275   /** \relates Fetcher::Impl Stream output */
276   inline std::ostream & operator<<( std::ostream & str, const Fetcher::Impl & obj )
277   {
278     return str << "Fetcher::Impl";
279   }
280
281   ///////////////////////////////////////////////////////////////////
282   //
283   //    CLASS NAME : Fetcher
284   //
285   ///////////////////////////////////////////////////////////////////
286
287   ///////////////////////////////////////////////////////////////////
288   //
289   //    METHOD NAME : Fetcher::Fetcher
290   //    METHOD TYPE : Ctor
291   //
292   Fetcher::Fetcher()
293   : _pimpl( Impl::nullimpl() )
294   {}
295
296   ///////////////////////////////////////////////////////////////////
297   //
298   //    METHOD NAME : Fetcher::~Fetcher
299   //    METHOD TYPE : Dtor
300   //
301   Fetcher::~Fetcher()
302   {}
303
304   void Fetcher::enqueueDigested( const OnMediaLocation &resource, const Fetcher::FileChecker &checker )
305   {
306     _pimpl->enqueue(resource, checker);
307   }
308   
309   void Fetcher::enqueue( const OnMediaLocation &resource, const Fetcher::FileChecker &checker  )
310   {
311     _pimpl->enqueue(resource, checker);
312   }
313   
314   void Fetcher::addCachePath( const Pathname &cache_dir )
315   {
316     _pimpl->addCachePath(cache_dir);
317   }
318   
319   void Fetcher::reset()
320   {
321     _pimpl->reset();
322   }
323
324   void Fetcher::start( const Pathname &dest_dir, MediaSetAccess &media )
325   {
326     _pimpl->start(dest_dir, media);
327   }
328
329
330   /******************************************************************
331   **
332   **    FUNCTION NAME : operator<<
333   **    FUNCTION TYPE : std::ostream &
334   */
335   std::ostream & operator<<( std::ostream & str, const Fetcher & obj )
336   {
337     return str << *obj._pimpl;
338   }
339
340   /////////////////////////////////////////////////////////////////
341 } // namespace zypp
342 ///////////////////////////////////////////////////////////////////
343