Imported Upstream version 16.3.2
[platform/upstream/libzypp.git] / zypp / RepoInfo.cc
index c471883..a91e9f5 100644 (file)
@@ -43,11 +43,12 @@ namespace zypp
   struct RepoInfo::Impl
   {
     Impl()
-      : _rawGpgCheck( indeterminate )
-      , _rawRepoGpgCheck( indeterminate )
-      , _rawPkgGpgCheck( indeterminate )
+      : _gpgCheck( indeterminate )
+      , _repoGpgCheck( indeterminate )
+      , _pkgGpgCheck( indeterminate )
       , _validRepoSignature( indeterminate )
       ,        keeppackages(indeterminate)
+      , _mirrorListForceMetalink(false)
       , type(repo::RepoType::NONE_e)
       , emptybaseurls(false)
     {}
@@ -57,6 +58,7 @@ namespace zypp
 
   public:
     static const unsigned defaultPriority = 99;
+    static const unsigned noPriority = unsigned(-1);
 
     void setProbedType( const repo::RepoType & t ) const
     {
@@ -79,7 +81,7 @@ namespace zypp
       {
         emptybaseurls = true;
         DBG << "MetadataPath: " << metadatapath << endl;
-       repo::RepoMirrorList rmurls( mlurl, metadatapath );
+       repo::RepoMirrorList rmurls( mlurl, metadatapath, _mirrorListForceMetalink );
        _baseUrls.raw().insert( _baseUrls.raw().end(), rmurls.getUrls().begin(), rmurls.getUrls().end() );
       }
       return _baseUrls;
@@ -98,15 +100,19 @@ namespace zypp
     RepoVariablesReplacedUrlList & gpgKeyUrls()
     { return _gpgKeyUrls; }
 
+
+    const std::set<std::string> & contentKeywords() const
+    { hasContent()/*init if not yet done*/; return _keywords.second; }
+
     void addContent( const std::string & keyword_r )
-    { _keywords.insert( keyword_r ); }
+    { _keywords.second.insert( keyword_r ); if ( ! hasContent() ) _keywords.first = true; }
 
-    bool hasContent( const std::string & keyword_r ) const
+    bool hasContent() const
     {
-      if ( _keywords.empty() && ! metadatapath.empty() )
+      if ( !_keywords.first && ! metadatapath.empty() )
       {
        // HACK directly check master index file until RepoManager offers
-       // some content probing ans zypepr uses it.
+       // some content probing and zypper uses it.
        /////////////////////////////////////////////////////////////////
        MIL << "Empty keywords...." << metadatapath << endl;
        Pathname master;
@@ -116,10 +122,10 @@ namespace zypp
          xml::Reader reader( master );
          while ( reader.seekToNode( 2, "content" ) )
          {
-           _keywords.insert( reader.nodeText().asString() );
+           _keywords.second.insert( reader.nodeText().asString() );
            reader.seekToEndNode( 2, "content" );
          }
-         _keywords.insert( "" );       // valid content in _keywords even if empty
+         _keywords.first = true;       // valid content in _keywords even if empty
        }
        else if ( PathInfo( (master=metadatapath/"/content") ).isFile() )
        {
@@ -133,31 +139,33 @@ namespace zypp
                                if ( str::split( line_r, std::back_inserter(words) ) > 1
                                  && words[0].length() == 12 /*"REPOKEYWORDS"*/ )
                                {
-                                 this->_keywords.insert( ++words.begin(), words.end() );
+                                 this->_keywords.second.insert( ++words.begin(), words.end() );
                                }
                                return true; // mult. occurrances are ok.
                              }
                              return( ! str::startsWith( line_r, "META " ) );   // no need to parse into META section.
                            } );
-         _keywords.insert( "" );
+         _keywords.first = true;       // valid content in _keywords even if empty
        }
        /////////////////////////////////////////////////////////////////
       }
-      return( _keywords.find( keyword_r ) != _keywords.end() );
+      return _keywords.first;
     }
 
+    bool hasContent( const std::string & keyword_r ) const
+    { return( hasContent() && _keywords.second.find( keyword_r ) != _keywords.second.end() ); }
+
     /** Signature check result needs to be stored/retrieved from _metadatapath.
      * Don't call them from outside validRepoSignature/setValidRepoSignature
      */
     //@{
     TriBool internalValidRepoSignature() const
     {
-      if ( ! indeterminate(_validRepoSignature) )
-       return _validRepoSignature;
+      if ( ! indeterminate(_validRepoSignature) )              return _validRepoSignature;
       // check metadata:
       if ( ! metadatapath.empty() )
       {
-       // A missing ".repo_gpgcheck" might be plaindir(no Downloader) or not yet refreshed signed repo!
+       //TODO: a missing ".repo_gpgcheck" might be plaindir(no Downloader) or not yet refreshed signed repo!
        TriBool linkval = triBoolFromPath( metadatapath / ".repo_gpgcheck" );
        return linkval;
       }
@@ -182,30 +190,12 @@ namespace zypp
       _validRepoSignature = value_r;
     }
 
-    /** We definitely have a symlink pointing to "indeterminate" (for repoGpgCheckIsMandatory)?
-     * I.e. user accepted the unsigned repo in Downloader. A test whether `internalValidRepoSignature`
-     * is indeterminate would include not yet checked repos, which is unwanted here.
-     */
-    bool internalUnsignedConfirmed() const
-    {
-      TriBool linkval( true ); // want to see it being switched to indeterminate
-      return triBoolFromPath( metadatapath / ".repo_gpgcheck", linkval ) && indeterminate(linkval);
-    }
-
     bool triBoolFromPath( const Pathname & path_r, TriBool & ret_r ) const
     {
       static const Pathname truePath( "true" );
       static const Pathname falsePath( "false" );
       static const Pathname indeterminatePath( "indeterminate" );
-
-      // Quiet readlink;
-      static const ssize_t bufsiz = 63;
-      static char buf[bufsiz+1];
-      ssize_t ret = ::readlink( path_r.c_str(), buf, bufsiz );
-      buf[ret == -1 ? 0 : ret] = '\0';
-
-      Pathname linkval( buf );
-
+      Pathname linkval( filesystem::readlink( path_r ) );
       bool known = true;
       if ( linkval == truePath )
        ret_r = true;
@@ -223,32 +213,16 @@ namespace zypp
 
     //@}
 
-  private:
-    TriBool _rawGpgCheck;      ///< default gpgcheck behavior: Y/N/ZConf
-    TriBool _rawRepoGpgCheck;  ///< need to check repo sign.: Y/N/(ZConf(Y/N/gpgCheck))
-    TriBool _rawPkgGpgCheck;   ///< need to check pkg sign.: Y/N/(ZConf(Y/N/gpgCheck))
-
   public:
-    TriBool rawGpgCheck() const                        { return _rawGpgCheck; }
-    TriBool rawRepoGpgCheck() const            { return _rawRepoGpgCheck; }
-    TriBool rawPkgGpgCheck() const             { return _rawPkgGpgCheck; }
-
-    void rawGpgCheck( TriBool val_r )          { _rawGpgCheck = val_r; }
-    void rawRepoGpgCheck( TriBool val_r )      { _rawRepoGpgCheck = val_r; }
-    void rawPkgGpgCheck( TriBool val_r )       { _rawPkgGpgCheck = val_r; }
-
-    bool cfgGpgCheck() const
-    { return indeterminate(_rawGpgCheck) ? ZConfig::instance().gpgCheck() : (bool)_rawGpgCheck; }
-    TriBool cfgRepoGpgCheck() const
-    { return indeterminate(_rawGpgCheck) && indeterminate(_rawRepoGpgCheck) ? ZConfig::instance().repoGpgCheck() : _rawRepoGpgCheck; }
-    TriBool cfgPkgGpgCheck() const
-    { return indeterminate(_rawGpgCheck) && indeterminate(_rawPkgGpgCheck) ? ZConfig::instance().pkgGpgCheck() : _rawPkgGpgCheck; }
-
+    TriBool _gpgCheck;         ///< default gpgcheck behavior: Y/N/ZConf
+    TriBool _repoGpgCheck;     ///< need to check repo sign.: Y/N/(ZConf(Y/N/gpgCheck))
+    TriBool _pkgGpgCheck;      ///< need to check pkg sign.: Y/N/(ZConf(Y/N/gpgCheck && no valid repo sign.))
   private:
     TriBool _validRepoSignature;///< have  signed and valid repo metadata
   public:
     TriBool keeppackages;
     RepoVariablesReplacedUrl _mirrorListUrl;
+    bool                     _mirrorListForceMetalink;
     repo::RepoType type;
     Pathname path;
     std::string service;
@@ -261,7 +235,7 @@ namespace zypp
 
   private:
     mutable RepoVariablesReplacedUrlList _baseUrls;
-    mutable std::set<std::string> _keywords;
+    mutable std::pair<FalseBool, std::set<std::string> > _keywords;
 
     RepoVariablesReplacedUrlList _gpgKeyUrls;
 
@@ -299,123 +273,70 @@ namespace zypp
   unsigned RepoInfo::defaultPriority()
   { return Impl::defaultPriority; }
 
+  unsigned RepoInfo::noPriority()
+  { return Impl::noPriority; }
+
   void RepoInfo::setPriority( unsigned newval_r )
   { _pimpl->priority = newval_r ? newval_r : Impl::defaultPriority; }
 
 
   bool RepoInfo::gpgCheck() const
-  { return _pimpl->cfgGpgCheck(); }
+  { return indeterminate(_pimpl->_gpgCheck) ? ZConfig::instance().gpgCheck() : (bool)_pimpl->_gpgCheck; }
 
   void RepoInfo::setGpgCheck( TriBool value_r )
-  { _pimpl->rawGpgCheck( value_r ); }
+  { _pimpl->_gpgCheck = value_r; }
 
   void RepoInfo::setGpgCheck( bool value_r ) // deprecated legacy and for squid
   { setGpgCheck( TriBool(value_r) ); }
 
 
   bool RepoInfo::repoGpgCheck() const
-  { return gpgCheck() || _pimpl->cfgRepoGpgCheck(); }
-
-  bool RepoInfo::repoGpgCheckIsMandatory() const
   {
-    bool ret = ( gpgCheck() && indeterminate(_pimpl->cfgRepoGpgCheck()) ) || _pimpl->cfgRepoGpgCheck();
-    if ( ret && _pimpl->internalUnsignedConfirmed() )  // relax if unsigned repo was confirmed in the past
-      ret = false;
-    return ret;
+    if ( ! indeterminate(_pimpl->_repoGpgCheck) )              return _pimpl->_repoGpgCheck;
+    if ( ! indeterminate(ZConfig::instance().repoGpgCheck()) ) return ZConfig::instance().repoGpgCheck();
+    return gpgCheck(); // no preference: follow gpgCheck
   }
 
   void RepoInfo::setRepoGpgCheck( TriBool value_r )
-  { _pimpl->rawRepoGpgCheck( value_r ); }
+  { _pimpl->_repoGpgCheck = value_r; }
 
 
   bool RepoInfo::pkgGpgCheck() const
-  { return _pimpl->cfgPkgGpgCheck() || ( gpgCheck() && !bool(validRepoSignature())/*enforced*/ ) ; }
-
-  bool RepoInfo::pkgGpgCheckIsMandatory() const
-  { return _pimpl->cfgPkgGpgCheck() || ( gpgCheck() && indeterminate(_pimpl->cfgPkgGpgCheck()) && !bool(validRepoSignature())/*enforced*/ ); }
+  {
+    if ( ! indeterminate(_pimpl->_pkgGpgCheck) )               return _pimpl->_pkgGpgCheck;
+    if ( ! indeterminate(ZConfig::instance().pkgGpgCheck()) )  return ZConfig::instance().pkgGpgCheck();
+    // no preference: follow gpgCheck and check package if repo signature not available or not checked
+    return gpgCheck() && ( !repoGpgCheck() || !(bool)validRepoSignature() );   // !(bool)TriBool ==> false or indeterminate
+  }
 
   void RepoInfo::setPkgGpgCheck( TriBool value_r )
-  { _pimpl->rawPkgGpgCheck( value_r ); }
-
+  { _pimpl->_pkgGpgCheck = value_r; }
 
   void RepoInfo::getRawGpgChecks( TriBool & g_r, TriBool & r_r, TriBool & p_r ) const
   {
-    g_r = _pimpl->rawGpgCheck();
-    r_r = _pimpl->rawRepoGpgCheck();
-    p_r = _pimpl->rawPkgGpgCheck();
+    g_r = _pimpl->_gpgCheck;
+    r_r = _pimpl->_repoGpgCheck;
+    p_r = _pimpl->_pkgGpgCheck;
   }
 
-
   TriBool RepoInfo::validRepoSignature() const
   {
-    TriBool ret( _pimpl->internalValidRepoSignature() );
-    if ( ret && !repoGpgCheck() ) ret = false; // invalidate any old signature if repoGpgCheck is off
+    TriBool ret = _pimpl->internalValidRepoSignature();
+    // keep indeterminate(=unsigned) but invalidate any signature if !repoGpgCheck
+    if ( !indeterminate(ret) && !repoGpgCheck() )
+      ret = false;
     return ret;
   }
 
   void RepoInfo::setValidRepoSignature( TriBool value_r )
   { _pimpl->internalSetValidRepoSignature( value_r ); }
 
-  ///////////////////////////////////////////////////////////////////
-  namespace
-  {
-    inline bool changeGpgCheckTo( TriBool & lhs, TriBool rhs )
-    { if ( ! sameTriboolState( lhs, rhs ) ) { lhs = rhs; return true; } return false; }
-
-    inline bool changeGpgCheckTo( TriBool ogpg[3], TriBool g, TriBool r, TriBool p )
-    {
-      bool changed = false;
-      if ( changeGpgCheckTo( ogpg[0], g ) ) changed = true;
-      if ( changeGpgCheckTo( ogpg[1], r ) ) changed = true;
-      if ( changeGpgCheckTo( ogpg[2], p ) ) changed = true;
-      return changed;
-    }
-  } // namespace
-  ///////////////////////////////////////////////////////////////////
-  bool RepoInfo::setGpgCheck( GpgCheck mode_r )
-  {
-    TriBool ogpg[3];   // Gpg RepoGpg PkgGpg
-    getRawGpgChecks( ogpg[0], ogpg[1], ogpg[2] );
-
-    bool changed = false;
-    switch ( mode_r.asEnum() )
-    {
-      case GpgCheck::On:
-       changed = changeGpgCheckTo( ogpg, true,          indeterminate, indeterminate );
-       break;
-      case GpgCheck::Strict:
-       changed = changeGpgCheckTo( ogpg, true,          true,          true          );
-       break;
-      case GpgCheck::AllowUnsigned:
-       changed = changeGpgCheckTo( ogpg, true,          false,         false         );
-       break;
-      case GpgCheck::AllowUnsignedRepo:
-       changed = changeGpgCheckTo( ogpg, true,          false,         indeterminate );
-       break;
-      case GpgCheck::AllowUnsignedPackage:
-       changed = changeGpgCheckTo( ogpg, true,          indeterminate, false         );
-       break;
-      case GpgCheck::Default:
-       changed = changeGpgCheckTo( ogpg, indeterminate, indeterminate, indeterminate );
-       break;
-      case GpgCheck::Off:
-       changed = changeGpgCheckTo( ogpg, false,         indeterminate, indeterminate );
-       break;
-      case GpgCheck::indeterminate:    // no change
-       break;
-    }
-
-    if ( changed )
-    {
-      setGpgCheck    ( ogpg[0] );
-      setRepoGpgCheck( ogpg[1] );
-      setPkgGpgCheck ( ogpg[2] );
-    }
-    return changed;
-  }
 
   void RepoInfo::setMirrorListUrl( const Url & url_r ) // Raw
-  { _pimpl->_mirrorListUrl.raw() = url_r; }
+  { _pimpl->_mirrorListUrl.raw() = url_r; _pimpl->_mirrorListForceMetalink = false; }
+
+  void  RepoInfo::setMetalinkUrl( const Url & url_r )  // Raw
+  { _pimpl->_mirrorListUrl.raw() = url_r; _pimpl->_mirrorListForceMetalink = true; }
 
   void RepoInfo::setGpgKeyUrls( url_set urls )
   { _pimpl->gpgKeyUrls().raw().swap( urls ); }
@@ -537,10 +458,15 @@ namespace zypp
   bool RepoInfo::baseUrlSet() const
   { return _pimpl->baseurl2dump(); }
 
+  const std::set<std::string> & RepoInfo::contentKeywords() const
+  { return _pimpl->contentKeywords(); }
 
   void RepoInfo::addContent( const std::string & keyword_r )
   { _pimpl->addContent( keyword_r ); }
 
+  bool RepoInfo::hasContent() const
+  { return _pimpl->hasContent(); }
+
   bool RepoInfo::hasContent( const std::string & keyword_r ) const
   { return _pimpl->hasContent( keyword_r ); }
 
@@ -576,7 +502,6 @@ namespace zypp
         accept = false;
       }
     }
-    prog.close();
     MIL << "License for " << name() << " has to be accepted: " << (accept?"true":"false" ) << endl;
     return accept;
   }
@@ -591,8 +516,7 @@ namespace zypp
       return std::string();
 
     Locale getLang( Locale::bestMatch( avlocales, lang_r ) );
-    if ( getLang == Locale::noCode
-         && avlocales.find( Locale::noCode ) == avlocales.end() )
+    if ( !getLang && avlocales.find( Locale::noCode ) == avlocales.end() )
     {
       WAR << "License.tar.gz contains no fallback text! " << *this << endl;
       // Using the fist locale instead of returning no text at all.
@@ -603,9 +527,8 @@ namespace zypp
 
     // now extract the license file.
     static const std::string licenseFileFallback( "license.txt" );
-    std::string licenseFile( getLang == Locale::noCode
-                             ? licenseFileFallback
-                             : str::form( "license.%s.txt", getLang.code().c_str() ) );
+    std::string licenseFile( !getLang ? licenseFileFallback
+                                     : str::form( "license.%s.txt", getLang.c_str() ) );
 
     ExternalProgram::Arguments cmd;
     cmd.push_back( "tar" );
@@ -676,17 +599,17 @@ namespace zypp
        str << tag_r << value_r << std::endl;
     });
 
-    strif( "- mirrorlist  : ", rawMirrorListUrl().asString() );
+    strif( (_pimpl->_mirrorListForceMetalink ? "- metalink    : " : "- mirrorlist  : "), rawMirrorListUrl().asString() );
     strif( "- path        : ", path().asString() );
     str << "- type        : " << type() << std::endl;
     str << "- priority    : " << priority() << std::endl;
 
     // Yes No Default(Y) Default(N)
 #define OUTS(T,B) ( indeterminate(T) ? (std::string("D(")+(B?"Y":"N")+")") : ((bool)T?"Y":"N") )
-    str << "- gpgcheck    : " << OUTS(_pimpl->rawGpgCheck(),gpgCheck())
-                              << " repo" << OUTS(_pimpl->rawRepoGpgCheck(),repoGpgCheck()) << (repoGpgCheckIsMandatory() ? "* ": " " )
-                             << "sig" << asString( validRepoSignature(), "?", "Y", "N" )
-                             << " pkg" << OUTS(_pimpl->rawPkgGpgCheck(),pkgGpgCheck()) << (pkgGpgCheckIsMandatory() ? "* ": " " )
+    str << "- gpgcheck    : " << OUTS(_pimpl->_gpgCheck,gpgCheck())
+                              << " repo" << OUTS(_pimpl->_repoGpgCheck,repoGpgCheck())
+                             << " sig" << asString( validRepoSignature(), "?", "Y", "N" )
+                             << " pkg" << OUTS(_pimpl->_pkgGpgCheck,pkgGpgCheck())
                              << std::endl;
 #undef OUTS
 
@@ -725,21 +648,21 @@ namespace zypp
       str << "path="<< path() << endl;
 
     if ( ! (rawMirrorListUrl().asString().empty()) )
-      str << "mirrorlist=" << rawMirrorListUrl() << endl;
+      str << (_pimpl->_mirrorListForceMetalink ? "metalink=" : "mirrorlist=") << rawMirrorListUrl() << endl;
 
     str << "type=" << type().asString() << endl;
 
     if ( priority() != defaultPriority() )
       str << "priority=" << priority() << endl;
 
-    if ( ! indeterminate(_pimpl->rawGpgCheck()) )
-      str << "gpgcheck=" << (_pimpl->rawGpgCheck() ? "1" : "0") << endl;
+    if ( ! indeterminate(_pimpl->_gpgCheck) )
+      str << "gpgcheck=" << (_pimpl->_gpgCheck ? "1" : "0") << endl;
 
-    if ( ! indeterminate(_pimpl->rawRepoGpgCheck()) )
-      str << "repo_gpgcheck=" << (_pimpl->rawRepoGpgCheck() ? "1" : "0") << endl;
+    if ( ! indeterminate(_pimpl->_repoGpgCheck) )
+      str << "repo_gpgcheck=" << (_pimpl->_repoGpgCheck ? "1" : "0") << endl;
 
-    if ( ! indeterminate(_pimpl->rawPkgGpgCheck()) )
-      str << "pkg_gpgcheck=" << (_pimpl->rawPkgGpgCheck() ? "1" : "0") << endl;
+    if ( ! indeterminate(_pimpl->_pkgGpgCheck) )
+      str << "pkg_gpgcheck=" << (_pimpl->_pkgGpgCheck ? "1" : "0") << endl;
 
     {
       std::string indent( "gpgkey=");
@@ -779,7 +702,7 @@ namespace zypp
     if (!(tmpstr = gpgKeyUrl().asString()).empty())
       str << " gpgkey=\"" << escape(tmpstr) << "\"";
     if (!(tmpstr = mirrorListUrl().asString()).empty())
-      str << " mirrorlist=\"" << escape(tmpstr) << "\"";
+      str << (_pimpl->_mirrorListForceMetalink ? " metalink=\"" : " mirrorlist=\"") << escape(tmpstr) << "\"";
     str << ">" << endl;
 
     if ( _pimpl->baseurl2dump() )
@@ -798,23 +721,6 @@ namespace zypp
     return obj.dumpOn(str);
   }
 
-  std::ostream & operator<<( std::ostream & str, const RepoInfo::GpgCheck & obj )
-  {
-    switch ( obj.asEnum() )
-    {
-#define OUTS( V ) case RepoInfo::V: return str << #V; break
-      OUTS( GpgCheck::On );
-      OUTS( GpgCheck::Strict );
-      OUTS( GpgCheck::AllowUnsigned );
-      OUTS( GpgCheck::AllowUnsignedRepo );
-      OUTS( GpgCheck::AllowUnsignedPackage );
-      OUTS( GpgCheck::Default );
-      OUTS( GpgCheck::Off );
-      OUTS( GpgCheck::indeterminate );
-#undef OUTS
-    }
-    return str << "GpgCheck::UNKNOWN";
-  }
 
   /////////////////////////////////////////////////////////////////
 } // namespace zypp