瀏覽代碼

merged from lp:~donkult/apt/sid

Michael Vogt 16 年之前
父節點
當前提交
189bb640d2
共有 52 個文件被更改,包括 1611 次插入586 次删除
  1. 1 1
      apt-inst/deb/dpkgdb.cc
  2. 21 6
      apt-pkg/acquire-item.cc
  3. 2 2
      apt-pkg/acquire-item.h
  4. 1 1
      apt-pkg/acquire-method.cc
  5. 6 6
      apt-pkg/acquire.cc
  6. 3 3
      apt-pkg/acquire.h
  7. 14 1
      apt-pkg/aptconfiguration.cc
  8. 81 25
      apt-pkg/cachefile.cc
  9. 23 7
      apt-pkg/cachefile.h
  10. 11 4
      apt-pkg/cacheiterators.h
  11. 280 0
      apt-pkg/cacheset.cc
  12. 239 0
      apt-pkg/cacheset.h
  13. 2 2
      apt-pkg/contrib/cmndline.cc
  14. 52 20
      apt-pkg/contrib/strutl.cc
  15. 3 1
      apt-pkg/contrib/strutl.h
  16. 10 8
      apt-pkg/deb/debindexfile.cc
  17. 3 3
      apt-pkg/deb/debindexfile.h
  18. 2 3
      apt-pkg/deb/deblistparser.cc
  19. 1 1
      apt-pkg/deb/debsystem.cc
  20. 70 10
      apt-pkg/deb/dpkgpm.cc
  21. 16 1
      apt-pkg/deb/dpkgpm.h
  22. 90 21
      apt-pkg/depcache.cc
  23. 10 7
      apt-pkg/depcache.h
  24. 6 2
      apt-pkg/indexfile.h
  25. 47 3
      apt-pkg/indexrecords.cc
  26. 6 0
      apt-pkg/indexrecords.h
  27. 3 2
      apt-pkg/makefile
  28. 20 1
      apt-pkg/pkgcache.cc
  29. 2 2
      apt-pkg/pkgcache.h
  30. 28 17
      apt-pkg/pkgcachegen.cc
  31. 8 2
      apt-pkg/pkgcachegen.h
  32. 24 0
      apt-pkg/tagfile.cc
  33. 1 0
      apt-pkg/tagfile.h
  34. 309 364
      cmdline/apt-cache.cc
  35. 1 2
      cmdline/apt-extracttemplates.cc
  36. 16 42
      cmdline/apt-get.cc
  37. 63 2
      debian/changelog
  38. 2 1
      doc/apt-ftparchive.1.xml
  39. 1 6
      doc/apt-mark.8.xml
  40. 24 0
      doc/apt.conf.5.xml
  41. 8 0
      doc/apt.ent
  42. 5 2
      doc/examples/configure-index
  43. 10 0
      ftparchive/writer.cc
  44. 1 0
      ftparchive/writer.h
  45. 1 2
      methods/ftp.cc
  46. 1 1
      methods/http.cc
  47. 1 2
      methods/rsh.cc
  48. 61 0
      test/libapt/getarchitectures_test.cc
  49. 5 0
      test/libapt/makefile
  50. 1 0
      test/libapt/run-tests.sh
  51. 14 0
      test/pre-upload-check.py
  52. 1 0
      test/testsources.list/sources.list.all-validuntil-broken

+ 1 - 1
apt-inst/deb/dpkgdb.cc

@@ -142,7 +142,7 @@ bool debDpkgDB::ReadyPkgCache(OpProgress &Progress)
       CacheMap = 0;
    }
    
-   if (pkgMakeOnlyStatusCache(Progress,&CacheMap) == false)
+   if (pkgCacheGenerator::MakeOnlyStatusCache(&Progress,&CacheMap) == false)
       return false;
    Cache->DropProgress();
    

+ 21 - 6
apt-pkg/acquire-item.cc

@@ -33,6 +33,7 @@
 #include <string>
 #include <sstream>
 #include <stdio.h>
+#include <ctime>
 									/*}}}*/
 
 using namespace std;
@@ -1164,13 +1165,16 @@ void pkgAcqMetaIndex::QueueIndexes(bool verify)				/*{{{*/
             return;
          }
       }
-      
-      // Queue Packages file (either diff or full packages files, depending
-      // on the users option)
-      if(_config->FindB("Acquire::PDiffs", true) == true) 
+
+      /* Queue Packages file (either diff or full packages files, depending
+         on the users option) - we also check if the PDiff Index file is listed
+         in the Meta-Index file. Ideal would be if pkgAcqDiffIndex would test this
+         instead, but passing the required info to it is to much hassle */
+      if(_config->FindB("Acquire::PDiffs",true) == true && (verify == false ||
+	  MetaIndexParser->Exists(string((*Target)->MetaKey).append(".diff/Index")) == true))
 	 new pkgAcqDiffIndex(Owner, (*Target)->URI, (*Target)->Description,
 			     (*Target)->ShortDesc, ExpectedIndexHash);
-      else 
+      else
 	 new pkgAcqIndex(Owner, (*Target)->URI, (*Target)->Description,
 			    (*Target)->ShortDesc, ExpectedIndexHash);
    }
@@ -1236,6 +1240,17 @@ bool pkgAcqMetaIndex::VerifyVendor(string Message)			/*{{{*/
       Transformed = "";
    }
 
+   if (_config->FindB("Acquire::Check-Valid-Until", true) == true &&
+       MetaIndexParser->GetValidUntil() > 0) {
+      time_t const invalid_since = time(NULL) - MetaIndexParser->GetValidUntil();
+      if (invalid_since > 0)
+	 // TRANSLATOR: The first %s is the URL of the bad Release file, the second is
+	 // the time since then the file is invalid - formated in the same way as in
+	 // the download progress display (e.g. 7d 3h 42min 1s)
+	 return _error->Error(_("Release file expired, ignoring %s (invalid since %s)"),
+	                      RealURI.c_str(), TimeToStr(invalid_since).c_str());
+   }
+
    if (_config->FindB("Debug::pkgAcquire::Auth", false)) 
    {
       std::cerr << "Got Codename: " << MetaIndexParser->GetDist() << std::endl;
@@ -1253,7 +1268,7 @@ bool pkgAcqMetaIndex::VerifyVendor(string Message)			/*{{{*/
 //       return false;
       if (!Transformed.empty())
       {
-         _error->Warning("Conflicting distribution: %s (expected %s but got %s)",
+         _error->Warning(_("Conflicting distribution: %s (expected %s but got %s)"),
                          Desc.Description.c_str(),
                          Transformed.c_str(),
                          MetaIndexParser->GetDist().c_str());

+ 2 - 2
apt-pkg/acquire-item.h

@@ -112,10 +112,10 @@ class pkgAcquire::Item : public WeakPointable
    string ErrorText;
 
    /** \brief The size of the object to fetch. */
-   unsigned long FileSize;
+   unsigned long long FileSize;
 
    /** \brief How much of the object was already fetched. */
-   unsigned long PartialSize;
+   unsigned long long PartialSize;
 
    /** \brief If not \b NULL, contains the name of a subprocess that
     *  is operating on this object (for instance, "gzip" or "gpgv").

+ 1 - 1
apt-pkg/acquire-method.cc

@@ -378,7 +378,7 @@ int pkgAcqMethod::Run(bool Single)
 	    
 	    Tmp->Uri = LookupTag(Message,"URI");
 	    Tmp->DestFile = LookupTag(Message,"FileName");
-	    if (StrToTime(LookupTag(Message,"Last-Modified"),Tmp->LastModified) == false)
+	    if (RFC1123StrToTime(LookupTag(Message,"Last-Modified").c_str(),Tmp->LastModified) == false)
 	       Tmp->LastModified = 0;
 	    Tmp->IndexFile = StringToBool(LookupTag(Message,"Index-File"),false);
 	    Tmp->FailIgnore = StringToBool(LookupTag(Message,"Fail-Ignore"),false);

+ 6 - 6
apt-pkg/acquire.cc

@@ -506,9 +506,9 @@ bool pkgAcquire::Clean(string Dir)
 // Acquire::TotalNeeded - Number of bytes to fetch			/*{{{*/
 // ---------------------------------------------------------------------
 /* This is the total number of bytes needed */
-double pkgAcquire::TotalNeeded()
+unsigned long long pkgAcquire::TotalNeeded()
 {
-   double Total = 0;
+   unsigned long long Total = 0;
    for (ItemCIterator I = ItemsBegin(); I != ItemsEnd(); I++)
       Total += (*I)->FileSize;
    return Total;
@@ -517,9 +517,9 @@ double pkgAcquire::TotalNeeded()
 // Acquire::FetchNeeded - Number of bytes needed to get			/*{{{*/
 // ---------------------------------------------------------------------
 /* This is the number of bytes that is not local */
-double pkgAcquire::FetchNeeded()
+unsigned long long pkgAcquire::FetchNeeded()
 {
-   double Total = 0;
+   unsigned long long Total = 0;
    for (ItemCIterator I = ItemsBegin(); I != ItemsEnd(); I++)
       if ((*I)->Local == false)
 	 Total += (*I)->FileSize;
@@ -529,9 +529,9 @@ double pkgAcquire::FetchNeeded()
 // Acquire::PartialPresent - Number of partial bytes we already have	/*{{{*/
 // ---------------------------------------------------------------------
 /* This is the number of bytes that is not local */
-double pkgAcquire::PartialPresent()
+unsigned long long pkgAcquire::PartialPresent()
 {
-  double Total = 0;
+  unsigned long long Total = 0;
    for (ItemCIterator I = ItemsBegin(); I != ItemsEnd(); I++)
       if ((*I)->Local == false)
 	 Total += (*I)->PartialSize;

+ 3 - 3
apt-pkg/acquire.h

@@ -323,17 +323,17 @@ class pkgAcquire
    /** \return the total size in bytes of all the items included in
     *  this download.
     */
-   double TotalNeeded();
+   unsigned long long TotalNeeded();
 
    /** \return the size in bytes of all non-local items included in
     *  this download.
     */
-   double FetchNeeded();
+   unsigned long long FetchNeeded();
 
    /** \return the amount of data to be fetched that is already
     *  present on the filesystem.
     */
-   double PartialPresent();
+   unsigned long long PartialPresent();
 
    /** \brief Delayed constructor
     *

+ 14 - 1
apt-pkg/aptconfiguration.cc

@@ -327,11 +327,24 @@ std::vector<std::string> const Configuration::getArchitectures(bool const &Cache
 	if (likely(Cached == true) && archs.empty() == false)
 		return archs;
 
-	string const arch = _config->Find("APT::Architecture");
 	archs = _config->FindVector("APT::Architectures");
+	string const arch = _config->Find("APT::Architecture");
+	if (unlikely(arch.empty() == true))
+		return archs;
+
 	if (archs.empty() == true ||
 	    std::find(archs.begin(), archs.end(), arch) == archs.end())
 		archs.push_back(arch);
+
+	// erase duplicates and empty strings
+	for (std::vector<string>::reverse_iterator a = archs.rbegin();
+	     a != archs.rend(); ++a) {
+		if (a->empty() == true || std::find(a + 1, archs.rend(), *a) != archs.rend())
+			archs.erase(a.base()-1);
+		if (a == archs.rend())
+			break;
+	}
+
 	return archs;
 }
 									/*}}}*/

+ 81 - 25
apt-pkg/cachefile.cc

@@ -27,7 +27,8 @@
 // CacheFile::CacheFile - Constructor					/*{{{*/
 // ---------------------------------------------------------------------
 /* */
-pkgCacheFile::pkgCacheFile() : Map(0), Cache(0), DCache(0), Policy(0)
+pkgCacheFile::pkgCacheFile() : Map(NULL), Cache(NULL), DCache(NULL),
+				Policy(NULL), SrcList(NULL)
 {
 }
 									/*}}}*/
@@ -38,16 +39,30 @@ pkgCacheFile::~pkgCacheFile()
 {
    delete DCache;
    delete Policy;
+   delete SrcList;
    delete Cache;
    delete Map;
    _system->UnLock(true);
-}   
+}
 									/*}}}*/
 // CacheFile::BuildCaches - Open and build the cache files		/*{{{*/
 // ---------------------------------------------------------------------
 /* */
-bool pkgCacheFile::BuildCaches(OpProgress &Progress,bool WithLock)
+bool pkgCacheFile::BuildCaches(OpProgress *Progress, bool WithLock)
 {
+   if (Cache != NULL)
+      return true;
+
+   if (_config->FindB("pkgCacheFile::Generate", true) == false)
+   {
+      Map = new MMap(*new FileFd(_config->FindFile("Dir::Cache::pkgcache"),
+		     FileFd::ReadOnly),MMap::Public|MMap::ReadOnly);
+      Cache = new pkgCache(Map);
+      if (_error->PendingError() == true)
+         return false;
+      return true;
+   }
+
    const bool ErrorWasEmpty = _error->empty();
    if (WithLock == true)
       if (_system->Lock() == false)
@@ -58,15 +73,13 @@ bool pkgCacheFile::BuildCaches(OpProgress &Progress,bool WithLock)
       
    if (_error->PendingError() == true)
       return false;
-   
-   // Read the source list
-   pkgSourceList List;
-   if (List.ReadMainList() == false)
-      return _error->Error(_("The list of sources could not be read."));
+
+   BuildSourceList(Progress);
 
    // Read the caches
-   bool Res = pkgMakeStatusCache(List,Progress,&Map,!WithLock);
-   Progress.Done();
+   bool Res = pkgCacheGenerator::MakeStatusCache(*SrcList,Progress,&Map,!WithLock);
+   if (Progress != NULL)
+      Progress->Done();
    if (Res == false)
       return _error->Error(_("The package lists or status file could not be parsed or opened."));
 
@@ -80,29 +93,70 @@ bool pkgCacheFile::BuildCaches(OpProgress &Progress,bool WithLock)
    return true;
 }
 									/*}}}*/
-// CacheFile::Open - Open the cache files, creating if necessary	/*{{{*/
+// CacheFile::BuildSourceList - Open and build all relevant sources.list/*{{{*/
 // ---------------------------------------------------------------------
 /* */
-bool pkgCacheFile::Open(OpProgress &Progress,bool WithLock)
+bool pkgCacheFile::BuildSourceList(OpProgress *Progress)
 {
-   if (BuildCaches(Progress,WithLock) == false)
-      return false;
-   
-   // The policy engine
+   if (SrcList != NULL)
+      return true;
+
+   SrcList = new pkgSourceList();
+   if (SrcList->ReadMainList() == false)
+      return _error->Error(_("The list of sources could not be read."));
+   return true;
+}
+									/*}}}*/
+// CacheFile::BuildPolicy - Open and build all relevant preferences	/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool pkgCacheFile::BuildPolicy(OpProgress *Progress)
+{
+   if (Policy != NULL)
+      return true;
+
    Policy = new pkgPolicy(Cache);
    if (_error->PendingError() == true)
       return false;
 
    if (ReadPinFile(*Policy) == false || ReadPinDir(*Policy) == false)
       return false;
-   
-   // Create the dependency cache
+
+   return true;
+}
+									/*}}}*/
+// CacheFile::BuildDepCache - Open and build the dependency cache	/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool pkgCacheFile::BuildDepCache(OpProgress *Progress)
+{
+   if (DCache != NULL)
+      return true;
+
    DCache = new pkgDepCache(Cache,Policy);
    if (_error->PendingError() == true)
       return false;
-   
-   DCache->Init(&Progress);
-   Progress.Done();
+
+   DCache->Init(Progress);
+   return true;
+}
+									/*}}}*/
+// CacheFile::Open - Open the cache files, creating if necessary	/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool pkgCacheFile::Open(OpProgress *Progress, bool WithLock)
+{
+   if (BuildCaches(Progress,WithLock) == false)
+      return false;
+
+   if (BuildPolicy(Progress) == false)
+      return false;
+
+   if (BuildDepCache(Progress) == false)
+      return false;
+
+   if (Progress != NULL)
+      Progress->Done();
    if (_error->PendingError() == true)
       return false;
    
@@ -117,12 +171,14 @@ void pkgCacheFile::Close()
    delete DCache;
    delete Policy;
    delete Cache;
+   delete SrcList;
    delete Map;
    _system->UnLock(true);
 
-   Map = 0;
-   DCache = 0;
-   Policy = 0;
-   Cache = 0;
+   Map = NULL;
+   DCache = NULL;
+   Policy = NULL;
+   Cache = NULL;
+   SrcList = NULL;
 }
 									/*}}}*/

+ 23 - 7
apt-pkg/cachefile.h

@@ -23,6 +23,7 @@
 #include <apt-pkg/sourcelist.h>
 
 class pkgPolicy;
+class pkgSourceList;
 class pkgCacheFile
 {
    protected:
@@ -30,27 +31,42 @@ class pkgCacheFile
    MMap *Map;
    pkgCache *Cache;
    pkgDepCache *DCache;
-   
+   pkgPolicy *Policy;
+   pkgSourceList *SrcList;
+
    public:
 
-   pkgPolicy *Policy;
-      
    // We look pretty much exactly like a pointer to a dep cache
    inline operator pkgCache &() {return *Cache;};
    inline operator pkgCache *() {return Cache;};
    inline operator pkgDepCache &() {return *DCache;};
    inline operator pkgDepCache *() {return DCache;};
+   inline operator pkgPolicy &() {return *Policy;};
+   inline operator pkgPolicy *() {return Policy;};
+   inline operator pkgSourceList &() {return *SrcList;};
+   inline operator pkgSourceList *() {return SrcList;};
    inline pkgDepCache *operator ->() {return DCache;};
    inline pkgDepCache &operator *() {return *DCache;};
    inline pkgDepCache::StateCache &operator [](pkgCache::PkgIterator const &I) {return (*DCache)[I];};
    inline unsigned char &operator [](pkgCache::DepIterator const &I) {return (*DCache)[I];};
 
-   bool BuildCaches(OpProgress &Progress,bool WithLock = true);
-   bool Open(OpProgress &Progress,bool WithLock = true);
+   bool BuildCaches(OpProgress *Progress = NULL,bool WithLock = true);
+   __deprecated bool BuildCaches(OpProgress &Progress,bool const &WithLock = true) { return BuildCaches(&Progress, WithLock); };
+   bool BuildSourceList(OpProgress *Progress = NULL);
+   bool BuildPolicy(OpProgress *Progress = NULL);
+   bool BuildDepCache(OpProgress *Progress = NULL);
+   bool Open(OpProgress *Progress = NULL, bool WithLock = true);
+   inline bool ReadOnlyOpen(OpProgress *Progress = NULL) { return Open(Progress, false); };
+   __deprecated bool Open(OpProgress &Progress,bool const &WithLock = true) { return Open(&Progress, WithLock); };
    void Close();
-   
+
+   inline pkgCache* GetPkgCache() { BuildCaches(NULL, false); return Cache; };
+   inline pkgDepCache* GetDepCache() { BuildDepCache(); return DCache; };
+   inline pkgPolicy* GetPolicy() { BuildPolicy(); return Policy; };
+   inline pkgSourceList* GetSourceList() { BuildSourceList(); return SrcList; };
+
    pkgCacheFile();
-   ~pkgCacheFile();
+   virtual ~pkgCacheFile();
 };
 
 #endif

+ 11 - 4
apt-pkg/cacheiterators.h

@@ -29,10 +29,12 @@
 									/*}}}*/
 #ifndef PKGLIB_CACHEITERATORS_H
 #define PKGLIB_CACHEITERATORS_H
+#include<iterator>
 // abstract Iterator template						/*{{{*/
 /* This template provides the very basic iterator methods we
    need to have for doing some walk-over-the-cache magic */
-template<typename Str, typename Itr> class pkgCache::Iterator {
+template<typename Str, typename Itr> class pkgCache::Iterator :
+			public std::iterator<std::forward_iterator_tag, Str> {
 	protected:
 	Str *S;
 	pkgCache *Owner;
@@ -64,7 +66,7 @@ template<typename Str, typename Itr> class pkgCache::Iterator {
 	inline operator Str const *() const {return S == OwnerPointer() ? 0 : S;};
 	inline Str &operator *() {return *S;};
 	inline Str const &operator *() const {return *S;};
-	inline pkgCache *Cache() {return Owner;};
+	inline pkgCache *Cache() const {return Owner;};
 
 	// Mixed stuff
 	inline void operator =(const Itr &B) {S = B.S; Owner = B.Owner;};
@@ -102,6 +104,11 @@ class pkgCache::GrpIterator: public Iterator<Group, GrpIterator> {
 	inline const char *Name() const {return S->Name == 0?0:Owner->StrP + S->Name;};
 	inline PkgIterator PackageList() const;
 	PkgIterator FindPkg(string Arch = "any");
+	/** \brief find the package with the "best" architecture
+
+	    The best architecture is either the "native" or the first
+	    in the list of Architectures which is not an end-Pointer */
+	PkgIterator FindPreferredPkg();
 	PkgIterator NextPkg(PkgIterator const &Pkg);
 
 	// Constructors
@@ -198,8 +205,8 @@ class pkgCache::VerIterator : public Iterator<Version, VerIterator> {
 	inline PrvIterator ProvidesList() const;
 	inline VerFileIterator FileList() const;
 	bool Downloadable() const;
-	inline const char *PriorityType() {return Owner->Priority(S->Priority);};
-	string RelStr();
+	inline const char *PriorityType() const {return Owner->Priority(S->Priority);};
+	string RelStr() const;
 
 	bool Automatic() const;
 	bool Pseudo() const;

+ 280 - 0
apt-pkg/cacheset.cc

@@ -0,0 +1,280 @@
+// -*- mode: cpp; mode: fold -*-
+// Description								/*{{{*/
+/* ######################################################################
+
+   Simple wrapper around a std::set to provide a similar interface to
+   a set of cache structures as to the complete set of all structures
+   in the pkgCache. Currently only Package is supported.
+
+   ##################################################################### */
+									/*}}}*/
+// Include Files							/*{{{*/
+#include <apt-pkg/aptconfiguration.h>
+#include <apt-pkg/error.h>
+#include <apt-pkg/cacheset.h>
+#include <apt-pkg/strutl.h>
+#include <apt-pkg/versionmatch.h>
+
+#include <apti18n.h>
+
+#include <vector>
+
+#include <regex.h>
+									/*}}}*/
+namespace APT {
+// FromRegEx - Return all packages in the cache matching a pattern	/*{{{*/
+PackageSet PackageSet::FromRegEx(pkgCacheFile &Cache, std::string pattern, std::ostream &out) {
+	PackageSet pkgset;
+	std::string arch = "native";
+	static const char * const isregex = ".?+*|[^$";
+
+	if (pattern.find_first_of(isregex) == std::string::npos)
+		return pkgset;
+
+	size_t archfound = pattern.find_last_of(':');
+	if (archfound != std::string::npos) {
+		arch = pattern.substr(archfound+1);
+		if (arch.find_first_of(isregex) == std::string::npos)
+			pattern.erase(archfound);
+		else
+			arch = "native";
+	}
+
+	regex_t Pattern;
+	int Res;
+	if ((Res = regcomp(&Pattern, pattern.c_str() , REG_EXTENDED | REG_ICASE | REG_NOSUB)) != 0) {
+		char Error[300];
+		regerror(Res, &Pattern, Error, sizeof(Error));
+		_error->Error(_("Regex compilation error - %s"), Error);
+		return pkgset;
+	}
+
+	for (pkgCache::GrpIterator Grp = Cache.GetPkgCache()->GrpBegin(); Grp.end() == false; ++Grp)
+	{
+		if (regexec(&Pattern, Grp.Name(), 0, 0, 0) != 0)
+			continue;
+		pkgCache::PkgIterator Pkg = Grp.FindPkg(arch);
+		if (Pkg.end() == true) {
+			if (archfound == std::string::npos) {
+				std::vector<std::string> archs = APT::Configuration::getArchitectures();
+				for (std::vector<std::string>::const_iterator a = archs.begin();
+				     a != archs.end() && Pkg.end() != true; ++a)
+					Pkg = Grp.FindPkg(*a);
+			}
+			if (Pkg.end() == true)
+				continue;
+		}
+
+		ioprintf(out, _("Note, selecting %s for regex '%s'\n"),
+			 Pkg.FullName(true).c_str(), pattern.c_str());
+
+		pkgset.insert(Pkg);
+	}
+
+	regfree(&Pattern);
+
+	return pkgset;
+}
+									/*}}}*/
+// GroupedFromCommandLine - Return all versions specified on commandline/*{{{*/
+std::map<unsigned short, PackageSet> PackageSet::GroupedFromCommandLine(
+		pkgCacheFile &Cache, const char **cmdline,
+		std::list<PackageSet::Modifier> const &mods,
+		unsigned short const &fallback, std::ostream &out) {
+	std::map<unsigned short, PackageSet> pkgsets;
+	for (const char **I = cmdline; *I != 0; ++I) {
+		unsigned short modID = fallback;
+		std::string str = *I;
+		for (std::list<PackageSet::Modifier>::const_iterator mod = mods.begin();
+		     mod != mods.end(); ++mod) {
+			size_t const alength = strlen(mod->Alias);
+			switch(mod->Pos) {
+			case PackageSet::Modifier::POSTFIX:
+				if (str.compare(str.length() - alength, alength,
+				    mod->Alias, 0, alength) != 0)
+					continue;
+				str.erase(str.length() - alength);
+				modID = mod->ID;
+				break;
+			case PackageSet::Modifier::PREFIX:
+				continue;
+			case PackageSet::Modifier::NONE:
+				continue;
+			}
+			break;
+		}
+		PackageSet pset = PackageSet::FromString(Cache, str, out);
+		pkgsets[modID].insert(pset.begin(), pset.end());
+	}
+	return pkgsets;
+}
+									/*}}}*/
+// FromCommandLine - Return all packages specified on commandline	/*{{{*/
+PackageSet PackageSet::FromCommandLine(pkgCacheFile &Cache, const char **cmdline, std::ostream &out) {
+	PackageSet pkgset;
+	for (const char **I = cmdline; *I != 0; ++I) {
+		PackageSet pset = FromString(Cache, *I, out);
+		pkgset.insert(pset.begin(), pset.end());
+	}
+	return pkgset;
+}
+									/*}}}*/
+// FromString - Return all packages matching a specific string		/*{{{*/
+PackageSet PackageSet::FromString(pkgCacheFile &Cache, std::string const &str, std::ostream &out) {
+	std::string pkg = str;
+	size_t archfound = pkg.find_last_of(':');
+	std::string arch;
+	if (archfound != std::string::npos) {
+		arch = pkg.substr(archfound+1);
+		pkg.erase(archfound);
+	}
+
+	pkgCache::PkgIterator Pkg;
+	if (arch.empty() == true) {
+		pkgCache::GrpIterator Grp = Cache.GetPkgCache()->FindGrp(pkg);
+		if (Grp.end() == false)
+			Pkg = Grp.FindPreferredPkg();
+	} else
+		Pkg = Cache.GetPkgCache()->FindPkg(pkg, arch);
+
+	if (Pkg.end() == false) {
+		PackageSet pkgset;
+		pkgset.insert(Pkg);
+		return pkgset;
+	}
+	PackageSet regex = FromRegEx(Cache, str, out);
+	if (regex.empty() == true)
+		_error->Warning(_("Unable to locate package %s"), str.c_str());
+	return regex;
+}
+									/*}}}*/
+// FromCommandLine - Return all versions specified on commandline	/*{{{*/
+APT::VersionSet VersionSet::FromCommandLine(pkgCacheFile &Cache, const char **cmdline,
+		APT::VersionSet::Version const &fallback, std::ostream &out) {
+	VersionSet verset;
+	for (const char **I = cmdline; *I != 0; ++I) {
+		std::string pkg = *I;
+		std::string ver;
+		bool verIsRel = false;
+		size_t const vertag = pkg.find_last_of("/=");
+		if (vertag != string::npos) {
+			ver = pkg.substr(vertag+1);
+			verIsRel = (pkg[vertag] == '/');
+			pkg.erase(vertag);
+		}
+		PackageSet pkgset = PackageSet::FromString(Cache, pkg.c_str(), out);
+		for (PackageSet::const_iterator P = pkgset.begin();
+		     P != pkgset.end(); ++P) {
+			if (vertag == string::npos) {
+				AddSelectedVersion(Cache, verset, P, fallback);
+				continue;
+			}
+			pkgCache::VerIterator V;
+			if (ver == "installed")
+				V = getInstalledVer(Cache, P);
+			else if (ver == "candidate")
+				V = getCandidateVer(Cache, P);
+			else {
+				pkgVersionMatch Match(ver, (verIsRel == true ? pkgVersionMatch::Release :
+						pkgVersionMatch::Version));
+				V = Match.Find(P);
+				if (V.end() == true) {
+					if (verIsRel == true)
+						_error->Error(_("Release '%s' for '%s' was not found"),
+								ver.c_str(), P.FullName(true).c_str());
+					else
+						_error->Error(_("Version '%s' for '%s' was not found"),
+								ver.c_str(), P.FullName(true).c_str());
+					continue;
+				}
+			}
+			if (V.end() == true)
+				continue;
+			if (ver == V.VerStr())
+				ioprintf(out, _("Selected version '%s' (%s) for '%s'\n"),
+					 V.VerStr(), V.RelStr().c_str(), P.FullName(true).c_str());
+			verset.insert(V);
+		}
+	}
+	return verset;
+}
+									/*}}}*/
+// AddSelectedVersion - add version from package based on fallback	/*{{{*/
+bool VersionSet::AddSelectedVersion(pkgCacheFile &Cache, VersionSet &verset,
+		pkgCache::PkgIterator const &P, VersionSet::Version const &fallback,
+		bool const &AllowError) {
+	pkgCache::VerIterator V;
+	switch(fallback) {
+	case VersionSet::ALL:
+		if (P->VersionList != 0)
+			for (V = P.VersionList(); V.end() != true; ++V)
+				verset.insert(V);
+		else if (AllowError == false)
+			return _error->Error(_("Can't select versions from package '%s' as it purely virtual"), P.FullName(true).c_str());
+		else
+			return false;
+		break;
+	case VersionSet::CANDANDINST:
+		verset.insert(getInstalledVer(Cache, P, AllowError));
+		verset.insert(getCandidateVer(Cache, P, AllowError));
+		break;
+	case VersionSet::CANDIDATE:
+		verset.insert(getCandidateVer(Cache, P, AllowError));
+		break;
+	case VersionSet::INSTALLED:
+		verset.insert(getInstalledVer(Cache, P, AllowError));
+		break;
+	case VersionSet::CANDINST:
+		V = getCandidateVer(Cache, P, true);
+		if (V.end() == true)
+			V = getInstalledVer(Cache, P, true);
+		if (V.end() == false)
+			verset.insert(V);
+		else if (AllowError == false)
+			return _error->Error(_("Can't select installed nor candidate version from package '%s' as it has neither of them"), P.FullName(true).c_str());
+		else
+			return false;
+		break;
+	case VersionSet::INSTCAND:
+		V = getInstalledVer(Cache, P, true);
+		if (V.end() == true)
+			V = getCandidateVer(Cache, P, true);
+		if (V.end() == false)
+			verset.insert(V);
+		else if (AllowError == false)
+			return _error->Error(_("Can't select installed nor candidate version from package '%s' as it has neither of them"), P.FullName(true).c_str());
+		else
+			return false;
+		break;
+	case VersionSet::NEWEST:
+		if (P->VersionList != 0)
+			verset.insert(P.VersionList());
+		else if (AllowError == false)
+			return _error->Error(_("Can't select newest version from package '%s' as it is purely virtual"), P.FullName(true).c_str());
+		else
+			return false;
+		break;
+	}
+	return true;
+}
+									/*}}}*/
+// getCandidateVer - Returns the candidate version of the given package	/*{{{*/
+pkgCache::VerIterator VersionSet::getCandidateVer(pkgCacheFile &Cache,
+		pkgCache::PkgIterator const &Pkg, bool const &AllowError) {
+	if (unlikely(Cache.BuildDepCache() == false))
+		return pkgCache::VerIterator(*Cache);
+	pkgCache::VerIterator Cand = Cache[Pkg].CandidateVerIter(Cache);
+	if (AllowError == false && Cand.end() == true)
+		_error->Error(_("Can't select candidate version from package %s as it has no candidate"), Pkg.FullName(true).c_str());
+	return Cand;
+}
+									/*}}}*/
+// getInstalledVer - Returns the installed version of the given package	/*{{{*/
+pkgCache::VerIterator VersionSet::getInstalledVer(pkgCacheFile &Cache,
+		pkgCache::PkgIterator const &Pkg, bool const &AllowError) {
+	if (AllowError == false && Pkg->CurrentVer == 0)
+		_error->Error(_("Can't select installed version from package %s as it is not installed"), Pkg.FullName(true).c_str());
+	return Pkg.CurrentVer();
+}
+									/*}}}*/
+}

+ 239 - 0
apt-pkg/cacheset.h

@@ -0,0 +1,239 @@
+// -*- mode: cpp; mode: fold -*-
+// Description								/*{{{*/
+/** \file cacheset.h
+   Wrappers around std::set to have set::iterators which behave
+   similar to the Iterators of the cache structures.
+
+   Provides also a few helper methods which work with these sets */
+									/*}}}*/
+#ifndef APT_CACHESET_H
+#define APT_CACHESET_H
+// Include Files							/*{{{*/
+#include <iostream>
+#include <fstream>
+#include <list>
+#include <map>
+#include <set>
+#include <string>
+
+#include <apt-pkg/cachefile.h>
+#include <apt-pkg/pkgcache.h>
+									/*}}}*/
+namespace APT {
+class PackageSet : public std::set<pkgCache::PkgIterator> {		/*{{{*/
+/** \class APT::PackageSet
+
+    Simple wrapper around a std::set to provide a similar interface to
+    a set of packages as to the complete set of all packages in the
+    pkgCache. */
+public:									/*{{{*/
+	/** \brief smell like a pkgCache::PkgIterator */
+	class const_iterator : public std::set<pkgCache::PkgIterator>::const_iterator {
+	public:
+		const_iterator(std::set<pkgCache::PkgIterator>::const_iterator x) :
+			 std::set<pkgCache::PkgIterator>::const_iterator(x) {}
+
+		operator pkgCache::PkgIterator(void) { return **this; }
+
+		inline const char *Name() const {return (**this).Name(); }
+		inline std::string FullName(bool const &Pretty) const { return (**this).FullName(Pretty); }
+		inline std::string FullName() const { return (**this).FullName(); }
+		inline const char *Section() const {return (**this).Section(); }
+		inline bool Purge() const {return (**this).Purge(); }
+		inline const char *Arch() const {return (**this).Arch(); }
+		inline pkgCache::GrpIterator Group() const { return (**this).Group(); }
+		inline pkgCache::VerIterator VersionList() const { return (**this).VersionList(); }
+		inline pkgCache::VerIterator CurrentVer() const { return (**this).CurrentVer(); }
+		inline pkgCache::DepIterator RevDependsList() const { return (**this).RevDependsList(); }
+		inline pkgCache::PrvIterator ProvidesList() const { return (**this).ProvidesList(); }
+		inline pkgCache::PkgIterator::OkState State() const { return (**this).State(); }
+		inline const char *CandVersion() const { return (**this).CandVersion(); }
+		inline const char *CurVersion() const { return (**this).CurVersion(); }
+		inline pkgCache *Cache() const { return (**this).Cache(); };
+		inline unsigned long Index() const {return (**this).Index();};
+		// we have only valid iterators here
+		inline bool end() const { return false; };
+
+		friend std::ostream& operator<<(std::ostream& out, const_iterator i) { return operator<<(out, (*i)); }
+
+		inline pkgCache::Package const * operator->() const {
+			return &***this;
+		};
+	};
+	// 103. set::iterator is required to be modifiable, but this allows modification of keys
+	typedef typename APT::PackageSet::const_iterator iterator;
+
+	using std::set<pkgCache::PkgIterator>::insert;
+	inline void insert(pkgCache::PkgIterator const &P) { if (P.end() == false) std::set<pkgCache::PkgIterator>::insert(P); };
+
+	/** \brief returns all packages in the cache whose name matchs a given pattern
+
+	    A simple helper responsible for executing a regular expression on all
+	    package names in the cache. Optional it prints a a notice about the
+	    packages chosen cause of the given package.
+	    \param Cache the packages are in
+	    \param pattern regular expression for package names
+	    \param out stream to print the notice to */
+	static APT::PackageSet FromRegEx(pkgCacheFile &Cache, std::string pattern, std::ostream &out);
+	static APT::PackageSet FromRegEx(pkgCacheFile &Cache, std::string const &pattern) {
+		std::ostream out (std::ofstream("/dev/null").rdbuf());
+		return APT::PackageSet::FromRegEx(Cache, pattern, out);
+	}
+
+	/** \brief returns all packages specified by a string
+
+	    \param Cache the packages are in
+	    \param string String the package name(s) should be extracted from
+	    \param out stream to print various notices to */
+	static APT::PackageSet FromString(pkgCacheFile &Cache, std::string const &string, std::ostream &out);
+	static APT::PackageSet FromString(pkgCacheFile &Cache, std::string const &string) {
+		std::ostream out (std::ofstream("/dev/null").rdbuf());
+		return APT::PackageSet::FromString(Cache, string, out);
+	}
+
+	/** \brief returns all packages specified on the commandline
+
+	    Get all package names from the commandline and executes regex's if needed.
+	    No special package command is supported, just plain names.
+	    \param Cache the packages are in
+	    \param cmdline Command line the package names should be extracted from
+	    \param out stream to print various notices to */
+	static APT::PackageSet FromCommandLine(pkgCacheFile &Cache, const char **cmdline, std::ostream &out);
+	static APT::PackageSet FromCommandLine(pkgCacheFile &Cache, const char **cmdline) {
+		std::ostream out (std::ofstream("/dev/null").rdbuf());
+		return APT::PackageSet::FromCommandLine(Cache, cmdline, out);
+	}
+
+	struct Modifier {
+		enum Position { NONE, PREFIX, POSTFIX };
+		unsigned short ID;
+		const char * const Alias;
+		Position Pos;
+		Modifier (unsigned short const &id, const char * const alias, Position const &pos) : ID(id), Alias(alias), Pos(pos) {};
+	};
+
+	static std::map<unsigned short, PackageSet> GroupedFromCommandLine(
+		pkgCacheFile &Cache, const char **cmdline,
+		std::list<PackageSet::Modifier> const &mods,
+		unsigned short const &fallback, std::ostream &out);
+	static std::map<unsigned short, PackageSet> GroupedFromCommandLine(
+		pkgCacheFile &Cache, const char **cmdline,
+		std::list<PackageSet::Modifier> const &mods,
+		unsigned short const &fallback) {
+		std::ostream out (std::ofstream("/dev/null").rdbuf());
+		return APT::PackageSet::GroupedFromCommandLine(Cache, cmdline,
+				mods, fallback, out);
+	}
+									/*}}}*/
+};									/*}}}*/
+class VersionSet : public std::set<pkgCache::VerIterator> {		/*{{{*/
+/** \class APT::VersionSet
+
+    Simple wrapper around a std::set to provide a similar interface to
+    a set of versions as to the complete set of all versions in the
+    pkgCache. */
+public:									/*{{{*/
+	/** \brief smell like a pkgCache::VerIterator */
+	class const_iterator : public std::set<pkgCache::VerIterator>::const_iterator {
+	public:
+		const_iterator(std::set<pkgCache::VerIterator>::const_iterator x) :
+			 std::set<pkgCache::VerIterator>::const_iterator(x) {}
+
+		operator pkgCache::VerIterator(void) { return **this; }
+
+		inline pkgCache *Cache() const { return (**this).Cache(); };
+		inline unsigned long Index() const {return (**this).Index();};
+		// we have only valid iterators here
+		inline bool end() const { return false; };
+
+		inline pkgCache::Version const * operator->() const {
+			return &***this;
+		};
+
+		inline int CompareVer(const pkgCache::VerIterator &B) const { return (**this).CompareVer(B); };
+		inline const char *VerStr() const { return (**this).VerStr(); };
+		inline const char *Section() const { return (**this).Section(); };
+		inline const char *Arch() const { return (**this).Arch(); };
+		inline const char *Arch(bool const pseudo) const { return (**this).Arch(pseudo); };
+		inline pkgCache::PkgIterator ParentPkg() const { return (**this).ParentPkg(); };
+		inline pkgCache::DescIterator DescriptionList() const { return (**this).DescriptionList(); };
+		inline pkgCache::DescIterator TranslatedDescription() const { return (**this).TranslatedDescription(); };
+		inline pkgCache::DepIterator DependsList() const { return (**this).DependsList(); };
+		inline pkgCache::PrvIterator ProvidesList() const { return (**this).ProvidesList(); };
+		inline pkgCache::VerFileIterator FileList() const { return (**this).FileList(); };
+		inline bool Downloadable() const { return (**this).Downloadable(); };
+		inline const char *PriorityType() const { return (**this).PriorityType(); };
+		inline string RelStr() const { return (**this).RelStr(); };
+		inline bool Automatic() const { return (**this).Automatic(); };
+		inline bool Pseudo() const { return (**this).Pseudo(); };
+		inline pkgCache::VerFileIterator NewestFile() const { return (**this).NewestFile(); };
+	};
+	// 103. set::iterator is required to be modifiable, but this allows modification of keys
+	typedef typename APT::VersionSet::const_iterator iterator;
+
+	using std::set<pkgCache::VerIterator>::insert;
+	inline void insert(pkgCache::VerIterator const &V) { if (V.end() == false) std::set<pkgCache::VerIterator>::insert(V); };
+
+	/** \brief specifies which version(s) will be returned if non is given */
+	enum Version {
+		/** All versions */
+		ALL,
+		/** Candidate and installed version */
+		CANDANDINST,
+		/** Candidate version */
+		CANDIDATE,
+		/** Installed version */
+		INSTALLED,
+		/** Candidate or if non installed version */
+		CANDINST,
+		/** Installed or if non candidate version */
+		INSTCAND,
+		/** Newest version */
+		NEWEST
+	};
+
+	/** \brief returns all versions specified on the commandline
+
+	    Get all versions from the commandline, uses given default version if
+	    non specifically requested  and executes regex's if needed on names.
+	    \param Cache the packages and versions are in
+	    \param cmdline Command line the versions should be extracted from
+	    \param out stream to print various notices to */
+	static APT::VersionSet FromCommandLine(pkgCacheFile &Cache, const char **cmdline,
+			APT::VersionSet::Version const &fallback, std::ostream &out);
+	static APT::VersionSet FromCommandLine(pkgCacheFile &Cache, const char **cmdline,
+			APT::VersionSet::Version const &fallback) {
+		std::ostream out (std::ofstream("/dev/null").rdbuf());
+		return APT::VersionSet::FromCommandLine(Cache, cmdline, fallback, out);
+	}
+	static APT::VersionSet FromCommandLine(pkgCacheFile &Cache, const char **cmdline) {
+		return APT::VersionSet::FromCommandLine(Cache, cmdline, CANDINST);
+	}
+									/*}}}*/
+protected:								/*{{{*/
+
+	/** \brief returns the candidate version of the package
+
+	    \param Cache to be used to query for information
+	    \param Pkg we want the candidate version from this package
+	    \param AllowError add an error to the stack if not */
+	static pkgCache::VerIterator getCandidateVer(pkgCacheFile &Cache,
+		pkgCache::PkgIterator const &Pkg, bool const &AllowError = false);
+
+	/** \brief returns the installed version of the package
+
+	    \param Cache to be used to query for information
+	    \param Pkg we want the installed version from this package
+	    \param AllowError add an error to the stack if not */
+	static pkgCache::VerIterator getInstalledVer(pkgCacheFile &Cache,
+		pkgCache::PkgIterator const &Pkg, bool const &AllowError = false);
+
+
+	static bool AddSelectedVersion(pkgCacheFile &Cache, VersionSet &verset,
+		pkgCache::PkgIterator const &P, VersionSet::Version const &fallback,
+		bool const &AllowError = false);
+
+									/*}}}*/
+};									/*}}}*/
+}
+#endif

+ 2 - 2
apt-pkg/contrib/cmndline.cc

@@ -360,11 +360,11 @@ bool CommandLine::DispatchArg(Dispatch *Map,bool NoMatch)
    than nothing after all. */
 void CommandLine::SaveInConfig(unsigned int const &argc, char const * const * const argv)
 {
-   char cmdline[300];
+   char cmdline[100 + argc * 50];
    unsigned int length = 0;
    bool lastWasOption = false;
    bool closeQuote = false;
-   for (unsigned int i = 0; i < argc; ++i, ++length)
+   for (unsigned int i = 0; i < argc && length < sizeof(cmdline); ++i, ++length)
    {
       for (unsigned int j = 0; argv[i][j] != '\0' && length < sizeof(cmdline)-1; ++j, ++length)
       {

+ 52 - 20
apt-pkg/contrib/strutl.cc

@@ -827,34 +827,66 @@ static int MonthConv(char *Month)
    }   
 }
 									/*}}}*/
-// timegm - Internal timegm function if gnu is not available		/*{{{*/
+// timegm - Internal timegm if the gnu version is not available		/*{{{*/
 // ---------------------------------------------------------------------
-/* Ripped this evil little function from wget - I prefer the use of 
-   GNU timegm if possible as this technique will have interesting problems
-   with leap seconds, timezones and other.
-   
-   Converts struct tm to time_t, assuming the data in tm is UTC rather
+/* Converts struct tm to time_t, assuming the data in tm is UTC rather
    than local timezone (mktime assumes the latter).
-   
-   Contributed by Roger Beeman <beeman@cisco.com>, with the help of
-   Mark Baushke <mdb@cisco.com> and the rest of the Gurus at CISCO. */
-
-/* Turned it into an autoconf check, because GNU is not the only thing which
-   can provide timegm. -- 2002-09-22, Joel Baker */
 
-#ifndef HAVE_TIMEGM // Now with autoconf!
+   This function is a nonstandard GNU extension that is also present on
+   the BSDs and maybe other systems. For others we follow the advice of
+   the manpage of timegm and use his portable replacement. */
+#ifndef HAVE_TIMEGM
 static time_t timegm(struct tm *t)
 {
-   time_t tl, tb;
-   
-   tl = mktime (t);
-   if (tl == -1)
-      return -1;
-   tb = mktime (gmtime (&tl));
-   return (tl <= tb ? (tl + (tl - tb)) : (tl - (tb - tl)));
+   char *tz = getenv("TZ");
+   setenv("TZ", "", 1);
+   tzset();
+   time_t ret = mktime(t);
+   if (tz)
+      setenv("TZ", tz, 1);
+   else
+      unsetenv("TZ");
+   tzset();
+   return ret;
 }
 #endif
 									/*}}}*/
+// FullDateToTime - Converts a HTTP1.1 full date strings into a time_t	/*{{{*/
+// ---------------------------------------------------------------------
+/* tries to parses a full date as specified in RFC2616 Section 3.3.1
+   with one exception: All timezones (%Z) are accepted but the protocol
+   says that it MUST be GMT, but this one is equal to UTC which we will
+   encounter from time to time (e.g. in Release files) so we accept all
+   here and just assume it is GMT (or UTC) later on */
+bool RFC1123StrToTime(const char* const str,time_t &time)
+{
+   struct tm Tm;
+   // Sun, 06 Nov 1994 08:49:37 GMT  ; RFC 822, updated by RFC 1123
+   if (strptime(str, "%a, %d %b %Y %H:%M:%S %Z", &Tm) == NULL &&
+   // Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036
+       strptime(str, "%A, %d-%b-%y %H:%M:%S %Z", &Tm) == NULL &&
+   // Sun Nov  6 08:49:37 1994       ; ANSI C's asctime() format
+       strptime(str, "%a %b %d %H:%M:%S %Y", &Tm) == NULL)
+      return false;
+
+   time = timegm(&Tm);
+   return true;
+}
+									/*}}}*/
+// FTPMDTMStrToTime - Converts a ftp modification date into a time_t	/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool FTPMDTMStrToTime(const char* const str,time_t &time)
+{
+   struct tm Tm;
+   // MDTM includes no whitespaces but recommend and ignored by strptime
+   if (strptime(str, "%Y %m %d %H %M %S", &Tm) == NULL)
+      return false;
+
+   time = timegm(&Tm);
+   return true;
+}
+									/*}}}*/
 // StrToTime - Converts a string into a time_t				/*{{{*/
 // ---------------------------------------------------------------------
 /* This handles all 3 populare time formats including RFC 1123, RFC 1036

+ 3 - 1
apt-pkg/contrib/strutl.h

@@ -45,7 +45,9 @@ string Base64Encode(const string &Str);
 string OutputInDepth(const unsigned long Depth, const char* Separator="  ");
 string URItoFileName(const string &URI);
 string TimeRFC1123(time_t Date);
-bool StrToTime(const string &Val,time_t &Result);
+bool RFC1123StrToTime(const char* const str,time_t &time) __must_check;
+bool FTPMDTMStrToTime(const char* const str,time_t &time) __must_check;
+__deprecated bool StrToTime(const string &Val,time_t &Result);
 string LookupTag(const string &Message,const char *Tag,const char *Default = 0);
 int StringToBool(const string &Text,int Default = -1);
 bool ReadMessages(int Fd, vector<string> &List);

+ 10 - 8
apt-pkg/deb/debindexfile.cc

@@ -262,15 +262,15 @@ unsigned long debPackagesIndex::Size() const
 // PackagesIndex::Merge - Load the index file into a cache		/*{{{*/
 // ---------------------------------------------------------------------
 /* */
-bool debPackagesIndex::Merge(pkgCacheGenerator &Gen,OpProgress &Prog) const
+bool debPackagesIndex::Merge(pkgCacheGenerator &Gen,OpProgress *Prog) const
 {
    string PackageFile = IndexFile("Packages");
    FileFd Pkg(PackageFile,FileFd::ReadOnly);
    debListParser Parser(&Pkg, Architecture);
    if (_error->PendingError() == true)
       return _error->Error("Problem opening %s",PackageFile.c_str());
-   
-   Prog.SubProgress(0,Info("Packages"));
+   if (Prog != NULL)
+      Prog->SubProgress(0,Info("Packages"));
    ::URI Tmp(URI);
    if (Gen.SelectFile(PackageFile,Tmp.Host,*this) == false)
       return _error->Error("Problem with SelectFile %s",PackageFile.c_str());
@@ -445,7 +445,7 @@ unsigned long debTranslationsIndex::Size() const
 // TranslationsIndex::Merge - Load the index file into a cache		/*{{{*/
 // ---------------------------------------------------------------------
 /* */
-bool debTranslationsIndex::Merge(pkgCacheGenerator &Gen,OpProgress &Prog) const
+bool debTranslationsIndex::Merge(pkgCacheGenerator &Gen,OpProgress *Prog) const
 {
    // Check the translation file, if in use
    string TranslationFile = IndexFile(Language);
@@ -456,7 +456,8 @@ bool debTranslationsIndex::Merge(pkgCacheGenerator &Gen,OpProgress &Prog) const
      if (_error->PendingError() == true)
        return false;
      
-     Prog.SubProgress(0, Info(TranslationFile.c_str()));
+     if (Prog != NULL)
+	Prog->SubProgress(0, Info(TranslationFile.c_str()));
      if (Gen.SelectFile(TranslationFile,string(),*this) == false)
        return _error->Error("Problem with SelectFile %s",TranslationFile.c_str());
 
@@ -529,7 +530,7 @@ unsigned long debStatusIndex::Size() const
 // StatusIndex::Merge - Load the index file into a cache		/*{{{*/
 // ---------------------------------------------------------------------
 /* */
-bool debStatusIndex::Merge(pkgCacheGenerator &Gen,OpProgress &Prog) const
+bool debStatusIndex::Merge(pkgCacheGenerator &Gen,OpProgress *Prog) const
 {
    FileFd Pkg(File,FileFd::ReadOnly);
    if (_error->PendingError() == true)
@@ -537,8 +538,9 @@ bool debStatusIndex::Merge(pkgCacheGenerator &Gen,OpProgress &Prog) const
    debListParser Parser(&Pkg);
    if (_error->PendingError() == true)
       return false;
-   
-   Prog.SubProgress(0,File);
+
+   if (Prog != NULL)
+      Prog->SubProgress(0,File);
    if (Gen.SelectFile(File,string(),*this,pkgCache::Flag::NotSource) == false)
       return _error->Error("Problem with SelectFile %s",File.c_str());
 

+ 3 - 3
apt-pkg/deb/debindexfile.h

@@ -35,7 +35,7 @@ class debStatusIndex : public pkgIndexFile
    virtual bool Exists() const;
    virtual bool HasPackages() const {return true;};
    virtual unsigned long Size() const;
-   virtual bool Merge(pkgCacheGenerator &Gen,OpProgress &Prog) const;
+   virtual bool Merge(pkgCacheGenerator &Gen,OpProgress *Prog) const;
    virtual pkgCache::PkgFileIterator FindInCache(pkgCache &Cache) const;
 
    debStatusIndex(string File);
@@ -67,7 +67,7 @@ class debPackagesIndex : public pkgIndexFile
    virtual bool Exists() const;
    virtual bool HasPackages() const {return true;};
    virtual unsigned long Size() const;
-   virtual bool Merge(pkgCacheGenerator &Gen,OpProgress &Prog) const;
+   virtual bool Merge(pkgCacheGenerator &Gen,OpProgress *Prog) const;
    virtual pkgCache::PkgFileIterator FindInCache(pkgCache &Cache) const;
 
    debPackagesIndex(string const &URI, string const &Dist, string const &Section,
@@ -99,7 +99,7 @@ class debTranslationsIndex : public pkgIndexFile
    virtual bool Exists() const;
    virtual bool HasPackages() const;
    virtual unsigned long Size() const;
-   virtual bool Merge(pkgCacheGenerator &Gen,OpProgress &Prog) const;
+   virtual bool Merge(pkgCacheGenerator &Gen,OpProgress *Prog) const;
    virtual pkgCache::PkgFileIterator FindInCache(pkgCache &Cache) const;
 
    debTranslationsIndex(string URI,string Dist,string Section, char const * const Language);

+ 2 - 3
apt-pkg/deb/deblistparser.cc

@@ -133,10 +133,9 @@ bool debListParser::NewVersion(pkgCache::VerIterator Ver)
    }
 
    // Archive Size
-   Ver->Size = (unsigned)Section.FindI("Size");
-   
+   Ver->Size = Section.FindULL("Size");
    // Unpacked Size (in K)
-   Ver->InstalledSize = (unsigned)Section.FindI("Installed-Size");
+   Ver->InstalledSize = Section.FindULL("Installed-Size");
    Ver->InstalledSize *= 1024;
 
    // Priority

+ 1 - 1
apt-pkg/deb/debsystem.cc

@@ -164,7 +164,7 @@ bool debSystem::Initialize(Configuration &Cnf)
    /* These really should be jammed into a generic 'Local Database' engine
       which is yet to be determined. The functions in pkgcachegen should
       be the only users of these */
-   Cnf.CndSet("Dir::State::userstatus","status.user"); // Defunct
+   Cnf.CndSet("Dir::State::extended_states", Cnf.FindDir("Dir::State").append("extended_states"));
    Cnf.CndSet("Dir::State::status","/var/lib/dpkg/status");
    Cnf.CndSet("Dir::Bin::dpkg","/usr/bin/dpkg");
 

+ 70 - 10
apt-pkg/deb/dpkgpm.cc

@@ -472,7 +472,7 @@ void pkgDPkgPM::ProcessDpkgStatusLine(int OutStatusFd, char *line)
 	 std::clog << "send: '" << status.str() << "'" << endl;
 
       if (strncmp(action, "disappear", strlen("disappear")) == 0)
-	 disappearedPkgs.insert(string(pkg_or_trigger));
+	 handleDisappearAction(pkg_or_trigger);
       return;
    }
 
@@ -542,6 +542,51 @@ void pkgDPkgPM::ProcessDpkgStatusLine(int OutStatusFd, char *line)
 		<< " action: " << action << endl;
 }
 									/*}}}*/
+// DPkgPM::handleDisappearAction					/*{{{*/
+void pkgDPkgPM::handleDisappearAction(string const &pkgname)
+{
+   // record the package name for display and stuff later
+   disappearedPkgs.insert(pkgname);
+
+   pkgCache::PkgIterator Pkg = Cache.FindPkg(pkgname);
+   if (unlikely(Pkg.end() == true))
+      return;
+   // the disappeared package was auto-installed - nothing to do
+   if ((Cache[Pkg].Flags & pkgCache::Flag::Auto) == pkgCache::Flag::Auto)
+      return;
+   pkgCache::VerIterator PkgVer = Pkg.CurrentVer();
+   if (unlikely(PkgVer.end() == true))
+      return;
+   /* search in the list of dependencies for (Pre)Depends,
+      check if this dependency has a Replaces on our package
+      and if so transfer the manual installed flag to it */
+   for (pkgCache::DepIterator Dep = PkgVer.DependsList(); Dep.end() != true; ++Dep)
+   {
+      if (Dep->Type != pkgCache::Dep::Depends &&
+	  Dep->Type != pkgCache::Dep::PreDepends)
+	 continue;
+      pkgCache::PkgIterator Tar = Dep.TargetPkg();
+      if (unlikely(Tar.end() == true))
+	 continue;
+      // the package is already marked as manual
+      if ((Cache[Tar].Flags & pkgCache::Flag::Auto) != pkgCache::Flag::Auto)
+	 continue;
+      pkgCache::VerIterator TarVer = Tar.CurrentVer();
+      for (pkgCache::DepIterator Rep = TarVer.DependsList(); Rep.end() != true; ++Rep)
+      {
+	 if (Rep->Type != pkgCache::Dep::Replaces)
+	    continue;
+	 if (Pkg != Rep.TargetPkg())
+	    continue;
+	 // okay, they are strongly connected - transfer manual-bit
+	 if (Debug == true)
+	    std::clog << "transfer manual-bit from disappeared »" << pkgname << "« to »" << Tar.FullName() << "«" << std::endl;
+	 Cache[Tar].Flags &= ~Flag::Auto;
+	 break;
+      }
+   }
+}
+									/*}}}*/
 // DPkgPM::DoDpkgStatusFd						/*{{{*/
 // ---------------------------------------------------------------------
 /*
@@ -580,15 +625,15 @@ void pkgDPkgPM::DoDpkgStatusFd(int statusfd, int OutStatusFd)
 }
 									/*}}}*/
 // DPkgPM::WriteHistoryTag						/*{{{*/
-void pkgDPkgPM::WriteHistoryTag(string tag, string value)
+void pkgDPkgPM::WriteHistoryTag(string const &tag, string value)
 {
-   if (value.size() > 0)
-   {
-      // poor mans rstrip(", ")
-      if (value[value.size()-2] == ',' && value[value.size()-1] == ' ')
-	 value.erase(value.size() - 2, 2);
-      fprintf(history_out, "%s: %s\n", tag.c_str(), value.c_str());
-   }
+   size_t const length = value.length();
+   if (length == 0)
+      return;
+   // poor mans rstrip(", ")
+   if (value[length-2] == ',' && value[length-1] == ' ')
+      value.erase(length - 2, 2);
+   fprintf(history_out, "%s: %s\n", tag.c_str(), value.c_str());
 }									/*}}}*/
 // DPkgPM::OpenLog							/*{{{*/
 bool pkgDPkgPM::OpenLog()
@@ -675,7 +720,22 @@ bool pkgDPkgPM::CloseLog()
 
    if(history_out)
    {
-      if (dpkg_error.size() > 0)
+      if (disappearedPkgs.empty() == false)
+      {
+	 string disappear;
+	 for (std::set<std::string>::const_iterator d = disappearedPkgs.begin();
+	      d != disappearedPkgs.end(); ++d)
+	 {
+	    pkgCache::PkgIterator P = Cache.FindPkg(*d);
+	    disappear.append(*d);
+	    if (P.end() == true)
+	       disappear.append(", ");
+	    else
+	       disappear.append(" (").append(Cache[P].CurVersion).append("), ");
+	 }
+	 WriteHistoryTag("Disappeared", disappear);
+      }
+      if (dpkg_error.empty() == false)
 	 fprintf(history_out, "Error: %s\n", dpkg_error.c_str());
       fprintf(history_out, "End-Date: %s\n", timestr);
       fclose(history_out);

+ 16 - 1
apt-pkg/deb/dpkgpm.h

@@ -32,6 +32,21 @@ class pkgDPkgPM : public pkgPackageManager
    FILE *history_out;
    string dpkg_error;
 
+   /** \brief record the disappear action and handle accordingly
+
+      dpkg let packages disappear then they have no files any longer and
+      nothing depends on them. We need to collect this as dpkg as well as
+      APT doesn't know beforehand that the package will disappear, so the
+      only possible option is to tell the user afterwards about it.
+      To enhance the experience we also try to forward the auto-install
+      flag so the disappear-causer(s) are not autoremoved next time -
+      for the transfer to happen the disappeared version needs to depend
+      on the package the flag should be forwarded to and this package
+      needs to declare a Replaces on the disappeared package.
+      \param pkgname Name of the package that disappeared
+   */
+   void handleDisappearAction(string const &pkgname);
+
    protected:
    int pkgFailures;
 
@@ -70,7 +85,7 @@ class pkgDPkgPM : public pkgPackageManager
    // Helpers
    bool RunScriptsWithPkgs(const char *Cnf);
    bool SendV2Pkgs(FILE *F);
-   void WriteHistoryTag(string tag, string value);
+   void WriteHistoryTag(string const &tag, string value);
 
    // apport integration
    void WriteApportReport(const char *pkgpath, const char *errormsg);

+ 90 - 21
apt-pkg/depcache.cc

@@ -165,7 +165,7 @@ bool pkgDepCache::Init(OpProgress *Prog)
 bool pkgDepCache::readStateFile(OpProgress *Prog)			/*{{{*/
 {
    FileFd state_file;
-   string const state = _config->FindDir("Dir::State") + "extended_states";
+   string const state = _config->FindFile("Dir::State::extended_states");
    if(FileExists(state)) {
       state_file.Open(state, FileFd::ReadOnly);
       int const file_size = state_file.Size();
@@ -222,7 +222,7 @@ bool pkgDepCache::writeStateFile(OpProgress *prog, bool InstalledOnly)	/*{{{*/
       std::clog << "pkgDepCache::writeStateFile()" << std::endl;
 
    FileFd StateFile;
-   string const state = _config->FindDir("Dir::State") + "extended_states";
+   string const state = _config->FindFile("Dir::State::extended_states");
 
    // if it does not exist, create a empty one
    if(!FileExists(state)) 
@@ -407,8 +407,11 @@ bool pkgDepCache::CheckDep(DepIterator Dep,int Type,PkgIterator &Res)
 									/*}}}*/
 // DepCache::AddSizes - Add the packages sizes to the counters		/*{{{*/
 // ---------------------------------------------------------------------
-/* Call with Mult = -1 to preform the inverse opration */
-void pkgDepCache::AddSizes(const PkgIterator &Pkg,signed long Mult)
+/* Call with Mult = -1 to preform the inverse opration
+   The Mult increases the complexity of the calulations here and is unused -
+   or do we really have a usecase for removing the size of a package two
+   times? So let us replace it with a simple bool and be done with it… */
+__deprecated void pkgDepCache::AddSizes(const PkgIterator &Pkg,signed long Mult)
 {
    StateCache &P = PkgState[Pkg->ID];
    
@@ -422,8 +425,8 @@ void pkgDepCache::AddSizes(const PkgIterator &Pkg,signed long Mult)
    // Compute the size data
    if (P.NewInstall() == true)
    {
-      iUsrSize += (signed)(Mult*P.InstVerIter(*this)->InstalledSize);
-      iDownloadSize += (signed)(Mult*P.InstVerIter(*this)->Size);
+      iUsrSize += (signed long long)(Mult*P.InstVerIter(*this)->InstalledSize);
+      iDownloadSize += (signed long long)(Mult*P.InstVerIter(*this)->Size);
       return;
    }
    
@@ -432,9 +435,9 @@ void pkgDepCache::AddSizes(const PkgIterator &Pkg,signed long Mult)
        (P.InstallVer != (Version *)Pkg.CurrentVer() || 
 	(P.iFlags & ReInstall) == ReInstall) && P.InstallVer != 0)
    {
-      iUsrSize += (signed)(Mult*((signed)P.InstVerIter(*this)->InstalledSize - 
-			(signed)Pkg.CurrentVer()->InstalledSize));
-      iDownloadSize += (signed)(Mult*P.InstVerIter(*this)->Size);
+      iUsrSize += (signed long long)(Mult*((signed long long)P.InstVerIter(*this)->InstalledSize - 
+			(signed long long)Pkg.CurrentVer()->InstalledSize));
+      iDownloadSize += (signed long long)(Mult*P.InstVerIter(*this)->Size);
       return;
    }
    
@@ -442,14 +445,80 @@ void pkgDepCache::AddSizes(const PkgIterator &Pkg,signed long Mult)
    if (Pkg.State() == pkgCache::PkgIterator::NeedsUnpack &&
        P.Delete() == false)
    {
-      iDownloadSize += (signed)(Mult*P.InstVerIter(*this)->Size);
+      iDownloadSize += (signed long long)(Mult*P.InstVerIter(*this)->Size);
       return;
    }
    
    // Removing
    if (Pkg->CurrentVer != 0 && P.InstallVer == 0)
    {
-      iUsrSize -= (signed)(Mult*Pkg.CurrentVer()->InstalledSize);
+      iUsrSize -= (signed long long)(Mult*Pkg.CurrentVer()->InstalledSize);
+      return;
+   }   
+}
+									/*}}}*/
+// DepCache::AddSizes - Add the packages sizes to the counters		/*{{{*/
+// ---------------------------------------------------------------------
+/* Call with Inverse = true to preform the inverse opration */
+void pkgDepCache::AddSizes(const PkgIterator &Pkg, bool const &Inverse)
+{
+   StateCache &P = PkgState[Pkg->ID];
+   
+   if (Pkg->VersionList == 0)
+      return;
+   
+   if (Pkg.State() == pkgCache::PkgIterator::NeedsConfigure && 
+       P.Keep() == true)
+      return;
+   
+   // Compute the size data
+   if (P.NewInstall() == true)
+   {
+      if (Inverse == false) {
+	 iUsrSize += P.InstVerIter(*this)->InstalledSize;
+	 iDownloadSize += P.InstVerIter(*this)->Size;
+      } else {
+	 iUsrSize -= P.InstVerIter(*this)->InstalledSize;
+	 iDownloadSize -= P.InstVerIter(*this)->Size;
+      }
+      return;
+   }
+   
+   // Upgrading
+   if (Pkg->CurrentVer != 0 && 
+       (P.InstallVer != (Version *)Pkg.CurrentVer() || 
+	(P.iFlags & ReInstall) == ReInstall) && P.InstallVer != 0)
+   {
+      if (Inverse == false) {
+	 iUsrSize -= Pkg.CurrentVer()->InstalledSize;
+	 iUsrSize += P.InstVerIter(*this)->InstalledSize;
+	 iDownloadSize += P.InstVerIter(*this)->Size;
+      } else {
+	 iUsrSize -= P.InstVerIter(*this)->InstalledSize;
+	 iUsrSize += Pkg.CurrentVer()->InstalledSize;
+	 iDownloadSize -= P.InstVerIter(*this)->Size;
+      }
+      return;
+   }
+   
+   // Reinstall
+   if (Pkg.State() == pkgCache::PkgIterator::NeedsUnpack &&
+       P.Delete() == false)
+   {
+      if (Inverse == false)
+	 iDownloadSize += P.InstVerIter(*this)->Size;
+      else
+	 iDownloadSize -= P.InstVerIter(*this)->Size;
+      return;
+   }
+   
+   // Removing
+   if (Pkg->CurrentVer != 0 && P.InstallVer == 0)
+   {
+      if (Inverse == false)
+	 iUsrSize -= Pkg.CurrentVer()->InstalledSize;
+      else
+	 iUsrSize += Pkg.CurrentVer()->InstalledSize;
       return;
    }   
 }
@@ -806,7 +875,7 @@ void pkgDepCache::Update(OpProgress *Prog)
 		a bit we increase with a kill, but we should do something more clever… */
       while(recheck.empty() == false)
 	 for (std::set<unsigned long>::const_iterator p = recheck.begin();
-	     p != recheck.end(); ++p) {
+	     p != recheck.end();) {
 	    if (Prog != 0 && Done%20 == 0)
 	       Prog->Progress(Done);
 	    PkgIterator P = PkgIterator(*Cache, Cache->PkgP + *p);
@@ -814,7 +883,7 @@ void pkgDepCache::Update(OpProgress *Prog)
 	       ++killed;
 	       ++Done;
 	    }
-	    recheck.erase(p);
+	    recheck.erase(p++);
 	 }
 
       /* Okay, we have killed a great amount of pseudopackages -
@@ -849,7 +918,7 @@ void pkgDepCache::Update(OpProgress *Prog)
 	 unsigned long const G = *g;
 	 recheck.erase(g);
 	 if (unlikely(ReInstallPseudoForGroup(G, recheck) == false))
-	    _error->Warning(_("Internal error, group '%s' has no installable pseudo package"), GrpIterator(*Cache, Cache->GrpP + *g).Name());
+	    _error->Warning(_("Internal error, group '%s' has no installable pseudo package"), GrpIterator(*Cache, Cache->GrpP + G).Name());
       }
    }
 
@@ -1638,8 +1707,11 @@ bool pkgDepCache::MarkRequired(InRootSetFunc &userFunc)
    {
       if(!(PkgState[p->ID].Flags & Flag::Auto) ||
 	  (p->Flags & Flag::Essential) ||
-	  userFunc.InRootSet(p))
-          
+	  userFunc.InRootSet(p) ||
+	  // be nice even then a required package violates the policy (#583517)
+	  // and do the full mark process also for required packages
+	  (p.CurrentVer().end() != true &&
+	   p.CurrentVer()->Priority == pkgCache::State::Required))
       {
 	 // the package is installed (and set to keep)
 	 if(PkgState[p->ID].Keep() && !p.CurrentVer().end())
@@ -1716,10 +1788,6 @@ void pkgDepCache::MarkPackage(const pkgCache::PkgIterator &pkg,
 
    // If the version belongs to a Multi-Arch all package
    // we will mark all others in this Group with this version also
-   // Beware: We compare versions here the lazy way: string comparision
-   // this is bad if multiple repositories provide different versions
-   // of the package with an identical version number - but even in this
-   // case the dependencies are likely the same.
    if (ver->MultiArch == pkgCache::Version::All &&
 	strcmp(ver.Arch(true), "all") == 0)
    {
@@ -1731,7 +1799,8 @@ void pkgDepCache::MarkPackage(const pkgCache::PkgIterator &pkg,
 	 for (VerIterator V = P.VersionList();
 	      V.end() != true; ++V)
 	 {
-	    if (strcmp(VerStr, V.VerStr()) != 0)
+	    if (ver->Hash != V->Hash ||
+		strcmp(VerStr, V.VerStr()) != 0)
 	       continue;
 	    MarkPackage(P, V, follow_recommends, follow_suggests);
 	    break;

+ 10 - 7
apt-pkg/depcache.h

@@ -286,9 +286,11 @@ class pkgDepCache : protected pkgCache::Namespace
    pkgCache *Cache;
    StateCache *PkgState;
    unsigned char *DepState;
-   
-   double iUsrSize;
-   double iDownloadSize;
+
+   /** Stores the space changes after installation */
+   signed long long iUsrSize;
+   /** Stores how much we need to download to get the packages */
+   unsigned long long iDownloadSize;
    unsigned long iInstCount;
    unsigned long iDelCount;
    unsigned long iKeepCount;
@@ -321,8 +323,9 @@ class pkgDepCache : protected pkgCache::Namespace
    void Update(PkgIterator const &P);
    
    // Count manipulators
-   void AddSizes(const PkgIterator &Pkg,signed long Mult = 1);
-   inline void RemoveSizes(const PkgIterator &Pkg) {AddSizes(Pkg,-1);};
+   void AddSizes(const PkgIterator &Pkg, bool const &Invert = false);
+   inline void RemoveSizes(const PkgIterator &Pkg) {AddSizes(Pkg, true);};
+   void AddSizes(const PkgIterator &Pkg,signed long Mult) __deprecated;
    void AddStates(const PkgIterator &Pkg,int Add = 1);
    inline void RemoveStates(const PkgIterator &Pkg) {AddStates(Pkg,-1);};
    
@@ -451,8 +454,8 @@ class pkgDepCache : protected pkgCache::Namespace
    bool writeStateFile(OpProgress *prog, bool InstalledOnly=true);
    
    // Size queries
-   inline double UsrSize() {return iUsrSize;};
-   inline double DebSize() {return iDownloadSize;};
+   inline signed long long UsrSize() {return iUsrSize;};
+   inline unsigned long long DebSize() {return iDownloadSize;};
    inline unsigned long DelCount() {return iDelCount;};
    inline unsigned long KeepCount() {return iKeepCount;};
    inline unsigned long InstCount() {return iInstCount;};

+ 6 - 2
apt-pkg/indexfile.h

@@ -74,8 +74,12 @@ class pkgIndexFile
    virtual bool Exists() const = 0;
    virtual bool HasPackages() const = 0;
    virtual unsigned long Size() const = 0;
-   virtual bool Merge(pkgCacheGenerator &/*Gen*/,OpProgress &/*Prog*/) const {return false;};
-   virtual bool MergeFileProvides(pkgCacheGenerator &/*Gen*/,OpProgress &/*Prog*/) const {return true;};
+   virtual bool Merge(pkgCacheGenerator &/*Gen*/,OpProgress* /*Prog*/) const { return false; };
+   __deprecated virtual bool Merge(pkgCacheGenerator &Gen, OpProgress &Prog) const
+      { return Merge(Gen, &Prog); };
+   virtual bool MergeFileProvides(pkgCacheGenerator &/*Gen*/,OpProgress* /*Prog*/) const {return true;};
+   __deprecated virtual bool MergeFileProvides(pkgCacheGenerator &Gen, OpProgress &Prog) const
+      {return MergeFileProvides(Gen, &Prog);};
    virtual pkgCache::PkgFileIterator FindInCache(pkgCache &Cache) const;
 
    static bool TranslationsAvailable();

+ 47 - 3
apt-pkg/indexrecords.cc

@@ -7,8 +7,11 @@
 #include <apt-pkg/tagfile.h>
 #include <apt-pkg/error.h>
 #include <apt-pkg/strutl.h>
+#include <apt-pkg/configuration.h>
 #include <apti18n.h>
 #include <sys/stat.h>
+#include <clocale>
+
 									/*}}}*/
 string indexRecords::GetDist() const
 {
@@ -26,11 +29,21 @@ string indexRecords::GetExpectedDist() const
    return this->ExpectedDist;
 }
 
+time_t indexRecords::GetValidUntil() const
+{
+   return this->ValidUntil;
+}
+
 const indexRecords::checkSum *indexRecords::Lookup(const string MetaKey)
 {
    return Entries[MetaKey];
 }
 
+bool indexRecords::Exists(string const &MetaKey) const
+{
+   return Entries.count(MetaKey) == 1;
+}
+
 bool indexRecords::Load(const string Filename)				/*{{{*/
 {
    FileFd Fd(Filename, FileFd::ReadOnly);
@@ -80,9 +93,40 @@ bool indexRecords::Load(const string Filename)				/*{{{*/
    {
       strprintf(ErrorText, _("No Hash entry in Release file %s"), Filename.c_str());
       return false;
-   }  
+   }
+
+   string Label = Section.FindS("Label");
+   string StrDate = Section.FindS("Date");
+   string StrValidUntil = Section.FindS("Valid-Until");
+
+   // if we have a Valid-Until header in the Release file, use it as default
+   if (StrValidUntil.empty() == false)
+   {
+      if(RFC1123StrToTime(StrValidUntil.c_str(), ValidUntil) == false)
+      {
+	 strprintf(ErrorText, _("Invalid 'Valid-Until' entry in Release file %s"), Filename.c_str());
+	 return false;
+      }
+   }
+   // get the user settings for this archive and use what expires earlier
+   int MaxAge = _config->FindI("Acquire::Max-ValidTime", 0);
+   if (Label.empty() == true)
+      MaxAge = _config->FindI(string("Acquire::Max-ValidTime::" + Label).c_str(), MaxAge);
+
+   if(MaxAge == 0) // No user settings, use the one from the Release file
+      return true;
+
+   time_t date;
+   if (RFC1123StrToTime(StrDate.c_str(), date) == false)
+   {
+      strprintf(ErrorText, _("Invalid 'Date' entry in Release file %s"), Filename.c_str());
+      return false;
+   }
+   date += 24*60*60*MaxAge;
+
+   if (ValidUntil == 0 || ValidUntil > date)
+      ValidUntil = date;
 
-   string Strdate = Section.FindS("Date"); // FIXME: verify this somehow?
    return true;
 }
 									/*}}}*/
@@ -160,6 +204,6 @@ indexRecords::indexRecords()
 }
 
 indexRecords::indexRecords(const string ExpectedDist) :
-   ExpectedDist(ExpectedDist)
+   ExpectedDist(ExpectedDist), ValidUntil(0)
 {
 }

+ 6 - 0
apt-pkg/indexrecords.h

@@ -12,6 +12,7 @@
 
 #include <map>
 #include <vector>
+#include <ctime>
 
 class indexRecords
 {
@@ -25,6 +26,8 @@ class indexRecords
    string Dist;
    string Suite;
    string ExpectedDist;
+   time_t ValidUntil;
+
    std::map<string,checkSum *> Entries;
 
    public:
@@ -34,10 +37,13 @@ class indexRecords
 
    // Lookup function
    virtual const checkSum *Lookup(const string MetaKey);
+   /** \brief tests if a checksum for this file is available */
+   bool Exists(string const &MetaKey) const;
    std::vector<std::string> MetaKeys();
 
    virtual bool Load(string Filename);
    string GetDist() const;
+   time_t GetValidUntil() const;
    virtual bool CheckDist(const string MaybeDist) const;
    string GetExpectedDist() const;
    virtual ~indexRecords(){};

+ 3 - 2
apt-pkg/makefile

@@ -35,14 +35,15 @@ SOURCE+= pkgcache.cc version.cc depcache.cc \
 	 srcrecords.cc cachefile.cc versionmatch.cc policy.cc \
 	 pkgsystem.cc indexfile.cc pkgcachegen.cc acquire-item.cc \
 	 indexrecords.cc vendor.cc vendorlist.cc cdrom.cc indexcopy.cc \
-	 aptconfiguration.cc
+	 aptconfiguration.cc cacheset.cc
 HEADERS+= algorithms.h depcache.h pkgcachegen.h cacheiterators.h \
 	  orderlist.h sourcelist.h packagemanager.h tagfile.h \
 	  init.h pkgcache.h version.h progress.h pkgrecords.h \
 	  acquire.h acquire-worker.h acquire-item.h acquire-method.h \
 	  clean.h srcrecords.h cachefile.h versionmatch.h policy.h \
 	  pkgsystem.h indexfile.h metaindex.h indexrecords.h vendor.h \
-          vendorlist.h cdrom.h indexcopy.h aptconfiguration.h
+          vendorlist.h cdrom.h indexcopy.h aptconfiguration.h \
+	  cacheset.h
 
 # Source code for the debian specific components
 # In theory the deb headers do not need to be exported..

+ 20 - 1
apt-pkg/pkgcache.cc

@@ -340,6 +340,25 @@ pkgCache::PkgIterator pkgCache::GrpIterator::FindPkg(string Arch) {
 			break;
 	}
 
+	return PkgIterator(*Owner, 0);
+}
+									/*}}}*/
+// GrpIterator::FindPreferredPkg - Locate the "best" package		/*{{{*/
+// ---------------------------------------------------------------------
+/* Returns an End-Pointer on error, pointer to the package otherwise */
+pkgCache::PkgIterator pkgCache::GrpIterator::FindPreferredPkg() {
+	pkgCache::PkgIterator Pkg = FindPkg("native");
+	if (Pkg.end() == false)
+		return Pkg;
+
+	std::vector<std::string> const archs = APT::Configuration::getArchitectures();
+	for (std::vector<std::string>::const_iterator a = archs.begin();
+	     a != archs.end(); ++a) {
+		Pkg = FindPkg(*a);
+		if (Pkg.end() == false)
+			return Pkg;
+	}
+
 	return PkgIterator(*Owner, 0);
 }
 									/*}}}*/
@@ -723,7 +742,7 @@ pkgCache::VerFileIterator pkgCache::VerIterator::NewestFile() const
 // ---------------------------------------------------------------------
 /* This describes the version from a release-centric manner. The output is a 
    list of Label:Version/Archive */
-string pkgCache::VerIterator::RelStr()
+string pkgCache::VerIterator::RelStr() const
 {
    bool First = true;
    string Res;

+ 2 - 2
apt-pkg/pkgcache.h

@@ -532,9 +532,9 @@ struct pkgCache::Version
    /** \brief archive size for this version
 
        For Debian this is the size of the .deb file. */
-   map_ptrloc Size;              // These are the .deb size
+   unsigned long long Size;      // These are the .deb size
    /** \brief uncompressed size for this version */
-   map_ptrloc InstalledSize;
+   unsigned long long InstalledSize;
    /** \brief characteristic value representing this version
 
        No two packages in existence should have the same VerStr

+ 28 - 17
apt-pkg/pkgcachegen.cc

@@ -526,7 +526,7 @@ map_ptrloc pkgCacheGenerator::NewDescription(pkgCache::DescIterator &Desc,
 // CacheGenerator::FinishCache - do various finish operations		/*{{{*/
 // ---------------------------------------------------------------------
 /* This prepares the Cache for delivery */
-bool pkgCacheGenerator::FinishCache(OpProgress &Progress)
+bool pkgCacheGenerator::FinishCache(OpProgress *Progress)
 {
    // FIXME: add progress reporting for this operation
    // Do we have different architectures in your groups ?
@@ -923,7 +923,7 @@ static unsigned long ComputeSize(FileIterator Start,FileIterator End)
 // ---------------------------------------------------------------------
 /* */
 static bool BuildCache(pkgCacheGenerator &Gen,
-		       OpProgress &Progress,
+		       OpProgress *Progress,
 		       unsigned long &CurrentSize,unsigned long TotalSize,
 		       FileIterator Start, FileIterator End)
 {
@@ -944,7 +944,8 @@ static bool BuildCache(pkgCacheGenerator &Gen,
       }
       
       unsigned long Size = (*I)->Size();
-      Progress.OverallProgress(CurrentSize,TotalSize,Size,_("Reading package lists"));
+      if (Progress != NULL)
+	 Progress->OverallProgress(CurrentSize,TotalSize,Size,_("Reading package lists"));
       CurrentSize += Size;
       
       if ((*I)->Merge(Gen,Progress) == false)
@@ -953,13 +954,15 @@ static bool BuildCache(pkgCacheGenerator &Gen,
 
    if (Gen.HasFileDeps() == true)
    {
-      Progress.Done();
+      if (Progress != NULL)
+	 Progress->Done();
       TotalSize = ComputeSize(Start, End);
       CurrentSize = 0;
       for (I = Start; I != End; I++)
       {
 	 unsigned long Size = (*I)->Size();
-	 Progress.OverallProgress(CurrentSize,TotalSize,Size,_("Collecting File Provides"));
+	 if (Progress != NULL)
+	    Progress->OverallProgress(CurrentSize,TotalSize,Size,_("Collecting File Provides"));
 	 CurrentSize += Size;
 	 if ((*I)->MergeFileProvides(Gen,Progress) == false)
 	    return false;
@@ -969,7 +972,7 @@ static bool BuildCache(pkgCacheGenerator &Gen,
    return true;
 }
 									/*}}}*/
-// MakeStatusCache - Construct the status cache				/*{{{*/
+// CacheGenerator::MakeStatusCache - Construct the status cache		/*{{{*/
 // ---------------------------------------------------------------------
 /* This makes sure that the status cache (the cache that has all 
    index files from the sources list and all local ones) is ready
@@ -977,7 +980,10 @@ static bool BuildCache(pkgCacheGenerator &Gen,
    the cache will be stored there. This is pretty much mandetory if you
    are using AllowMem. AllowMem lets the function be run as non-root
    where it builds the cache 'fast' into a memory buffer. */
-bool pkgMakeStatusCache(pkgSourceList &List,OpProgress &Progress,
+__deprecated bool pkgMakeStatusCache(pkgSourceList &List,OpProgress &Progress,
+			MMap **OutMap, bool AllowMem)
+   { return pkgCacheGenerator::MakeStatusCache(List, &Progress, OutMap, AllowMem); }
+bool pkgCacheGenerator::MakeStatusCache(pkgSourceList &List,OpProgress *Progress,
 			MMap **OutMap,bool AllowMem)
 {
    bool const Debug = _config->FindB("Debug::pkgCacheGen", false);
@@ -1028,13 +1034,15 @@ bool pkgMakeStatusCache(pkgSourceList &List,OpProgress &Progress,
 
    if (Writeable == false && AllowMem == false && CacheFile.empty() == false)
       return _error->Error(_("Unable to write to %s"),flNotFile(CacheFile).c_str());
-   
-   Progress.OverallProgress(0,1,1,_("Reading package lists"));
-   
+
+   if (Progress != NULL)
+      Progress->OverallProgress(0,1,1,_("Reading package lists"));
+
    // Cache is OK, Fin.
    if (CheckValidity(CacheFile,Files.begin(),Files.end(),OutMap) == true)
    {
-      Progress.OverallProgress(1,1,1,_("Reading package lists"));
+      if (Progress != NULL)
+	 Progress->OverallProgress(1,1,1,_("Reading package lists"));
       if (Debug == true)
 	 std::clog << "pkgcache.bin is valid - no need to build anything" << std::endl;
       return true;
@@ -1084,7 +1092,7 @@ bool pkgMakeStatusCache(pkgSourceList &List,OpProgress &Progress,
       TotalSize = ComputeSize(Files.begin()+EndOfSource,Files.end());
 
       // Build the status cache
-      pkgCacheGenerator Gen(Map.Get(),&Progress);
+      pkgCacheGenerator Gen(Map.Get(),Progress);
       if (_error->PendingError() == true)
 	 return false;
       if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
@@ -1101,7 +1109,7 @@ bool pkgMakeStatusCache(pkgSourceList &List,OpProgress &Progress,
       TotalSize = ComputeSize(Files.begin(),Files.end());
       
       // Build the source cache
-      pkgCacheGenerator Gen(Map.Get(),&Progress);
+      pkgCacheGenerator Gen(Map.Get(),Progress);
       if (_error->PendingError() == true)
 	 return false;
       if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
@@ -1160,10 +1168,12 @@ bool pkgMakeStatusCache(pkgSourceList &List,OpProgress &Progress,
    return true;
 }
 									/*}}}*/
-// MakeOnlyStatusCache - Build a cache with just the status files	/*{{{*/
+// CacheGenerator::MakeOnlyStatusCache - Build only a status files cache/*{{{*/
 // ---------------------------------------------------------------------
 /* */
-bool pkgMakeOnlyStatusCache(OpProgress &Progress,DynamicMMap **OutMap)
+__deprecated bool pkgMakeOnlyStatusCache(OpProgress &Progress,DynamicMMap **OutMap)
+   { return pkgCacheGenerator::MakeOnlyStatusCache(&Progress, OutMap); }
+bool pkgCacheGenerator::MakeOnlyStatusCache(OpProgress *Progress,DynamicMMap **OutMap)
 {
    unsigned long MapSize = _config->FindI("APT::Cache-Limit",20*1024*1024);
    vector<pkgIndexFile *> Files;
@@ -1178,8 +1188,9 @@ bool pkgMakeOnlyStatusCache(OpProgress &Progress,DynamicMMap **OutMap)
    TotalSize = ComputeSize(Files.begin()+EndOfSource,Files.end());
    
    // Build the status cache
-   Progress.OverallProgress(0,1,1,_("Reading package lists"));
-   pkgCacheGenerator Gen(Map.Get(),&Progress);
+   if (Progress != NULL)
+      Progress->OverallProgress(0,1,1,_("Reading package lists"));
+   pkgCacheGenerator Gen(Map.Get(),Progress);
    if (_error->PendingError() == true)
       return false;
    if (BuildCache(Gen,Progress,CurrentSize,TotalSize,

+ 8 - 2
apt-pkg/pkgcachegen.h

@@ -76,7 +76,11 @@ class pkgCacheGenerator							/*{{{*/
 
    bool HasFileDeps() {return FoundFileDeps;};
    bool MergeFileProvides(ListParser &List);
-   bool FinishCache(OpProgress &Progress);
+   bool FinishCache(OpProgress *Progress);
+
+   static bool MakeStatusCache(pkgSourceList &List,OpProgress *Progress,
+			MMap **OutMap = 0,bool AllowMem = false);
+   static bool MakeOnlyStatusCache(OpProgress *Progress,DynamicMMap **OutMap);
 
    pkgCacheGenerator(DynamicMMap *Map,OpProgress *Progress);
    ~pkgCacheGenerator();
@@ -134,10 +138,12 @@ class pkgCacheGenerator::ListParser
    virtual ~ListParser() {};
 };
 									/*}}}*/
+
 bool pkgMakeStatusCache(pkgSourceList &List,OpProgress &Progress,
 			MMap **OutMap = 0,bool AllowMem = false);
 bool pkgMakeOnlyStatusCache(OpProgress &Progress,DynamicMMap **OutMap);
 
+
 #ifdef APT_COMPATIBILITY
 #if APT_COMPATIBILITY != 986
 #warning "Using APT_COMPATIBILITY"
@@ -145,7 +151,7 @@ bool pkgMakeOnlyStatusCache(OpProgress &Progress,DynamicMMap **OutMap);
 MMap *pkgMakeStatusCacheMem(pkgSourceList &List,OpProgress &Progress)
 {
    MMap *Map = 0;
-   if (pkgMakeStatusCache(List,Progress,&Map,true) == false)
+   if (pkgCacheGenerator::MakeStatusCache(List,&Progress,&Map,true) == false)
       return 0;
    return Map;
 }

+ 24 - 0
apt-pkg/tagfile.cc

@@ -365,6 +365,30 @@ signed int pkgTagSection::FindI(const char *Tag,signed long Default) const
    return Result;
 }
 									/*}}}*/
+// TagSection::FindULL - Find an unsigned long long integer		/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+unsigned long long pkgTagSection::FindULL(const char *Tag, unsigned long long const &Default) const
+{
+   const char *Start;
+   const char *Stop;
+   if (Find(Tag,Start,Stop) == false)
+      return Default;
+
+   // Copy it into a temp buffer so we can use strtoull
+   char S[100];
+   if ((unsigned)(Stop - Start) >= sizeof(S))
+      return Default;
+   strncpy(S,Start,Stop-Start);
+   S[Stop - Start] = 0;
+   
+   char *End;
+   unsigned long long Result = strtoull(S,&End,10);
+   if (S == End)
+      return Default;
+   return Result;
+}
+									/*}}}*/
 // TagSection::FindFlag - Locate a yes/no type flag			/*{{{*/
 // ---------------------------------------------------------------------
 /* The bits marked in Flag are masked on/off in Flags */

+ 1 - 0
apt-pkg/tagfile.h

@@ -57,6 +57,7 @@ class pkgTagSection
    bool Find(const char *Tag,unsigned &Pos) const;
    string FindS(const char *Tag) const;
    signed int FindI(const char *Tag,signed long Default = 0) const ;
+   unsigned long long FindULL(const char *Tag, unsigned long long const &Default = 0) const;
    bool FindFlag(const char *Tag,unsigned long &Flags,
 		 unsigned long Flag) const;
    bool Scan(const char *Start,unsigned long MaxLength);

文件差異過大導致無法顯示
+ 309 - 364
cmdline/apt-cache.cc


+ 1 - 2
cmdline/apt-extracttemplates.cc

@@ -296,8 +296,7 @@ bool Go(CommandLine &CmdL)
 	MMap *Map = 0;
 	pkgSourceList List;
 	List.ReadMainList();
-	OpProgress Prog;
-	pkgMakeStatusCache(List,Prog,&Map,true);
+	pkgCacheGenerator::MakeStatusCache(List,NULL,&Map,true);
 	if (Map == 0)
 	   return false;
 	DebFile::Cache = new pkgCache(Map);

+ 16 - 42
cmdline/apt-get.cc

@@ -40,7 +40,8 @@
 #include <apt-pkg/sptr.h>
 #include <apt-pkg/md5.h>
 #include <apt-pkg/versionmatch.h>
-    
+#include <apt-pkg/cacheset.h>
+
 #include <config.h>
 #include <apti18n.h>
 
@@ -90,14 +91,14 @@ class CacheFile : public pkgCacheFile
    bool BuildCaches(bool WithLock = true)
    {
       OpTextProgress Prog(*_config);
-      if (pkgCacheFile::BuildCaches(Prog,WithLock) == false)
+      if (pkgCacheFile::BuildCaches(&Prog,WithLock) == false)
 	 return false;
       return true;
    }
    bool Open(bool WithLock = true) 
    {
       OpTextProgress Prog(*_config);
-      if (pkgCacheFile::Open(Prog,WithLock) == false)
+      if (pkgCacheFile::Open(&Prog,WithLock) == false)
 	 return false;
       Sort();
       
@@ -837,9 +838,9 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true,
       return false;
 
    // Display statistics
-   double FetchBytes = Fetcher.FetchNeeded();
-   double FetchPBytes = Fetcher.PartialPresent();
-   double DebBytes = Fetcher.TotalNeeded();
+   unsigned long long FetchBytes = Fetcher.FetchNeeded();
+   unsigned long long FetchPBytes = Fetcher.PartialPresent();
+   unsigned long long DebBytes = Fetcher.TotalNeeded();
    if (DebBytes != Cache->DebSize())
    {
       c0out << DebBytes << ',' << Cache->DebSize() << endl;
@@ -1780,51 +1781,24 @@ bool DoInstall(CommandLine &CmdL)
 	 Packages++;
 	 if (Pkg.end() == true)
 	 {
-	    // Check if the name is a regex
-	    const char *I;
-	    for (I = S; *I != 0; I++)
-	       if (*I == '?' || *I == '*' || *I == '|' ||
-		   *I == '[' || *I == '^' || *I == '$')
-		  break;
-	    if (*I == 0)
+	    APT::PackageSet pkgset = APT::PackageSet::FromRegEx(Cache, S, c1out);
+	    if (pkgset.empty() == true)
 	       return _error->Error(_("Couldn't find package %s"),S);
 
 	    // Regexs must always be confirmed
 	    ExpectedInst += 1000;
-	 
-	    // Compile the regex pattern
-	    regex_t Pattern;
-	    int Res;
-	    if ((Res = regcomp(&Pattern,S,REG_EXTENDED | REG_ICASE |
-			       REG_NOSUB)) != 0)
-	    {
-	       char Error[300];	    
-	       regerror(Res,&Pattern,Error,sizeof(Error));
-	       return _error->Error(_("Regex compilation error - %s"),Error);
-	    }
-	 
-	    // Run over the matches
+
 	    bool Hit = false;
-	    for (pkgCache::GrpIterator Grp = Cache->GrpBegin(); Grp.end() == false; ++Grp)
+	    for (APT::PackageSet::const_iterator Pkg = pkgset.begin(); Pkg != pkgset.end(); ++Pkg)
 	    {
-	       if (regexec(&Pattern,Grp.Name(),0,0,0) != 0)
-		  continue;
-	       Pkg = Grp.FindPkg("native");
-	       if (unlikely(Pkg.end() == true))
-		  continue;
-
-	       ioprintf(c1out,_("Note, selecting %s for regex '%s'\n"),
-			Pkg.Name(),S);
-	    
 	       if (VerTag != 0)
 		  if (TryToChangeVer(Pkg,Cache,VerTag,VerIsRel) == false)
 		     return false;
-	    
+
 	       Hit |= TryToInstall(Pkg,Cache,Fix,Remove,BrokenFix,
 				   ExpectedInst,false);
 	    }
-	    regfree(&Pattern);
-	 
+
 	    if (Hit == false)
 	       return _error->Error(_("Couldn't find package %s"),S);
 	 }
@@ -2389,9 +2363,9 @@ bool DoSource(CommandLine &CmdL)
    }
    
    // Display statistics
-   double FetchBytes = Fetcher.FetchNeeded();
-   double FetchPBytes = Fetcher.PartialPresent();
-   double DebBytes = Fetcher.TotalNeeded();
+   unsigned long long FetchBytes = Fetcher.FetchNeeded();
+   unsigned long long FetchPBytes = Fetcher.PartialPresent();
+   unsigned long long DebBytes = Fetcher.TotalNeeded();
 
    // Check for enough free space
    struct statvfs Buf;

+ 63 - 2
debian/changelog

@@ -1,4 +1,4 @@
-apt (0.7.26~exp6) experimental; urgency=low
+apt (0.7.26~exp6) UNRELEASED; urgency=low
 
   [ Michael Vogt ]
   * merge the remaining Ubuntu change:
@@ -20,8 +20,69 @@ apt (0.7.26~exp6) experimental; urgency=low
     - write apport crash file on package failure (disabled by default
       on debian until apport is available)
     - support mirror failure reporting (disabled by default on debian)
+  
+  [ David Kalnischkies ]
+  * apt-pkg/deb/dpkgpm.cc:
+    - write Disappeared also to the history.log
+    - forward manual-installed bit on package disappearance
+  * apt-pkg/deb/debsystem.cc:
+    - add better config item for extended_states file
+  * apt-pkg/pkgcache.h:
+    - switch {,Install-}Size to unsigned long long
+  * apt-pkg/depcache.cc:
+    - do the autoremove mark process also for required packages to handle
+      these illegally depending on lower priority packages (Closes: #583517)
+    - try harder to find the other pseudo versions for autoremove multiarch
+    - correct "Dangerous iterator usage" pointed out by cppcheck
+    - deal with long long, not with int to remove 2GB Limit (LP: #250909)
+    - deprecate AddSize with Multiplier as it is unused and switch to
+      boolean instead to handle the sizes more gracefully.
+    - switch i{Download,Usr}Size from double to (un)signed long long
+  * apt-pkg/aptconfiguration.cc:
+    - remove duplicate architectures in getArchitectures()
+  * apt-pkg/indexrecords.{cc,h}:
+    - backport forgotten Valid-Until patch from the obsolete experimental
+      branch to prevent replay attacks better, thanks to Thomas Viehmann
+      for the initial patch! (Closes: #499897)
+    - add a constant Exists check for MetaKeys
+  * apt-pkg/acquire-item.cc:
+    - do not try PDiff if it is not listed in the Meta file
+  * apt-pkg/cacheiterator.h:
+    - let pkgCache::Iterator inherent std::iterator
+  * ftparchive/writer.h:
+    - add a virtual destructor to FTWScanner class (for cppcheck)
+  * apt-pkg/cacheset.{cc,h}:
+    - add simple wrapper around std::set for cache structures
+    - move regex magic from apt-get to new FromRegEx method
+    - move cmdline parsing from apt-cache to new FromCommandLine method
+    - support special release-modifier 'installed' and 'candidate'
+  * apt-pkg/contrib/cmdline.cc:
+    - fix segfault in SaveInConfig caused by writing over char[] sizes
+  * apt-pkg/pkgcache.cc:
+    - get the best matching arch package from a group with FindPreferredPkg
+  * cmdline/apt-cache.cc:
+    - make the search multiarch compatible by using GrpIterator instead
+    - use pkgCacheFile and the new CacheSets all over the place
+    - add --target-release option (Closes: #115520)
+    - accept pkg/release and pkg=version in show and co. (Closes: #236270)
+    - accept package versions in the unmet command
+  * cmdline/apt-get.cc:
+    - use unsigned long long instead of double to store values it gets
+  * apt-pkg/cachefile.{cc,h}:
+    - split Open() into submethods to be able to build only parts
+    - make the OpProgress optional in the Cache buildprocess
+    - store also the SourceList we use internally for export
+  * doc/apt.conf.5.xml:
+    - document the new Valid-Until related options
+  * apt-pkg/contrib/strutl.cc:
+    - split StrToTime() into HTTP1.1 and FTP date parser methods and
+      use strptime() instead of some self-made scanf mangling
+    - use the portable timegm shown in his manpage instead of a strange
+      looking code copycat from wget
+  * ftparchive/writer.cc:
+    - add ValidTime option to generate a Valid-Until header in Release file
 
- -- Michael Vogt <mvo@debian.org>  Wed, 09 Jun 2010 10:50:17 +0200
+ -- David Kalnischkies <kalnischkies@gmail.com>  Wed, 09 Jun 2010 10:52:31 +0200
 
 apt (0.7.26~exp5) experimental; urgency=low
 

+ 2 - 1
doc/apt-ftparchive.1.xml

@@ -122,7 +122,8 @@
      e.g. <literal>APT::FTPArchive::Release::Origin</literal>.  The supported fields
      are: <literal>Origin</literal>, <literal>Label</literal>, <literal>Suite</literal>,
      <literal>Version</literal>, <literal>Codename</literal>, <literal>Date</literal>,
-     <literal>Architectures</literal>, <literal>Components</literal>, <literal>Description</literal>.</para></listitem>
+     <literal>Valid-Until</literal>, <literal>Architectures</literal>,
+     <literal>Components</literal>, <literal>Description</literal>.</para></listitem>
 
      </varlistentry>
 

+ 1 - 6
doc/apt-mark.8.xml

@@ -121,12 +121,7 @@
 
  <refsect1><title>Files</title>
    <variablelist>
-      <varlistentry><term><filename>/var/lib/apt/extended_states</filename></term>
-      <listitem><para>Status list of auto-installed packages.
-		      Configuration Item: <literal>Dir::State</literal>
-		      sets the path to the <filename>extended_states</filename> file.
-      </para></listitem>
-      </varlistentry>
+	&file-extended_states;
    </variablelist>
  </refsect1>
 

+ 24 - 0
doc/apt.conf.5.xml

@@ -230,6 +230,30 @@ DPkg::Pre-Install-Pkgs {"/usr/sbin/dpkg-preconfigure --apt";};
    and the URI handlers. 
 
    <variablelist>
+     <varlistentry><term>Check-Valid-Until</term>
+	 <listitem><para>Security related option defaulting to true as an
+	 expiring validation for a Release file prevents longtime replay attacks
+	 and can e.g. also help users to identify no longer updated mirrors -
+	 but the feature depends on the correctness of the time on the user system.
+	 Archive maintainers are encouraged to create Release files with the
+	 <literal>Valid-Until</literal> header, but if they don't or a stricter value
+	 is volitional the following <literal>Max-ValidTime</literal> option can be used.
+	 </para></listitem>
+     </varlistentry>
+
+     <varlistentry><term>Max-ValidTime</term>
+	 <listitem><para>Seconds the Release file should be considered valid after
+	 it was created. The default is "for ever" (0) if the Release file of the
+	 archive doesn't include a <literal>Valid-Until</literal> header.
+	 If it does then this date is the default. The date from the Release file or
+	 the date specified by the creation time of the Release file
+	 (<literal>Date</literal> header) plus the seconds specified with this
+	 options are used to check if the validation of a file has expired by using
+	 the earlier date of the two. Archive specific settings can be made by
+	 appending the label of the archive to the option name.
+	 </para></listitem>
+     </varlistentry>
+
      <varlistentry><term>PDiffs</term>
 	 <listitem><para>Try to download deltas called <literal>PDiffs</literal> for
 	 Packages or Sources files instead of downloading whole ones. True

+ 8 - 0
doc/apt.ent

@@ -363,6 +363,14 @@
      </varlistentry>
 ">
 
+<!ENTITY file-extended_states "
+      <varlistentry><term><filename>/var/lib/apt/extended_states</filename></term>
+      <listitem><para>Status list of auto-installed packages.
+      Configuration Item: <literal>Dir::State::extended_states</literal>.
+      </para></listitem>
+      </varlistentry>
+">
+
 <!-- TRANSLATOR: This is the section header for the following paragraphs - comparable
      to the other headers like NAME and DESCRIPTION and should therefore be uppercase. -->
 <!ENTITY translation-title "TRANSLATION">

+ 5 - 2
doc/examples/configure-index

@@ -176,6 +176,10 @@ Acquire
   PDiffs::SizeLimit "50"; // don't use diffs if size of all patches excess
 			  // 50% of the size of the original file
 
+  Check-Valid-Until "true";
+  Max-ValidTime "864000"; // 10 days
+  Max-ValidTime::Debian-Security "604800"; // 7 days, label specific configuration
+
   // HTTP method configuration
   http 
   {
@@ -294,9 +298,8 @@ Dir "/"
   State "var/lib/apt/" 
   {
      Lists "lists/";
-     xstatus "xstatus";
-     userstatus "status.user";
      status "/var/lib/dpkg/status";
+     extended_states "extended_states";
      cdroms "cdroms.list";
   };
   

+ 10 - 0
ftparchive/writer.cc

@@ -924,6 +924,15 @@ ReleaseWriter::ReleaseWriter(string const &DB)
       datestr[0] = '\0';
    }
 
+   time_t const validuntil = now + _config->FindI("APT::FTPArchive::Release::ValidTime", 0);
+   char validstr[128];
+   if (now == validuntil ||
+       strftime(validstr, sizeof(validstr), "%a, %d %b %Y %H:%M:%S UTC",
+                gmtime(&validuntil)) == 0)
+   {
+      datestr[0] = '\0';
+   }
+
    map<string,string> Fields;
    Fields["Origin"] = "";
    Fields["Label"] = "";
@@ -931,6 +940,7 @@ ReleaseWriter::ReleaseWriter(string const &DB)
    Fields["Version"] = "";
    Fields["Codename"] = "";
    Fields["Date"] = datestr;
+   Fields["Valid-Until"] = validstr;
    Fields["Architectures"] = "";
    Fields["Components"] = "";
    Fields["Description"] = "";

+ 1 - 0
ftparchive/writer.h

@@ -72,6 +72,7 @@ class FTWScanner
    bool SetExts(string const &Vals);
       
    FTWScanner(string const &Arch = string());
+   virtual ~FTWScanner() {};
 };
 
 class TranslationWriter

+ 1 - 2
methods/ftp.cc

@@ -661,8 +661,7 @@ bool FTPConn::ModTime(const char *Path, time_t &Time)
       return true;
    
    // Parse it
-   StrToTime(Msg,Time);
-   return true;
+   return FTPMDTMStrToTime(Msg.c_str(), Time);
 }
 									/*}}}*/
 // FTPConn::CreateDataFd - Get a data connection			/*{{{*/

+ 1 - 1
methods/http.cc

@@ -631,7 +631,7 @@ bool ServerState::HeaderLine(string Line)
    
    if (stringcasecmp(Tag,"Last-Modified:") == 0)
    {
-      if (StrToTime(Val,Date) == false)
+      if (RFC1123StrToTime(Val.c_str(), Date) == false)
 	 return _error->Error(_("Unknown date format"));
       return true;
    }

+ 1 - 2
methods/rsh.cc

@@ -278,8 +278,7 @@ bool RSHConn::ModTime(const char *Path, time_t &Time)
       return false;
 
    // Parse it
-   StrToTime(Msg,Time);
-   return true;
+   return FTPMDTMStrToTime(Msg.c_str(), Time);
 }
 									/*}}}*/
 // RSHConn::Get - Get a file						/*{{{*/

+ 61 - 0
test/libapt/getarchitectures_test.cc

@@ -0,0 +1,61 @@
+#include <apt-pkg/aptconfiguration.h>
+#include <apt-pkg/configuration.h>
+
+#include "assert.h"
+#include <string>
+#include <vector>
+
+#include <iostream>
+
+// simple helper to quickly output a vector of strings
+void dumpVector(std::vector<std::string> vec) {
+	for (std::vector<std::string>::const_iterator v = vec.begin();
+	     v != vec.end(); v++)
+		std::cout << *v << std::endl;
+}
+
+int main(int argc,char *argv[])
+{
+	std::vector<std::string> vec;
+
+	_config->Set("APT::Architectures::1", "i386");
+	_config->Set("APT::Architectures::2", "amd64");
+	vec = APT::Configuration::getArchitectures(false);
+	equals(vec.size(), 2);
+	equals(vec[0], "i386");
+	equals(vec[1], "amd64");
+
+	_config->Set("APT::Architecture", "i386");
+	vec = APT::Configuration::getArchitectures(false);
+	equals(vec.size(), 2);
+	equals(vec[0], "i386");
+	equals(vec[1], "amd64");
+
+	_config->Set("APT::Architectures::2", "");
+	vec = APT::Configuration::getArchitectures(false);
+	equals(vec.size(), 1);
+	equals(vec[0], "i386");
+
+	_config->Set("APT::Architecture", "armel");
+	vec = APT::Configuration::getArchitectures(false);
+	equals(vec.size(), 2);
+	equals(vec[0], "i386");
+	equals(vec[1], "armel");
+
+	_config->Set("APT::Architectures::2", "amd64");
+	_config->Set("APT::Architectures::3", "i386");
+	_config->Set("APT::Architectures::4", "armel");
+	_config->Set("APT::Architectures::5", "i386");
+	_config->Set("APT::Architectures::6", "amd64");
+	_config->Set("APT::Architectures::7", "armel");
+	_config->Set("APT::Architectures::8", "armel");
+	_config->Set("APT::Architectures::9", "amd64");
+	_config->Set("APT::Architectures::10", "amd64");
+	vec = APT::Configuration::getArchitectures(false);
+	equals(vec.size(), 3);
+	equals(vec[0], "i386");
+	equals(vec[1], "amd64");
+	equals(vec[2], "armel");
+
+	return 0;
+}

+ 5 - 0
test/libapt/makefile

@@ -12,6 +12,11 @@ SLIBS = -lapt-pkg
 SOURCE = getlanguages_test.cc
 include $(PROGRAM_H)
 
+PROGRAM = getArchitectures${BASENAME}
+SLIBS = -lapt-pkg
+SOURCE = getarchitectures_test.cc
+include $(PROGRAM_H)
+
 # Program for testing ParseDepends
 PROGRAM = ParseDepends${BASENAME}
 SLIBS = -lapt-pkg

+ 1 - 0
test/libapt/run-tests.sh

@@ -2,6 +2,7 @@
 set -e
 
 echo "Compiling the tests ..."
+test -d '../../build/obj/test/libapt/' || mkdir -p '../../build/obj/test/libapt/'
 make
 echo "Running all testcases ..."
 LDPATH=$(pwd)/../../build/bin

+ 14 - 0
test/pre-upload-check.py

@@ -192,6 +192,20 @@ class testAuthentication(unittest.TestCase):
                 self.assert_(len(glob.glob("/var/lib/apt/lists/partial/*")) == 0,
                              "partial/ dir has leftover files: %s" % glob.glob("/var/lib/apt/lists/partial/*"))
 
+    def testValid(self):
+        for f in glob.glob("testsources.list/sources.list*validuntil*"):
+            self._cleanup()
+            (prefix, testtype, result) = f.split("-")
+            expected_res = self._expectedRes(result)
+            cmd = ["update"]
+            res = call([self.apt,"-o","Dir::Etc::sourcelist=./%s" % f]+cmd+apt_args,
+                       stdout=stdout, stderr=stderr)
+            self.assert_(res == expected_res,
+                         "test '%s' failed (got %s expected %s" % (f,res,expected_res))
+            if expected_res == 0:
+                self.assert_(len(glob.glob("/var/lib/apt/lists/partial/*")) == 0,
+                             "partial/ dir has leftover files: %s" % glob.glob("/var/lib/apt/lists/partial/*"))
+
 
 class testLocalRepositories(unittest.TestCase):
     " test local repository regressions "

+ 1 - 0
test/testsources.list/sources.list.all-validuntil-broken

@@ -0,0 +1 @@
+deb http://people.ubuntu.com/~mvo/apt/auth-test-suit/all-validuntil-broken/ /