libzypp  10.5.0
Downloader.cc
Go to the documentation of this file.
00001 
00002 #include <iostream>
00003 #include <fstream>
00004 
00005 #include "zypp/base/LogTools.h"
00006 #include "zypp/base/String.h"
00007 #include "zypp/base/Regex.h"
00008 #include "zypp/OnMediaLocation.h"
00009 #include "zypp/MediaSetAccess.h"
00010 #include "zypp/Fetcher.h"
00011 #include "zypp/Locale.h"
00012 #include "zypp/ZConfig.h"
00013 #include "zypp/repo/MediaInfoDownloader.h"
00014 #include "zypp/repo/susetags/Downloader.h"
00015 #include "zypp/parser/ParseException.h"
00016 #include "zypp/parser/susetags/RepoIndex.h"
00017 #include "zypp/base/UserRequestException.h"
00018 #include "zypp/KeyContext.h" // for SignatureFileChecker
00019 
00020 using namespace std;
00021 using namespace zypp::parser;
00022 using namespace zypp::parser::susetags;
00023 
00024 namespace zypp
00025 {
00026 namespace repo
00027 {
00028 namespace susetags
00029 {
00030 
00031 Downloader::Downloader( const RepoInfo &repoinfo, const Pathname &delta_dir )
00032   : repo::Downloader(repoinfo), _delta_dir(delta_dir)
00033 {
00034 }
00035 
00036 RepoStatus Downloader::status( MediaSetAccess &media )
00037 {
00038   Pathname content = media.provideFile( repoInfo().path() + "/content");
00039   // the media.1 is always in the root of the media, not like the content
00040   // file which is in the path() location
00041   Pathname mediafile = media.provideFile( "/media.1/media" );
00042 
00043   return RepoStatus(content) && RepoStatus(mediafile);
00044 }
00045 
00046 // search old repository file file to run the delta algorithm on
00047 static Pathname search_deltafile( const Pathname &dir, const Pathname &file )
00048 {
00049   Pathname deltafile(dir + file.basename());
00050   if (PathInfo(deltafile).isExist())
00051     return deltafile;
00052   return Pathname();
00053 }
00054 
00055 void Downloader::download( MediaSetAccess &media,
00056                            const Pathname &dest_dir,
00057                            const ProgressData::ReceiverFnc & progress )
00058 {
00059   downloadMediaInfo( dest_dir, media );
00060 
00061   SignatureFileChecker sigchecker/*(repoInfo().name())*/;
00062 
00063   Pathname sig = repoInfo().path() + "/content.asc";
00064 
00065   enqueue( OnMediaLocation( sig, 1 ).setOptional(true) );
00066   start( dest_dir, media );
00067   // only if there is a signature in the destination directory
00068   if ( PathInfo(dest_dir / sig ).isExist() )
00069       sigchecker = SignatureFileChecker( dest_dir + sig/*, repoInfo().name() */);
00070   reset();
00071 
00072   Pathname key = repoInfo().path() + "/content.key";
00073 
00074   enqueue( OnMediaLocation( key, 1 ).setOptional(true) );
00075   start( dest_dir, media );
00076 
00077   KeyContext context;
00078   context.setRepoInfo(repoInfo());
00079   // only if there is a key in the destination directory
00080   if ( PathInfo(dest_dir / key).isExist() )
00081     sigchecker.addPublicKey(dest_dir + key, context);
00082   // set the checker context even if the key is not known (unsigned repo, key
00083   // file missing; bnc #495977)
00084   else
00085     sigchecker.setKeyContext(context);
00086 
00087   reset();
00088 
00089   if ( ! repoInfo().gpgCheck() )
00090   {
00091     WAR << "Signature checking disabled in config of repository " << repoInfo().alias() << endl;
00092   }
00093   enqueue( OnMediaLocation( repoInfo().path() + "/content", 1 ),
00094                  repoInfo().gpgCheck() ? FileChecker(sigchecker) : FileChecker(NullFileChecker()) );
00095   start( dest_dir, media );
00096   reset();
00097 
00098   Pathname descr_dir;
00099 
00100   // Content file first to get the repoindex
00101   {
00102     Pathname inputfile( dest_dir +  repoInfo().path() + "/content" );
00103     ContentFileReader content;
00104     content.setRepoIndexConsumer( bind( &Downloader::consumeIndex, this, _1 ) );
00105     content.parse( inputfile );
00106   }
00107   if ( ! _repoindex )
00108   {
00109     ZYPP_THROW( ParseException( (dest_dir+repoInfo().path()).asString() + ": " + "No repository index in content file." ) );
00110   }
00111   MIL << "RepoIndex: " << _repoindex << endl;
00112   if ( _repoindex->metaFileChecksums.empty() )
00113   {
00114     ZYPP_THROW( ParseException( (dest_dir+repoInfo().path()).asString() + ": " + "No metadata checksums in content file." ) );
00115   }
00116   if ( _repoindex->signingKeys.empty() )
00117   {
00118     WAR << "No signing keys defined." << endl;
00119   }
00120 
00121   // Prepare parsing
00122   descr_dir = _repoindex->descrdir; // path below reporoot
00123   //_datadir  = _repoIndex->datadir;  // path below reporoot
00124 
00125   std::map<std::string,RepoIndex::FileChecksumMap::const_iterator> availablePackageTranslations;
00126 
00127   for_( it, _repoindex->metaFileChecksums.begin(), _repoindex->metaFileChecksums.end() )
00128   {
00129     // omit unwanted translations
00130     if ( str::hasPrefix( it->first, "packages" ) )
00131     {
00132       static const str::regex rx_packages( "^packages((.gz)?|(.([^.]*))(.gz)?)$" );
00133       str::smatch what;
00134       if ( str::regex_match( it->first, what, rx_packages ) )
00135       {
00136         if ( what[4].empty() // packages(.gz)?
00137           || what[4] == "DU"
00138           || what[4] == "en" )
00139         { ; /* always downloaded */ }
00140         else if ( what[4] == "FL" )
00141         { continue; /* never downloaded */ }
00142         else
00143         {
00144           // remember and decide later
00145           availablePackageTranslations[what[4]] = it;
00146           continue;
00147         }
00148       }
00149       else
00150         continue; // discard
00151     }
00152     else if ( it->first == "patterns.pat"
00153               || it->first == "patterns.pat.gz" )
00154     {
00155       // take all patterns in one go
00156     }
00157     else if ( str::endsWith( it->first, ".pat" )
00158               || str::endsWith( it->first, ".pat.gz" ) )
00159     {
00160 
00161       // *** see also zypp/parser/susetags/RepoParser.cc ***
00162 
00163       // omit unwanted patterns, see https://bugzilla.novell.com/show_bug.cgi?id=298716
00164       // expect "<name>.<arch>.pat[.gz]", <name> might contain additional dots
00165       // split at dots, take .pat or .pat.gz into account
00166 
00167       std::vector<std::string> patparts;
00168       unsigned archpos = 2;
00169       // expect "<name>.<arch>.pat[.gz]", <name> might contain additional dots
00170       unsigned count = str::split( it->first, std::back_inserter(patparts), "." );
00171       if ( patparts[count-1] == "gz" )
00172           archpos++;
00173 
00174       if ( count > archpos )
00175       {
00176         try                             // might by an invalid architecture
00177         {
00178           Arch patarch( patparts[count-archpos] );
00179           if ( !patarch.compatibleWith( ZConfig::instance().systemArchitecture() ) )
00180           {
00181             // discard, if not compatible
00182             MIL << "Discarding pattern " << it->first << endl;
00183             continue;
00184           }
00185         }
00186         catch ( const Exception & excpt )
00187         {
00188           WAR << "Pattern file name does not contain recognizable architecture: " << it->first << endl;
00189           // keep .pat file if it doesn't contain an recognizable arch
00190         }
00191       }
00192     }
00193     MIL << "adding job " << it->first << endl;
00194     OnMediaLocation location( repoInfo().path() + descr_dir + it->first, 1 );
00195     location.setChecksum( it->second );
00196     enqueueDigested(location, FileChecker(), search_deltafile(_delta_dir + descr_dir, it->first));
00197   }
00198 
00199   // check whether to download more package translations:
00200   {
00201     auto fnc_checkTransaltions( [&]( const Locale & locale_r ) {
00202       for ( Locale toGet( locale_r ); toGet != Locale::noCode; toGet = toGet.fallback() )
00203       {
00204         auto it( availablePackageTranslations.find( toGet.code() ) );
00205         if ( it != availablePackageTranslations.end() )
00206         {
00207           auto mit( it->second );
00208           MIL << "adding job " << mit->first << endl;
00209           OnMediaLocation location( repoInfo().path() + descr_dir + mit->first, 1 );
00210           location.setChecksum( mit->second );
00211           enqueueDigested(location, FileChecker(), search_deltafile(_delta_dir + descr_dir, mit->first));
00212           break;
00213         }
00214       }
00215     });
00216     for ( const Locale & it : ZConfig::instance().repoRefreshLocales() )
00217     {
00218       fnc_checkTransaltions( it );
00219     }
00220     fnc_checkTransaltions( ZConfig::instance().textLocale() );
00221   }
00222 
00223   for_( it, _repoindex->mediaFileChecksums.begin(), _repoindex->mediaFileChecksums.end() )
00224   {
00225     // Repo adopts license files listed in HASH
00226     if ( it->first != "license.tar.gz" )
00227       continue;
00228 
00229     MIL << "adding job " << it->first << endl;
00230     OnMediaLocation location( repoInfo().path() + it->first, 1 );
00231     location.setChecksum( it->second );
00232     enqueueDigested(location, FileChecker(), search_deltafile(_delta_dir, it->first));
00233   }
00234 
00235   for_( it, _repoindex->signingKeys.begin(),_repoindex->signingKeys.end() )
00236   {
00237     MIL << "adding job " << it->first << endl;
00238     OnMediaLocation location( repoInfo().path() + it->first, 1 );
00239     location.setChecksum( it->second );
00240     enqueueDigested(location);
00241   }
00242 
00243   start( dest_dir, media );
00244 }
00245 
00246 void Downloader::consumeIndex( const RepoIndex_Ptr & data_r )
00247 {
00248   MIL << "Consuming repo index" << endl;
00249   _repoindex = data_r;
00250 }
00251 
00252 }// ns susetags
00253 }// ns source
00254 } // ns zypp