- make FileChecker use exceptions instead of bool
[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/Fetcher.h"
18
19 using namespace std;
20
21 ///////////////////////////////////////////////////////////////////
22 namespace zypp
23 { /////////////////////////////////////////////////////////////////
24
25   /**
26    * Class to encapsulate the \ref OnMediaLocation object
27    * and the \ref FileChcker together
28    */
29   struct FetcherJob
30   {
31     FetcherJob( const OnMediaLocation &loc )
32       : location(loc)
33     {
34
35     }
36
37     OnMediaLocation location;
38     CompositeFileChecker checkers;
39   };
40
41   ///////////////////////////////////////////////////////////////////
42   //
43   //    CLASS NAME : Fetcher::Impl
44   //
45   /** Fetcher implementation. */
46   struct Fetcher::Impl
47   {
48
49   public:
50
51     void enqueue( const OnMediaLocation &resource, const FileChecker &checker  );
52     void enqueueDigested( const OnMediaLocation &resource, const FileChecker &checker );
53     void addCachePath( const Pathname &cache_dir );
54     void reset();
55     void start( const Pathname &dest_dir, MediaSetAccess &media );
56
57     /** Offer default Impl. */
58     static shared_ptr<Impl> nullimpl()
59     {
60       static shared_ptr<Impl> _nullimpl( new Impl );
61       return _nullimpl;
62     }
63
64   private:
65     friend Impl * rwcowClone<Impl>( const Impl * rhs );
66     /** clone for RWCOW_pointer */
67     Impl * clone() const
68     { return new Impl( *this ); }
69
70     std::list<FetcherJob> _resources;
71     std::list<Pathname> _caches;
72   };
73   ///////////////////////////////////////////////////////////////////
74
75
76   void Fetcher::Impl::enqueueDigested( const OnMediaLocation &resource, const FileChecker &checker )
77   {
78     CompositeFileChecker composite;
79     composite.add(ChecksumFileChecker(resource.checksum()));
80     composite.add(checker);
81     enqueue(resource, composite);
82   }
83   
84   void Fetcher::Impl::enqueue( const OnMediaLocation &resource, const FileChecker &checker )
85   {
86     FetcherJob job(resource);
87     job.checkers.add(checker);
88     _resources.push_back(resource);
89   }
90
91   void Fetcher::Impl::reset()
92   {
93     _resources.clear();
94     _caches.clear();
95   }
96   
97   void Fetcher::Impl::addCachePath( const Pathname &cache_dir )
98   {
99     _caches.push_back(cache_dir);
100   }
101   
102   void Fetcher::Impl::start( const Pathname &dest_dir, MediaSetAccess &media )
103   {
104     for ( list<FetcherJob>::const_iterator it_res = _resources.begin(); it_res != _resources.end(); ++it_res )
105     {
106       bool got_from_cache = false;
107       for ( list<Pathname>::const_iterator it_cache = _caches.begin(); it_cache != _caches.end(); ++it_cache )
108       {
109         // Pathinfos could be cached to avoid too many stats?
110         PathInfo info(*it_cache);
111         if ( info.isDir() )
112         {
113           // does the current file exists in the current cache?
114           Pathname cached_file = *it_cache + (*it_res).location.filename();
115           if ( PathInfo( cached_file ).isExist() )
116           {
117             // check the checksum
118             if ( is_checksum( cached_file, (*it_res).location.checksum() ) )
119             {
120               // cached
121               MIL << "file " << (*it_res).location.filename() << " found in previous cache. Using cached copy." << endl;
122               // checksum is already checked.
123               // we could later implement double failover and try to download if file copy fails.
124   
125               // replicate the complete path in the target directory
126               Pathname dest_full_path = dest_dir + (*it_res).location.filename();
127               if ( assert_dir( dest_full_path.dirname() ) != 0 )
128                 ZYPP_THROW( Exception("Can't create " + dest_full_path.dirname().asString()));
129   
130               if ( filesystem::copy(cached_file, dest_full_path ) != 0 )
131               { //copy_file2dir
132                 //ZYPP_THROW(SourceIOException("Can't copy " + cached_file.asString() + " to " + destination.asString()));
133                 ERR << "Can't copy " << cached_file + " to " + dest_dir << endl;
134                 // try next cache
135                 continue;
136               }
137   
138               got_from_cache = true;
139               break;
140             }
141           }
142           else
143           {
144             // File exists in cache but with a different checksum
145             // so just try next cache
146             continue;
147           }
148         }
149         else
150         {
151           // skip bad cache directory and try with next one
152           ERR << "Skipping cache : " << *it_cache << endl;
153           continue;
154         }
155       }
156   
157       if ( ! got_from_cache )
158       {
159         // try to get the file from the net
160         try
161         {
162           Pathname tmp_file = media.provideFile((*it_res).location);
163           Pathname dest_full_path = dest_dir + (*it_res).location.filename();
164           if ( assert_dir( dest_full_path.dirname() ) != 0 )
165                 ZYPP_THROW( Exception("Can't create " + dest_full_path.dirname().asString()));
166           if ( filesystem::copy(tmp_file, dest_full_path ) != 0 )
167           {
168             ZYPP_THROW( Exception("Can't copy " + tmp_file.asString() + " to " + dest_dir.asString()));
169           }
170           
171           
172         }
173         catch (const Exception & excpt_r)
174         {
175           ZYPP_CAUGHT(excpt_r);
176           ZYPP_THROW(Exception("Can't provide " + (*it_res).location.filename().asString() + " : " + excpt_r.msg() ));
177         }
178       }
179       else
180       {
181         // We got the file from cache
182         // continue with next file
183         continue;
184       }
185       
186       // no matter where did we got the file, try to validate it:
187        Pathname localfile = dest_dir + (*it_res).location.filename();
188        // call the checker function
189        try {
190          (*it_res).checkers(localfile);
191        }
192        catch ( const FileCheckException &e )
193        {
194           ZYPP_RETHROW(e);
195        }
196        catch ( const Exception &e )
197        {
198           ZYPP_RETHROW(e);
199        }
200        catch (...)
201        {
202           ZYPP_THROW(Exception("Unknown error while validating " + (*it_res).location.filename().asString()));
203        }
204     } // for each job
205   }
206
207   /** \relates Fetcher::Impl Stream output */
208   inline std::ostream & operator<<( std::ostream & str, const Fetcher::Impl & obj )
209   {
210     return str << "Fetcher::Impl";
211   }
212
213   ///////////////////////////////////////////////////////////////////
214   //
215   //    CLASS NAME : Fetcher
216   //
217   ///////////////////////////////////////////////////////////////////
218
219   ///////////////////////////////////////////////////////////////////
220   //
221   //    METHOD NAME : Fetcher::Fetcher
222   //    METHOD TYPE : Ctor
223   //
224   Fetcher::Fetcher()
225   : _pimpl( Impl::nullimpl() )
226   {}
227
228   ///////////////////////////////////////////////////////////////////
229   //
230   //    METHOD NAME : Fetcher::~Fetcher
231   //    METHOD TYPE : Dtor
232   //
233   Fetcher::~Fetcher()
234   {}
235
236   void Fetcher::enqueueDigested( const OnMediaLocation &resource, const FileChecker &checker )
237   {
238     _pimpl->enqueue(resource, checker);
239   }
240   
241   void Fetcher::enqueue( const OnMediaLocation &resource, const FileChecker &checker  )
242   {
243     _pimpl->enqueue(resource, checker);
244   }
245   
246   void Fetcher::addCachePath( const Pathname &cache_dir )
247   {
248     _pimpl->addCachePath(cache_dir);
249   }
250   
251   void Fetcher::reset()
252   {
253     _pimpl->reset();
254   }
255
256   void Fetcher::start( const Pathname &dest_dir, MediaSetAccess &media )
257   {
258     _pimpl->start(dest_dir, media);
259   }
260
261
262   /******************************************************************
263   **
264   **    FUNCTION NAME : operator<<
265   **    FUNCTION TYPE : std::ostream &
266   */
267   std::ostream & operator<<( std::ostream & str, const Fetcher & obj )
268   {
269     return str << *obj._pimpl;
270   }
271
272   /////////////////////////////////////////////////////////////////
273 } // namespace zypp
274 ///////////////////////////////////////////////////////////////////
275