Fetcher.cc

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------\
00002 |                          ____ _   __ __ ___                          |
00003 |                         |__  / \ / / . \ . \                         |
00004 |                           / / \ V /|  _/  _/                         |
00005 |                          / /__ | | | | | |                           |
00006 |                         /_____||_| |_| |_|                           |
00007 |                                                                      |
00008 \---------------------------------------------------------------------*/
00012 #include <iostream>
00013 #include <fstream>
00014 #include <list>
00015 #include <map>
00016 
00017 #include "zypp/base/Easy.h"
00018 #include "zypp/base/LogControl.h"
00019 #include "zypp/base/LogTools.h"
00020 #include "zypp/base/PtrTypes.h"
00021 #include "zypp/base/DefaultIntegral.h"
00022 #include "zypp/base/String.h"
00023 #include "zypp/Fetcher.h"
00024 #include "zypp/ZYppFactory.h"
00025 #include "zypp/CheckSum.h"
00026 #include "zypp/base/UserRequestException.h"
00027 #include "zypp/parser/susetags/ContentFileReader.h"
00028 #include "zypp/parser/susetags/RepoIndex.h"
00029 
00030 using namespace std;
00031 
00032 #undef ZYPP_BASE_LOGGER_LOGGROUP
00033 #define ZYPP_BASE_LOGGER_LOGGROUP "zypp:fetcher"
00034 
00036 namespace zypp
00037 { 
00038 
00044   struct FetcherIndex
00045   {
00046     FetcherIndex( const OnMediaLocation &loc )
00047       : location(loc)
00048     {}
00050     OnMediaLocation             location;
00052     DefaultIntegral<bool,false> read;
00053   };
00054 
00055   typedef shared_ptr<FetcherIndex> FetcherIndex_Ptr;
00056 
00058   struct SameFetcherIndex
00059   {
00060     bool operator()( const FetcherIndex_Ptr & lhs, const FetcherIndex_Ptr & rhs )
00061     {
00062       if ( lhs == rhs )
00063         return false; // incl. NULL == NULL
00064       if ( ! lhs )
00065         return true;  // NULL < nonNULL
00066       if ( ! rhs )
00067         return false; // nonNULL > NULL
00068       // both nonNULL ==> compare medianr and path
00069       if ( lhs->location.medianr() == rhs->location.medianr() )
00070         return lhs->location.filename() < rhs->location.filename();
00071       //else
00072         return lhs->location.medianr() < rhs->location.medianr();
00073     }
00074   };
00075 
00080   struct FetcherJob
00081   {
00082     enum Flag
00083     {
00084         None      = 0x0000,
00085         Directory = 0x0001,
00086         Recursive = 0x0002,
00087         RecursiveDirectory = Directory | Recursive,
00088         // check checksums even if there is no such
00089         // checksum (warns of no checksum)
00090         AlwaysVerifyChecksum = 0x0004,
00091     };
00092     ZYPP_DECLARE_FLAGS(Flags, Flag);
00093 
00094 
00095     FetcherJob( const OnMediaLocation &loc )
00096       : location(loc)
00097       , flags(None)
00098     {
00099       //MIL << location << endl;
00100     }
00101 
00102     ~FetcherJob()
00103     {
00104       //MIL << location << " | * " << checkers.size() << endl;
00105     }
00106 
00107     OnMediaLocation location;
00108     //CompositeFileChecker checkers;
00109     list<FileChecker> checkers;
00110     Flags flags;
00111   };
00112 
00113   ZYPP_DECLARE_OPERATORS_FOR_FLAGS(FetcherJob::Flags);
00114   typedef shared_ptr<FetcherJob> FetcherJob_Ptr;
00115 
00116   std::ostream & operator<<( std::ostream & str, const FetcherJob_Ptr & obj )
00117   {
00118     return str << obj->location;
00119   }
00120 
00122   //
00123   //    CLASS NAME : Fetcher::Impl
00124   //
00126   class Fetcher::Impl
00127   {
00128     friend std::ostream & operator<<( std::ostream & str, const Fetcher::Impl & obj );
00129 
00130   public:
00131     Impl();
00132 
00133     ~Impl() {}
00134 
00135     void setOptions( Fetcher::Options options );
00136     Fetcher::Options options() const;
00137 
00138     void addIndex( const OnMediaLocation &resource );
00139 
00140     void enqueueDir( const OnMediaLocation &resource, bool recursive, const FileChecker &checker = FileChecker() );
00141     void enqueueDigestedDir( const OnMediaLocation &resource, bool recursive, const FileChecker &checker = FileChecker() );
00142 
00143     void enqueue( const OnMediaLocation &resource, const FileChecker &checker = FileChecker()  );
00144     void enqueueDigested( const OnMediaLocation &resource, const FileChecker &checker = FileChecker() );
00145     void addCachePath( const Pathname &cache_dir );
00146     void reset();
00147     void start( const Pathname &dest_dir,
00148                 MediaSetAccess &media,
00149                 const ProgressData::ReceiverFnc & progress_receiver );
00150 
00152     static shared_ptr<Impl> nullimpl()
00153     {
00154       static shared_ptr<Impl> _nullimpl( new Impl );
00155       return _nullimpl;
00156     }
00157   private:
00161       void downloadAndReadIndexList( MediaSetAccess &media, const Pathname &dest_dir);
00162 
00166       void downloadIndex( MediaSetAccess &media, const OnMediaLocation &resource, const Pathname &dest_dir);
00167 
00175       void readIndex( const Pathname &index, const Pathname &basedir );
00176 
00178       void readSha1sumsIndex( const Pathname &index, const Pathname &basedir );
00179 
00181       void readContentFileIndex( const Pathname &index, const Pathname &basedir );
00182 
00184       void getDirectoryContent( MediaSetAccess &media, const OnMediaLocation &resource, filesystem::DirContent &content );
00185 
00191       bool provideFromCache( const OnMediaLocation &resource, const Pathname &dest_dir );
00197       void validate( const OnMediaLocation &resource, const Pathname &dest_dir, const list<FileChecker> &checkers );
00198 
00202        void addDirJobs( MediaSetAccess &media, const OnMediaLocation &resource,
00203                         const Pathname &dest_dir, FetcherJob::Flags flags );
00204 
00208       void autoaddIndexes( const filesystem::DirContent &content,
00209                            MediaSetAccess &media,
00210                            const OnMediaLocation &resource,
00211                            const Pathname &dest_dir );
00215       void provideToDest( MediaSetAccess &media, const OnMediaLocation &resource, const Pathname &dest_dir );
00216 
00217   private:
00218     friend Impl * rwcowClone<Impl>( const Impl * rhs );
00220     Impl * clone() const
00221     { return new Impl( *this ); }
00222 
00223     list<FetcherJob_Ptr>   _resources;
00224     std::set<FetcherIndex_Ptr,SameFetcherIndex> _indexes;
00225     std::set<Pathname> _caches;
00226     // checksums read from the indexes
00227     map<string, CheckSum> _checksums;
00228     // cache of dir contents
00229     map<string, filesystem::DirContent> _dircontent;
00230 
00231     Fetcher::Options _options;
00232   };
00234 
00235   void Fetcher::Impl::enqueueDigested( const OnMediaLocation &resource, const FileChecker &checker )
00236   {
00237     FetcherJob_Ptr job;
00238     job.reset(new FetcherJob(resource));
00239     job->flags |= FetcherJob:: AlwaysVerifyChecksum;
00240     _resources.push_back(job);
00241   }
00242 
00243   Fetcher::Impl::Impl()
00244       : _options(0)
00245   {
00246   }
00247 
00248   void Fetcher::Impl::setOptions( Fetcher::Options options )
00249   { _options = options; }
00250 
00251   Fetcher::Options Fetcher::Impl::options() const
00252   { return _options; }
00253 
00254   void Fetcher::Impl::enqueueDir( const OnMediaLocation &resource,
00255                                   bool recursive,
00256                                   const FileChecker &checker )
00257   {
00258     FetcherJob_Ptr job;
00259     job.reset(new FetcherJob(resource));
00260     if ( checker )
00261         job->checkers.push_back(checker);
00262     if ( recursive )
00263         job->flags |= FetcherJob::Recursive;
00264     job->flags |= FetcherJob::Directory;
00265 
00266     _resources.push_back(job);
00267   }
00268 
00269   void Fetcher::Impl::enqueueDigestedDir( const OnMediaLocation &resource,
00270                                           bool recursive,
00271                                           const FileChecker &checker )
00272   {
00273     FetcherJob_Ptr job;
00274     job.reset(new FetcherJob(resource));
00275     if ( checker )
00276         job->checkers.push_back(checker);
00277     if ( recursive )
00278         job->flags |= FetcherJob::Recursive;
00279     job->flags |= FetcherJob::Directory;
00280     job->flags |= FetcherJob::AlwaysVerifyChecksum;
00281 
00282     _resources.push_back(job);
00283 
00284   }
00285 
00286   void Fetcher::Impl::enqueue( const OnMediaLocation &resource, const FileChecker &checker )
00287   {
00288     FetcherJob_Ptr job;
00289     job.reset(new FetcherJob(resource));
00290     if ( checker )
00291       job->checkers.push_back(checker);
00292     _resources.push_back(job);
00293   }
00294 
00295   void Fetcher::Impl::addIndex( const OnMediaLocation &resource )
00296   {
00297     MIL << "adding index " << resource << endl;
00298     _indexes.insert(FetcherIndex_Ptr(new FetcherIndex(resource)));
00299   }
00300 
00301 
00302   void Fetcher::Impl::reset()
00303   {
00304     _resources.clear();
00305     _indexes.clear();
00306     _checksums.clear();
00307     _dircontent.clear();
00308   }
00309 
00310   void Fetcher::Impl::addCachePath( const Pathname &cache_dir )
00311   {
00312     PathInfo info(cache_dir);
00313     if ( info.isExist() )
00314     {
00315       if ( info.isDir() )
00316       {
00317         DBG << "Adding fetcher cache: '" << cache_dir << "'." << endl;
00318         _caches.insert(cache_dir);
00319       }
00320       else
00321       {
00322         // don't add bad cache directory, just log the error
00323         ERR << "Not adding cache: '" << cache_dir << "'. Not a directory." << endl;
00324       }
00325     }
00326     else
00327     {
00328         ERR << "Not adding cache '" << cache_dir << "'. Path does not exists." << endl;
00329     }
00330 
00331   }
00332 
00333   // tries to provide resource to dest_dir from any of the configured additional
00334   // cache paths where the file may already be present. returns true if the
00335   // file was provided from the cache.
00336   bool Fetcher::Impl::provideFromCache( const OnMediaLocation &resource, const Pathname &dest_dir )
00337   {
00338     Pathname dest_full_path = dest_dir + resource.filename();
00339 
00340     // first check in the destination directory
00341     if ( PathInfo(dest_full_path).isExist() )
00342     {
00343       if ( is_checksum( dest_full_path, resource.checksum() )
00344            && (! resource.checksum().empty() ) )
00345           return true;
00346     }
00347 
00348     MIL << "start fetcher with " << _caches.size() << " cache directories." << endl;
00349     for_ ( it_cache, _caches.begin(), _caches.end() )
00350     {
00351       // does the current file exists in the current cache?
00352       Pathname cached_file = *it_cache + resource.filename();
00353       if ( PathInfo( cached_file ).isExist() )
00354       {
00355         DBG << "File '" << cached_file << "' exist, testing checksum " << resource.checksum() << endl;
00356          // check the checksum
00357         if ( is_checksum( cached_file, resource.checksum() ) && (! resource.checksum().empty() ) )
00358         {
00359           // cached
00360           MIL << "file " << resource.filename() << " found in previous cache. Using cached copy." << endl;
00361           // checksum is already checked.
00362           // we could later implement double failover and try to download if file copy fails.
00363            // replicate the complete path in the target directory
00364           if( dest_full_path != cached_file )
00365           {
00366             if ( assert_dir( dest_full_path.dirname() ) != 0 )
00367               ZYPP_THROW( Exception("Can't create " + dest_full_path.dirname().asString()));
00368 
00369             if ( filesystem::hardlinkCopy(cached_file, dest_full_path ) != 0 )
00370             {
00371               ERR << "Can't hardlink/copy " << cached_file + " to " + dest_dir << endl;
00372               continue;
00373             }
00374           }
00375           // found in cache
00376           return true;
00377         }
00378       }
00379     } // iterate over caches
00380     return false;
00381   }
00382 
00383     void Fetcher::Impl::validate( const OnMediaLocation &resource, const Pathname &dest_dir, const list<FileChecker> &checkers )
00384   {
00385     // no matter where did we got the file, try to validate it:
00386     Pathname localfile = dest_dir + resource.filename();
00387     // call the checker function
00388     try
00389     {
00390       MIL << "Checking job [" << localfile << "] (" << checkers.size() << " checkers )" << endl;
00391 
00392       for ( list<FileChecker>::const_iterator it = checkers.begin();
00393             it != checkers.end();
00394             ++it )
00395       {
00396         if (*it)
00397         {
00398           (*it)(localfile);
00399         }
00400         else
00401         {
00402           ERR << "Invalid checker for '" << localfile << "'" << endl;
00403         }
00404       }
00405 
00406     }
00407     catch ( const FileCheckException &e )
00408     {
00409       ZYPP_RETHROW(e);
00410     }
00411     catch ( const Exception &e )
00412     {
00413       ZYPP_RETHROW(e);
00414     }
00415     catch (...)
00416     {
00417       ZYPP_THROW(Exception("Unknown error while validating " + resource.filename().asString()));
00418     }
00419   }
00420 
00421   void Fetcher::Impl::autoaddIndexes( const filesystem::DirContent &content,
00422                                       MediaSetAccess &media,
00423                                       const OnMediaLocation &resource,
00424                                       const Pathname &dest_dir )
00425   {
00426       if ( _options & AutoAddSha1sumsIndexes )
00427       {
00428           // only try to add an index if it exists
00429           filesystem::DirEntry shafile;
00430           shafile.name = "SHA1SUMS"; shafile.type = filesystem::FT_FILE;
00431           if ( find( content.begin(), content.end(), shafile ) != content.end() )
00432           {
00433               // add the index of this directory
00434               OnMediaLocation indexloc(resource);
00435               indexloc.changeFilename(resource.filename() + "SHA1SUMS");
00436               addIndex(indexloc);
00437               // we need to read it now
00438               downloadAndReadIndexList(media, dest_dir);
00439           }
00440       }
00441       if ( _options & AutoAddContentFileIndexes )
00442       {
00443           // only try to add an index if it exists
00444           filesystem::DirEntry contentfile;
00445           contentfile.name = "content"; contentfile.type = filesystem::FT_FILE;
00446           if ( find( content.begin(), content.end(), contentfile ) != content.end() )
00447           {
00448               // add the index of this directory
00449               OnMediaLocation indexloc(resource);
00450               indexloc.changeFilename(resource.filename() + "content");
00451               addIndex(indexloc);
00452               // we need to read it now
00453               downloadAndReadIndexList(media, dest_dir);
00454           }
00455       }
00456   }
00457 
00458   void Fetcher::Impl::getDirectoryContent( MediaSetAccess &media,
00459                                            const OnMediaLocation &resource,
00460                                            filesystem::DirContent &content )
00461   {
00462       if ( _dircontent.find(resource.filename().asString())
00463            != _dircontent.end() )
00464       {
00465           filesystem::DirContent filled(_dircontent[resource.filename().asString()]);
00466 
00467           std::copy(filled.begin(), filled.end(), std::back_inserter(content));
00468       }
00469       else
00470       {
00471           filesystem::DirContent tofill;
00472           media.dirInfo( tofill,
00473                          resource.filename(),
00474                          false /* dots */,
00475                          resource.medianr());
00476           std::copy(tofill.begin(), tofill.end(), std::back_inserter(content));
00477           _dircontent[resource.filename().asString()] = tofill;
00478       }
00479   }
00480 
00481   void Fetcher::Impl::addDirJobs( MediaSetAccess &media,
00482                                   const OnMediaLocation &resource,
00483                                   const Pathname &dest_dir, FetcherJob::Flags flags  )
00484   {
00485       // first get the content of the directory so we can add
00486       // individual transfer jobs
00487       MIL << "Adding directory " << resource.filename() << endl;
00488       filesystem::DirContent content;
00489       getDirectoryContent(media, resource, content);
00490 
00491       // this method test for the option flags so indexes are added
00492       // only if the options are enabled
00493       autoaddIndexes(content, media, resource, dest_dir);
00494 
00495       for ( filesystem::DirContent::const_iterator it = content.begin();
00496             it != content.end();
00497             ++it )
00498       {
00499           // skip SHA1SUMS* as they were already retrieved
00500           if ( str::hasPrefix(it->name, "SHA1SUMS") )
00501               continue;
00502 
00503           Pathname filename = resource.filename() + it->name;
00504 
00505           switch ( it->type )
00506           {
00507           case filesystem::FT_NOT_AVAIL: // old directory.yast contains no typeinfo at all
00508           case filesystem::FT_FILE:
00509           {
00510               CheckSum chksm(resource.checksum());
00511               if ( _checksums.find(filename.asString()) != _checksums.end() )
00512               {
00513                   // the checksum can be replaced with the one in the index.
00514                   chksm = _checksums[filename.asString()];
00515                   //MIL << "resource " << filename << " has checksum in the index file." << endl;
00516               }
00517               else
00518                   WAR << "Resource " << filename << " has no checksum in the index either." << endl;
00519 
00520               if ( flags & FetcherJob::AlwaysVerifyChecksum )
00521                   enqueueDigested(OnMediaLocation(filename, resource.medianr()).setChecksum(chksm));
00522               else
00523                   enqueue(OnMediaLocation(filename, resource.medianr()).setChecksum(chksm));
00524               break;
00525           }
00526           case filesystem::FT_DIR: // newer directory.yast contain at least directory info
00527               if ( flags & FetcherJob::Recursive )
00528                   addDirJobs(media, filename, dest_dir, flags);
00529               break;
00530           default:
00531               // don't provide devices, sockets, etc.
00532               break;
00533           }
00534       }
00535   }
00536 
00537   void Fetcher::Impl::provideToDest( MediaSetAccess &media, const OnMediaLocation &resource, const Pathname &dest_dir )
00538   {
00539     bool got_from_cache = false;
00540 
00541     // start look in cache
00542     got_from_cache = provideFromCache(resource, dest_dir);
00543 
00544     if ( ! got_from_cache )
00545     {
00546       MIL << "Not found in cache, downloading" << endl;
00547 
00548       // try to get the file from the net
00549       try
00550       {
00551         Pathname tmp_file = media.provideFile(resource, resource.optional() ? MediaSetAccess::PROVIDE_NON_INTERACTIVE : MediaSetAccess::PROVIDE_DEFAULT );
00552 
00553         Pathname dest_full_path = dest_dir + resource.filename();
00554 
00555         if ( assert_dir( dest_full_path.dirname() ) != 0 )
00556               ZYPP_THROW( Exception("Can't create " + dest_full_path.dirname().asString()));
00557         if ( filesystem::hardlinkCopy( tmp_file, dest_full_path ) != 0 )
00558         {
00559           if ( ! PathInfo(tmp_file).isExist() )
00560               ERR << tmp_file << " does not exist" << endl;
00561           if ( ! PathInfo(dest_full_path.dirname()).isExist() )
00562               ERR << dest_full_path.dirname() << " does not exist" << endl;
00563 
00564           media.releaseFile(resource); //not needed anymore, only eat space
00565           ZYPP_THROW( Exception("Can't hardlink/copy " + tmp_file.asString() + " to " + dest_dir.asString()));
00566         }
00567 
00568         media.releaseFile(resource); //not needed anymore, only eat space
00569       }
00570       catch (Exception & excpt_r)
00571       {
00572         ZYPP_CAUGHT(excpt_r);
00573         excpt_r.remember("Can't provide " + resource.filename().asString() + " : " + excpt_r.msg());
00574 
00575         if ( resource.optional() )
00576         {
00577             WAR << "optional resource " << resource << " could not be transfered" << endl;
00578             return;
00579         }
00580         else
00581         {
00582             ZYPP_RETHROW(excpt_r);
00583         }
00584       }
00585     }
00586     else
00587     {
00588       // We got the file from cache
00589       // continue with next file
00590         return;
00591     }
00592   }
00593 
00594   // helper class to consume a content file
00595   struct ContentReaderHelper : public parser::susetags::ContentFileReader
00596   {
00597     ContentReaderHelper()
00598     {
00599       setRepoIndexConsumer( bind( &ContentReaderHelper::consumeIndex, this, _1 ) );
00600     }
00601 
00602     void consumeIndex( const parser::susetags::RepoIndex_Ptr & data_r )
00603     { _repoindex = data_r; }
00604 
00605     parser::susetags::RepoIndex_Ptr _repoindex;
00606   };
00607 
00608   // generic function for reading indexes
00609   void Fetcher::Impl::readIndex( const Pathname &index, const Pathname &basedir )
00610   {
00611     if ( index.basename() == "SHA1SUMS" )
00612       readSha1sumsIndex(index, basedir);
00613     else if ( index.basename() == "content" )
00614       readContentFileIndex(index, basedir);
00615     else
00616       WAR << index << ": index file format not known" << endl;
00617   }
00618 
00619   // reads a content file index
00620   void Fetcher::Impl::readContentFileIndex( const Pathname &index, const Pathname &basedir )
00621   {
00622       ContentReaderHelper reader;
00623       reader.parse(index);
00624       MIL << index << " contains " << reader._repoindex->mediaFileChecksums.size() << " checksums." << endl;
00625       for_( it, reader._repoindex->mediaFileChecksums.begin(), reader._repoindex->mediaFileChecksums.end() )
00626       {
00627           // content file entries don't start with /
00628           _checksums[(basedir + it->first).asString()] = it->second;
00629       }
00630   }
00631 
00632   // reads a SHA1SUMS file index
00633   void Fetcher::Impl::readSha1sumsIndex( const Pathname &index, const Pathname &basedir )
00634   {
00635       std::ifstream in( index.c_str() );
00636       string buffer;
00637       if ( ! in.fail() )
00638       {
00639           while ( getline(in, buffer) )
00640           {
00641               vector<string> words;
00642               str::split( buffer, back_inserter(words) );
00643               if ( words.size() != 2 )
00644                   ZYPP_THROW(Exception("Wrong format for SHA1SUMS file"));
00645               //MIL << "check: '" << words[0] << "' | '" << words[1] << "'" << endl;
00646               if ( ! words[1].empty() )
00647                   _checksums[(basedir + words[1]).asString()] = CheckSum::sha1(words[0]);
00648           }
00649       }
00650       else
00651           ZYPP_THROW(Exception("Can't open SHA1SUMS file: " + index.asString()));
00652   }
00653 
00654   void Fetcher::Impl::downloadIndex( MediaSetAccess &media, const OnMediaLocation &resource, const Pathname &dest_dir)
00655   {
00656     MIL << "downloading index " << resource << endl;
00657     // create a new fetcher with a different state to transfer the
00658     // file containing checksums and its signature
00659     Fetcher fetcher;
00660     // signature checker for index. We havent got the signature from
00661     // the nextwork yet.
00662     SignatureFileChecker sigchecker;
00663 
00664     // build the name of the index and the signature
00665     OnMediaLocation idxloc(resource);
00666     OnMediaLocation sigloc(resource);
00667     OnMediaLocation keyloc(resource);
00668 
00669     // we should not fail the download if those don't exists
00670     // the checking will warn later
00671     sigloc.setOptional(true);
00672     keyloc.setOptional(true);
00673 
00674     // calculate signature and key name
00675     sigloc.changeFilename( sigloc.filename().extend(".asc") );
00676     keyloc.changeFilename( keyloc.filename().extend(".key") );
00677 
00678     //assert_dir(dest_dir + idxloc.filename().dirname());
00679 
00680     // transfer the signature
00681     fetcher.enqueue(sigloc);
00682     fetcher.start( dest_dir, media );
00683     // if we get the signature, update the checker
00684     if ( PathInfo(dest_dir + sigloc.filename()).isExist() )
00685         sigchecker = SignatureFileChecker(dest_dir + sigloc.filename());
00686 
00687     fetcher.reset();
00688 
00689     // now the key
00690     fetcher.enqueue(keyloc);
00691     fetcher.start( dest_dir, media );
00692     fetcher.reset();
00693 
00694     // try to import the key
00695     if ( PathInfo(dest_dir + keyloc.filename()).isExist() )
00696         getZYpp()->keyRing()->importKey(PublicKey(dest_dir + keyloc.filename()), false);
00697     else
00698         WAR << "No public key specified by user for index '" << keyloc.filename() << "'"<< endl;
00699 
00700     // now the index itself
00701     fetcher.enqueue( idxloc, FileChecker(sigchecker) );
00702     fetcher.start( dest_dir, media );
00703     fetcher.reset();
00704  }
00705 
00706   // this method takes all the user pointed indexes, gets them and also tries to
00707   // download their signature, and verify them. After that, its parses each one
00708   // to fill the checksum cache.
00709   void Fetcher::Impl::downloadAndReadIndexList( MediaSetAccess &media, const Pathname &dest_dir)
00710   {
00711       // if there is no indexes, then just return to avoid
00712       // the directory listing
00713       if ( _indexes.empty() )
00714       {
00715           MIL << "No indexes to read." << endl;
00716           return;
00717       }
00718 
00719       for_( it_idx, _indexes.begin(), _indexes.end() )
00720       {
00721         if ( (*it_idx)->read )
00722         {
00723           DBG << "Already read index " << PathInfo(dest_dir + (*it_idx)->location.filename()) << endl;
00724         }
00725         else
00726         {
00727           // base::LogControl::TmpLineWriter shutUp;
00728           downloadIndex( media, (*it_idx)->location, dest_dir );
00729           // now we have the indexes in dest_dir
00730           readIndex( dest_dir + (*it_idx)->location.filename(), (*it_idx)->location.filename().dirname() );
00731           // Take care we don't process it again
00732           MIL << "Remember read index " << PathInfo(dest_dir + (*it_idx)->location.filename()) << endl;
00733           (*it_idx)->read = true;
00734         }
00735       }
00736       MIL << "done reading indexes" << endl;
00737   }
00738 
00739   // start processing all fetcher jobs.
00740   // it processes any user pointed index first
00741   void Fetcher::Impl::start( const Pathname &dest_dir,
00742                              MediaSetAccess &media,
00743                              const ProgressData::ReceiverFnc & progress_receiver )
00744   {
00745     ProgressData progress(_resources.size());
00746     progress.sendTo(progress_receiver);
00747 
00748     downloadAndReadIndexList(media, dest_dir);
00749 
00750     for ( list<FetcherJob_Ptr>::const_iterator it_res = _resources.begin(); it_res != _resources.end(); ++it_res )
00751     {
00752 
00753       if ( (*it_res)->flags & FetcherJob::Directory )
00754       {
00755           const OnMediaLocation location((*it_res)->location);
00756           addDirJobs(media, location, dest_dir, (*it_res)->flags);
00757           continue;
00758       }
00759 
00760       // may be this code can be factored out
00761       // together with the autodiscovery of indexes
00762       // of addDirJobs
00763       if ( ( _options & AutoAddSha1sumsIndexes ) ||
00764            ( _options & AutoAddContentFileIndexes ) )
00765       {
00766           // if auto indexing is enabled, then we need to read the
00767           // index for each file. We look only in the directory
00768           // where the file is. this is expensive of course.
00769           filesystem::DirContent content;
00770           getDirectoryContent(media, (*it_res)->location.filename().dirname(), content);
00771           // this method test for the option flags so indexes are added
00772           // only if the options are enabled
00773           MIL << "Autodiscovering signed indexes on '"
00774               << (*it_res)->location.filename().dirname() << "' for '"
00775               << (*it_res)->location.filename() << "'" << endl;
00776 
00777           autoaddIndexes(content, media, (*it_res)->location.filename().dirname(), dest_dir);
00778 
00779           // also look in the root of the media
00780           content.clear();
00781           getDirectoryContent(media, Pathname("/"), content);
00782           // this method test for the option flags so indexes are added
00783           // only if the options are enabled
00784           MIL << "Autodiscovering signed indexes on '"
00785               << "/" << "' for '"
00786               << (*it_res)->location.filename() << "'" << endl;
00787 
00788           autoaddIndexes(content, media, Pathname("/"), dest_dir);
00789       }
00790 
00791       provideToDest(media, (*it_res)->location, dest_dir);
00792 
00793       // if the file was not transfered, and no exception, just
00794       // return, as it was an optional file
00795       if ( ! PathInfo(dest_dir + (*it_res)->location.filename()).isExist() )
00796           return;
00797 
00798       // if the checksum is empty, but the checksum is in one of the
00799       // indexes checksum, then add a checker
00800       if ( (*it_res)->location.checksum().empty() )
00801       {
00802           if ( _checksums.find((*it_res)->location.filename().asString())
00803                != _checksums.end() )
00804           {
00805               CheckSum chksm = _checksums[(*it_res)->location.filename().asString()];
00806               ChecksumFileChecker digest_check(chksm);
00807               (*it_res)->checkers.push_back(digest_check);
00808           }
00809           else
00810           {
00811               // if the index checksum is empty too, we only add the checker
00812               // if the  AlwaysVerifyChecksum option is set on
00813               if ( (*it_res)->flags & FetcherJob::AlwaysVerifyChecksum )
00814               {
00815                   // add the checker with the empty checksum
00816                   ChecksumFileChecker digest_check((*it_res)->location.checksum());
00817                   (*it_res)->checkers.push_back(digest_check);
00818               }
00819           }
00820       }
00821       else
00822       {
00823           // checksum is not empty, so add a checksum checker
00824           ChecksumFileChecker digest_check((*it_res)->location.checksum());
00825           (*it_res)->checkers.push_back(digest_check);
00826       }
00827 
00828       // validate job, this throws if not valid
00829       validate((*it_res)->location, dest_dir, (*it_res)->checkers);
00830 
00831       if ( ! progress.incr() )
00832         ZYPP_THROW(AbortRequestException());
00833     } // for each job
00834   }
00835 
00837   inline std::ostream & operator<<( std::ostream & str, const Fetcher::Impl & obj )
00838   {
00839       for ( list<FetcherJob_Ptr>::const_iterator it_res = obj._resources.begin(); it_res != obj._resources.end(); ++it_res )
00840       {
00841           str << *it_res;
00842       }
00843       return str;
00844   }
00845 
00846   Fetcher::Fetcher()
00847   : _pimpl( new Impl() )
00848   {}
00849 
00850   Fetcher::~Fetcher()
00851   {}
00852 
00853   void Fetcher::setOptions( Fetcher::Options options )
00854   {
00855     _pimpl->setOptions(options);
00856   }
00857 
00858   Fetcher::Options Fetcher::options() const
00859   {
00860     return _pimpl->options();
00861   }
00862 
00863   void Fetcher::enqueueDigested( const OnMediaLocation &resource, const FileChecker &checker )
00864   {
00865     _pimpl->enqueueDigested(resource, checker);
00866   }
00867 
00868   void Fetcher::enqueueDir( const OnMediaLocation &resource,
00869                             bool recursive,
00870                             const FileChecker &checker )
00871   {
00872       _pimpl->enqueueDir(resource, recursive, checker);
00873   }
00874 
00875   void Fetcher::enqueueDigestedDir( const OnMediaLocation &resource,
00876                                     bool recursive,
00877                                     const FileChecker &checker )
00878   {
00879       _pimpl->enqueueDigestedDir(resource, recursive, checker);
00880   }
00881 
00882 
00883   void Fetcher::addIndex( const OnMediaLocation &resource )
00884   {
00885     _pimpl->addIndex(resource);
00886   }
00887 
00888 
00889   void Fetcher::enqueue( const OnMediaLocation &resource, const FileChecker &checker  )
00890   {
00891     _pimpl->enqueue(resource, checker);
00892   }
00893 
00894   void Fetcher::addCachePath( const Pathname &cache_dir )
00895   {
00896     _pimpl->addCachePath(cache_dir);
00897   }
00898 
00899   void Fetcher::reset()
00900   {
00901     _pimpl->reset();
00902   }
00903 
00904   void Fetcher::start( const Pathname &dest_dir,
00905                        MediaSetAccess &media,
00906                        const ProgressData::ReceiverFnc & progress_receiver )
00907   {
00908     _pimpl->start(dest_dir, media, progress_receiver);
00909   }
00910 
00911   std::ostream & operator<<( std::ostream & str, const Fetcher & obj )
00912   {
00913     return str << *obj._pimpl;
00914   }
00915 
00917 } // namespace zypp
00919 

doxygen