Преглед изворни кода

* merge of the debian-expermental-ma branch

* debian/control:
- add dependency on zlib-dev for libapt-pkg-dev
* apt-pkg/cacheset.cc:
- [ABI BREAK] add an ErrorType option to CacheSetHelper
* cmdline/apt-cache.cc:
- use Notice instead of Error in the CacheSetHelper messages
for compat reasons. Otherwise tools like sbuild blow up
- return success in show if a virtual package was given
* debian/control:
- remove libcurl3-gnutls-dev alternative as the package is gone
- increase needed version of libcurl4-gnutls-dev to >= 7.19.0
as we use CURLOPT_{ISSUERCERT,CRLFILE} (Closes: #589642)
* apt-pkg/deb/dpkgpm.cc:
- Write architecture information to history file.
- Add to history whether a change was automatic or not.
* apt-pkg/contrib/fileutl.cc:
- Add FileFd::OpenDescriptor() (needed for python-apt's #383617).
* cmdline/apt-get.cc:
- Support large filesystems by using statvfs64() instead of statvfs()
and statfs64() instead of statfs() (Closes: #590513).
* apt-pkg/cdrom.cc:
- Use link() instead of rename() for creating the CD database backup;
otherwise there would be a short time without any database.
* apt-pkg/depcache.cc:
- handle "circular" conflicts for "all" packages correctly
* cmdline/apt-cache.cc:
- be able to omit dependency types in (r)depends (Closes: #319006)
- show in (r)depends the canidate per default instead of newest
- share the (r)depends code instead of codecopy
* apt-pkg/cacheset.cc:
- move them back to the library as they look stable now
- add a 'newest' pseudo target release as in pkg/newest
* apt-pkg/pkgcache.cc:
- prefer non-virtual packages in FindPreferredPkg (Closes: #590041)
* test/integration/*:
- add with bug#590041 testcase a small test "framework"
* apt-pkg/orderlist.cc:
- try to install another or-group member in DepRemove before
breaking the or group (Closes: #590438)
- configure also the replacement before remove by adding Immediate flag

* apt-pkg/contrib/error.{cc,h}
- docstring cleanup
- add inline DumpError() to avoid subtle API break
* apt-pkg/contrib/error.{cc,h}:
- remove constness of va_list parameter to fix build on amd64 and co
Thanks Eric Valette! (Closes: #588610)
* apt-pkg/deb/debmetaindex.cc:
- do not query each architecture for flat file archives
- fix typo preventing display of architecture in Info()
* methods/bzip2.cc:
- add a copycat of the old gzip.cc as we need it for bzip2 and lzma
* debian/rules:
- Make DEB_BUILD_OPTIONS=noopt actually work by passing the right
CXXFLAGS.
* apt-pkg/contrib/fileutl.{h,cc}:
- Add support for reading of gzipped files with the new "ReadOnlyGzip"
OpenMode. (Closes: #188407)
- Link against zlib (in apt-pkg/makefile) and add zlib build dependency.
- [ABI BREAK] This adds a new private member to FileFd, but its
initialization is in the public header file.
* configure.in:
- Check for zlib library and headers.
* apt-pkg/acquire-item.cc, apt-pkg/deb/debindexfile.cc,
apt-pkg/deb/debrecords.cc, apt-pkg/deb/debsrcrecords.h,
cmdline/apt-cache.cc:
- Open Packages, Sources, and Translations indexes in "ReadOnlyGzip" mode.
* apt-pkg/deb/debindexfile.cc:
- If we do not find uncompressed package/source/translation indexes, look
for gzip compressed ones.
* apt-pkg/acquire-item.cc:
- If the Acquire::GzipIndexes option is true and we download a gzipped
index file, keep it as it is (and rename to .gz) instead of
uncompressing it.
* doc/apt.conf.5.xml:
- Document the new Acquire::GzipIndexes option.
* doc/po/apt-doc.pot, doc/po/de.po:
- German translation of new Acquire::GzipIndexes option.
* Add test/test-indexes.sh:
- Test behaviour of index retrieval and usage, in particular with
uncompressed and gzip compressed indexes.
* methods/gzip.cc: With FileFd now being able to read gzipped files, there
is no need for the gzip method any more to spawn an external gzip process.
Rewrite it to use FileFd directly, which makes the code a lot simpler, and
also using less memory and overhead.
* doc/apt.conf.5.xml:
- add and document APT::Cache-{Start,Grow,Limit} options for mmap control
* apt-pkg/contrib/fileutl.cc:
- do not fail von double close()
* cmdline/cacheset.cc:
- doesn't include it in the library for now as it is too volatile
- get the candidate either from an already built depcache
or use the policy which is a bit faster than depcache generation
- get packages by task^ with FromTask()
- only print errors if all tries to get a package by string failed
- factor out code to get a single package FromName()
- check in Grouped* first without modifier interpretation
* cmdline/apt-get.cc:
- use the cachsets in the install commands
- make the specify order of packages irrelevant (Closes: #196021)
* apt-pkg/orderlist.cc:
- untouched packages are never missing
* apt-pkg/packagemanager.cc:
- packages that are not touched doesn't need to be unpacked
* debian/control:
- remove intltool's dependency as it is an ubuntu artefact
* apt-pkg/depcache.cc:
- SetCandidateVer for all pseudo packages
- SetReInstall for the "all" package of a pseudo package
- use the new MatchAgainstConfig for the DefaultRootSetFunc
- always mark the all package if a pseudo package is marked for install
* apt-pkg/contrib/error.{cc,h}:
- complete rewrite but use the same API
- add NOTICE and DEBUG as new types of a message
- add a simple stack handling to be able to delay error handling
* apt-pkg/aptconfiguration.cc:
- show a deprecation notice for APT::Acquire::Translation
* apt-pkg/contrib/configuration.{cc,h}:
- add a wrapper to match strings against configurable regex patterns
* apt-pkg/contrib/fileutl.cc:
- show notice about ignored file instead of being always silent
- add a Dir::Ignore-Files-Silently list option to control the notice
* apt-pkg/policy.h:
- add another round of const& madness as the previous round accidentally
NOT overrides the virtual GetCandidateVer() method (Closes: #587725)
* apt-pkg/pkgcachegen.{cc,h}:
- make the used MMap moveable (and therefore dynamic resizeable) by
applying (some) mad pointer magic (Closes: #195018)
* apt-pkg/deb/dpkgpm.cc:
- make the apt/term.log output unbuffered (thanks to Matt Zimmerman)
* methods/ftp.h:
- Handle different logins on the same server (Closes: #586904).
* apt-pkg/deb/deblistparser.cc:
- Handle architecture wildcards (Closes: #547724).
* apt-pkg/versionmatch.cc:
- Support matching pins by regular expressions or glob() like patterns,
regular expressions have to be put between to slashes; for example,
/.*/.
* apt-pkg/contrib/fileutl.cc:
- Make FileFd replace files atomically in WriteTemp mode (for cache, etc).
* debian/control:
- Set Standards-Version to 3.9.0
* apt-pkg/cachefile.h:
- make pkgPolicy public again, libapt-pkg-perl (and probably
others) get unhappy without that
* merge the remaining Ubuntu change:
- on gpg verification failure warn and restore the last known
good state
- on failure display the IP of the server (useful for servers
that use round robin DNS)
- support Original-Maintainer in RewritePackageOrder
- enable cdrom autodetection via libudev by default
- show message about Vcs in use when apt-get source is run for
packages maintained in a Vcs
- better support transitional packages with mark auto-installed.
when the transitional package is in "oldlibs" the new package
is not marked auto installed (same is true for section
metapackages)
- provide new "deb mirror://archive.foo/mirrors.list sid main"
method expects a list of mirrors (generated on the server e.g.
via geoip) and will use that, including cycle on failure
- 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)

* 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
- sent Last-Modified header also for Translation files
* 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
* apt-pkg/policy.cc:
- get the candidate right for a not-installed pseudo package if
his non-pseudo friend is installed
* apt-pkg/indexcopy.cc:
- move the gpg codecopy to a new method and use it also in methods/gpgv.cc
* cmdline/apt-get.cc:
- rerun dpkg-source in source if --fix-broken is given (Closes: #576752)
- don't suggest held packages as they are installed (Closes: #578135)
- handle multiple --{tar,diff,dsc}-only options correctly
- show at the end of the install process a list of disappeared packages
* cmdline/apt-cache.cc:
- use GroupCount for package names in stats and add a package struct line
* methods/rred.cc:
- use the patchfile modification time instead of the one from the
"old" file - thanks to Philipp Weis for noticing! (Closes: #571541)
* debian/rules:
- remove targets referring to CVS or arch as they are useless
- use $(CURDIR) instead of $(pwd)
- use dpkg-buildflags if available for CXXFLAGS
* README.arch:
- remove the file completely as it has no use nowadays
* apt-pkg/depcache.cc:
- be doublesure that the killer query is empty before starting reinstall
* methods/gpgv.cc:
- remove the keyrings count limit by using vector magic
* contrib/mmap.cc:
- clarify "MMap reached size limit" error message, thanks Ivan Masár!
* doc/apt.ent
- add entities for the current oldstable/stable/testing codenames
* doc/sources.list.5.xml:
- use stable-codename instead of stable in the examples (Closes: #531492)
* doc/apt_preferences.5.xml:
- adapt some examples here to use current codenames as well
- add "NotAutomatic: yes" handling, thanks Osamu Aoki (Closes: #490347)
* debian/libapt-pkg-doc.doc-base.cache:
- remove yet another reference to the removed cache.sgml
* doc/apt-get.8.xml:
- do not say explicit target_release_{name,version,codename}, it should
be clear by itself and 'man' can break lines again (Closes: #566166)
- remove the gnome-apt reference as it is removed from unstable
* apt-pkg/deb/dpkgpm.cc:
- add 'disappear' to the known processing states, thanks Jonathan Nieder
* apt-pkg/packagemanager.h:
- export info about disappeared packages with GetDisappearedPackages()
* methods/http.{cc,h}:
- code cleanup, use enums instead of magic ints

* debian/rules:
- spell out some less known options to reduce manpage consultation-rate
- Use POSIX command substitution: $(<command sequence>)
- Remove EOL whitespace (Closes: #577804)
* apt-pkg/acquire-item.cc:
- Fix pkgAcqFile::Custom600Headers() to always return something.

* apt-pkg/depcache.cc:
- rewrite the pseudo package reinstaller to be more intelligent
in his package choices
* apt-pkg/packagemanager.cc:
- don't try to "unpack" pseudo packages twice
* apt-pkg/contrib/fileutl.cc:
- add a parent-guarded "mkdir -p" as CreateDirectory()
* apt-pkg/acquire.{cc,h}:
- add a delayed constructor with Setup() for success reporting
- check for and create directories in Setup if needed instead of
error out unfriendly in the Constructor (Closes: #523920, #525783)
- optional handle a lock file in Setup()
* apt-pkg/acquire-item.cc:
- Acquire::ForceHash to force method for expected hash
* cmdline/apt-get.cc:
- remove the lock file handling and let Acquire take care of it instead
- display MD5Sum in --print-uris if not forced to use another method
instead of displaying the strongest available (Closes: #576420)
- regex for package names executed on Grp- not PkgIterator
- show non-candidates as fallback for virtual packages (Closes: #578385)
- set also "all" to this version for pseudo packages in TryToChangeVer
* apt-pkg/deb/dpkgpm.cc:
- remove Chroot-Directory from files passed to install commands.
Thanks to Kel Modderman for report & patch! (Closes: #577226)
* ftparchive/writer.cc:
- remove 999 chars Files and Checksums rewrite limit (Closes: #577759)
* cmdline/apt-cache.cc:
- align Installed and Candidate Version in policy so they can be compared
easier, thanks Ralf Gesellensetter for the pointer! (Closes: #578657)
* doc/apt.ent:
- Add a note about APT_CONFIG in the -c description (Closes: #578267)
* doc/po/de.po:
- correct typos in german apt_preferences manpage, thanks Chris Leick!
* apt-pkg/sourcelist.cc:
- be less strict and accept [option=value] as well
* apt-pkg/contrib/configuration.cc:
- error out if #clear directive has no argument
* doc/files.sgml:
- sync documentation with status quo, regarding files/directories in
use, extended_states and uri schemes.
* doc/cache.sgml:
- drop the file in favor of inplace documentation with doxygen
* apt-pkg/pkgcache.h:
- enhance the Groups ABI by providing a ID as the other structs does
- check also the size of the Group struct then checking for the others
* cmdline/apt-get.cc:
- replace backticks with single quotes around fix-broken command
in the broken packages message. (Closes: #577168)
* dselect/install:
- modernize if-statements not to use 'x' (Closes: #577117)
- replace backticks with POSIX $() (Closes: #577116)
* cmdline/apt-get.cc:
- fix crash when pkg.VersionList() is empty
- install html doxygen in libapt-pkg-doc
* debian/control:
- build-depend on doxygen
* apt-pkg/contrib/weakptr.h:
- add a class WeakPointable which allows one to register weak pointers to
an object which will be set to NULL when the object is deallocated.
* [ABI break] apt-pkg/acquire{-worker,-item,}.h:
- subclass pkgAcquire::{Worker,Item,ItemDesc} from WeakPointable.
* apt-pkg/pkgcache.cc:
- Merge fix from David to correct handling in single-arch environments.
* cmdline/apt-cache.cc:
- Add a showauto command to apt-cache.
* cmdline/apt-get.cc:
- Add apt-get markauto and unmarkauto commands.
* [BREAK] merge MultiArch-ABI. We don't support MultiArch,
but we support the usage of the new ABI so libapt users
can start to prepare for MultiArch (Closes: #536029)
* Ignore :qualifiers after package name in build dependencies
in the library by default, but try to honour them in apt-get
as we have some sort of MultiArch support ready (Closes: #558103)
* add translation of the manpages to PT (portuguese)
Thanks to Américo Monteiro!
* Switch to dpkg-source 3.0 (native) format
* apt-pkg/depcache.cc:
- remove Auto-Installed information from extended_states
together with the package itself (Closes: #572364)
* cmdline/apt-mark:
- don't crash if no arguments are given (Closes: #570962)
* debian/control:
- remove some years old and obsolete Replaces
- add automake/conf build-depends/conflicts as recommend by
the autotools-dev README (Closes: #572615)
* apt-pkg/contrib/mmap.{h,cc}:
- add char[] fallback for filesystems without shared writable
mmap() like JFFS2. Thanks to Marius Vollmer for writing
and to Loïc Minier for pointing to the patch! (Closes: #314334)
* doc/apt_preferences.5.xml:
- fix two typos and be more verbose in the novice warning.
Thanks to Osamu Aoki for pointing it out! (Closes: #567669)
- fix a=sid vs. n=sid typo, thanks Ansgar Burchardt!
- origin can be used to match a hostname (Closes: #352667)
- remove wrong pin-priority is optional remark (Closes: #574944)
* apt-pkg/deb/dpkgpm.cc:
- fix error message construction in OpenLog()
- if available store the Commandline in the history
* cmdline/apt-get.cc:
- add a --only-upgrade flag to install command (Closes: #572259)
- fix memory leaks in error conditions in DoSource()
- try version match in FindSrc first exact than fuzzy (LP: #551178)
* apt-pkg/contrib/cmndline.cc:
- save Commandline in Commandline::AsString for logging
* apt-pkg/deb/debversion.cc:
- consider absent of debian revision equivalent to 0 (Closes: #573592)
* doc/makefile, doc/*:
- generate subdirectories for building the manpages in on the fly
depending on the po files we have.
* apt-pkg/pkgcachegen.cc:
- merge versions correctly even if multiple different versions
with the same version number are available.
Thanks to Magnus Holmgren for the patch! (Closes: #351056)
* ftparchive/writer.cc:
- write LongDescriptions if they shouldn't be included in Packages
file into i18n/Translation-en by default.
* doc/po/de.po:
- correct a few typos in the german manpage translation.
Thanks to Chris Leick and Georg Koppen! (Closes: #574962)
* apt-pkg/contrib/strutl.cc:
- convert all toupper calls to tolower_ascii for a little speedup
* apt-pkg/contrib/strutl.cc:
- always escape '%' (LP: #130289) (Closes: #500560)
- unescape '%' sequence only if followed by 2 hex digit
- username/password are urlencoded in proxy string (RFC 3986)

Michael Vogt пре 16 година
родитељ
комит
b5cabd30cc
100 измењених фајлова са 7964 додато и 3002 уклоњено
  1. 12 9
      .bzrignore
  2. 113 0
      README.MultiArch
  3. 0 12
      README.arch
  4. 1 1
      apt-inst/deb/dpkgdb.cc
  5. 176 60
      apt-pkg/acquire-item.cc
  6. 19 5
      apt-pkg/acquire-item.h
  7. 15 9
      apt-pkg/acquire-method.cc
  8. 10 6
      apt-pkg/acquire-method.h
  9. 2 1
      apt-pkg/acquire-worker.h
  10. 81 29
      apt-pkg/acquire.cc
  11. 31 9
      apt-pkg/acquire.h
  12. 57 12
      apt-pkg/algorithms.cc
  13. 1 1
      apt-pkg/algorithms.h
  14. 43 1
      apt-pkg/aptconfiguration.cc
  15. 16 0
      apt-pkg/aptconfiguration.h
  16. 81 25
      apt-pkg/cachefile.cc
  17. 28 8
      apt-pkg/cachefile.h
  18. 54 0
      apt-pkg/cachefilter.cc
  19. 29 0
      apt-pkg/cachefilter.h
  20. 370 378
      apt-pkg/cacheiterators.h
  21. 511 0
      apt-pkg/cacheset.cc
  22. 389 0
      apt-pkg/cacheset.h
  23. 16 23
      apt-pkg/cdrom.cc
  24. 3 3
      apt-pkg/clean.cc
  25. 41 1
      apt-pkg/contrib/cmndline.cc
  26. 1 0
      apt-pkg/contrib/cmndline.h
  27. 45 0
      apt-pkg/contrib/configuration.cc
  28. 18 1
      apt-pkg/contrib/configuration.h
  29. 201 179
      apt-pkg/contrib/error.cc
  30. 263 29
      apt-pkg/contrib/error.h
  31. 146 18
      apt-pkg/contrib/fileutl.cc
  32. 18 10
      apt-pkg/contrib/fileutl.h
  33. 18 16
      apt-pkg/contrib/macros.h
  34. 82 23
      apt-pkg/contrib/mmap.cc
  35. 5 0
      apt-pkg/contrib/mmap.h
  36. 100 52
      apt-pkg/contrib/strutl.cc
  37. 11 17
      apt-pkg/contrib/strutl.h
  38. 62 0
      apt-pkg/contrib/weakptr.h
  39. 52 21
      apt-pkg/deb/debindexfile.cc
  40. 6 4
      apt-pkg/deb/debindexfile.h
  41. 204 56
      apt-pkg/deb/deblistparser.cc
  42. 13 9
      apt-pkg/deb/deblistparser.h
  43. 194 110
      apt-pkg/deb/debmetaindex.cc
  44. 16 12
      apt-pkg/deb/debmetaindex.h
  45. 1 1
      apt-pkg/deb/debrecords.cc
  46. 1 1
      apt-pkg/deb/debsrcrecords.h
  47. 9 3
      apt-pkg/deb/debsystem.cc
  48. 16 2
      apt-pkg/deb/debversion.cc
  49. 311 27
      apt-pkg/deb/dpkgpm.cc
  50. 21 1
      apt-pkg/deb/dpkgpm.h
  51. 499 135
      apt-pkg/depcache.cc
  52. 36 34
      apt-pkg/depcache.h
  53. 108 41
      apt-pkg/indexcopy.cc
  54. 9 0
      apt-pkg/indexcopy.h
  55. 6 2
      apt-pkg/indexfile.h
  56. 47 3
      apt-pkg/indexrecords.cc
  57. 6 0
      apt-pkg/indexrecords.h
  58. 8 2
      apt-pkg/init.cc
  59. 1 1
      apt-pkg/init.h
  60. 5 4
      apt-pkg/makefile
  61. 2 2
      apt-pkg/metaindex.h
  62. 89 6
      apt-pkg/orderlist.cc
  63. 34 9
      apt-pkg/packagemanager.cc
  64. 14 2
      apt-pkg/packagemanager.h
  65. 231 46
      apt-pkg/pkgcache.cc
  66. 422 91
      apt-pkg/pkgcache.h
  67. 460 139
      apt-pkg/pkgcachegen.cc
  68. 50 16
      apt-pkg/pkgcachegen.h
  69. 45 32
      apt-pkg/policy.cc
  70. 3 3
      apt-pkg/policy.h
  71. 56 40
      apt-pkg/sourcelist.cc
  72. 5 3
      apt-pkg/sourcelist.h
  73. 28 11
      apt-pkg/tagfile.cc
  74. 15 1
      apt-pkg/tagfile.h
  75. 54 12
      apt-pkg/versionmatch.cc
  76. 4 0
      apt-pkg/versionmatch.h
  77. 489 499
      cmdline/apt-cache.cc
  78. 7 9
      cmdline/apt-cdrom.cc
  79. 1 2
      cmdline/apt-extracttemplates.cc
  80. 542 480
      cmdline/apt-get.cc
  81. 6 1
      cmdline/apt-mark
  82. 29 0
      cmdline/apt-report-mirror-failure
  83. 6 0
      cmdline/makefile
  84. 5 1
      configure.in
  85. 2 1
      debian/apt-doc.docs
  86. 19 4
      debian/apt.conf.autoremove
  87. 1 0
      debian/apt.dirs
  88. 489 14
      debian/changelog
  89. 5 6
      debian/control
  90. 0 18
      debian/libapt-pkg-doc.doc-base.cache
  91. 37 81
      debian/rules
  92. 1 0
      debian/source/format
  93. 14 0
      doc/apt-cache.8.xml
  94. 33 7
      doc/apt-ftparchive.1.xml
  95. 14 21
      doc/apt-get.8.xml
  96. 1 6
      doc/apt-mark.8.xml
  97. 59 5
      doc/apt.conf.5.xml
  98. 22 9
      doc/apt.ent
  99. 32 18
      doc/apt_preferences.5.xml
  100. 0 0
      doc/cache.sgml

+ 12 - 9
.bzrignore

@@ -11,14 +11,17 @@ configure
 buildlib/config.sub
 buildlib/config.sub
 buildlib/config.guess
 buildlib/config.guess
 
 
+# abichecker related files/dir
+abicheck/apt_build.xml
+abicheck/apt_installed.xml
+abicheck/compat_reports/
+abicheck/descriptors_storage/
+abicheck/header_compile_errors/
+abicheck/test_results/
+abicheck/tests/
+
 # generated files in the progress to build all
 # generated files in the progress to build all
 # apt man pages and other documentation
 # apt man pages and other documentation
-doc/*.1
-doc/*.5
-doc/*.8
-doc/*/*.1
-doc/*/*.5
-doc/*/*.8
-doc/*/apt.ent
-doc/*/*.xml
-doc/*/*.sgml
+./doc/*/
+!./doc/examples/
+!./doc/po/

+ 113 - 0
README.MultiArch

@@ -0,0 +1,113 @@
+Before we start with this topic: Note that MultiArch is not yet ready for
+prime time and/or for the casual user. The implementation is so far widely
+untested and only useful for developers of packagemanagment tools which
+use APT and his friends and maintainers of (upcoming) MultiArch packages.
+This README is especially NOT written for the casual user and is NOT a
+usage guide - you have been warned. It is assumed that the reader has
+at least a bit of knowledge about APT internals, dependency relations
+and the MultiArch spec [0].
+
+Note also that the toolchain isn't ready yet, e.g. while you can simulate
+the installation of MultiArch packages they will more sooner than later
+cause enormous problems if really installed as dpkg can't handle MultiArch
+yet (no, --force-{overwrite,architecture} aren't good options here).
+Other parts of the big picture are missing and/or untested too.
+You have been warned!
+
+
+The implementation is focused on NOT breaking existing singleArch-only
+applications and/or systems as this is the current status-quo for all
+systems. Also, many systems don't need (or can't make use of) MultiArch,
+so APT will proceed in thinking SingleArch as long as it is not explicitly
+told to handle MultiArch:
+To activate MultiArch handling you need to specify architectures you
+want to be considered by APT with the config list APT::Architectures
+(Insert architectures in order of preference).
+APT will download Packages files for all these architectures in the
+update step. Exception: In the sourcelist is the optionfield used:
+deb [ arch=amd64,i386 ] http://example.org/ experimental main
+(This optionfield is a NOP in previous apt versions)
+
+Internally in APT a package is represented as a PkgIterator -
+before MultiArch this PkgIterator was architecture unaware,
+only VerIterators include the architecture they came from.
+This is/was a big problem as all versions in a package are
+considered for dependency resolution, so pinning will not work in all cases.
+
+The problem is solved by a conceptional change:
+A PkgIterator is now architecture aware, so the packages
+of foobar for amd64 and for i386 are now for apt internal totally
+different packages. That is a good thing for e.g. pinning, but
+sometimes you need the information that such packages are belonging together:
+All these foobar packages therefore form a Group accessible with GrpIterators.
+Note that the GrpIterator has the same name as all the packages in this group,
+so e.g. apt-cache pkgnames iterates over GrpIterator to get the package names:
+This is compatible to SingleArch as a Group consists only of a single package
+and also to MultiArch as a Group consists of possible many packages which
+all have the same name and are therefore out of interest for pkgnames.
+
+
+Caused by the paragraph "Dependencies involving Architecture: all packages"
+in the MultiArch spec we have a second major conceptional change
+which could even break existing applications, but we hope for the best…
+An Architecture: all package is internally split into pseudo packages
+for all MultiArch Architectures and additional a package with the
+architecture "all" with no dependencies which is a dependency of all
+these architecture depending packages. While the architecture depending
+packages are mainly used for dependency resolution (a package of arch A which
+depends on an arch all package assumes that the dependencies of this package
+are also from arch A. Packages also sometimes change from any to all or v.v.)
+the arch "all" package is used for scheduling download/installation of the
+underlying "real" package. Note that the architecture depending packages can
+be detected with Pseudo() while the "all" package reports exactly this arch
+as package architecture and as pseudo architecture of the versions of this pkg.
+Beware: All versions of a "real" architecture all package will be report "all"
+as their architecture if asked with Arch() regardless if they are the "all" or
+the architecture depending packages. If you want to know the architecture this
+pseudo package was created for call Arch(true). Also, while the spec say that
+arch:all packages are not allowed to have a MultiArch flag APT assigns a
+special value to them: MultiArch: all.
+
+
+As you might guess this arch:all handling has a few problems (but we think so
+far that the problems are minor compared to the problems we would have with
+other implementations.)
+APT doesn't know which pseudo packages of such an arch all package are
+"installed" (to satisfy dependencies), so APT will generate a Cache in which
+all these pseudo packages are installed (e.g. apt-cache policy will display
+them all as installed). Later in the DepCache step it will "remove"
+all pseudo packages whose dependencies are not satisfied.
+The expense is that if the package state is broken APT could come to the
+conclusion to "remove" too many pseudo packages, but in a stable environment
+APT should never end up in a broken system state…
+
+
+Given all these internal changes it is quite interesting that the actual
+implementation of MultiArch is trivial: Some implicit dependencies and a few
+more provides are all changes needed to get it working. Especially noteworthy
+is that it wasn't needed to change the resolver in any way and other parts only
+need to be told about ignoring pseudo packages or using GrpIterator instead of
+PkgIterator, so chances are good that libapt-applications will proceed to work
+without or at least only require minor changes, but your mileage may vary…
+
+
+Known Issues and/or noteworthy stuff:
+* The implementation is mostly untested, so it is very likely that APT will
+  eat your kids if you aren't as lucky as the author of these patches.
+* the (install)size of a pseudo package is always NULL - if you want to know
+  the (install)size you need to get the info from the arch "all" package.
+* It is maybe confusing, but the arch "all" package does have the same versions
+  and in general roughly the same information with one subtil difference:
+  It doesn't have any dependency, regardless of the type. The pseudo packages
+  depend on this package.
+* apt-cache policy foobar on installed architecture all package foobar will
+  report all architecture depending packages as installed. Displaying here the
+  correct information would require to build the complete DepCache…
+* [BUG] An installed package which changes the architecture from any to all
+  (and v.v.) shows up in the NEW packages section instead of UPGRADE.
+* [TODO] Investigate the DepCache pseudo-package killer heuristic:
+  e.g. add more safety guards…
+* [FIXME] a few corner cases/missing features marked as FIXME in the code
+
+
+[0] https://wiki.ubuntu.com/MultiarchSpec

+ 0 - 12
README.arch

@@ -1,12 +0,0 @@
-
-You can build apt from arch, but this needs the following additional
-packages (in addtion to the usual build-depends):
-autoconf automake xmlto perlsgml sgml2x sgmlspl docbook doxygen
-
-then run:
-
-$ debian/rules arch-build
-
-that will build packages in the "debian/arch-build" directory. It will
-honor "DEB_BUILD_PROG_OPTS" as options that are passed to debuild (e.g. -S 
-may be usefull).

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

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

+ 176 - 60
apt-pkg/acquire-item.cc

@@ -33,6 +33,7 @@
 #include <string>
 #include <string>
 #include <sstream>
 #include <sstream>
 #include <stdio.h>
 #include <stdio.h>
+#include <ctime>
 									/*}}}*/
 									/*}}}*/
 
 
 using namespace std;
 using namespace std;
@@ -64,6 +65,7 @@ void pkgAcquire::Item::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
 {
 {
    Status = StatIdle;
    Status = StatIdle;
    ErrorText = LookupTag(Message,"Message");
    ErrorText = LookupTag(Message,"Message");
+   UsedMirror =  LookupTag(Message,"UsedMirror");
    if (QueueCounter <= 1)
    if (QueueCounter <= 1)
    {
    {
       /* This indicates that the file is not available right now but might
       /* This indicates that the file is not available right now but might
@@ -76,10 +78,17 @@ void pkgAcquire::Item::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
 	 Dequeue();
 	 Dequeue();
 	 return;
 	 return;
       }
       }
-      
+
       Status = StatError;
       Status = StatError;
       Dequeue();
       Dequeue();
    }   
    }   
+
+   // report mirror failure back to LP if we actually use a mirror
+   string FailReason = LookupTag(Message, "FailReason");
+   if(FailReason.size() != 0)
+      ReportMirrorFailure(FailReason);
+   else
+      ReportMirrorFailure(ErrorText);
 }
 }
 									/*}}}*/
 									/*}}}*/
 // Acquire::Item::Start - Item has begun to download			/*{{{*/
 // Acquire::Item::Start - Item has begun to download			/*{{{*/
@@ -101,7 +110,7 @@ void pkgAcquire::Item::Done(string Message,unsigned long Size,string Hash,
 {
 {
    // We just downloaded something..
    // We just downloaded something..
    string FileName = LookupTag(Message,"Filename");
    string FileName = LookupTag(Message,"Filename");
-   // we only inform the Log class if it was actually not a local thing
+   UsedMirror =  LookupTag(Message,"UsedMirror");
    if (Complete == false && !Local && FileName == DestFile)
    if (Complete == false && !Local && FileName == DestFile)
    {
    {
       if (Owner->Log != 0)
       if (Owner->Log != 0)
@@ -110,7 +119,6 @@ void pkgAcquire::Item::Done(string Message,unsigned long Size,string Hash,
 
 
    if (FileSize == 0)
    if (FileSize == 0)
       FileSize= Size;
       FileSize= Size;
-   
    Status = StatDone;
    Status = StatDone;
    ErrorText = string();
    ErrorText = string();
    Owner->Dequeue(this);
    Owner->Dequeue(this);
@@ -132,6 +140,50 @@ void pkgAcquire::Item::Rename(string From,string To)
    }   
    }   
 }
 }
 									/*}}}*/
 									/*}}}*/
+// Acquire::Item::ReportMirrorFailure					/*{{{*/
+// ---------------------------------------------------------------------
+void pkgAcquire::Item::ReportMirrorFailure(string FailCode)
+{
+   // we only act if a mirror was used at all
+   if(UsedMirror.empty())
+      return;
+#if 0
+   std::cerr << "\nReportMirrorFailure: " 
+	     << UsedMirror
+	     << " Uri: " << DescURI()
+	     << " FailCode: " 
+	     << FailCode << std::endl;
+#endif
+   const char *Args[40];
+   unsigned int i = 0;
+   string report = _config->Find("Methods::Mirror::ProblemReporting", 
+				 "/usr/lib/apt/apt-report-mirror-failure");
+   if(!FileExists(report))
+      return;
+   Args[i++] = report.c_str();
+   Args[i++] = UsedMirror.c_str();
+   Args[i++] = DescURI().c_str();
+   Args[i++] = FailCode.c_str();
+   Args[i++] = NULL;
+   pid_t pid = ExecFork();
+   if(pid < 0) 
+   {
+      _error->Error("ReportMirrorFailure Fork failed");
+      return;
+   }
+   else if(pid == 0) 
+   {
+      execvp(Args[0], (char**)Args);
+      std::cerr << "Could not exec " << Args[0] << std::endl;
+      _exit(100);
+   }
+   if(!ExecWait(pid, "report-mirror-failure")) 
+   {
+      _error->Warning("Couldn't report problem to '%s'",
+		      _config->Find("Methods::Mirror::ProblemReporting").c_str());
+   }
+}
+									/*}}}*/
 // AcqDiffIndex::AcqDiffIndex - Constructor				/*{{{*/
 // AcqDiffIndex::AcqDiffIndex - Constructor				/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /* Get the DiffIndex file first and see if there are patches availabe 
 /* Get the DiffIndex file first and see if there are patches availabe 
@@ -228,7 +280,7 @@ bool pkgAcqDiffIndex::ParseDiffIndex(string IndexDiffFile)		/*{{{*/
       ss >> ServerSha1 >> size;
       ss >> ServerSha1 >> size;
       unsigned long const ServerSize = atol(size.c_str());
       unsigned long const ServerSize = atol(size.c_str());
 
 
-      FileFd fd(CurrentPackagesFile, FileFd::ReadOnly);
+      FileFd fd(CurrentPackagesFile, FileFd::ReadOnlyGzip);
       SHA1Summation SHA1;
       SHA1Summation SHA1;
       SHA1.AddFD(fd.Fd(), fd.Size());
       SHA1.AddFD(fd.Fd(), fd.Size());
       string const local_sha1 = SHA1.Result();
       string const local_sha1 = SHA1.Result();
@@ -459,7 +511,7 @@ bool pkgAcqIndexDiffs::QueueNextDiff()					/*{{{*/
    string FinalFile = _config->FindDir("Dir::State::lists");
    string FinalFile = _config->FindDir("Dir::State::lists");
    FinalFile += URItoFileName(RealURI);
    FinalFile += URItoFileName(RealURI);
 
 
-   FileFd fd(FinalFile, FileFd::ReadOnly);
+   FileFd fd(FinalFile, FileFd::ReadOnlyGzip);
    SHA1Summation SHA1;
    SHA1Summation SHA1;
    SHA1.AddFD(fd.Fd(), fd.Size());
    SHA1.AddFD(fd.Fd(), fd.Size());
    string local_sha1 = string(SHA1.Result());
    string local_sha1 = string(SHA1.Result());
@@ -620,11 +672,12 @@ string pkgAcqIndex::Custom600Headers()
 {
 {
    string Final = _config->FindDir("Dir::State::lists");
    string Final = _config->FindDir("Dir::State::lists");
    Final += URItoFileName(RealURI);
    Final += URItoFileName(RealURI);
+   if (_config->FindB("Acquire::GzipIndexes",false))
+      Final += ".gz";
    
    
    struct stat Buf;
    struct stat Buf;
    if (stat(Final.c_str(),&Buf) != 0)
    if (stat(Final.c_str(),&Buf) != 0)
       return "\nIndex-File: true";
       return "\nIndex-File: true";
-   
    return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
    return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
 }
 }
 									/*}}}*/
 									/*}}}*/
@@ -692,6 +745,7 @@ void pkgAcqIndex::Done(string Message,unsigned long Size,string Hash,
          Status = StatAuthError;
          Status = StatAuthError;
          ErrorText = _("Hash Sum mismatch");
          ErrorText = _("Hash Sum mismatch");
          Rename(DestFile,DestFile + ".FAILED");
          Rename(DestFile,DestFile + ".FAILED");
+	 ReportMirrorFailure("HashChecksumFailure");
          return;
          return;
       }
       }
       // Done, move it into position
       // Done, move it into position
@@ -737,18 +791,36 @@ void pkgAcqIndex::Done(string Message,unsigned long Size,string Hash,
       ErrorText = "Method gave a blank filename";
       ErrorText = "Method gave a blank filename";
    }
    }
    
    
+   string compExt = flExtension(flNotDir(URI(Desc.URI).Path));
+
    // The files timestamp matches
    // The files timestamp matches
-   if (StringToBool(LookupTag(Message,"IMS-Hit"),false) == true)
+   if (StringToBool(LookupTag(Message,"IMS-Hit"),false) == true) {
+       if (_config->FindB("Acquire::GzipIndexes",false) && compExt == "gz")
+	  // Update DestFile for .gz suffix so that the clean operation keeps it
+	  DestFile += ".gz";
       return;
       return;
+    }
 
 
    if (FileName == DestFile)
    if (FileName == DestFile)
       Erase = true;
       Erase = true;
    else
    else
       Local = true;
       Local = true;
    
    
-   string compExt = flExtension(flNotDir(URI(Desc.URI).Path));
    string decompProg;
    string decompProg;
 
 
+   // If we enable compressed indexes and already have gzip, keep it
+   if (_config->FindB("Acquire::GzipIndexes",false) && compExt == "gz" && !Local) {
+      string FinalFile = _config->FindDir("Dir::State::lists");
+      FinalFile += URItoFileName(RealURI) + ".gz";
+      Rename(DestFile,FinalFile);
+      chmod(FinalFile.c_str(),0644);
+      
+      // Update DestFile for .gz suffix so that the clean operation keeps it
+      DestFile = _config->FindDir("Dir::State::lists") + "partial/";
+      DestFile += URItoFileName(RealURI) + ".gz";
+      return;
+    }
+
    // get the binary name for your used compression type
    // get the binary name for your used compression type
    decompProg = _config->Find(string("Acquire::CompressionTypes::").append(compExt),"");
    decompProg = _config->Find(string("Acquire::CompressionTypes::").append(compExt),"");
    if(decompProg.empty() == false);
    if(decompProg.empty() == false);
@@ -778,6 +850,19 @@ pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire *Owner,
 			    string URI,string URIDesc,string ShortDesc) 
 			    string URI,string URIDesc,string ShortDesc) 
   : pkgAcqIndex(Owner, URI, URIDesc, ShortDesc, HashString(), "")
   : pkgAcqIndex(Owner, URI, URIDesc, ShortDesc, HashString(), "")
 {
 {
+}
+									/*}}}*/
+// AcqIndexTrans::Custom600Headers - Insert custom request headers	/*{{{*/
+// ---------------------------------------------------------------------
+string pkgAcqIndexTrans::Custom600Headers()
+{
+   string Final = _config->FindDir("Dir::State::lists");
+   Final += URItoFileName(RealURI);
+
+   struct stat Buf;
+   if (stat(Final.c_str(),&Buf) != 0)
+      return "\nFail-Ignore: true";
+   return "\nFail-Ignore: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
 }
 }
 									/*}}}*/
 									/*}}}*/
 // AcqIndexTrans::Failed - Silence failure messages for missing files	/*{{{*/
 // AcqIndexTrans::Failed - Silence failure messages for missing files	/*{{{*/
@@ -882,8 +967,9 @@ void pkgAcqMetaSig::Done(string Message,unsigned long Size,string MD5,
       Rename(LastGoodSig, DestFile);
       Rename(LastGoodSig, DestFile);
 
 
    // queue a pkgAcqMetaIndex to be verified against the sig we just retrieved
    // queue a pkgAcqMetaIndex to be verified against the sig we just retrieved
-   new pkgAcqMetaIndex(Owner, MetaIndexURI, MetaIndexURIDesc, MetaIndexShortDesc,
-		       DestFile, IndexTargets, MetaIndexParser);
+   new pkgAcqMetaIndex(Owner, MetaIndexURI, MetaIndexURIDesc, 
+		       MetaIndexShortDesc,  DestFile, IndexTargets, 
+		       MetaIndexParser);
 
 
 }
 }
 									/*}}}*/
 									/*}}}*/
@@ -896,7 +982,7 @@ void pkgAcqMetaSig::Failed(string Message,pkgAcquire::MethodConfig *Cnf)/*{{{*/
    {
    {
       Item::Failed(Message,Cnf);
       Item::Failed(Message,Cnf);
       // move the sigfile back on transient network failures 
       // move the sigfile back on transient network failures 
-      if(FileExists(DestFile))
+      if(FileExists(LastGoodSig))
  	 Rename(LastGoodSig,Final);
  	 Rename(LastGoodSig,Final);
 
 
       // set the status back to , Item::Failed likes to reset it
       // set the status back to , Item::Failed likes to reset it
@@ -971,6 +1057,15 @@ void pkgAcqMetaIndex::Done(string Message,unsigned long Size,string Hash,	/*{{{*
    if (AuthPass == true)
    if (AuthPass == true)
    {
    {
       AuthDone(Message);
       AuthDone(Message);
+
+      // all cool, move Release file into place
+      Complete = true;
+
+      string FinalFile = _config->FindDir("Dir::State::lists");
+      FinalFile += URItoFileName(RealURI);
+      Rename(DestFile,FinalFile);
+      chmod(FinalFile.c_str(),0644);
+      DestFile = FinalFile;
    }
    }
    else
    else
    {
    {
@@ -1022,22 +1117,15 @@ void pkgAcqMetaIndex::RetrievalDone(string Message)			/*{{{*/
       return;
       return;
    }
    }
 
 
-   // see if the download was a IMSHit
+   // make sure to verify against the right file on I-M-S hit
    IMSHit = StringToBool(LookupTag(Message,"IMS-Hit"),false);
    IMSHit = StringToBool(LookupTag(Message,"IMS-Hit"),false);
+   if(IMSHit)
+   {
+      string FinalFile = _config->FindDir("Dir::State::lists");
+      FinalFile += URItoFileName(RealURI);
+      DestFile = FinalFile;
+   }
    Complete = true;
    Complete = true;
-
-   string FinalFile = _config->FindDir("Dir::State::lists");
-   FinalFile += URItoFileName(RealURI);
-
-   // If we get a IMS hit we can remove the empty file in partial
-   // othersie we move the file in place
-   if (IMSHit)
-      unlink(DestFile.c_str());
-   else
-      Rename(DestFile,FinalFile);
-
-   chmod(FinalFile.c_str(),0644);
-   DestFile = FinalFile;
 }
 }
 									/*}}}*/
 									/*}}}*/
 void pkgAcqMetaIndex::AuthDone(string Message)				/*{{{*/
 void pkgAcqMetaIndex::AuthDone(string Message)				/*{{{*/
@@ -1067,7 +1155,6 @@ void pkgAcqMetaIndex::AuthDone(string Message)				/*{{{*/
    QueueIndexes(true);
    QueueIndexes(true);
 
 
    // Done, move signature file into position
    // Done, move signature file into position
-
    string VerifiedSigFile = _config->FindDir("Dir::State::lists") +
    string VerifiedSigFile = _config->FindDir("Dir::State::lists") +
       URItoFileName(RealURI) + ".gpg";
       URItoFileName(RealURI) + ".gpg";
    Rename(SigFile,VerifiedSigFile);
    Rename(SigFile,VerifiedSigFile);
@@ -1105,13 +1192,16 @@ void pkgAcqMetaIndex::QueueIndexes(bool verify)				/*{{{*/
             return;
             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,
 	 new pkgAcqDiffIndex(Owner, (*Target)->URI, (*Target)->Description,
 			     (*Target)->ShortDesc, ExpectedIndexHash);
 			     (*Target)->ShortDesc, ExpectedIndexHash);
-      else 
+      else
 	 new pkgAcqIndex(Owner, (*Target)->URI, (*Target)->Description,
 	 new pkgAcqIndex(Owner, (*Target)->URI, (*Target)->Description,
 			    (*Target)->ShortDesc, ExpectedIndexHash);
 			    (*Target)->ShortDesc, ExpectedIndexHash);
    }
    }
@@ -1177,6 +1267,17 @@ bool pkgAcqMetaIndex::VerifyVendor(string Message)			/*{{{*/
       Transformed = "";
       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)) 
    if (_config->FindB("Debug::pkgAcquire::Auth", false)) 
    {
    {
       std::cerr << "Got Codename: " << MetaIndexParser->GetDist() << std::endl;
       std::cerr << "Got Codename: " << MetaIndexParser->GetDist() << std::endl;
@@ -1194,7 +1295,7 @@ bool pkgAcqMetaIndex::VerifyVendor(string Message)			/*{{{*/
 //       return false;
 //       return false;
       if (!Transformed.empty())
       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(),
                          Desc.Description.c_str(),
                          Transformed.c_str(),
                          Transformed.c_str(),
                          MetaIndexParser->GetDist().c_str());
                          MetaIndexParser->GetDist().c_str());
@@ -1211,30 +1312,30 @@ void pkgAcqMetaIndex::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
 {
 {
    if (AuthPass == true)
    if (AuthPass == true)
    {
    {
-      // if we fail the authentication but got the file via a IMS-Hit 
-      // this means that the file wasn't downloaded and that it might be
-      // just stale (server problem, proxy etc). we delete what we have
-      // queue it again without i-m-s 
-      // alternatively we could just unlink the file and let the user try again
-      if (IMSHit)
+      // gpgv method failed, if we have a good signature 
+      string LastGoodSigFile = _config->FindDir("Dir::State::lists") +
+	 "partial/" + URItoFileName(RealURI) + ".gpg.reverify";
+      if(FileExists(LastGoodSigFile))
       {
       {
-	 Complete = false;
-	 Local = false;
-	 AuthPass = false;
-	 unlink(DestFile.c_str());
-
-	 DestFile = _config->FindDir("Dir::State::lists") + "partial/";
-	 DestFile += URItoFileName(RealURI);
-	 Desc.URI = RealURI;
-	 QueueURI(Desc);
+	 string VerifiedSigFile = _config->FindDir("Dir::State::lists") +
+	    URItoFileName(RealURI) + ".gpg";
+	 Rename(LastGoodSigFile,VerifiedSigFile);
+	 Status = StatTransientNetworkError;
+	 _error->Warning(_("A error occurred during the signature "
+			   "verification. The repository is not updated "
+			   "and the previous index files will be used."
+			   "GPG error: %s: %s\n"),
+			 Desc.Description.c_str(),
+			 LookupTag(Message,"Message").c_str());
+	 RunScripts("APT::Update::Auth-Failure");
 	 return;
 	 return;
+      } else {
+	 _error->Warning(_("GPG error: %s: %s"),
+			 Desc.Description.c_str(),
+			 LookupTag(Message,"Message").c_str());
       }
       }
-
       // gpgv method failed 
       // gpgv method failed 
-      _error->Warning("GPG error: %s: %s",
-                      Desc.Description.c_str(),
-                      LookupTag(Message,"Message").c_str());
-
+      ReportMirrorFailure("GPGFailure");
    }
    }
 
 
    // No Release file was present, or verification failed, so fall
    // No Release file was present, or verification failed, so fall
@@ -1327,7 +1428,8 @@ pkgAcqArchive::pkgAcqArchive(pkgAcquire *Owner,pkgSourceList *Sources,
    the archive is already available in the cache and stashs the MD5 for
    the archive is already available in the cache and stashs the MD5 for
    checking later. */
    checking later. */
 bool pkgAcqArchive::QueueNext()
 bool pkgAcqArchive::QueueNext()
-{   
+{
+   string const ForceHash = _config->Find("Acquire::ForceHash");
    for (; Vf.end() == false; Vf++)
    for (; Vf.end() == false; Vf++)
    {
    {
       // Ignore not source sources
       // Ignore not source sources
@@ -1350,12 +1452,25 @@ bool pkgAcqArchive::QueueNext()
 	 return false;
 	 return false;
       
       
       string PkgFile = Parse.FileName();
       string PkgFile = Parse.FileName();
-      if(Parse.SHA256Hash() != "")
-	 ExpectedHash = HashString("SHA256", Parse.SHA256Hash());
-      else if (Parse.SHA1Hash() != "")
-	 ExpectedHash = HashString("SHA1", Parse.SHA1Hash());
-      else 
-	 ExpectedHash = HashString("MD5Sum", Parse.MD5Hash());
+      if (ForceHash.empty() == false)
+      {
+	 if(stringcasecmp(ForceHash, "sha256") == 0)
+	    ExpectedHash = HashString("SHA256", Parse.SHA256Hash());
+	 else if (stringcasecmp(ForceHash, "sha1") == 0)
+	    ExpectedHash = HashString("SHA1", Parse.SHA1Hash());
+	 else
+	    ExpectedHash = HashString("MD5Sum", Parse.MD5Hash());
+      }
+      else
+      {
+	 string Hash;
+	 if ((Hash = Parse.SHA256Hash()).empty() == false)
+	    ExpectedHash = HashString("SHA256", Hash);
+	 else if ((Hash = Parse.SHA1Hash()).empty() == false)
+	    ExpectedHash = HashString("SHA1", Hash);
+	 else
+	    ExpectedHash = HashString("MD5Sum", Parse.MD5Hash());
+      }
       if (PkgFile.empty() == true)
       if (PkgFile.empty() == true)
 	 return _error->Error(_("The package index files are corrupted. No Filename: "
 	 return _error->Error(_("The package index files are corrupted. No Filename: "
 			      "field for package %s."),
 			      "field for package %s."),
@@ -1595,7 +1710,7 @@ void pkgAcqFile::Done(string Message,unsigned long Size,string CalcHash,
    if(!ExpectedHash.empty() && ExpectedHash.toStr() != CalcHash)
    if(!ExpectedHash.empty() && ExpectedHash.toStr() != CalcHash)
    {
    {
       Status = StatError;
       Status = StatError;
-      ErrorText = "Hash Sum mismatch";
+      ErrorText = _("Hash Sum mismatch");
       Rename(DestFile,DestFile + ".FAILED");
       Rename(DestFile,DestFile + ".FAILED");
       return;
       return;
    }
    }
@@ -1671,5 +1786,6 @@ string pkgAcqFile::Custom600Headers()
 {
 {
    if (IsIndexFile)
    if (IsIndexFile)
       return "\nIndex-File: true";
       return "\nIndex-File: true";
+   return "";
 }
 }
 									/*}}}*/
 									/*}}}*/

+ 19 - 5
apt-pkg/acquire-item.h

@@ -27,6 +27,7 @@
 #include <apt-pkg/pkgrecords.h>
 #include <apt-pkg/pkgrecords.h>
 #include <apt-pkg/indexrecords.h>
 #include <apt-pkg/indexrecords.h>
 #include <apt-pkg/hashes.h>
 #include <apt-pkg/hashes.h>
+#include <apt-pkg/weakptr.h>
 
 
 /** \addtogroup acquire
 /** \addtogroup acquire
  *  @{
  *  @{
@@ -46,7 +47,7 @@
  *
  *
  *  \see pkgAcquire
  *  \see pkgAcquire
  */
  */
-class pkgAcquire::Item
+class pkgAcquire::Item : public WeakPointable
 {  
 {  
    protected:
    protected:
    
    
@@ -111,10 +112,10 @@ class pkgAcquire::Item
    string ErrorText;
    string ErrorText;
 
 
    /** \brief The size of the object to fetch. */
    /** \brief The size of the object to fetch. */
-   unsigned long FileSize;
+   unsigned long long FileSize;
 
 
    /** \brief How much of the object was already fetched. */
    /** \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
    /** \brief If not \b NULL, contains the name of a subprocess that
     *  is operating on this object (for instance, "gzip" or "gpgv").
     *  is operating on this object (for instance, "gzip" or "gpgv").
@@ -142,6 +143,7 @@ class pkgAcquire::Item
     *  download progress indicator's overall statistics.
     *  download progress indicator's overall statistics.
     */
     */
    bool Local;
    bool Local;
+   string UsedMirror;
 
 
    /** \brief The number of fetch queues into which this item has been
    /** \brief The number of fetch queues into which this item has been
     *  inserted.
     *  inserted.
@@ -242,6 +244,17 @@ class pkgAcquire::Item
 
 
    /** \return \b true if this object is being fetched from a trusted source. */
    /** \return \b true if this object is being fetched from a trusted source. */
    virtual bool IsTrusted() {return false;};
    virtual bool IsTrusted() {return false;};
+   
+   // report mirror problems
+   /** \brief Report mirror problem
+    * 
+    *  This allows reporting mirror failures back to a centralized
+    *  server. The apt-report-mirror-failure script is called for this
+    * 
+    *  \param FailCode A short failure string that is send
+    */
+   void ReportMirrorFailure(string FailCode);
+
 
 
    /** \brief Initialize an item.
    /** \brief Initialize an item.
     *
     *
@@ -550,7 +563,8 @@ class pkgAcqIndex : public pkgAcquire::Item
     *  fallback is ".gz" or none.
     *  fallback is ".gz" or none.
     */
     */
    pkgAcqIndex(pkgAcquire *Owner,string URI,string URIDesc,
    pkgAcqIndex(pkgAcquire *Owner,string URI,string URIDesc,
-	       string ShortDesc, HashString ExpectedHash, string compressExt="");
+	       string ShortDesc, HashString ExpectedHash, 
+	       string compressExt="");
 };
 };
 									/*}}}*/
 									/*}}}*/
 /** \brief An acquire item that is responsible for fetching a		{{{
 /** \brief An acquire item that is responsible for fetching a		{{{
@@ -565,6 +579,7 @@ class pkgAcqIndexTrans : public pkgAcqIndex
    public:
    public:
   
   
    virtual void Failed(string Message,pkgAcquire::MethodConfig *Cnf);
    virtual void Failed(string Message,pkgAcquire::MethodConfig *Cnf);
+   virtual string Custom600Headers();
 
 
    /** \brief Create a pkgAcqIndexTrans.
    /** \brief Create a pkgAcqIndexTrans.
     *
     *
@@ -613,7 +628,6 @@ class pkgAcqMetaSig : public pkgAcquire::Item
    /** \brief The last good signature file */
    /** \brief The last good signature file */
    string LastGoodSig;
    string LastGoodSig;
 
 
-
    /** \brief The fetch request that is currently being processed. */
    /** \brief The fetch request that is currently being processed. */
    pkgAcquire::ItemDesc Desc;
    pkgAcquire::ItemDesc Desc;
 
 

+ 15 - 9
apt-pkg/acquire-method.cc

@@ -96,12 +96,11 @@ void pkgAcqMethod::Fail(string Err,bool Transient)
    }
    }
    
    
    char S[1024];
    char S[1024];
+   char *End = S;
    if (Queue != 0)
    if (Queue != 0)
    {
    {
-      snprintf(S,sizeof(S)-50,"400 URI Failure\nURI: %s\n"
-	       "Message: %s %s\n",Queue->Uri.c_str(),Err.c_str(),
-	       FailExtra.c_str());
-
+      End += snprintf(S,sizeof(S)-50,"400 URI Failure\nURI: %s\n"
+		      "Message: %s %s\n",Queue->Uri.c_str(), Err.c_str(), IP.c_str());
       // Dequeue
       // Dequeue
       FetchItem *Tmp = Queue;
       FetchItem *Tmp = Queue;
       Queue = Queue->Next;
       Queue = Queue->Next;
@@ -110,10 +109,14 @@ void pkgAcqMethod::Fail(string Err,bool Transient)
 	 QueueBack = Queue;
 	 QueueBack = Queue;
    }
    }
    else
    else
-      snprintf(S,sizeof(S)-50,"400 URI Failure\nURI: <UNKNOWN>\n"
-	       "Message: %s %s\n",Err.c_str(),
-	       FailExtra.c_str());
-      
+   {
+      End += snprintf(S,sizeof(S)-50,"400 URI Failure\nURI: <UNKNOWN>\n"
+		      "Message: %s\n",Err.c_str());
+   }
+   if(FailReason.empty() == false)
+      End += snprintf(End,sizeof(S)-50 - (End - S),"FailReason: %s\n",FailReason.c_str());
+   if (UsedMirror.empty() == false)
+      End += snprintf(End,sizeof(S)-50 - (End - S),"UsedMirror: %s\n",UsedMirror.c_str());
    // Set the transient flag 
    // Set the transient flag 
    if (Transient == true)
    if (Transient == true)
       strcat(S,"Transient-Failure: true\n\n");
       strcat(S,"Transient-Failure: true\n\n");
@@ -184,6 +187,8 @@ void pkgAcqMethod::URIDone(FetchResult &Res, FetchResult *Alt)
       End += snprintf(End,sizeof(S)-50 - (End - S),"SHA1-Hash: %s\n",Res.SHA1Sum.c_str());
       End += snprintf(End,sizeof(S)-50 - (End - S),"SHA1-Hash: %s\n",Res.SHA1Sum.c_str());
    if (Res.SHA256Sum.empty() == false)
    if (Res.SHA256Sum.empty() == false)
       End += snprintf(End,sizeof(S)-50 - (End - S),"SHA256-Hash: %s\n",Res.SHA256Sum.c_str());
       End += snprintf(End,sizeof(S)-50 - (End - S),"SHA256-Hash: %s\n",Res.SHA256Sum.c_str());
+   if (UsedMirror.empty() == false)
+      End += snprintf(End,sizeof(S)-50 - (End - S),"UsedMirror: %s\n",UsedMirror.c_str());
    if (Res.GPGVOutput.size() > 0)
    if (Res.GPGVOutput.size() > 0)
       End += snprintf(End,sizeof(S)-50 - (End - S),"GPGVOutput:\n");     
       End += snprintf(End,sizeof(S)-50 - (End - S),"GPGVOutput:\n");     
    for (vector<string>::iterator I = Res.GPGVOutput.begin();
    for (vector<string>::iterator I = Res.GPGVOutput.begin();
@@ -373,9 +378,10 @@ int pkgAcqMethod::Run(bool Single)
 	    
 	    
 	    Tmp->Uri = LookupTag(Message,"URI");
 	    Tmp->Uri = LookupTag(Message,"URI");
 	    Tmp->DestFile = LookupTag(Message,"FileName");
 	    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->LastModified = 0;
 	    Tmp->IndexFile = StringToBool(LookupTag(Message,"Index-File"),false);
 	    Tmp->IndexFile = StringToBool(LookupTag(Message,"Index-File"),false);
+	    Tmp->FailIgnore = StringToBool(LookupTag(Message,"Fail-Ignore"),false);
 	    Tmp->Next = 0;
 	    Tmp->Next = 0;
 	    
 	    
 	    // Append it to the list
 	    // Append it to the list

+ 10 - 6
apt-pkg/acquire-method.h

@@ -37,6 +37,7 @@ class pkgAcqMethod
       string DestFile;
       string DestFile;
       time_t LastModified;
       time_t LastModified;
       bool IndexFile;
       bool IndexFile;
+      bool FailIgnore;
    };
    };
    
    
    struct FetchResult
    struct FetchResult
@@ -59,7 +60,9 @@ class pkgAcqMethod
    vector<string> Messages;
    vector<string> Messages;
    FetchItem *Queue;
    FetchItem *Queue;
    FetchItem *QueueBack;
    FetchItem *QueueBack;
-   string FailExtra;
+   string FailReason;
+   string UsedMirror;
+   string IP;
    
    
    // Handlers for messages
    // Handlers for messages
    virtual bool Configuration(string Message);
    virtual bool Configuration(string Message);
@@ -68,14 +71,14 @@ class pkgAcqMethod
    // Outgoing messages
    // Outgoing messages
    void Fail(bool Transient = false);
    void Fail(bool Transient = false);
    inline void Fail(const char *Why, bool Transient = false) {Fail(string(Why),Transient);};
    inline void Fail(const char *Why, bool Transient = false) {Fail(string(Why),Transient);};
-   void Fail(string Why, bool Transient = false);
-   void URIStart(FetchResult &Res);
-   void URIDone(FetchResult &Res,FetchResult *Alt = 0);
+   virtual void Fail(string Why, bool Transient = false);
+   virtual void URIStart(FetchResult &Res);
+   virtual void URIDone(FetchResult &Res,FetchResult *Alt = 0);
+
    bool MediaFail(string Required,string Drive);
    bool MediaFail(string Required,string Drive);
    virtual void Exit() {};
    virtual void Exit() {};
 
 
    public:
    public:
-
    enum CnfFlags {SingleInstance = (1<<0),
    enum CnfFlags {SingleInstance = (1<<0),
                   Pipeline = (1<<1), SendConfig = (1<<2),
                   Pipeline = (1<<1), SendConfig = (1<<2),
                   LocalOnly = (1<<3), NeedsCleanup = (1<<4), 
                   LocalOnly = (1<<3), NeedsCleanup = (1<<4), 
@@ -87,7 +90,8 @@ class pkgAcqMethod
    void Redirect(const string &NewURI);
    void Redirect(const string &NewURI);
  
  
    int Run(bool Single = false);
    int Run(bool Single = false);
-   inline void SetFailExtraMsg(string Msg) {FailExtra = Msg;};
+   inline void SetFailReason(string Msg) {FailReason = Msg;};
+   inline void SetIP(string aIP) {IP = aIP;};
    
    
    pkgAcqMethod(const char *Ver,unsigned long Flags = 0);
    pkgAcqMethod(const char *Ver,unsigned long Flags = 0);
    virtual ~pkgAcqMethod() {};
    virtual ~pkgAcqMethod() {};

+ 2 - 1
apt-pkg/acquire-worker.h

@@ -20,6 +20,7 @@
 #define PKGLIB_ACQUIRE_WORKER_H
 #define PKGLIB_ACQUIRE_WORKER_H
 
 
 #include <apt-pkg/acquire.h>
 #include <apt-pkg/acquire.h>
+#include <apt-pkg/weakptr.h>
 
 
 
 
 /** \brief A fetch subprocess.
 /** \brief A fetch subprocess.
@@ -41,7 +42,7 @@
  *
  *
  *  \sa pkgAcqMethod, pkgAcquire::Item, pkgAcquire
  *  \sa pkgAcqMethod, pkgAcquire::Item, pkgAcquire
  */
  */
-class pkgAcquire::Worker
+class pkgAcquire::Worker : public WeakPointable
 {
 {
    friend class pkgAcquire;
    friend class pkgAcquire;
    
    

+ 81 - 29
apt-pkg/acquire.cc

@@ -19,6 +19,7 @@
 #include <apt-pkg/configuration.h>
 #include <apt-pkg/configuration.h>
 #include <apt-pkg/error.h>
 #include <apt-pkg/error.h>
 #include <apt-pkg/strutl.h>
 #include <apt-pkg/strutl.h>
+#include <apt-pkg/fileutl.h>
 
 
 #include <apti18n.h>
 #include <apti18n.h>
 
 
@@ -29,7 +30,6 @@
 #include <dirent.h>
 #include <dirent.h>
 #include <sys/time.h>
 #include <sys/time.h>
 #include <errno.h>
 #include <errno.h>
-#include <sys/stat.h>
 									/*}}}*/
 									/*}}}*/
 
 
 using namespace std;
 using namespace std;
@@ -37,32 +37,81 @@ using namespace std;
 // Acquire::pkgAcquire - Constructor					/*{{{*/
 // Acquire::pkgAcquire - Constructor					/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /* We grab some runtime state from the configuration space */
 /* We grab some runtime state from the configuration space */
-pkgAcquire::pkgAcquire(pkgAcquireStatus *Log) : Log(Log)
+pkgAcquire::pkgAcquire() : Queues(0), Workers(0), Configs(0), Log(NULL), ToFetch(0),
+			   Debug(_config->FindB("Debug::pkgAcquire",false)),
+			   Running(false), LockFD(-1)
 {
 {
-   Queues = 0;
-   Configs = 0;
-   Workers = 0;
-   ToFetch = 0;
-   Running = false;
-   
-   string Mode = _config->Find("Acquire::Queue-Mode","host");
+   string const Mode = _config->Find("Acquire::Queue-Mode","host");
    if (strcasecmp(Mode.c_str(),"host") == 0)
    if (strcasecmp(Mode.c_str(),"host") == 0)
       QueueMode = QueueHost;
       QueueMode = QueueHost;
    if (strcasecmp(Mode.c_str(),"access") == 0)
    if (strcasecmp(Mode.c_str(),"access") == 0)
-      QueueMode = QueueAccess;   
+      QueueMode = QueueAccess;
+}
+pkgAcquire::pkgAcquire(pkgAcquireStatus *Progress) : Queues(0), Workers(0),
+			   Configs(0), Log(Progress), ToFetch(0),
+			   Debug(_config->FindB("Debug::pkgAcquire",false)),
+			   Running(false), LockFD(-1)
+{
+   string const Mode = _config->Find("Acquire::Queue-Mode","host");
+   if (strcasecmp(Mode.c_str(),"host") == 0)
+      QueueMode = QueueHost;
+   if (strcasecmp(Mode.c_str(),"access") == 0)
+      QueueMode = QueueAccess;
+   Setup(Progress, "");
+}
+									/*}}}*/
+// Acquire::Setup - Delayed Constructor					/*{{{*/
+// ---------------------------------------------------------------------
+/* Do everything needed to be a complete Acquire object and report the
+   success (or failure) back so the user knows that something is wrong… */
+bool pkgAcquire::Setup(pkgAcquireStatus *Progress, string const &Lock)
+{
+   Log = Progress;
 
 
-   Debug = _config->FindB("Debug::pkgAcquire",false);
-   
-   // This is really a stupid place for this
-   struct stat St;
-   if (stat((_config->FindDir("Dir::State::lists") + "partial/").c_str(),&St) != 0 ||
-       S_ISDIR(St.st_mode) == 0)
-      _error->Error(_("Lists directory %spartial is missing."),
-		    _config->FindDir("Dir::State::lists").c_str());
-   if (stat((_config->FindDir("Dir::Cache::Archives") + "partial/").c_str(),&St) != 0 ||
-       S_ISDIR(St.st_mode) == 0)
-      _error->Error(_("Archive directory %spartial is missing."),
-		    _config->FindDir("Dir::Cache::Archives").c_str());
+   // check for existence and possibly create auxiliary directories
+   string const listDir = _config->FindDir("Dir::State::lists");
+   string const partialListDir = listDir + "partial/";
+   string const archivesDir = _config->FindDir("Dir::Cache::Archives");
+   string const partialArchivesDir = archivesDir + "partial/";
+
+   if (CheckDirectory(_config->FindDir("Dir::State"), partialListDir) == false &&
+       CheckDirectory(listDir, partialListDir) == false)
+      return _error->Errno("Acquire", _("List directory %spartial is missing."), listDir.c_str());
+
+   if (CheckDirectory(_config->FindDir("Dir::Cache"), partialArchivesDir) == false &&
+       CheckDirectory(archivesDir, partialArchivesDir) == false)
+      return _error->Errno("Acquire", _("Archives directory %spartial is missing."), archivesDir.c_str());
+
+   if (Lock.empty() == true || _config->FindB("Debug::NoLocking", false) == true)
+      return true;
+
+   // Lock the directory this acquire object will work in
+   LockFD = GetLock(flCombine(Lock, "lock"));
+   if (LockFD == -1)
+      return _error->Error(_("Unable to lock directory %s"), Lock.c_str());
+
+   return true;
+}
+									/*}}}*/
+// Acquire::CheckDirectory - ensure that the given directory exists	/*{{{*/
+// ---------------------------------------------------------------------
+/* a small wrapper around CreateDirectory to check if it exists and to
+   remove the trailing "/apt/" from the parent directory if needed */
+bool pkgAcquire::CheckDirectory(string const &Parent, string const &Path) const
+{
+   if (DirectoryExists(Path) == true)
+      return true;
+
+   size_t const len = Parent.size();
+   if (len > 5 && Parent.find("/apt/", len - 6, 5) == len - 5)
+   {
+      if (CreateDirectory(Parent.substr(0,len-5), Path) == true)
+	 return true;
+   }
+   else if (CreateDirectory(Parent, Path) == true)
+      return true;
+
+   return false;
 }
 }
 									/*}}}*/
 									/*}}}*/
 // Acquire::~pkgAcquire	- Destructor					/*{{{*/
 // Acquire::~pkgAcquire	- Destructor					/*{{{*/
@@ -71,7 +120,10 @@ pkgAcquire::pkgAcquire(pkgAcquireStatus *Log) : Log(Log)
 pkgAcquire::~pkgAcquire()
 pkgAcquire::~pkgAcquire()
 {
 {
    Shutdown();
    Shutdown();
-   
+
+   if (LockFD != -1)
+      close(LockFD);
+
    while (Configs != 0)
    while (Configs != 0)
    {
    {
       MethodConfig *Jnk = Configs;
       MethodConfig *Jnk = Configs;
@@ -454,9 +506,9 @@ bool pkgAcquire::Clean(string Dir)
 // Acquire::TotalNeeded - Number of bytes to fetch			/*{{{*/
 // Acquire::TotalNeeded - Number of bytes to fetch			/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /* This is the total number of bytes needed */
 /* 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++)
    for (ItemCIterator I = ItemsBegin(); I != ItemsEnd(); I++)
       Total += (*I)->FileSize;
       Total += (*I)->FileSize;
    return Total;
    return Total;
@@ -465,9 +517,9 @@ double pkgAcquire::TotalNeeded()
 // Acquire::FetchNeeded - Number of bytes needed to get			/*{{{*/
 // Acquire::FetchNeeded - Number of bytes needed to get			/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /* This is the number of bytes that is not local */
 /* 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++)
    for (ItemCIterator I = ItemsBegin(); I != ItemsEnd(); I++)
       if ((*I)->Local == false)
       if ((*I)->Local == false)
 	 Total += (*I)->FileSize;
 	 Total += (*I)->FileSize;
@@ -477,9 +529,9 @@ double pkgAcquire::FetchNeeded()
 // Acquire::PartialPresent - Number of partial bytes we already have	/*{{{*/
 // Acquire::PartialPresent - Number of partial bytes we already have	/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /* This is the number of bytes that is not local */
 /* 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++)
    for (ItemCIterator I = ItemsBegin(); I != ItemsEnd(); I++)
       if ((*I)->Local == false)
       if ((*I)->Local == false)
 	 Total += (*I)->PartialSize;
 	 Total += (*I)->PartialSize;

+ 31 - 9
apt-pkg/acquire.h

@@ -66,6 +66,9 @@
 #ifndef PKGLIB_ACQUIRE_H
 #ifndef PKGLIB_ACQUIRE_H
 #define PKGLIB_ACQUIRE_H
 #define PKGLIB_ACQUIRE_H
 
 
+#include <apt-pkg/macros.h>
+#include <apt-pkg/weakptr.h>
+
 #include <vector>
 #include <vector>
 #include <string>
 #include <string>
 
 
@@ -161,7 +164,7 @@ class pkgAcquire
      QueueAccess} QueueMode;
      QueueAccess} QueueMode;
 
 
    /** \brief If \b true, debugging information will be dumped to std::clog. */
    /** \brief If \b true, debugging information will be dumped to std::clog. */
-   bool Debug;
+   bool const Debug;
    /** \brief If \b true, a download is currently in progress. */
    /** \brief If \b true, a download is currently in progress. */
    bool Running;
    bool Running;
 
 
@@ -320,27 +323,34 @@ class pkgAcquire
    /** \return the total size in bytes of all the items included in
    /** \return the total size in bytes of all the items included in
     *  this download.
     *  this download.
     */
     */
-   double TotalNeeded();
+   unsigned long long TotalNeeded();
 
 
    /** \return the size in bytes of all non-local items included in
    /** \return the size in bytes of all non-local items included in
     *  this download.
     *  this download.
     */
     */
-   double FetchNeeded();
+   unsigned long long FetchNeeded();
 
 
    /** \return the amount of data to be fetched that is already
    /** \return the amount of data to be fetched that is already
     *  present on the filesystem.
     *  present on the filesystem.
     */
     */
-   double PartialPresent();
+   unsigned long long PartialPresent();
 
 
-   /** \brief Construct a new pkgAcquire.
+   /** \brief Delayed constructor
     *
     *
-    *  \param Log The progress indicator associated with this
-    *  download, or \b NULL for none.  This object is not owned by the
+    *  \param Progress indicator associated with this download or
+    *  \b NULL for none.  This object is not owned by the
     *  download process and will not be deleted when the pkgAcquire
     *  download process and will not be deleted when the pkgAcquire
     *  object is destroyed.  Naturally, it should live for at least as
     *  object is destroyed.  Naturally, it should live for at least as
     *  long as the pkgAcquire object does.
     *  long as the pkgAcquire object does.
+    *  \param Lock defines a lock file that should be acquired to ensure
+    *  only one Acquire class is in action at the time or an empty string
+    *  if no lock file should be used.
     */
     */
-   pkgAcquire(pkgAcquireStatus *Log = 0);
+   bool Setup(pkgAcquireStatus *Progress = NULL, string const &Lock = "");
+
+   /** \brief Construct a new pkgAcquire. */
+   pkgAcquire(pkgAcquireStatus *Log) __deprecated;
+   pkgAcquire();
 
 
    /** \brief Destroy this pkgAcquire object.
    /** \brief Destroy this pkgAcquire object.
     *
     *
@@ -348,6 +358,18 @@ class pkgAcquire
     *  this download.
     *  this download.
     */
     */
    virtual ~pkgAcquire();
    virtual ~pkgAcquire();
+
+   private:
+   /** \brief FD of the Lock file we acquire in Setup (if any) */
+   int LockFD;
+
+   /** \brief Ensure the existence of the given Path
+    *
+    *  \param Parent directory of the Path directory - a trailing
+    *  /apt/ will be removed before CreateDirectory call.
+    *  \param Path which should exist after (successful) call
+    */
+   bool CheckDirectory(string const &Parent, string const &Path) const;
 };
 };
 
 
 /** \brief Represents a single download source from which an item
 /** \brief Represents a single download source from which an item
@@ -355,7 +377,7 @@ class pkgAcquire
  *
  *
  *  An item may have several assocated ItemDescs over its lifetime.
  *  An item may have several assocated ItemDescs over its lifetime.
  */
  */
-struct pkgAcquire::ItemDesc
+struct pkgAcquire::ItemDesc : public WeakPointable
 {
 {
    /** \brief The URI from which to download this item. */
    /** \brief The URI from which to download this item. */
    string URI;
    string URI;

+ 57 - 12
apt-pkg/algorithms.cc

@@ -83,13 +83,28 @@ void pkgSimulate::Describe(PkgIterator Pkg,ostream &out,bool Current,bool Candid
 bool pkgSimulate::Install(PkgIterator iPkg,string /*File*/)
 bool pkgSimulate::Install(PkgIterator iPkg,string /*File*/)
 {
 {
    // Adapt the iterator
    // Adapt the iterator
-   PkgIterator Pkg = Sim.FindPkg(iPkg.Name());
+   PkgIterator Pkg = Sim.FindPkg(iPkg.Name(), iPkg.Arch());
    Flags[Pkg->ID] = 1;
    Flags[Pkg->ID] = 1;
    
    
    cout << "Inst ";
    cout << "Inst ";
    Describe(Pkg,cout,true,true);
    Describe(Pkg,cout,true,true);
    Sim.MarkInstall(Pkg,false);
    Sim.MarkInstall(Pkg,false);
-   
+
+   if (strcmp(Pkg.Arch(),"all") == 0)
+   {
+      pkgCache::GrpIterator G = Pkg.Group();
+      pkgCache::GrpIterator iG = iPkg.Group();
+      for (pkgCache::PkgIterator P = G.FindPkg("any"); P.end() != true; P = G.NextPkg(P))
+      {
+	 if (strcmp(P.Arch(), "all") == 0)
+	    continue;
+	 if (iG.FindPkg(P.Arch())->CurrentVer == 0)
+	    continue;
+	 Flags[P->ID] = 1;
+	 Sim.MarkInstall(P, false);
+      }
+   }
+
    // Look for broken conflicts+predepends.
    // Look for broken conflicts+predepends.
    for (PkgIterator I = Sim.PkgBegin(); I.end() == false; I++)
    for (PkgIterator I = Sim.PkgBegin(); I.end() == false; I++)
    {
    {
@@ -131,9 +146,22 @@ bool pkgSimulate::Install(PkgIterator iPkg,string /*File*/)
 bool pkgSimulate::Configure(PkgIterator iPkg)
 bool pkgSimulate::Configure(PkgIterator iPkg)
 {
 {
    // Adapt the iterator
    // Adapt the iterator
-   PkgIterator Pkg = Sim.FindPkg(iPkg.Name());
+   PkgIterator Pkg = Sim.FindPkg(iPkg.Name(), iPkg.Arch());
    
    
    Flags[Pkg->ID] = 2;
    Flags[Pkg->ID] = 2;
+
+   if (strcmp(Pkg.Arch(),"all") == 0)
+   {
+      pkgCache::GrpIterator G = Pkg.Group();
+      for (pkgCache::PkgIterator P = G.FindPkg("any"); P.end() != true; P = G.NextPkg(P))
+      {
+	 if (strcmp(P.Arch(), "all") == 0)
+	    continue;
+	 if (Flags[P->ID] == 1)
+	    Flags[P->ID] = 2;
+      }
+   }
+
 //   Sim.MarkInstall(Pkg,false);
 //   Sim.MarkInstall(Pkg,false);
    if (Sim[Pkg].InstBroken() == true)
    if (Sim[Pkg].InstBroken() == true)
    {
    {
@@ -181,10 +209,26 @@ bool pkgSimulate::Configure(PkgIterator iPkg)
 bool pkgSimulate::Remove(PkgIterator iPkg,bool Purge)
 bool pkgSimulate::Remove(PkgIterator iPkg,bool Purge)
 {
 {
    // Adapt the iterator
    // Adapt the iterator
-   PkgIterator Pkg = Sim.FindPkg(iPkg.Name());
+   PkgIterator Pkg = Sim.FindPkg(iPkg.Name(), iPkg.Arch());
 
 
    Flags[Pkg->ID] = 3;
    Flags[Pkg->ID] = 3;
    Sim.MarkDelete(Pkg);
    Sim.MarkDelete(Pkg);
+
+   if (strcmp(Pkg.Arch(),"all") == 0)
+   {
+      pkgCache::GrpIterator G = Pkg.Group();
+      pkgCache::GrpIterator iG = iPkg.Group();
+      for (pkgCache::PkgIterator P = G.FindPkg("any"); P.end() != true; P = G.NextPkg(P))
+      {
+	 if (strcmp(P.Arch(), "all") == 0)
+	    continue;
+	 if (iG.FindPkg(P.Arch())->CurrentVer == 0)
+	    continue;
+	 Flags[P->ID] = 3;
+	 Sim.MarkDelete(P);
+      }
+   }
+
    if (Purge == true)
    if (Purge == true)
       cout << "Purg ";
       cout << "Purg ";
    else
    else
@@ -491,11 +535,11 @@ void pkgProblemResolver::MakeScores()
    // Important Required Standard Optional Extra
    // Important Required Standard Optional Extra
    signed short PrioMap[] = {
    signed short PrioMap[] = {
       0,
       0,
-      _config->FindI("pkgProblemResolver::Scores::Important",3),
-      _config->FindI("pkgProblemResolver::Scores::Required",2),
-      _config->FindI("pkgProblemResolver::Scores::Standard",1),
-      _config->FindI("pkgProblemResolver::Scores::Optional",-1),
-      _config->FindI("pkgProblemResolver::Scores::Extra",-2)
+      (signed short) _config->FindI("pkgProblemResolver::Scores::Important",3),
+      (signed short) _config->FindI("pkgProblemResolver::Scores::Required",2),
+      (signed short) _config->FindI("pkgProblemResolver::Scores::Standard",1),
+      (signed short) _config->FindI("pkgProblemResolver::Scores::Optional",-1),
+      (signed short) _config->FindI("pkgProblemResolver::Scores::Extra",-2)
    };
    };
    signed short PrioEssentials = _config->FindI("pkgProblemResolver::Scores::Essentials",100);
    signed short PrioEssentials = _config->FindI("pkgProblemResolver::Scores::Essentials",100);
    signed short PrioInstalledAndNotObsolete = _config->FindI("pkgProblemResolver::Scores::NotObsolete",1);
    signed short PrioInstalledAndNotObsolete = _config->FindI("pkgProblemResolver::Scores::NotObsolete",1);
@@ -1140,8 +1184,7 @@ bool pkgProblemResolver::Resolve(bool BrokenFix)
       return _error->Error(_("Unable to correct problems, you have held broken packages."));
       return _error->Error(_("Unable to correct problems, you have held broken packages."));
    }
    }
    
    
-   // set the auto-flags (mvo: I'm not sure if we _really_ need this, but
-   // I didn't managed 
+   // set the auto-flags (mvo: I'm not sure if we _really_ need this)
    pkgCache::PkgIterator I = Cache.PkgBegin();
    pkgCache::PkgIterator I = Cache.PkgBegin();
    for (;I.end() != true; I++) {
    for (;I.end() != true; I++) {
       if (Cache[I].NewInstall() && !(Flags[I->ID] & PreInstalled)) {
       if (Cache[I].NewInstall() && !(Flags[I->ID] & PreInstalled)) {
@@ -1354,7 +1397,9 @@ bool ListUpdate(pkgAcquireStatus &Stat,
 		int PulseInterval)
 		int PulseInterval)
 {
 {
    pkgAcquire::RunResult res;
    pkgAcquire::RunResult res;
-   pkgAcquire Fetcher(&Stat);
+   pkgAcquire Fetcher;
+   if (Fetcher.Setup(&Stat, _config->FindDir("Dir::State::Lists")) == false)
+      return false;
 
 
    // Populate it with the source selection
    // Populate it with the source selection
    if (List.GetIndexes(&Fetcher) == false)
    if (List.GetIndexes(&Fetcher) == false)

+ 1 - 1
apt-pkg/algorithms.h

@@ -48,7 +48,7 @@ class pkgSimulate : public pkgPackageManager				/*{{{*/
       pkgDepCache *Cache;
       pkgDepCache *Cache;
       public:
       public:
       
       
-      virtual VerIterator GetCandidateVer(PkgIterator Pkg)
+      virtual VerIterator GetCandidateVer(PkgIterator const &Pkg)
       {
       {
 	 return (*Cache)[Pkg].CandidateVerIter(*Cache);
 	 return (*Cache)[Pkg].CandidateVerIter(*Cache);
       }
       }

+ 43 - 1
apt-pkg/aptconfiguration.cc

@@ -10,6 +10,7 @@
 // Include Files							/*{{{*/
 // Include Files							/*{{{*/
 #include <apt-pkg/aptconfiguration.h>
 #include <apt-pkg/aptconfiguration.h>
 #include <apt-pkg/configuration.h>
 #include <apt-pkg/configuration.h>
+#include <apt-pkg/error.h>
 #include <apt-pkg/fileutl.h>
 #include <apt-pkg/fileutl.h>
 #include <apt-pkg/macros.h>
 #include <apt-pkg/macros.h>
 #include <apt-pkg/strutl.h>
 #include <apt-pkg/strutl.h>
@@ -152,6 +153,7 @@ std::vector<std::string> const Configuration::getLanguages(bool const &All,
 			builtin.push_back(c);
 			builtin.push_back(c);
 		}
 		}
 	}
 	}
+	closedir(D);
 
 
 	// get the environment language codes: LC_MESSAGES (and later LANGUAGE)
 	// get the environment language codes: LC_MESSAGES (and later LANGUAGE)
 	// we extract both, a long and a short code and then we will
 	// we extract both, a long and a short code and then we will
@@ -195,6 +197,9 @@ std::vector<std::string> const Configuration::getLanguages(bool const &All,
 	// it was undocumented and so it should be not very widthly used
 	// it was undocumented and so it should be not very widthly used
 	string const oldAcquire = _config->Find("APT::Acquire::Translation","");
 	string const oldAcquire = _config->Find("APT::Acquire::Translation","");
 	if (oldAcquire.empty() == false && oldAcquire != "environment") {
 	if (oldAcquire.empty() == false && oldAcquire != "environment") {
+		// TRANSLATORS: the two %s are APT configuration options
+		_error->Notice("Option '%s' is deprecated. Please use '%s' instead, see 'man 5 apt.conf' for details.",
+				"APT::Acquire::Translation", "Acquire::Languages");
 		if (oldAcquire != "none")
 		if (oldAcquire != "none")
 			codes.push_back(oldAcquire);
 			codes.push_back(oldAcquire);
 		codes.push_back("en");
 		codes.push_back("en");
@@ -220,7 +225,7 @@ std::vector<std::string> const Configuration::getLanguages(bool const &All,
 	const char *language_env = getenv("LANGUAGE") == 0 ? "" : getenv("LANGUAGE");
 	const char *language_env = getenv("LANGUAGE") == 0 ? "" : getenv("LANGUAGE");
 	string envLang = Locale == 0 ? language_env : *(Locale+1);
 	string envLang = Locale == 0 ? language_env : *(Locale+1);
 	if (envLang.empty() == false) {
 	if (envLang.empty() == false) {
-		std::vector<string> env = ExplodeString(envLang,':');
+		std::vector<string> env = VectorizeString(envLang,':');
 		short addedLangs = 0; // add a maximum of 3 fallbacks from the environment
 		short addedLangs = 0; // add a maximum of 3 fallbacks from the environment
 		for (std::vector<string>::const_iterator e = env.begin();
 		for (std::vector<string>::const_iterator e = env.begin();
 		     e != env.end() && addedLangs < 3; ++e) {
 		     e != env.end() && addedLangs < 3; ++e) {
@@ -318,4 +323,41 @@ std::vector<std::string> const Configuration::getLanguages(bool const &All,
 		return codes;
 		return codes;
 }
 }
 									/*}}}*/
 									/*}}}*/
+// getArchitectures - Return Vector of prefered Architectures		/*{{{*/
+std::vector<std::string> const Configuration::getArchitectures(bool const &Cached) {
+	using std::string;
+
+	std::vector<string> static archs;
+	if (likely(Cached == true) && archs.empty() == false)
+		return archs;
+
+	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;
+}
+									/*}}}*/
+// checkArchitecture - are we interested in the given Architecture?	/*{{{*/
+bool const Configuration::checkArchitecture(std::string const &Arch) {
+	if (Arch == "all")
+		return true;
+	std::vector<std::string> const archs = getArchitectures(true);
+	return (std::find(archs.begin(), archs.end(), Arch) != archs.end());
+}
+									/*}}}*/
 }
 }

+ 16 - 0
apt-pkg/aptconfiguration.h

@@ -66,6 +66,22 @@ public:									/*{{{*/
 	std::vector<std::string> static const getLanguages(bool const &All = false,
 	std::vector<std::string> static const getLanguages(bool const &All = false,
 			bool const &Cached = true, char const ** const Locale = 0);
 			bool const &Cached = true, char const ** const Locale = 0);
 
 
+	/** \brief Returns a vector of Architectures we support
+	 *
+	 *  \param Cached saves the result so we need to calculated it only once
+	 *                this parameter should ony be used for testing purposes.
+	 *
+	 *  \return a vector of Architectures in prefered order
+	 */
+	std::vector<std::string> static const getArchitectures(bool const &Cached = true);
+
+	/** \brief Are we interested in the given Architecture?
+	 *
+	 *  \param Arch we want to check
+	 *  \return true if we are interested, false otherwise
+	 */
+	bool static const checkArchitecture(std::string const &Arch);
+
 									/*}}}*/
 									/*}}}*/
 };
 };
 									/*}}}*/
 									/*}}}*/

+ 81 - 25
apt-pkg/cachefile.cc

@@ -27,7 +27,8 @@
 // CacheFile::CacheFile - Constructor					/*{{{*/
 // CacheFile::CacheFile - Constructor					/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /* */
 /* */
-pkgCacheFile::pkgCacheFile() : Map(0), Cache(0), DCache(0), Policy(0)
+pkgCacheFile::pkgCacheFile() : Map(NULL), Cache(NULL), DCache(NULL),
+				SrcList(NULL), Policy(NULL)
 {
 {
 }
 }
 									/*}}}*/
 									/*}}}*/
@@ -38,16 +39,30 @@ pkgCacheFile::~pkgCacheFile()
 {
 {
    delete DCache;
    delete DCache;
    delete Policy;
    delete Policy;
+   delete SrcList;
    delete Cache;
    delete Cache;
    delete Map;
    delete Map;
    _system->UnLock(true);
    _system->UnLock(true);
-}   
+}
 									/*}}}*/
 									/*}}}*/
 // CacheFile::BuildCaches - Open and build the cache files		/*{{{*/
 // 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();
    const bool ErrorWasEmpty = _error->empty();
    if (WithLock == true)
    if (WithLock == true)
       if (_system->Lock() == false)
       if (_system->Lock() == false)
@@ -58,15 +73,13 @@ bool pkgCacheFile::BuildCaches(OpProgress &Progress,bool WithLock)
       
       
    if (_error->PendingError() == true)
    if (_error->PendingError() == true)
       return false;
       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
    // 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)
    if (Res == false)
       return _error->Error(_("The package lists or status file could not be parsed or opened."));
       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;
    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);
    Policy = new pkgPolicy(Cache);
    if (_error->PendingError() == true)
    if (_error->PendingError() == true)
       return false;
       return false;
 
 
    if (ReadPinFile(*Policy) == false || ReadPinDir(*Policy) == false)
    if (ReadPinFile(*Policy) == false || ReadPinDir(*Policy) == false)
       return 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);
    DCache = new pkgDepCache(Cache,Policy);
    if (_error->PendingError() == true)
    if (_error->PendingError() == true)
       return false;
       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)
    if (_error->PendingError() == true)
       return false;
       return false;
    
    
@@ -117,12 +171,14 @@ void pkgCacheFile::Close()
    delete DCache;
    delete DCache;
    delete Policy;
    delete Policy;
    delete Cache;
    delete Cache;
+   delete SrcList;
    delete Map;
    delete Map;
    _system->UnLock(true);
    _system->UnLock(true);
 
 
-   Map = 0;
-   DCache = 0;
-   Policy = 0;
-   Cache = 0;
+   Map = NULL;
+   DCache = NULL;
+   Policy = NULL;
+   Cache = NULL;
+   SrcList = NULL;
 }
 }
 									/*}}}*/
 									/*}}}*/

+ 28 - 8
apt-pkg/cachefile.h

@@ -20,9 +20,9 @@
 
 
 #include <apt-pkg/depcache.h>
 #include <apt-pkg/depcache.h>
 #include <apt-pkg/acquire.h>
 #include <apt-pkg/acquire.h>
+#include <apt-pkg/policy.h>
 #include <apt-pkg/sourcelist.h>
 #include <apt-pkg/sourcelist.h>
 
 
-class pkgPolicy;
 class pkgCacheFile
 class pkgCacheFile
 {
 {
    protected:
    protected:
@@ -30,27 +30,47 @@ class pkgCacheFile
    MMap *Map;
    MMap *Map;
    pkgCache *Cache;
    pkgCache *Cache;
    pkgDepCache *DCache;
    pkgDepCache *DCache;
-   
-   public:
+   pkgSourceList *SrcList;
 
 
+   public:
    pkgPolicy *Policy;
    pkgPolicy *Policy;
-      
+
    // We look pretty much exactly like a pointer to a dep cache
    // We look pretty much exactly like a pointer to a dep cache
    inline operator pkgCache &() {return *Cache;};
    inline operator pkgCache &() {return *Cache;};
    inline operator pkgCache *() {return Cache;};
    inline operator pkgCache *() {return Cache;};
    inline operator pkgDepCache &() {return *DCache;};
    inline operator pkgDepCache &() {return *DCache;};
    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 &operator *() {return *DCache;};
    inline pkgDepCache &operator *() {return *DCache;};
    inline pkgDepCache::StateCache &operator [](pkgCache::PkgIterator const &I) {return (*DCache)[I];};
    inline pkgDepCache::StateCache &operator [](pkgCache::PkgIterator const &I) {return (*DCache)[I];};
    inline unsigned char &operator [](pkgCache::DepIterator 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();
    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; };
+
+   inline bool IsPkgCacheBuilt() const { return (Cache != NULL); };
+   inline bool IsDepCacheBuilt() const { return (DCache != NULL); };
+   inline bool IsPolicyBuilt() const { return (Policy != NULL); };
+   inline bool IsSrcListBuilt() const { return (SrcList != NULL); };
+
    pkgCacheFile();
    pkgCacheFile();
-   ~pkgCacheFile();
+   virtual ~pkgCacheFile();
 };
 };
 
 
 #endif
 #endif

+ 54 - 0
apt-pkg/cachefilter.cc

@@ -0,0 +1,54 @@
+// -*- mode: cpp; mode: fold -*-
+// Description								/*{{{*/
+/** \file cachefilter.h
+    Collection of functor classes */
+									/*}}}*/
+// Include Files							/*{{{*/
+#include <apt-pkg/cachefilter.h>
+#include <apt-pkg/error.h>
+#include <apt-pkg/pkgcache.h>
+
+#include <apti18n.h>
+
+#include <string>
+
+#include <regex.h>
+									/*}}}*/
+namespace APT {
+namespace CacheFilter {
+PackageNameMatchesRegEx::PackageNameMatchesRegEx(std::string const &Pattern) {/*{{{*/
+	pattern = new regex_t;
+	int const Res = regcomp(pattern, Pattern.c_str(), REG_EXTENDED | REG_ICASE | REG_NOSUB);
+	if (Res == 0)
+		return;
+
+	delete pattern;
+	pattern = NULL;
+	char Error[300];
+	regerror(Res, pattern, Error, sizeof(Error));
+	_error->Error(_("Regex compilation error - %s"), Error);
+}
+									/*}}}*/
+bool PackageNameMatchesRegEx::operator() (pkgCache::PkgIterator const &Pkg) {/*{{{*/
+	if (unlikely(pattern == NULL))
+		return false;
+	else
+		return regexec(pattern, Pkg.Name(), 0, 0, 0) == 0;
+}
+									/*}}}*/
+bool PackageNameMatchesRegEx::operator() (pkgCache::GrpIterator const &Grp) {/*{{{*/
+	if (unlikely(pattern == NULL))
+		return false;
+	else
+		return regexec(pattern, Grp.Name(), 0, 0, 0) == 0;
+}
+									/*}}}*/
+PackageNameMatchesRegEx::~PackageNameMatchesRegEx() {			/*{{{*/
+	if (pattern == NULL)
+		return;
+	regfree(pattern);
+	delete pattern;
+}
+									/*}}}*/
+}
+}

+ 29 - 0
apt-pkg/cachefilter.h

@@ -0,0 +1,29 @@
+// -*- mode: cpp; mode: fold -*-
+// Description								/*{{{*/
+/** \file cachefilter.h
+   Collection of functor classes */
+									/*}}}*/
+#ifndef APT_CACHEFILTER_H
+#define APT_CACHEFILTER_H
+// Include Files							/*{{{*/
+#include <apt-pkg/pkgcache.h>
+
+#include <string>
+
+#include <regex.h>
+									/*}}}*/
+namespace APT {
+namespace CacheFilter {
+// PackageNameMatchesRegEx						/*{{{*/
+class PackageNameMatchesRegEx {
+	regex_t* pattern;
+public:
+	PackageNameMatchesRegEx(std::string const &Pattern);
+	bool operator() (pkgCache::PkgIterator const &Pkg);
+	bool operator() (pkgCache::GrpIterator const &Grp);
+	~PackageNameMatchesRegEx();
+};
+									/*}}}*/
+}
+}
+#endif

+ 370 - 378
apt-pkg/cacheiterators.h

@@ -1,6 +1,5 @@
 // -*- mode: cpp; mode: fold -*-
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
 // Description								/*{{{*/
-// $Id: cacheiterators.h,v 1.18.2.1 2004/05/08 22:44:27 mdz Exp $
 /* ######################################################################
 /* ######################################################################
    
    
    Cache Iterators - Iterators for navigating the cache structure
    Cache Iterators - Iterators for navigating the cache structure
@@ -30,417 +29,410 @@
 									/*}}}*/
 									/*}}}*/
 #ifndef PKGLIB_CACHEITERATORS_H
 #ifndef PKGLIB_CACHEITERATORS_H
 #define PKGLIB_CACHEITERATORS_H
 #define PKGLIB_CACHEITERATORS_H
+#include<iterator>
+
+#include<string.h>
+// 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 :
+			public std::iterator<std::forward_iterator_tag, Str> {
+	protected:
+	Str *S;
+	pkgCache *Owner;
+
+	/** \brief Returns the Pointer for this struct in the owner
+	 *  The implementation of this method should be pretty short
+	 *  as it will only return the Pointer into the mmap stored
+	 *  in the owner but the name of this pointer is different for
+	 *  each stucture and we want to abstract here at least for the
+	 *  basic methods from the actual structure.
+	 *  \return Pointer to the first structure of this type
+	 */
+	virtual Str* OwnerPointer() const = 0;
+
+	public:
+	// Iteration
+	virtual void operator ++(int) = 0;
+	virtual void operator ++() = 0; // Should be {operator ++(0);};
+	inline bool end() const {return Owner == 0 || S == OwnerPointer();};
+
+	// Comparison
+	inline bool operator ==(const Itr &B) const {return S == B.S;};
+	inline bool operator !=(const Itr &B) const {return S != B.S;};
+
+	// Accessors
+	inline Str *operator ->() {return S;};
+	inline Str const *operator ->() const {return S;};
+	inline operator Str *() {return S == OwnerPointer() ? 0 : S;};
+	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() const {return Owner;};
+
+	// Mixed stuff
+	inline void operator =(const Itr &B) {S = B.S; Owner = B.Owner;};
+	inline bool IsGood() const { return S && Owner && ! end();};
+	inline unsigned long Index() const {return S - OwnerPointer();};
+
+	void ReMap(void const * const oldMap, void const * const newMap) {
+		if (Owner == 0 || S == 0)
+			return;
+		S += (Str*)(newMap) - (Str*)(oldMap);
+	}
+
+	// Constructors - look out for the variable assigning
+	inline Iterator() : S(0), Owner(0) {};
+	inline Iterator(pkgCache &Owner,Str *T = 0) : S(T), Owner(&Owner) {};
+};
+									/*}}}*/
+// Group Iterator							/*{{{*/
+/* Packages with the same name are collected in a Group so someone only
+   interest in package names can iterate easily over the names, so the
+   different architectures can be treated as of the "same" package
+   (apt internally treat them as totally different packages) */
+class pkgCache::GrpIterator: public Iterator<Group, GrpIterator> {
+	long HashIndex;
+
+	protected:
+	inline Group* OwnerPointer() const {
+		return Owner->GrpP;
+	};
+
+	public:
+	// This constructor is the 'begin' constructor, never use it.
+	inline GrpIterator(pkgCache &Owner) : Iterator<Group, GrpIterator>(Owner), HashIndex(-1) {
+		S = OwnerPointer();
+		operator ++(0);
+	};
+
+	virtual void operator ++(int);
+	virtual void operator ++() {operator ++(0);};
+
+	inline const char *Name() const {return S->Name == 0?0:Owner->StrP + S->Name;};
+	inline PkgIterator PackageList() const;
+	PkgIterator FindPkg(string Arch = "any") const;
+	/** \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
+
+	    \param PreferNonVirtual tries to respond with a non-virtual package
+		   and only if this fails returns the best virtual package */
+	PkgIterator FindPreferredPkg(bool const &PreferNonVirtual = true) const;
+	PkgIterator NextPkg(PkgIterator const &Pkg) const;
+
+	// Constructors
+	inline GrpIterator(pkgCache &Owner, Group *Trg) : Iterator<Group, GrpIterator>(Owner, Trg), HashIndex(0) {
+		if (S == 0)
+			S = OwnerPointer();
+	};
+	inline GrpIterator() : Iterator<Group, GrpIterator>(), HashIndex(0) {};
 
 
-
+};
+									/*}}}*/
 // Package Iterator							/*{{{*/
 // Package Iterator							/*{{{*/
-class pkgCache::PkgIterator
-{
-   friend class pkgCache;
-   Package *Pkg;
-   pkgCache *Owner;
-   long HashIndex;
-
-   protected:
-   
-   // This constructor is the 'begin' constructor, never use it.
-   inline PkgIterator(pkgCache &Owner) : Owner(&Owner), HashIndex(-1)
-   {
-      Pkg = Owner.PkgP;
-      operator ++(0);
-   };
-   
-   public:
-
-   enum OkState {NeedsNothing,NeedsUnpack,NeedsConfigure};
-      
-   // Iteration
-   void operator ++(int);
-   inline void operator ++() {operator ++(0);};
-   inline bool end() const {return Owner == 0 || Pkg == Owner->PkgP?true:false;};
-
-   // Comparison
-   inline bool operator ==(const PkgIterator &B) const {return Pkg == B.Pkg;};
-   inline bool operator !=(const PkgIterator &B) const {return Pkg != B.Pkg;};
-			   
-   // Accessors
-   inline Package *operator ->() {return Pkg;};
-   inline Package const *operator ->() const {return Pkg;};
-   inline Package const &operator *() const {return *Pkg;};
-   inline operator Package *() {return Pkg == Owner->PkgP?0:Pkg;};
-   inline operator Package const *() const {return Pkg == Owner->PkgP?0:Pkg;};
-   inline pkgCache *Cache() {return Owner;};
-   
-   inline const char *Name() const {return Pkg->Name == 0?0:Owner->StrP + Pkg->Name;};
-   inline const char *Section() const {return Pkg->Section == 0?0:Owner->StrP + Pkg->Section;};
-   inline bool Purge() const {return Pkg->CurrentState == pkgCache::State::Purge ||
-	 (Pkg->CurrentVer == 0 && Pkg->CurrentState == pkgCache::State::NotInstalled);};
-   inline VerIterator VersionList() const;
-   inline VerIterator CurrentVer() const;
-   inline DepIterator RevDependsList() const;
-   inline PrvIterator ProvidesList() const;
-   inline unsigned long Index() const {return Pkg - Owner->PkgP;};
-   OkState State() const;
-
-   //Nice printable representation
-   friend std::ostream& operator<<(std::ostream& out, pkgCache::PkgIterator Pkg);
-
-   const char *CandVersion() const;
-   const char *CurVersion() const;
-
-   // Constructors
-   inline PkgIterator(pkgCache &Owner,Package *Trg) : Pkg(Trg), Owner(&Owner),
-          HashIndex(0) 
-   { 
-      if (Pkg == 0)
-	 Pkg = Owner.PkgP;
-   };
-   inline PkgIterator() : Pkg(0), Owner(0), HashIndex(0) {};
+class pkgCache::PkgIterator: public Iterator<Package, PkgIterator> {
+	long HashIndex;
+
+	protected:
+	inline Package* OwnerPointer() const {
+		return Owner->PkgP;
+	};
+
+	public:
+	// This constructor is the 'begin' constructor, never use it.
+	inline PkgIterator(pkgCache &Owner) : Iterator<Package, PkgIterator>(Owner), HashIndex(-1) {
+		S = OwnerPointer();
+		operator ++(0);
+	};
+
+	virtual void operator ++(int);
+	virtual void operator ++() {operator ++(0);};
+
+	enum OkState {NeedsNothing,NeedsUnpack,NeedsConfigure};
+
+	// Accessors
+	inline const char *Name() const {return S->Name == 0?0:Owner->StrP + S->Name;};
+	inline const char *Section() const {return S->Section == 0?0:Owner->StrP + S->Section;};
+	inline bool Purge() const {return S->CurrentState == pkgCache::State::Purge ||
+		(S->CurrentVer == 0 && S->CurrentState == pkgCache::State::NotInstalled);};
+	inline const char *Arch() const {return S->Arch == 0?0:Owner->StrP + S->Arch;};
+	inline GrpIterator Group() const { return GrpIterator(*Owner, Owner->GrpP + S->Group);};
+
+	inline VerIterator VersionList() const;
+	inline VerIterator CurrentVer() const;
+	inline DepIterator RevDependsList() const;
+	inline PrvIterator ProvidesList() const;
+	OkState State() const;
+	const char *CandVersion() const;
+	const char *CurVersion() const;
+
+	//Nice printable representation
+	friend std::ostream& operator <<(std::ostream& out, PkgIterator i);
+	std::string FullName(bool const &Pretty = false) const;
+
+	// Constructors
+	inline PkgIterator(pkgCache &Owner,Package *Trg) : Iterator<Package, PkgIterator>(Owner, Trg), HashIndex(0) {
+		if (S == 0)
+			S = OwnerPointer();
+	};
+	inline PkgIterator() : Iterator<Package, PkgIterator>(), HashIndex(0) {};
 };
 };
 									/*}}}*/
 									/*}}}*/
 // Version Iterator							/*{{{*/
 // Version Iterator							/*{{{*/
-class pkgCache::VerIterator
-{
-   Version *Ver;
-   pkgCache *Owner;
-
-   void _dummy();
-   
-   public:
-
-   // Iteration
-   void operator ++(int) {if (Ver != Owner->VerP) Ver = Owner->VerP + Ver->NextVer;};
-   inline void operator ++() {operator ++(0);};
-   inline bool end() const {return Owner == 0 || (Ver == Owner->VerP?true:false);};
-   inline void operator =(const VerIterator &B) {Ver = B.Ver; Owner = B.Owner;};
-   
-   // Comparison
-   inline bool operator ==(const VerIterator &B) const {return Ver == B.Ver;};
-   inline bool operator !=(const VerIterator &B) const {return Ver != B.Ver;};
-   int CompareVer(const VerIterator &B) const;
-
-   // Testing
-   inline bool IsGood() const { return Ver && Owner && ! end();};
-
-   // Accessors
-   inline Version *operator ->() {return Ver;};
-   inline Version const *operator ->() const {return Ver;};
-   inline Version &operator *() {return *Ver;};
-   inline Version const &operator *() const {return *Ver;};
-   inline operator Version *() {return Ver == Owner->VerP?0:Ver;};
-   inline operator Version const *() const {return Ver == Owner->VerP?0:Ver;};
-   inline pkgCache *Cache() {return Owner;};
-      
-   inline const char *VerStr() const {return Ver->VerStr == 0?0:Owner->StrP + Ver->VerStr;};
-   inline const char *Section() const {return Ver->Section == 0?0:Owner->StrP + Ver->Section;};
-   inline const char *Arch() const {return Ver->Arch == 0?0:Owner->StrP + Ver->Arch;};
-   inline PkgIterator ParentPkg() const {return PkgIterator(*Owner,Owner->PkgP + Ver->ParentPkg);};
-   inline DescIterator DescriptionList() const;
-   DescIterator TranslatedDescription() const;
-   inline DepIterator DependsList() const;
-   inline PrvIterator ProvidesList() const;
-   inline VerFileIterator FileList() const;
-   inline unsigned long Index() const {return Ver - Owner->VerP;};
-   bool Downloadable() const;
-   inline const char *PriorityType() {return Owner->Priority(Ver->Priority);};
-   string RelStr();
-   
-   bool Automatic() const;
-   VerFileIterator NewestFile() const;
-
-   inline VerIterator() : Ver(0), Owner(0) {};   
-   inline VerIterator(pkgCache &Owner,Version *Trg = 0) : Ver(Trg), 
-              Owner(&Owner) 
-   { 
-      if (Ver == 0)
-	 Ver = Owner.VerP;
-   };
+class pkgCache::VerIterator : public Iterator<Version, VerIterator> {
+	protected:
+	inline Version* OwnerPointer() const {
+		return Owner->VerP;
+	};
+
+	public:
+	// Iteration
+	void operator ++(int) {if (S != Owner->VerP) S = Owner->VerP + S->NextVer;};
+	inline void operator ++() {operator ++(0);};
+
+	// Comparison
+	int CompareVer(const VerIterator &B) const;
+	/** \brief compares two version and returns if they are similar
+
+	    This method should be used to identify if two pseudo versions are
+	    refering to the same "real" version */
+	inline bool SimilarVer(const VerIterator &B) const {
+		return (B.end() == false && S->Hash == B->Hash && strcmp(VerStr(), B.VerStr()) == 0);
+	};
+
+	// Accessors
+	inline const char *VerStr() const {return S->VerStr == 0?0:Owner->StrP + S->VerStr;};
+	inline const char *Section() const {return S->Section == 0?0:Owner->StrP + S->Section;};
+	inline const char *Arch() const {
+		if(S->MultiArch == pkgCache::Version::All)
+			return "all";
+		return S->ParentPkg == 0?0:Owner->StrP + ParentPkg()->Arch;
+	};
+	inline const char *Arch(bool const pseudo) const {
+		if(pseudo == false)
+			return Arch();
+		return S->ParentPkg == 0?0:Owner->StrP + ParentPkg()->Arch;
+	};
+	inline PkgIterator ParentPkg() const {return PkgIterator(*Owner,Owner->PkgP + S->ParentPkg);};
+
+	inline DescIterator DescriptionList() const;
+	DescIterator TranslatedDescription() const;
+	inline DepIterator DependsList() const;
+	inline PrvIterator ProvidesList() const;
+	inline VerFileIterator FileList() const;
+	bool Downloadable() const;
+	inline const char *PriorityType() const {return Owner->Priority(S->Priority);};
+	string RelStr() const;
+
+	bool Automatic() const;
+	bool Pseudo() const;
+	VerFileIterator NewestFile() const;
+
+	inline VerIterator(pkgCache &Owner,Version *Trg = 0) : Iterator<Version, VerIterator>(Owner, Trg) {
+		if (S == 0)
+			S = OwnerPointer();
+	};
+	inline VerIterator() : Iterator<Version, VerIterator>() {};
 };
 };
 									/*}}}*/
 									/*}}}*/
 // Description Iterator							/*{{{*/
 // Description Iterator							/*{{{*/
-class pkgCache::DescIterator
-{
-   Description *Desc;
-   pkgCache *Owner;
-   
-   void _dummy();
-   
-   public:
-
-   // Iteration
-   void operator ++(int) {if (Desc != Owner->DescP) Desc = Owner->DescP + Desc->NextDesc;};
-   inline void operator ++() {operator ++(0);};
-   inline bool end() const {return Owner == 0 || Desc == Owner->DescP?true:false;};
-   inline void operator =(const DescIterator &B) {Desc = B.Desc; Owner = B.Owner;};
-   
-   // Comparison
-   inline bool operator ==(const DescIterator &B) const {return Desc == B.Desc;};
-   inline bool operator !=(const DescIterator &B) const {return Desc != B.Desc;};
-   int CompareDesc(const DescIterator &B) const;
-   
-   // Accessors
-   inline Description *operator ->() {return Desc;};
-   inline Description const *operator ->() const {return Desc;};
-   inline Description &operator *() {return *Desc;};
-   inline Description const &operator *() const {return *Desc;};
-   inline operator Description *() {return Desc == Owner->DescP?0:Desc;};
-   inline operator Description const *() const {return Desc == Owner->DescP?0:Desc;};
-   inline pkgCache *Cache() {return Owner;};
-      
-   inline const char *LanguageCode() const {return Owner->StrP + Desc->language_code;};
-   inline const char *md5() const {return Owner->StrP + Desc->md5sum;};
-   inline DescFileIterator FileList() const;
-   inline unsigned long Index() const {return Desc - Owner->DescP;};
-
-   inline DescIterator() : Desc(0), Owner(0) {};   
-   inline DescIterator(pkgCache &Owner,Description *Trg = 0) : Desc(Trg), 
-              Owner(&Owner) 
-   { 
-      if (Desc == 0)
-	 Desc = Owner.DescP;
-   };
+class pkgCache::DescIterator : public Iterator<Description, DescIterator> {
+	protected:
+	inline Description* OwnerPointer() const {
+		return Owner->DescP;
+	};
+
+	public:
+	// Iteration
+	void operator ++(int) {if (S != Owner->DescP) S = Owner->DescP + S->NextDesc;};
+	inline void operator ++() {operator ++(0);};
+
+	// Comparison
+	int CompareDesc(const DescIterator &B) const;
+
+	// Accessors
+	inline const char *LanguageCode() const {return Owner->StrP + S->language_code;};
+	inline const char *md5() const {return Owner->StrP + S->md5sum;};
+	inline DescFileIterator FileList() const;
+
+	inline DescIterator() : Iterator<Description, DescIterator>() {};
+	inline DescIterator(pkgCache &Owner,Description *Trg = 0) : Iterator<Description, DescIterator>(Owner, Trg) {
+		if (S == 0)
+			S = Owner.DescP;
+	};
 };
 };
 									/*}}}*/
 									/*}}}*/
 // Dependency iterator							/*{{{*/
 // Dependency iterator							/*{{{*/
-class pkgCache::DepIterator
-{
-   Dependency *Dep;
-   enum {DepVer, DepRev} Type;
-   pkgCache *Owner;
-   
-   void _dummy();
-   
-   public:
-
-   // Iteration
-   void operator ++(int) {if (Dep != Owner->DepP) Dep = Owner->DepP +
-	(Type == DepVer?Dep->NextDepends:Dep->NextRevDepends);};
-   inline void operator ++() {operator ++(0);};
-   inline bool end() const {return Owner == 0 || Dep == Owner->DepP?true:false;};
-   
-   // Comparison
-   inline bool operator ==(const DepIterator &B) const {return Dep == B.Dep;};
-   inline bool operator !=(const DepIterator &B) const {return Dep != B.Dep;};
-
-   // Accessors
-   inline Dependency *operator ->() {return Dep;};
-   inline Dependency const *operator ->() const {return Dep;};
-   inline Dependency &operator *() {return *Dep;};
-   inline Dependency const &operator *() const {return *Dep;};
-   inline operator Dependency *() {return Dep == Owner->DepP?0:Dep;};
-   inline operator Dependency const *() const {return Dep == Owner->DepP?0:Dep;};
-   inline pkgCache *Cache() {return Owner;};
-   
-   inline const char *TargetVer() const {return Dep->Version == 0?0:Owner->StrP + Dep->Version;};
-   inline PkgIterator TargetPkg() {return PkgIterator(*Owner,Owner->PkgP + Dep->Package);};
-   inline PkgIterator SmartTargetPkg() {PkgIterator R(*Owner,0);SmartTargetPkg(R);return R;};
-   inline VerIterator ParentVer() {return VerIterator(*Owner,Owner->VerP + Dep->ParentVer);};
-   inline PkgIterator ParentPkg() {return PkgIterator(*Owner,Owner->PkgP + Owner->VerP[Dep->ParentVer].ParentPkg);};
-   inline bool Reverse() {return Type == DepRev;};
-   inline unsigned long Index() const {return Dep - Owner->DepP;};
-   bool IsCritical();
-   void GlobOr(DepIterator &Start,DepIterator &End);
-   Version **AllTargets();   
-   bool SmartTargetPkg(PkgIterator &Result);
-   inline const char *CompType() {return Owner->CompType(Dep->CompareOp);};
-   inline const char *DepType() {return Owner->DepType(Dep->Type);};
-   
-   inline DepIterator(pkgCache &Owner,Dependency *Trg,Version * = 0) :
-          Dep(Trg), Type(DepVer), Owner(&Owner) 
-   {
-      if (Dep == 0)
-	 Dep = Owner.DepP;
-   };
-   inline DepIterator(pkgCache &Owner,Dependency *Trg,Package *) :
-          Dep(Trg), Type(DepRev), Owner(&Owner)
-   {
-      if (Dep == 0)
-	 Dep = Owner.DepP;
-   };
-   inline DepIterator() : Dep(0), Type(DepVer), Owner(0) {};
+class pkgCache::DepIterator : public Iterator<Dependency, DepIterator> {
+	enum {DepVer, DepRev} Type;
+
+	protected:
+	inline Dependency* OwnerPointer() const {
+		return Owner->DepP;
+	};
+
+	public:
+	// Iteration
+	void operator ++(int) {if (S != Owner->DepP) S = Owner->DepP +
+		(Type == DepVer ? S->NextDepends : S->NextRevDepends);};
+	inline void operator ++() {operator ++(0);};
+
+	// Accessors
+	inline const char *TargetVer() const {return S->Version == 0?0:Owner->StrP + S->Version;};
+	inline PkgIterator TargetPkg() const {return PkgIterator(*Owner,Owner->PkgP + S->Package);};
+	inline PkgIterator SmartTargetPkg() const {PkgIterator R(*Owner,0);SmartTargetPkg(R);return R;};
+	inline VerIterator ParentVer() const {return VerIterator(*Owner,Owner->VerP + S->ParentVer);};
+	inline PkgIterator ParentPkg() const {return PkgIterator(*Owner,Owner->PkgP + Owner->VerP[S->ParentVer].ParentPkg);};
+	inline bool Reverse() const {return Type == DepRev;};
+	bool IsCritical() const;
+	void GlobOr(DepIterator &Start,DepIterator &End);
+	Version **AllTargets() const;
+	bool SmartTargetPkg(PkgIterator &Result) const;
+	inline const char *CompType() const {return Owner->CompType(S->CompareOp);};
+	inline const char *DepType() const {return Owner->DepType(S->Type);};
+
+	inline DepIterator(pkgCache &Owner, Dependency *Trg, Version* = 0) :
+		Iterator<Dependency, DepIterator>(Owner, Trg), Type(DepVer) {
+		if (S == 0)
+			S = Owner.DepP;
+	};
+	inline DepIterator(pkgCache &Owner, Dependency *Trg, Package*) :
+		Iterator<Dependency, DepIterator>(Owner, Trg), Type(DepRev) {
+		if (S == 0)
+			S = Owner.DepP;
+	};
+	inline DepIterator() : Iterator<Dependency, DepIterator>(), Type(DepVer) {};
 };
 };
 									/*}}}*/
 									/*}}}*/
 // Provides iterator							/*{{{*/
 // Provides iterator							/*{{{*/
-class pkgCache::PrvIterator
-{
-   Provides *Prv;
-   enum {PrvVer, PrvPkg} Type;
-   pkgCache *Owner;
-   
-   void _dummy();
-   
-   public:
-
-   // Iteration
-   void operator ++(int) {if (Prv != Owner->ProvideP) Prv = Owner->ProvideP +
-	(Type == PrvVer?Prv->NextPkgProv:Prv->NextProvides);};
-   inline void operator ++() {operator ++(0);};
-   inline bool end() const {return Owner == 0 || Prv == Owner->ProvideP?true:false;};
-   
-   // Comparison
-   inline bool operator ==(const PrvIterator &B) const {return Prv == B.Prv;};
-   inline bool operator !=(const PrvIterator &B) const {return Prv != B.Prv;};
-
-   // Accessors
-   inline Provides *operator ->() {return Prv;};
-   inline Provides const *operator ->() const {return Prv;};
-   inline Provides &operator *() {return *Prv;};
-   inline Provides const &operator *() const {return *Prv;};
-   inline operator Provides *() {return Prv == Owner->ProvideP?0:Prv;};
-   inline operator Provides const *() const {return Prv == Owner->ProvideP?0:Prv;};
-   inline pkgCache *Cache() {return Owner;};
-
-   inline const char *Name() const {return Owner->StrP + Owner->PkgP[Prv->ParentPkg].Name;};
-   inline const char *ProvideVersion() const {return Prv->ProvideVersion == 0?0:Owner->StrP + Prv->ProvideVersion;};
-   inline PkgIterator ParentPkg() {return PkgIterator(*Owner,Owner->PkgP + Prv->ParentPkg);};
-   inline VerIterator OwnerVer() {return VerIterator(*Owner,Owner->VerP + Prv->Version);};
-   inline PkgIterator OwnerPkg() {return PkgIterator(*Owner,Owner->PkgP + Owner->VerP[Prv->Version].ParentPkg);};
-   inline unsigned long Index() const {return Prv - Owner->ProvideP;};
-
-   inline PrvIterator() : Prv(0), Type(PrvVer), Owner(0)  {};
-
-   inline PrvIterator(pkgCache &Owner,Provides *Trg,Version *) :
-          Prv(Trg), Type(PrvVer), Owner(&Owner) 
-   {
-      if (Prv == 0)
-	 Prv = Owner.ProvideP;
-   };
-   inline PrvIterator(pkgCache &Owner,Provides *Trg,Package *) : 
-          Prv(Trg), Type(PrvPkg), Owner(&Owner)
-   {
-      if (Prv == 0)
-	 Prv = Owner.ProvideP;
-   };
+class pkgCache::PrvIterator : public Iterator<Provides, PrvIterator> {
+	enum {PrvVer, PrvPkg} Type;
+
+	protected:
+	inline Provides* OwnerPointer() const {
+		return Owner->ProvideP;
+	};
+
+	public:
+	// Iteration
+	void operator ++(int) {if (S != Owner->ProvideP) S = Owner->ProvideP +
+		(Type == PrvVer?S->NextPkgProv:S->NextProvides);};
+	inline void operator ++() {operator ++(0);};
+
+	// Accessors
+	inline const char *Name() const {return Owner->StrP + Owner->PkgP[S->ParentPkg].Name;};
+	inline const char *ProvideVersion() const {return S->ProvideVersion == 0?0:Owner->StrP + S->ProvideVersion;};
+	inline PkgIterator ParentPkg() const {return PkgIterator(*Owner,Owner->PkgP + S->ParentPkg);};
+	inline VerIterator OwnerVer() const {return VerIterator(*Owner,Owner->VerP + S->Version);};
+	inline PkgIterator OwnerPkg() const {return PkgIterator(*Owner,Owner->PkgP + Owner->VerP[S->Version].ParentPkg);};
+
+	inline PrvIterator() : Iterator<Provides, PrvIterator>(), Type(PrvVer) {};
+
+	inline PrvIterator(pkgCache &Owner, Provides *Trg, Version*) :
+		Iterator<Provides, PrvIterator>(Owner, Trg), Type(PrvVer) {
+		if (S == 0)
+			S = Owner.ProvideP;
+	};
+	inline PrvIterator(pkgCache &Owner, Provides *Trg, Package*) :
+		Iterator<Provides, PrvIterator>(Owner, Trg), Type(PrvPkg) {
+		if (S == 0)
+			S = Owner.ProvideP;
+	};
 };
 };
 									/*}}}*/
 									/*}}}*/
 // Package file								/*{{{*/
 // Package file								/*{{{*/
-class pkgCache::PkgFileIterator
-{
-   pkgCache *Owner;
-   PackageFile *File;
-
-   public:
-
-   // Iteration
-   void operator ++(int) {if (File!= Owner->PkgFileP) File = Owner->PkgFileP + File->NextFile;};
-   inline void operator ++() {operator ++(0);};
-   inline bool end() const {return Owner == 0 || File == Owner->PkgFileP?true:false;};
-
-   // Comparison
-   inline bool operator ==(const PkgFileIterator &B) const {return File == B.File;};
-   inline bool operator !=(const PkgFileIterator &B) const {return File != B.File;};
-			   
-   // Accessors
-   inline PackageFile *operator ->() {return File;};
-   inline PackageFile const *operator ->() const {return File;};
-   inline PackageFile const &operator *() const {return *File;};
-   inline operator PackageFile *() {return File == Owner->PkgFileP?0:File;};
-   inline operator PackageFile const *() const {return File == Owner->PkgFileP?0:File;};
-   inline pkgCache *Cache() {return Owner;};
-
-   inline const char *FileName() const {return File->FileName == 0?0:Owner->StrP + File->FileName;};
-   inline const char *Archive() const {return File->Archive == 0?0:Owner->StrP + File->Archive;};
-   inline const char *Component() const {return File->Component == 0?0:Owner->StrP + File->Component;};
-   inline const char *Version() const {return File->Version == 0?0:Owner->StrP + File->Version;};
-   inline const char *Origin() const {return File->Origin == 0?0:Owner->StrP + File->Origin;};
-   inline const char *Codename() const {return File->Codename ==0?0:Owner->StrP + File->Codename;};
-   inline const char *Label() const {return File->Label == 0?0:Owner->StrP + File->Label;};
-   inline const char *Site() const {return File->Site == 0?0:Owner->StrP + File->Site;};
-   inline const char *Architecture() const {return File->Architecture == 0?0:Owner->StrP + File->Architecture;};
-   inline const char *IndexType() const {return File->IndexType == 0?0:Owner->StrP + File->IndexType;};
-
-   inline unsigned long Index() const {return File - Owner->PkgFileP;};
-
-   bool IsOk();
-   string RelStr();
-   
-   // Constructors
-   inline PkgFileIterator() : Owner(0), File(0) {};
-   inline PkgFileIterator(pkgCache &Owner) : Owner(&Owner), File(Owner.PkgFileP) {};
-   inline PkgFileIterator(pkgCache &Owner,PackageFile *Trg) : Owner(&Owner), File(Trg) {};
+class pkgCache::PkgFileIterator : public Iterator<PackageFile, PkgFileIterator> {
+	protected:
+	inline PackageFile* OwnerPointer() const {
+		return Owner->PkgFileP;
+	};
+
+	public:
+	// Iteration
+	void operator ++(int) {if (S != Owner->PkgFileP) S = Owner->PkgFileP + S->NextFile;};
+	inline void operator ++() {operator ++(0);};
+
+	// Accessors
+	inline const char *FileName() const {return S->FileName == 0?0:Owner->StrP + S->FileName;};
+	inline const char *Archive() const {return S->Archive == 0?0:Owner->StrP + S->Archive;};
+	inline const char *Component() const {return S->Component == 0?0:Owner->StrP + S->Component;};
+	inline const char *Version() const {return S->Version == 0?0:Owner->StrP + S->Version;};
+	inline const char *Origin() const {return S->Origin == 0?0:Owner->StrP + S->Origin;};
+	inline const char *Codename() const {return S->Codename ==0?0:Owner->StrP + S->Codename;};
+	inline const char *Label() const {return S->Label == 0?0:Owner->StrP + S->Label;};
+	inline const char *Site() const {return S->Site == 0?0:Owner->StrP + S->Site;};
+	inline const char *Architecture() const {return S->Architecture == 0?0:Owner->StrP + S->Architecture;};
+	inline const char *IndexType() const {return S->IndexType == 0?0:Owner->StrP + S->IndexType;};
+
+	bool IsOk();
+	string RelStr();
+
+	// Constructors
+	inline PkgFileIterator() : Iterator<PackageFile, PkgFileIterator>() {};
+	inline PkgFileIterator(pkgCache &Owner) : Iterator<PackageFile, PkgFileIterator>(Owner, Owner.PkgFileP) {};
+	inline PkgFileIterator(pkgCache &Owner,PackageFile *Trg) : Iterator<PackageFile, PkgFileIterator>(Owner, Trg) {};
 };
 };
 									/*}}}*/
 									/*}}}*/
 // Version File								/*{{{*/
 // Version File								/*{{{*/
-class pkgCache::VerFileIterator
-{
-   pkgCache *Owner;
-   VerFile *FileP;
-
-   public:
-
-   // Iteration
-   void operator ++(int) {if (FileP != Owner->VerFileP) FileP = Owner->VerFileP + FileP->NextFile;};
-   inline void operator ++() {operator ++(0);};
-   inline bool end() const {return Owner == 0 || FileP == Owner->VerFileP?true:false;};
-
-   // Comparison
-   inline bool operator ==(const VerFileIterator &B) const {return FileP == B.FileP;};
-   inline bool operator !=(const VerFileIterator &B) const {return FileP != B.FileP;};
-			   
-   // Accessors
-   inline VerFile *operator ->() {return FileP;};
-   inline VerFile const *operator ->() const {return FileP;};
-   inline VerFile const &operator *() const {return *FileP;};
-   inline operator VerFile *() {return FileP == Owner->VerFileP?0:FileP;};
-   inline operator VerFile const *() const {return FileP == Owner->VerFileP?0:FileP;};
-   inline pkgCache *Cache() {return Owner;};
-  
-   inline PkgFileIterator File() const {return PkgFileIterator(*Owner,FileP->File + Owner->PkgFileP);};
-   inline unsigned long Index() const {return FileP - Owner->VerFileP;};
-      
-   inline VerFileIterator() : Owner(0), FileP(0) {};
-   inline VerFileIterator(pkgCache &Owner,VerFile *Trg) : Owner(&Owner), FileP(Trg) {};
+class pkgCache::VerFileIterator : public pkgCache::Iterator<VerFile, VerFileIterator> {
+	protected:
+	inline VerFile* OwnerPointer() const {
+		return Owner->VerFileP;
+	};
+
+	public:
+	// Iteration
+	void operator ++(int) {if (S != Owner->VerFileP) S = Owner->VerFileP + S->NextFile;};
+	inline void operator ++() {operator ++(0);};
+
+	// Accessors
+	inline PkgFileIterator File() const {return PkgFileIterator(*Owner,S->File + Owner->PkgFileP);};
+
+	inline VerFileIterator() : Iterator<VerFile, VerFileIterator>() {};
+	inline VerFileIterator(pkgCache &Owner,VerFile *Trg) : Iterator<VerFile, VerFileIterator>(Owner, Trg) {};
 };
 };
 									/*}}}*/
 									/*}}}*/
 // Description File							/*{{{*/
 // Description File							/*{{{*/
-class pkgCache::DescFileIterator
-{
-   pkgCache *Owner;
-   DescFile *FileP;
-
-   public:
-
-   // Iteration
-   void operator ++(int) {if (FileP != Owner->DescFileP) FileP = Owner->DescFileP + FileP->NextFile;};
-   inline void operator ++() {operator ++(0);};
-   inline bool end() const {return Owner == 0 ||  FileP == Owner->DescFileP?true:false;};
-
-   // Comparison
-   inline bool operator ==(const DescFileIterator &B) const {return FileP == B.FileP;};
-   inline bool operator !=(const DescFileIterator &B) const {return FileP != B.FileP;};
-			   
-   // Accessors
-   inline DescFile *operator ->() {return FileP;};
-   inline DescFile const *operator ->() const {return FileP;};
-   inline DescFile const &operator *() const {return *FileP;};
-   inline operator DescFile *() {return FileP == Owner->DescFileP?0:FileP;};
-   inline operator DescFile const *() const {return FileP == Owner->DescFileP?0:FileP;};
-   inline pkgCache *Cache() {return Owner;};
-  
-   inline PkgFileIterator File() const {return PkgFileIterator(*Owner,FileP->File + Owner->PkgFileP);};
-   inline unsigned long Index() const {return FileP - Owner->DescFileP;};
-      
-   inline DescFileIterator() : Owner(0), FileP(0) {};
-   inline DescFileIterator(pkgCache &Owner,DescFile *Trg) : Owner(&Owner), FileP(Trg) {};
+class pkgCache::DescFileIterator : public Iterator<DescFile, DescFileIterator> {
+	protected:
+	inline DescFile* OwnerPointer() const {
+		return Owner->DescFileP;
+	};
+
+	public:
+	// Iteration
+	void operator ++(int) {if (S != Owner->DescFileP) S = Owner->DescFileP + S->NextFile;};
+	inline void operator ++() {operator ++(0);};
+
+	// Accessors
+	inline PkgFileIterator File() const {return PkgFileIterator(*Owner,S->File + Owner->PkgFileP);};
+
+	inline DescFileIterator() : Iterator<DescFile, DescFileIterator>() {};
+	inline DescFileIterator(pkgCache &Owner,DescFile *Trg) : Iterator<DescFile, DescFileIterator>(Owner, Trg) {};
 };
 };
 									/*}}}*/
 									/*}}}*/
 // Inlined Begin functions cant be in the class because of order problems /*{{{*/
 // Inlined Begin functions cant be in the class because of order problems /*{{{*/
+inline pkgCache::PkgIterator pkgCache::GrpIterator::PackageList() const
+       {return PkgIterator(*Owner,Owner->PkgP + S->FirstPackage);};
 inline pkgCache::VerIterator pkgCache::PkgIterator::VersionList() const
 inline pkgCache::VerIterator pkgCache::PkgIterator::VersionList() const
-       {return VerIterator(*Owner,Owner->VerP + Pkg->VersionList);};
+       {return VerIterator(*Owner,Owner->VerP + S->VersionList);};
 inline pkgCache::VerIterator pkgCache::PkgIterator::CurrentVer() const
 inline pkgCache::VerIterator pkgCache::PkgIterator::CurrentVer() const
-       {return VerIterator(*Owner,Owner->VerP + Pkg->CurrentVer);};
+       {return VerIterator(*Owner,Owner->VerP + S->CurrentVer);};
 inline pkgCache::DepIterator pkgCache::PkgIterator::RevDependsList() const
 inline pkgCache::DepIterator pkgCache::PkgIterator::RevDependsList() const
-       {return DepIterator(*Owner,Owner->DepP + Pkg->RevDepends,Pkg);};
+       {return DepIterator(*Owner,Owner->DepP + S->RevDepends,S);};
 inline pkgCache::PrvIterator pkgCache::PkgIterator::ProvidesList() const
 inline pkgCache::PrvIterator pkgCache::PkgIterator::ProvidesList() const
-       {return PrvIterator(*Owner,Owner->ProvideP + Pkg->ProvidesList,Pkg);};
+       {return PrvIterator(*Owner,Owner->ProvideP + S->ProvidesList,S);};
 inline pkgCache::DescIterator pkgCache::VerIterator::DescriptionList() const
 inline pkgCache::DescIterator pkgCache::VerIterator::DescriptionList() const
-       {return DescIterator(*Owner,Owner->DescP + Ver->DescriptionList);};
+       {return DescIterator(*Owner,Owner->DescP + S->DescriptionList);};
 inline pkgCache::PrvIterator pkgCache::VerIterator::ProvidesList() const
 inline pkgCache::PrvIterator pkgCache::VerIterator::ProvidesList() const
-       {return PrvIterator(*Owner,Owner->ProvideP + Ver->ProvidesList,Ver);};
+       {return PrvIterator(*Owner,Owner->ProvideP + S->ProvidesList,S);};
 inline pkgCache::DepIterator pkgCache::VerIterator::DependsList() const
 inline pkgCache::DepIterator pkgCache::VerIterator::DependsList() const
-       {return DepIterator(*Owner,Owner->DepP + Ver->DependsList,Ver);};
+       {return DepIterator(*Owner,Owner->DepP + S->DependsList,S);};
 inline pkgCache::VerFileIterator pkgCache::VerIterator::FileList() const
 inline pkgCache::VerFileIterator pkgCache::VerIterator::FileList() const
-       {return VerFileIterator(*Owner,Owner->VerFileP + Ver->FileList);};
+       {return VerFileIterator(*Owner,Owner->VerFileP + S->FileList);};
 inline pkgCache::DescFileIterator pkgCache::DescIterator::FileList() const
 inline pkgCache::DescFileIterator pkgCache::DescIterator::FileList() const
-       {return DescFileIterator(*Owner,Owner->DescFileP + Desc->FileList);};
+       {return DescFileIterator(*Owner,Owner->DescFileP + S->FileList);};
 									/*}}}*/
 									/*}}}*/
 #endif
 #endif

+ 511 - 0
apt-pkg/cacheset.cc

@@ -0,0 +1,511 @@
+// -*- 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/cachefilter.h>
+#include <apt-pkg/cacheset.h>
+#include <apt-pkg/error.h>
+#include <apt-pkg/strutl.h>
+#include <apt-pkg/versionmatch.h>
+
+#include <apti18n.h>
+
+#include <vector>
+
+#include <regex.h>
+									/*}}}*/
+namespace APT {
+// FromTask - Return all packages in the cache from a specific task	/*{{{*/
+PackageSet PackageSet::FromTask(pkgCacheFile &Cache, std::string pattern, CacheSetHelper &helper) {
+	size_t const archfound = pattern.find_last_of(':');
+	std::string arch = "native";
+	if (archfound != std::string::npos) {
+		arch = pattern.substr(archfound+1);
+		pattern.erase(archfound);
+	}
+
+	if (pattern[pattern.length() -1] != '^')
+		return APT::PackageSet(TASK);
+	pattern.erase(pattern.length()-1);
+
+	if (unlikely(Cache.GetPkgCache() == 0 || Cache.GetDepCache() == 0))
+		return APT::PackageSet(TASK);
+
+	PackageSet pkgset(TASK);
+	// get the records
+	pkgRecords Recs(Cache);
+
+	// build regexp for the task
+	regex_t Pattern;
+	char S[300];
+	snprintf(S, sizeof(S), "^Task:.*[, ]%s([, ]|$)", pattern.c_str());
+	if(regcomp(&Pattern,S, REG_EXTENDED | REG_NOSUB | REG_NEWLINE) != 0) {
+		_error->Error("Failed to compile task regexp");
+		return pkgset;
+	}
+
+	for (pkgCache::GrpIterator Grp = Cache->GrpBegin(); Grp.end() == false; ++Grp) {
+		pkgCache::PkgIterator Pkg = Grp.FindPkg(arch);
+		if (Pkg.end() == true)
+			continue;
+		pkgCache::VerIterator ver = Cache[Pkg].CandidateVerIter(Cache);
+		if(ver.end() == true)
+			continue;
+
+		pkgRecords::Parser &parser = Recs.Lookup(ver.FileList());
+		const char *start, *end;
+		parser.GetRec(start,end);
+		unsigned int const length = end - start;
+		char buf[length];
+		strncpy(buf, start, length);
+		buf[length-1] = '\0';
+		if (regexec(&Pattern, buf, 0, 0, 0) != 0)
+			continue;
+
+		pkgset.insert(Pkg);
+	}
+	regfree(&Pattern);
+
+	if (pkgset.empty() == true)
+		return helper.canNotFindTask(Cache, pattern);
+
+	helper.showTaskSelection(pkgset, pattern);
+	return pkgset;
+}
+									/*}}}*/
+// FromRegEx - Return all packages in the cache matching a pattern	/*{{{*/
+PackageSet PackageSet::FromRegEx(pkgCacheFile &Cache, std::string pattern, CacheSetHelper &helper) {
+	static const char * const isregex = ".?+*|[^$";
+	if (pattern.find_first_of(isregex) == std::string::npos)
+		return PackageSet(REGEX);
+
+	size_t archfound = pattern.find_last_of(':');
+	std::string arch = "native";
+	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";
+	}
+
+	if (unlikely(Cache.GetPkgCache() == 0))
+		return PackageSet(REGEX);
+
+	APT::CacheFilter::PackageNameMatchesRegEx regexfilter(pattern);
+
+	PackageSet pkgset(REGEX);
+	for (pkgCache::GrpIterator Grp = Cache.GetPkgCache()->GrpBegin(); Grp.end() == false; ++Grp) {
+		if (regexfilter(Grp) == false)
+			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;
+		}
+
+		pkgset.insert(Pkg);
+	}
+
+	if (pkgset.empty() == true)
+		return helper.canNotFindRegEx(Cache, pattern);
+
+	helper.showRegExSelection(pkgset, pattern);
+	return pkgset;
+}
+									/*}}}*/
+// FromName - Returns the package defined  by this string		/*{{{*/
+pkgCache::PkgIterator PackageSet::FromName(pkgCacheFile &Cache,
+			std::string const &str, CacheSetHelper &helper) {
+	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);
+	}
+
+	if (Cache.GetPkgCache() == 0)
+		return pkgCache::PkgIterator(Cache, 0);
+
+	pkgCache::PkgIterator Pkg(Cache, 0);
+	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() == true)
+		return helper.canNotFindPkgName(Cache, str);
+	return Pkg;
+}
+									/*}}}*/
+// 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, CacheSetHelper &helper) {
+	std::map<unsigned short, PackageSet> pkgsets;
+	for (const char **I = cmdline; *I != 0; ++I) {
+		unsigned short modID = fallback;
+		std::string str = *I;
+		bool modifierPresent = false;
+		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;
+			}
+			modifierPresent = true;
+			break;
+		}
+		if (modifierPresent == true) {
+			bool const errors = helper.showErrors(false);
+			pkgCache::PkgIterator Pkg = FromName(Cache, *I, helper);
+			helper.showErrors(errors);
+			if (Pkg.end() == false) {
+				pkgsets[fallback].insert(Pkg);
+				continue;
+			}
+		}
+		pkgsets[modID].insert(PackageSet::FromString(Cache, str, helper));
+	}
+	return pkgsets;
+}
+									/*}}}*/
+// FromCommandLine - Return all packages specified on commandline	/*{{{*/
+PackageSet PackageSet::FromCommandLine(pkgCacheFile &Cache, const char **cmdline, CacheSetHelper &helper) {
+	PackageSet pkgset;
+	for (const char **I = cmdline; *I != 0; ++I) {
+		PackageSet pset = FromString(Cache, *I, helper);
+		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, CacheSetHelper &helper) {
+	_error->PushToStack();
+
+	PackageSet pkgset;
+	pkgCache::PkgIterator Pkg = FromName(Cache, str, helper);
+	if (Pkg.end() == false)
+		pkgset.insert(Pkg);
+	else {
+		pkgset = FromTask(Cache, str, helper);
+		if (pkgset.empty() == true) {
+			pkgset = FromRegEx(Cache, str, helper);
+			if (pkgset.empty() == true)
+				pkgset = helper.canNotFindPackage(Cache, str);
+		}
+	}
+
+	if (pkgset.empty() == false)
+		_error->RevertToStack();
+	else
+		_error->MergeWithStack();
+	return pkgset;
+}
+									/*}}}*/
+// GroupedFromCommandLine - Return all versions specified on commandline/*{{{*/
+std::map<unsigned short, VersionSet> VersionSet::GroupedFromCommandLine(
+		pkgCacheFile &Cache, const char **cmdline,
+		std::list<VersionSet::Modifier> const &mods,
+		unsigned short const &fallback, CacheSetHelper &helper) {
+	std::map<unsigned short, VersionSet> versets;
+	for (const char **I = cmdline; *I != 0; ++I) {
+		unsigned short modID = fallback;
+		VersionSet::Version select = VersionSet::NEWEST;
+		std::string str = *I;
+		bool modifierPresent = false;
+		for (std::list<VersionSet::Modifier>::const_iterator mod = mods.begin();
+		     mod != mods.end(); ++mod) {
+			if (modID == fallback && mod->ID == fallback)
+				select = mod->SelectVersion;
+			size_t const alength = strlen(mod->Alias);
+			switch(mod->Pos) {
+			case VersionSet::Modifier::POSTFIX:
+				if (str.compare(str.length() - alength, alength,
+						mod->Alias, 0, alength) != 0)
+					continue;
+				str.erase(str.length() - alength);
+				modID = mod->ID;
+				select = mod->SelectVersion;
+				break;
+			case VersionSet::Modifier::PREFIX:
+				continue;
+			case VersionSet::Modifier::NONE:
+				continue;
+			}
+			modifierPresent = true;
+			break;
+		}
+
+		if (modifierPresent == true) {
+			bool const errors = helper.showErrors(false);
+			VersionSet const vset = VersionSet::FromString(Cache, std::string(*I), select, helper, true);
+			helper.showErrors(errors);
+			if (vset.empty() == false) {
+				versets[fallback].insert(vset);
+				continue;
+			}
+		}
+		versets[modID].insert(VersionSet::FromString(Cache, str, select , helper));
+	}
+	return versets;
+}
+									/*}}}*/
+// FromCommandLine - Return all versions specified on commandline	/*{{{*/
+APT::VersionSet VersionSet::FromCommandLine(pkgCacheFile &Cache, const char **cmdline,
+		APT::VersionSet::Version const &fallback, CacheSetHelper &helper) {
+	VersionSet verset;
+	for (const char **I = cmdline; *I != 0; ++I)
+		verset.insert(VersionSet::FromString(Cache, *I, fallback, helper));
+	return verset;
+}
+									/*}}}*/
+// FromString - Returns all versions spedcified by a string		/*{{{*/
+APT::VersionSet VersionSet::FromString(pkgCacheFile &Cache, std::string pkg,
+		APT::VersionSet::Version const &fallback, CacheSetHelper &helper,
+		bool const &onlyFromName) {
+	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;
+	if (onlyFromName == false)
+		pkgset = PackageSet::FromString(Cache, pkg, helper);
+	else {
+		pkgset.insert(PackageSet::FromName(Cache, pkg, helper));
+	}
+
+	VersionSet verset;
+	bool errors = true;
+	if (pkgset.getConstructor() != PackageSet::UNKNOWN)
+		errors = helper.showErrors(false);
+	for (PackageSet::const_iterator P = pkgset.begin();
+	     P != pkgset.end(); ++P) {
+		if (vertag == string::npos) {
+			verset.insert(VersionSet::FromPackage(Cache, P, fallback, helper));
+			continue;
+		}
+		pkgCache::VerIterator V;
+		if (ver == "installed")
+			V = getInstalledVer(Cache, P, helper);
+		else if (ver == "candidate")
+			V = getCandidateVer(Cache, P, helper);
+		else if (ver == "newest") {
+			if (P->VersionList != 0)
+				V = P.VersionList();
+			else
+				V = helper.canNotFindNewestVer(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;
+		helper.showSelectedVersion(P, V, ver, verIsRel);
+		verset.insert(V);
+	}
+	if (pkgset.getConstructor() != PackageSet::UNKNOWN)
+		helper.showErrors(errors);
+	return verset;
+}
+									/*}}}*/
+// FromPackage - versions from package based on fallback		/*{{{*/
+VersionSet VersionSet::FromPackage(pkgCacheFile &Cache, pkgCache::PkgIterator const &P,
+		VersionSet::Version const &fallback, CacheSetHelper &helper) {
+	VersionSet verset;
+	pkgCache::VerIterator V;
+	bool showErrors;
+	switch(fallback) {
+	case VersionSet::ALL:
+		if (P->VersionList != 0)
+			for (V = P.VersionList(); V.end() != true; ++V)
+				verset.insert(V);
+		else
+			verset.insert(helper.canNotFindAllVer(Cache, P));
+		break;
+	case VersionSet::CANDANDINST:
+		verset.insert(getInstalledVer(Cache, P, helper));
+		verset.insert(getCandidateVer(Cache, P, helper));
+		break;
+	case VersionSet::CANDIDATE:
+		verset.insert(getCandidateVer(Cache, P, helper));
+		break;
+	case VersionSet::INSTALLED:
+		verset.insert(getInstalledVer(Cache, P, helper));
+		break;
+	case VersionSet::CANDINST:
+		showErrors = helper.showErrors(false);
+		V = getCandidateVer(Cache, P, helper);
+		if (V.end() == true)
+			V = getInstalledVer(Cache, P, helper);
+		helper.showErrors(showErrors);
+		if (V.end() == false)
+			verset.insert(V);
+		else
+			verset.insert(helper.canNotFindInstCandVer(Cache, P));
+		break;
+	case VersionSet::INSTCAND:
+		showErrors = helper.showErrors(false);
+		V = getInstalledVer(Cache, P, helper);
+		if (V.end() == true)
+			V = getCandidateVer(Cache, P, helper);
+		helper.showErrors(showErrors);
+		if (V.end() == false)
+			verset.insert(V);
+		else
+			verset.insert(helper.canNotFindInstCandVer(Cache, P));
+		break;
+	case VersionSet::NEWEST:
+		if (P->VersionList != 0)
+			verset.insert(P.VersionList());
+		else
+			verset.insert(helper.canNotFindNewestVer(Cache, P));
+		break;
+	}
+	return verset;
+}
+									/*}}}*/
+// getCandidateVer - Returns the candidate version of the given package	/*{{{*/
+pkgCache::VerIterator VersionSet::getCandidateVer(pkgCacheFile &Cache,
+		pkgCache::PkgIterator const &Pkg, CacheSetHelper &helper) {
+	pkgCache::VerIterator Cand;
+	if (Cache.IsPolicyBuilt() == true || Cache.IsDepCacheBuilt() == false)
+	{
+		if (unlikely(Cache.GetPolicy() == 0))
+			return pkgCache::VerIterator(Cache);
+		Cand = Cache.GetPolicy()->GetCandidateVer(Pkg);
+	} else {
+		Cand = Cache[Pkg].CandidateVerIter(Cache);
+	}
+	if (Cand.end() == true)
+		return helper.canNotFindCandidateVer(Cache, Pkg);
+	return Cand;
+}
+									/*}}}*/
+// getInstalledVer - Returns the installed version of the given package	/*{{{*/
+pkgCache::VerIterator VersionSet::getInstalledVer(pkgCacheFile &Cache,
+		pkgCache::PkgIterator const &Pkg, CacheSetHelper &helper) {
+	if (Pkg->CurrentVer == 0)
+		return helper.canNotFindInstalledVer(Cache, Pkg);
+	return Pkg.CurrentVer();
+}
+									/*}}}*/
+// canNotFindPkgName - handle the case no package has this name		/*{{{*/
+pkgCache::PkgIterator CacheSetHelper::canNotFindPkgName(pkgCacheFile &Cache,
+			std::string const &str) {
+	if (ShowError == true)
+		_error->Insert(ErrorType, _("Unable to locate package %s"), str.c_str());
+	return pkgCache::PkgIterator(Cache, 0);
+}
+									/*}}}*/
+// canNotFindTask - handle the case no package is found for a task	/*{{{*/
+PackageSet CacheSetHelper::canNotFindTask(pkgCacheFile &Cache, std::string pattern) {
+	if (ShowError == true)
+		_error->Insert(ErrorType, _("Couldn't find task '%s'"), pattern.c_str());
+	return PackageSet();
+}
+									/*}}}*/
+// canNotFindRegEx - handle the case no package is found by a regex	/*{{{*/
+PackageSet CacheSetHelper::canNotFindRegEx(pkgCacheFile &Cache, std::string pattern) {
+	if (ShowError == true)
+		_error->Insert(ErrorType, _("Couldn't find any package by regex '%s'"), pattern.c_str());
+	return PackageSet();
+}
+									/*}}}*/
+// canNotFindPackage - handle the case no package is found from a string/*{{{*/
+PackageSet CacheSetHelper::canNotFindPackage(pkgCacheFile &Cache, std::string const &str) {
+	return PackageSet();
+}
+									/*}}}*/
+// canNotFindAllVer							/*{{{*/
+VersionSet CacheSetHelper::canNotFindAllVer(pkgCacheFile &Cache,
+		pkgCache::PkgIterator const &Pkg) {
+	if (ShowError == true)
+		_error->Insert(ErrorType, _("Can't select versions from package '%s' as it purely virtual"), Pkg.FullName(true).c_str());
+	return VersionSet();
+}
+									/*}}}*/
+// canNotFindInstCandVer						/*{{{*/
+VersionSet CacheSetHelper::canNotFindInstCandVer(pkgCacheFile &Cache,
+		pkgCache::PkgIterator const &Pkg) {
+	if (ShowError == true)
+		_error->Insert(ErrorType, _("Can't select installed nor candidate version from package '%s' as it has neither of them"), Pkg.FullName(true).c_str());
+	return VersionSet();
+}
+									/*}}}*/
+// canNotFindInstCandVer						/*{{{*/
+VersionSet CacheSetHelper::canNotFindCandInstVer(pkgCacheFile &Cache,
+		pkgCache::PkgIterator const &Pkg) {
+	if (ShowError == true)
+		_error->Insert(ErrorType, _("Can't select installed nor candidate version from package '%s' as it has neither of them"), Pkg.FullName(true).c_str());
+	return VersionSet();
+}
+									/*}}}*/
+// canNotFindNewestVer							/*{{{*/
+pkgCache::VerIterator CacheSetHelper::canNotFindNewestVer(pkgCacheFile &Cache,
+		pkgCache::PkgIterator const &Pkg) {
+	if (ShowError == true)
+		_error->Insert(ErrorType, _("Can't select newest version from package '%s' as it is purely virtual"), Pkg.FullName(true).c_str());
+	return pkgCache::VerIterator(Cache, 0);
+}
+									/*}}}*/
+// canNotFindCandidateVer						/*{{{*/
+pkgCache::VerIterator CacheSetHelper::canNotFindCandidateVer(pkgCacheFile &Cache,
+		pkgCache::PkgIterator const &Pkg) {
+	if (ShowError == true)
+		_error->Insert(ErrorType, _("Can't select candidate version from package %s as it has no candidate"), Pkg.FullName(true).c_str());
+	return pkgCache::VerIterator(Cache, 0);
+}
+									/*}}}*/
+// canNotFindInstalledVer						/*{{{*/
+pkgCache::VerIterator CacheSetHelper::canNotFindInstalledVer(pkgCacheFile &Cache,
+		pkgCache::PkgIterator const &Pkg) {
+	if (ShowError == true)
+		_error->Insert(ErrorType, _("Can't select installed version from package %s as it is not installed"), Pkg.FullName(true).c_str());
+	return pkgCache::VerIterator(Cache, 0);
+}
+									/*}}}*/
+}

+ 389 - 0
apt-pkg/cacheset.h

@@ -0,0 +1,389 @@
+// -*- 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;
+class VersionSet;
+class CacheSetHelper {							/*{{{*/
+/** \class APT::CacheSetHelper
+    Simple base class with a lot of virtual methods which can be overridden
+    to alter the behavior or the output of the CacheSets.
+
+    This helper is passed around by the static methods in the CacheSets and
+    used every time they hit an error condition or something could be
+    printed out.
+*/
+public:									/*{{{*/
+	CacheSetHelper(bool const &ShowError = true,
+		GlobalError::MsgType ErrorType = GlobalError::ERROR) :
+			ShowError(ShowError), ErrorType(ErrorType) {};
+	virtual ~CacheSetHelper() {};
+
+	virtual void showTaskSelection(PackageSet const &pkgset, string const &pattern) {};
+	virtual void showRegExSelection(PackageSet const &pkgset, string const &pattern) {};
+	virtual void showSelectedVersion(pkgCache::PkgIterator const &Pkg, pkgCache::VerIterator const Ver,
+				 string const &ver, bool const &verIsRel) {};
+
+	virtual pkgCache::PkgIterator canNotFindPkgName(pkgCacheFile &Cache, std::string const &str);
+	virtual PackageSet canNotFindTask(pkgCacheFile &Cache, std::string pattern);
+	virtual PackageSet canNotFindRegEx(pkgCacheFile &Cache, std::string pattern);
+	virtual PackageSet canNotFindPackage(pkgCacheFile &Cache, std::string const &str);
+	virtual VersionSet canNotFindAllVer(pkgCacheFile &Cache, pkgCache::PkgIterator const &Pkg);
+	virtual VersionSet canNotFindInstCandVer(pkgCacheFile &Cache,
+				pkgCache::PkgIterator const &Pkg);
+	virtual VersionSet canNotFindCandInstVer(pkgCacheFile &Cache,
+				pkgCache::PkgIterator const &Pkg);
+	virtual pkgCache::VerIterator canNotFindNewestVer(pkgCacheFile &Cache,
+				pkgCache::PkgIterator const &Pkg);
+	virtual pkgCache::VerIterator canNotFindCandidateVer(pkgCacheFile &Cache,
+				pkgCache::PkgIterator const &Pkg);
+	virtual pkgCache::VerIterator canNotFindInstalledVer(pkgCacheFile &Cache,
+				pkgCache::PkgIterator const &Pkg);
+
+	bool showErrors() const { return ShowError; };
+	bool showErrors(bool const &newValue) { if (ShowError == newValue) return ShowError; else return ((ShowError = newValue) == false); };
+	GlobalError::MsgType errorType() const { return ErrorType; };
+	GlobalError::MsgType errorType(GlobalError::MsgType const &newValue)
+	{
+		if (ErrorType == newValue) return ErrorType;
+		else {
+			GlobalError::MsgType const &oldValue = ErrorType;
+			ErrorType = newValue;
+			return oldValue;
+		}
+	};
+
+									/*}}}*/
+protected:
+	bool ShowError;
+	GlobalError::MsgType ErrorType;
+};									/*}}}*/
+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 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); };
+	inline void insert(PackageSet const &pkgset) { insert(pkgset.begin(), pkgset.end()); };
+
+	/** \brief returns all packages in the cache who belong to the given task
+
+	    A simple helper responsible for search for all members of a task
+	    in the cache. Optional it prints a a notice about the
+	    packages chosen cause of the given task.
+	    \param Cache the packages are in
+	    \param pattern name of the task
+	    \param helper responsible for error and message handling */
+	static APT::PackageSet FromTask(pkgCacheFile &Cache, std::string pattern, CacheSetHelper &helper);
+	static APT::PackageSet FromTask(pkgCacheFile &Cache, std::string const &pattern) {
+		CacheSetHelper helper;
+		return APT::PackageSet::FromTask(Cache, pattern, helper);
+	}
+
+	/** \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 helper responsible for error and message handling */
+	static APT::PackageSet FromRegEx(pkgCacheFile &Cache, std::string pattern, CacheSetHelper &helper);
+	static APT::PackageSet FromRegEx(pkgCacheFile &Cache, std::string const &pattern) {
+		CacheSetHelper helper;
+		return APT::PackageSet::FromRegEx(Cache, pattern, helper);
+	}
+
+	/** \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 helper responsible for error and message handling */
+	static APT::PackageSet FromString(pkgCacheFile &Cache, std::string const &string, CacheSetHelper &helper);
+	static APT::PackageSet FromString(pkgCacheFile &Cache, std::string const &string) {
+		CacheSetHelper helper;
+		return APT::PackageSet::FromString(Cache, string, helper);
+	}
+
+	/** \brief returns a package specified by a string
+
+	    \param Cache the package is in
+	    \param string String the package name should be extracted from
+	    \param helper responsible for error and message handling */
+	static pkgCache::PkgIterator FromName(pkgCacheFile &Cache, std::string const &string, CacheSetHelper &helper);
+	static pkgCache::PkgIterator FromName(pkgCacheFile &Cache, std::string const &string) {
+		CacheSetHelper helper;
+		return APT::PackageSet::FromName(Cache, string, helper);
+	}
+
+	/** \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 helper responsible for error and message handling */
+	static APT::PackageSet FromCommandLine(pkgCacheFile &Cache, const char **cmdline, CacheSetHelper &helper);
+	static APT::PackageSet FromCommandLine(pkgCacheFile &Cache, const char **cmdline) {
+		CacheSetHelper helper;
+		return APT::PackageSet::FromCommandLine(Cache, cmdline, helper);
+	}
+
+	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) {};
+	};
+
+	/** \brief group packages by a action modifiers
+
+	    At some point it is needed to get from the same commandline
+	    different package sets grouped by a modifier. Take
+		apt-get install apt awesome-
+	    as an example.
+	    \param Cache the packages are in
+	    \param cmdline Command line the package names should be extracted from
+	    \param mods list of modifiers the method should accept
+	    \param fallback the default modifier group for a package
+	    \param helper responsible for error and message handling */
+	static std::map<unsigned short, PackageSet> GroupedFromCommandLine(
+		pkgCacheFile &Cache, const char **cmdline,
+		std::list<PackageSet::Modifier> const &mods,
+		unsigned short const &fallback, CacheSetHelper &helper);
+	static std::map<unsigned short, PackageSet> GroupedFromCommandLine(
+		pkgCacheFile &Cache, const char **cmdline,
+		std::list<PackageSet::Modifier> const &mods,
+		unsigned short const &fallback) {
+		CacheSetHelper helper;
+		return APT::PackageSet::GroupedFromCommandLine(Cache, cmdline,
+				mods, fallback, helper);
+	}
+
+	enum Constructor { UNKNOWN, REGEX, TASK };
+	Constructor getConstructor() const { return ConstructedBy; };
+
+	PackageSet() : ConstructedBy(UNKNOWN) {};
+	PackageSet(Constructor const &by) : ConstructedBy(by) {};
+									/*}}}*/
+private:								/*{{{*/
+	Constructor ConstructedBy;
+									/*}}}*/
+};									/*}}}*/
+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 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); };
+	inline void insert(VersionSet const &verset) { insert(verset.begin(), verset.end()); };
+
+	/** \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 helper responsible for error and message handling */
+	static APT::VersionSet FromCommandLine(pkgCacheFile &Cache, const char **cmdline,
+			APT::VersionSet::Version const &fallback, CacheSetHelper &helper);
+	static APT::VersionSet FromCommandLine(pkgCacheFile &Cache, const char **cmdline,
+			APT::VersionSet::Version const &fallback) {
+		CacheSetHelper helper;
+		return APT::VersionSet::FromCommandLine(Cache, cmdline, fallback, helper);
+	}
+	static APT::VersionSet FromCommandLine(pkgCacheFile &Cache, const char **cmdline) {
+		return APT::VersionSet::FromCommandLine(Cache, cmdline, CANDINST);
+	}
+
+	static APT::VersionSet FromString(pkgCacheFile &Cache, std::string pkg,
+			APT::VersionSet::Version const &fallback, CacheSetHelper &helper,
+			bool const &onlyFromName = false);
+	static APT::VersionSet FromString(pkgCacheFile &Cache, std::string pkg,
+			APT::VersionSet::Version const &fallback) {
+		CacheSetHelper helper;
+		return APT::VersionSet::FromString(Cache, pkg, fallback, helper);
+	}
+	static APT::VersionSet FromString(pkgCacheFile &Cache, std::string pkg) {
+		return APT::VersionSet::FromString(Cache, pkg, CANDINST);
+	}
+
+	/** \brief returns all versions specified for the package
+
+	    \param Cache the package and versions are in
+	    \param P the package in question
+	    \param fallback the version(s) you want to get
+	    \param helper the helper used for display and error handling */
+	static APT::VersionSet FromPackage(pkgCacheFile &Cache, pkgCache::PkgIterator const &P,
+		VersionSet::Version const &fallback, CacheSetHelper &helper);
+	static APT::VersionSet FromPackage(pkgCacheFile &Cache, pkgCache::PkgIterator const &P,
+			APT::VersionSet::Version const &fallback) {
+		CacheSetHelper helper;
+		return APT::VersionSet::FromPackage(Cache, P, fallback, helper);
+	}
+	static APT::VersionSet FromPackage(pkgCacheFile &Cache, pkgCache::PkgIterator const &P) {
+		return APT::VersionSet::FromPackage(Cache, P, CANDINST);
+	}
+
+	struct Modifier {
+		enum Position { NONE, PREFIX, POSTFIX };
+		unsigned short ID;
+		const char * const Alias;
+		Position Pos;
+		VersionSet::Version SelectVersion;
+		Modifier (unsigned short const &id, const char * const alias, Position const &pos,
+			  VersionSet::Version const &select) : ID(id), Alias(alias), Pos(pos),
+			 SelectVersion(select) {};
+	};
+
+	static std::map<unsigned short, VersionSet> GroupedFromCommandLine(
+		pkgCacheFile &Cache, const char **cmdline,
+		std::list<VersionSet::Modifier> const &mods,
+		unsigned short const &fallback, CacheSetHelper &helper);
+	static std::map<unsigned short, VersionSet> GroupedFromCommandLine(
+		pkgCacheFile &Cache, const char **cmdline,
+		std::list<VersionSet::Modifier> const &mods,
+		unsigned short const &fallback) {
+		CacheSetHelper helper;
+		return APT::VersionSet::GroupedFromCommandLine(Cache, cmdline,
+				mods, fallback, helper);
+	}
+									/*}}}*/
+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 */
+	static pkgCache::VerIterator getCandidateVer(pkgCacheFile &Cache,
+		pkgCache::PkgIterator const &Pkg, CacheSetHelper &helper);
+
+	/** \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 */
+	static pkgCache::VerIterator getInstalledVer(pkgCacheFile &Cache,
+		pkgCache::PkgIterator const &Pkg, CacheSetHelper &helper);
+									/*}}}*/
+};									/*}}}*/
+}
+#endif

+ 16 - 23
apt-pkg/cdrom.cc

@@ -6,6 +6,8 @@
 #include<apt-pkg/cdromutl.h>
 #include<apt-pkg/cdromutl.h>
 #include<apt-pkg/strutl.h>
 #include<apt-pkg/strutl.h>
 #include<apt-pkg/cdrom.h>
 #include<apt-pkg/cdrom.h>
+#include<apt-pkg/aptconfiguration.h>
+
 #include<sstream>
 #include<sstream>
 #include<fstream>
 #include<fstream>
 #include<config.h>
 #include<config.h>
@@ -216,33 +218,23 @@ int pkgCdrom::Score(string Path)
 /* Here we drop everything that is not this machines arch */
 /* Here we drop everything that is not this machines arch */
 bool pkgCdrom::DropBinaryArch(vector<string> &List)
 bool pkgCdrom::DropBinaryArch(vector<string> &List)
 {
 {
-   char S[300];
-   snprintf(S,sizeof(S),"/binary-%s/",
-	    _config->Find("Apt::Architecture").c_str());
-   
+
    for (unsigned int I = 0; I < List.size(); I++)
    for (unsigned int I = 0; I < List.size(); I++)
    {
    {
       const char *Str = List[I].c_str();
       const char *Str = List[I].c_str();
-      
-      const char *Res;
-      if ((Res = strstr(Str,"/binary-")) == 0)
+      const char *Start, *End;
+      if ((Start = strstr(Str,"/binary-")) == 0)
 	 continue;
 	 continue;
 
 
-      // Weird, remove it.
-      if (strlen(Res) < strlen(S))
-      {
-	 List.erase(List.begin() + I);
-	 I--;
-	 continue;
-      }
-	  
-      // See if it is our arch
-      if (stringcmp(Res,Res + strlen(S),S) == 0)
-	 continue;
-      
-      // Erase it
+      // Between Start and End is the architecture
+      Start += 8;
+      if ((End = strstr(Start,"/")) != 0 && Start != End &&
+          APT::Configuration::checkArchitecture(string(Start, --End)) == true)
+	 continue; // okay, architecture is accepted
+
+      // not accepted -> Erase it
       List.erase(List.begin() + I);
       List.erase(List.begin() + I);
-      I--;
+      --I; // the next entry is at the same index after the erase
    }
    }
    
    
    return true;
    return true;
@@ -289,7 +281,8 @@ bool pkgCdrom::DropRepeats(vector<string> &List,const char *Name)
 	 List[J] = string();
 	 List[J] = string();
       }
       }
    }  
    }  
- 
+   delete[] Inodes;
+
    // Wipe erased entries
    // Wipe erased entries
    for (unsigned int I = 0; I < List.size();)
    for (unsigned int I = 0; I < List.size();)
    {
    {
@@ -390,7 +383,7 @@ bool pkgCdrom::WriteDatabase(Configuration &Cnf)
 
 
    Out.close();
    Out.close();
    
    
-   rename(DFile.c_str(),string(DFile + '~').c_str());
+   link(DFile.c_str(),string(DFile + '~').c_str());
    if (rename(NewFile.c_str(),DFile.c_str()) != 0)
    if (rename(NewFile.c_str(),DFile.c_str()) != 0)
       return _error->Errno("rename","Failed to rename %s.new to %s",
       return _error->Errno("rename","Failed to rename %s.new to %s",
 			   DFile.c_str(),DFile.c_str());
 			   DFile.c_str(),DFile.c_str());

+ 3 - 3
apt-pkg/clean.cc

@@ -12,6 +12,7 @@
 #include <apt-pkg/strutl.h>
 #include <apt-pkg/strutl.h>
 #include <apt-pkg/error.h>
 #include <apt-pkg/error.h>
 #include <apt-pkg/configuration.h>
 #include <apt-pkg/configuration.h>
+#include <apt-pkg/aptconfiguration.h>
 
 
 #include <apti18n.h>    
 #include <apti18n.h>    
 
 
@@ -26,7 +27,6 @@
 bool pkgArchiveCleaner::Go(string Dir,pkgCache &Cache)
 bool pkgArchiveCleaner::Go(string Dir,pkgCache &Cache)
 {
 {
    bool CleanInstalled = _config->FindB("APT::Clean-Installed",true);
    bool CleanInstalled = _config->FindB("APT::Clean-Installed",true);
-   string MyArch = _config->Find("APT::Architecture");
       
       
    DIR *D = opendir(Dir.c_str());
    DIR *D = opendir(Dir.c_str());
    if (D == 0)
    if (D == 0)
@@ -75,9 +75,9 @@ bool pkgArchiveCleaner::Go(string Dir,pkgCache &Cache)
       for (I = Start; *I != 0 && *I != '.' ;I++);
       for (I = Start; *I != 0 && *I != '.' ;I++);
       if (*I != '.')
       if (*I != '.')
 	 continue;
 	 continue;
-      string Arch = DeQuoteString(string(Start,I-Start));
+      string const Arch = DeQuoteString(string(Start,I-Start));
       
       
-      if (Arch != "all" && Arch != MyArch)
+      if (APT::Configuration::checkArchitecture(Arch) == false)
 	 continue;
 	 continue;
       
       
       // Lookup the package
       // Lookup the package

+ 41 - 1
apt-pkg/contrib/cmndline.cc

@@ -135,7 +135,9 @@ bool CommandLine::Parse(int argc,const char **argv)
    for (; I != argc; I++)
    for (; I != argc; I++)
       *Files++ = argv[I];
       *Files++ = argv[I];
    *Files = 0;
    *Files = 0;
-   
+
+   SaveInConfig(argc, argv);
+
    return true;
    return true;
 }
 }
 									/*}}}*/
 									/*}}}*/
@@ -351,3 +353,41 @@ bool CommandLine::DispatchArg(Dispatch *Map,bool NoMatch)
    return false;
    return false;
 }
 }
 									/*}}}*/
 									/*}}}*/
+// CommandLine::SaveInConfig - for output later in a logfile or so	/*{{{*/
+// ---------------------------------------------------------------------
+/* We save the commandline here to have it around later for e.g. logging.
+   It feels a bit like a hack here and isn't bulletproof, but it is better
+   than nothing after all. */
+void CommandLine::SaveInConfig(unsigned int const &argc, char const * const * const argv)
+{
+   char cmdline[100 + argc * 50];
+   unsigned int length = 0;
+   bool lastWasOption = false;
+   bool closeQuote = false;
+   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)
+      {
+	 cmdline[length] = argv[i][j];
+	 if (lastWasOption == true && argv[i][j] == '=')
+	 {
+	    // That is possibly an option: Quote it if it includes spaces,
+	    // the benefit is that this will eliminate also most false positives
+	    const char* c = &argv[i][j+1];
+	    for (; *c != '\0' && *c != ' '; ++c);
+	    if (*c == '\0') continue;
+	    cmdline[++length] = '"';
+	    closeQuote = true;
+	 }
+      }
+      if (closeQuote == true)
+	 cmdline[length++] = '"';
+      // Problem: detects also --hello
+      if (cmdline[length-1] == 'o')
+	 lastWasOption = true;
+      cmdline[length] = ' ';
+   }
+   cmdline[--length] = '\0';
+   _config->Set("CommandLine::AsString", cmdline);
+}
+									/*}}}*/

+ 1 - 0
apt-pkg/contrib/cmndline.h

@@ -60,6 +60,7 @@ class CommandLine
    Configuration *Conf;
    Configuration *Conf;
    bool HandleOpt(int &I,int argc,const char *argv[],
    bool HandleOpt(int &I,int argc,const char *argv[],
 		  const char *&Opt,Args *A,bool PreceedeMatch = false);
 		  const char *&Opt,Args *A,bool PreceedeMatch = false);
+   void static SaveInConfig(unsigned int const &argc, char const * const * const argv);
 
 
    public:
    public:
    
    

+ 45 - 0
apt-pkg/contrib/configuration.cc

@@ -773,6 +773,8 @@ bool ReadConfigFile(Configuration &Conf,const string &FName,bool const &AsSectio
 	       else
 	       else
 		  return _error->Error(_("Syntax error %s:%u: Unsupported directive '%s'"),FName.c_str(),CurLine,Tag.c_str());
 		  return _error->Error(_("Syntax error %s:%u: Unsupported directive '%s'"),FName.c_str(),CurLine,Tag.c_str());
 	    }
 	    }
+	    else if (Tag.empty() == true && NoWord == false && Word == "#clear")
+	       return _error->Error(_("Syntax error %s:%u: clear directive requires an option tree as argument"),FName.c_str(),CurLine);
 	    else
 	    else
 	    {
 	    {
 	       // Set the item in the configuration class
 	       // Set the item in the configuration class
@@ -841,3 +843,46 @@ bool ReadConfigDir(Configuration &Conf,const string &Dir,
    return true;
    return true;
 }
 }
 									/*}}}*/
 									/*}}}*/
+// MatchAgainstConfig Constructor					/*{{{*/
+Configuration::MatchAgainstConfig::MatchAgainstConfig(char const * Config)
+{
+   std::vector<std::string> const strings = _config->FindVector(Config);
+   for (std::vector<std::string>::const_iterator s = strings.begin();
+	s != strings.end(); ++s)
+   {
+      regex_t *p = new regex_t;
+      if (regcomp(p, s->c_str(), REG_EXTENDED | REG_ICASE | REG_NOSUB) == 0)
+	 patterns.push_back(p);
+      else
+      {
+	 regfree(p);
+	 delete p;
+	 _error->Warning("Regex compilation error for '%s' in configuration option '%s'",
+				s->c_str(), Config);
+      }
+    }
+
+}
+									/*}}}*/
+// MatchAgainstConfig Destructor					/*{{{*/
+Configuration::MatchAgainstConfig::~MatchAgainstConfig()
+{
+   for(std::vector<regex_t *>::const_iterator p = patterns.begin();
+	p != patterns.end(); ++p)
+   {
+      regfree(*p);
+      delete *p;
+   }
+}
+									/*}}}*/
+// MatchAgainstConfig::Match - returns true if a pattern matches	/*{{{*/
+bool Configuration::MatchAgainstConfig::Match(char const * str) const
+{
+   for(std::vector<regex_t *>::const_iterator p = patterns.begin();
+	p != patterns.end(); ++p)
+      if (regexec(*p, str, 0, 0, 0) == 0)
+	 return true;
+
+   return false;
+}
+									/*}}}*/

+ 18 - 1
apt-pkg/contrib/configuration.h

@@ -28,7 +28,7 @@
 #ifndef PKGLIB_CONFIGURATION_H
 #ifndef PKGLIB_CONFIGURATION_H
 #define PKGLIB_CONFIGURATION_H
 #define PKGLIB_CONFIGURATION_H
 
 
-
+#include <regex.h>
 
 
 #include <string>
 #include <string>
 #include <vector>
 #include <vector>
@@ -104,6 +104,23 @@ class Configuration
    Configuration(const Item *Root);
    Configuration(const Item *Root);
    Configuration();
    Configuration();
    ~Configuration();
    ~Configuration();
+
+   /** \brief match a string against a configurable list of patterns */
+   class MatchAgainstConfig
+   {
+     std::vector<regex_t *> patterns;
+
+   public:
+     MatchAgainstConfig(char const * Config);
+     virtual ~MatchAgainstConfig();
+
+     /** \brief Returns \b true for a string matching one of the patterns */
+     bool Match(char const * str) const;
+     bool Match(std::string const &str) const { return Match(str.c_str()); };
+
+     /** \brief returns if the matcher setup was successful */
+     bool wasConstructedSuccessfully() const { return patterns.empty() == false; }
+   };
 };
 };
 
 
 extern Configuration *_config;
 extern Configuration *_config;

+ 201 - 179
apt-pkg/contrib/error.cc

@@ -1,16 +1,15 @@
 // -*- mode: cpp; mode: fold -*-
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
 // Description								/*{{{*/
-// $Id: error.cc,v 1.11 2002/03/26 07:38:58 jgg Exp $
 /* ######################################################################
 /* ######################################################################
-   
-   Global Erorr Class - Global error mechanism
+
+   Global Error Class - Global error mechanism
 
 
    We use a simple STL vector to store each error record. A PendingFlag
    We use a simple STL vector to store each error record. A PendingFlag
    is kept which indicates when the vector contains a Sever error.
    is kept which indicates when the vector contains a Sever error.
-   
+
    This source is placed in the Public Domain, do with it what you will
    This source is placed in the Public Domain, do with it what you will
    It was originally written by Jason Gunthorpe.
    It was originally written by Jason Gunthorpe.
-   
+
    ##################################################################### */
    ##################################################################### */
 									/*}}}*/
 									/*}}}*/
 // Include Files							/*{{{*/
 // Include Files							/*{{{*/
@@ -19,7 +18,6 @@
 #include <iostream>
 #include <iostream>
 #include <errno.h>
 #include <errno.h>
 #include <stdio.h>
 #include <stdio.h>
-#include <stdarg.h>
 #include <unistd.h>
 #include <unistd.h>
 
 
 #include <string>
 #include <string>
@@ -28,209 +26,233 @@
 #include "config.h"
 #include "config.h"
    									/*}}}*/
    									/*}}}*/
 
 
-using namespace std;
-
 // Global Error Object							/*{{{*/
 // Global Error Object							/*{{{*/
 /* If the implementation supports posix threads then the accessor function
 /* If the implementation supports posix threads then the accessor function
    is compiled to be thread safe otherwise a non-safe version is used. A
    is compiled to be thread safe otherwise a non-safe version is used. A
    Per-Thread error object is maintained in much the same manner as libc
    Per-Thread error object is maintained in much the same manner as libc
    manages errno */
    manages errno */
 #if defined(_POSIX_THREADS) && defined(HAVE_PTHREAD)
 #if defined(_POSIX_THREADS) && defined(HAVE_PTHREAD)
- #include <pthread.h>
-
- static pthread_key_t ErrorKey;
- static void ErrorDestroy(void *Obj) {delete (GlobalError *)Obj;};
- static void KeyAlloc() {pthread_key_create(&ErrorKey,ErrorDestroy);};
-
- GlobalError *_GetErrorObj()
- {
-    static pthread_once_t Once = PTHREAD_ONCE_INIT;
-    pthread_once(&Once,KeyAlloc);
-    
-    void *Res = pthread_getspecific(ErrorKey);
-    if (Res == 0)
-       pthread_setspecific(ErrorKey,Res = new GlobalError);
-    return (GlobalError *)Res;
- }
+	#include <pthread.h>
+
+	static pthread_key_t ErrorKey;
+	static void ErrorDestroy(void *Obj) {delete (GlobalError *)Obj;};
+	static void KeyAlloc() {pthread_key_create(&ErrorKey,ErrorDestroy);};
+
+	GlobalError *_GetErrorObj() {
+		static pthread_once_t Once = PTHREAD_ONCE_INIT;
+		pthread_once(&Once,KeyAlloc);
+
+		void *Res = pthread_getspecific(ErrorKey);
+		if (Res == 0)
+			pthread_setspecific(ErrorKey,Res = new GlobalError);
+		return (GlobalError *)Res;
+	}
 #else
 #else
- GlobalError *_GetErrorObj()
- {
-    static GlobalError *Obj = new GlobalError;
-    return Obj;
- }
+	GlobalError *_GetErrorObj() {
+		static GlobalError *Obj = new GlobalError;
+		return Obj;
+	}
 #endif
 #endif
 									/*}}}*/
 									/*}}}*/
-
 // GlobalError::GlobalError - Constructor				/*{{{*/
 // GlobalError::GlobalError - Constructor				/*{{{*/
-// ---------------------------------------------------------------------
-/* */
-GlobalError::GlobalError() : List(0), PendingFlag(false)
-{
+GlobalError::GlobalError() : PendingFlag(false) {}
+									/*}}}*/
+// GlobalError::FatalE - Get part of the error string from errno	/*{{{*/
+bool GlobalError::FatalE(const char *Function,const char *Description,...) {
+	va_list args;
+	va_start(args,Description);
+	return InsertErrno(FATAL, Function, Description, args);
 }
 }
 									/*}}}*/
 									/*}}}*/
 // GlobalError::Errno - Get part of the error string from errno		/*{{{*/
 // GlobalError::Errno - Get part of the error string from errno		/*{{{*/
-// ---------------------------------------------------------------------
-/* Function indicates the stdlib function that failed and Description is
-   a user string that leads the text. Form is:
-     Description - Function (errno: strerror)
-   Carefull of the buffer overrun, sprintf.
- */
-bool GlobalError::Errno(const char *Function,const char *Description,...)
+bool GlobalError::Errno(const char *Function,const char *Description,...) {
+	va_list args;
+	va_start(args,Description);
+	return InsertErrno(ERROR, Function, Description, args);
+}
+									/*}}}*/
+// GlobalError::WarningE - Get part of the warning string from errno	/*{{{*/
+bool GlobalError::WarningE(const char *Function,const char *Description,...) {
+	va_list args;
+	va_start(args,Description);
+	return InsertErrno(WARNING, Function, Description, args);
+}
+									/*}}}*/
+// GlobalError::NoticeE - Get part of the notice string from errno	/*{{{*/
+bool GlobalError::NoticeE(const char *Function,const char *Description,...) {
+	va_list args;
+	va_start(args,Description);
+	return InsertErrno(NOTICE, Function, Description, args);
+}
+									/*}}}*/
+// GlobalError::DebugE - Get part of the debug string from errno	/*{{{*/
+bool GlobalError::DebugE(const char *Function,const char *Description,...) {
+	va_list args;
+	va_start(args,Description);
+	return InsertErrno(DEBUG, Function, Description, args);
+}
+									/*}}}*/
+// GlobalError::InsertErrno - Get part of the errortype string from errno/*{{{*/
+bool GlobalError::InsertErrno(MsgType const &type, const char *Function,
+				const char *Description,...) {
+	va_list args;
+	va_start(args,Description);
+	return InsertErrno(type, Function, Description, args);
+}
+									/*}}}*/
+// GlobalError::InsertErrno - formats an error message with the errno	/*{{{*/
+bool GlobalError::InsertErrno(MsgType type, const char* Function,
+			      const char* Description, va_list &args) {
+	char S[400];
+	snprintf(S, sizeof(S), "%s - %s (%i: %s)", Description,
+		 Function, errno, strerror(errno));
+	return Insert(type, S, args);
+}
+									/*}}}*/
+// GlobalError::Fatal - Add a fatal error to the list			/*{{{*/
+bool GlobalError::Fatal(const char *Description,...) {
+	va_list args;
+	va_start(args,Description);
+	return Insert(FATAL, Description, args);
+}
+									/*}}}*/
+// GlobalError::Error - Add an error to the list			/*{{{*/
+bool GlobalError::Error(const char *Description,...) {
+	va_list args;
+	va_start(args,Description);
+	return Insert(ERROR, Description, args);
+}
+									/*}}}*/
+// GlobalError::Warning - Add a warning to the list			/*{{{*/
+bool GlobalError::Warning(const char *Description,...) {
+	va_list args;
+	va_start(args,Description);
+	return Insert(WARNING, Description, args);
+}
+									/*}}}*/
+// GlobalError::Notice - Add a notice to the list			/*{{{*/
+bool GlobalError::Notice(const char *Description,...)
+{
+	va_list args;
+	va_start(args,Description);
+	return Insert(NOTICE, Description, args);
+}
+									/*}}}*/
+// GlobalError::Debug - Add a debug to the list				/*{{{*/
+bool GlobalError::Debug(const char *Description,...)
 {
 {
-   va_list args;
-   va_start(args,Description);
-
-   // sprintf the description
-   char S[400];
-   vsnprintf(S,sizeof(S),Description,args);
-   snprintf(S + strlen(S),sizeof(S) - strlen(S),
-	    " - %s (%i: %s)",Function,errno,strerror(errno));
-
-   // Put it on the list
-   Item *Itm = new Item;
-   Itm->Text = S;
-   Itm->Error = true;
-   Insert(Itm);
-
-   PendingFlag = true;
-
-   return false;
-}
-									/*}}}*/
-// GlobalError::WarningE - Get part of the warn string from errno	/*{{{*/
-// ---------------------------------------------------------------------
-/* Function indicates the stdlib function that failed and Description is
-   a user string that leads the text. Form is:
-     Description - Function (errno: strerror)
-   Carefull of the buffer overrun, sprintf.
- */
-bool GlobalError::WarningE(const char *Function,const char *Description,...)
+	va_list args;
+	va_start(args,Description);
+	return Insert(DEBUG, Description, args);
+}
+									/*}}}*/
+// GlobalError::Insert - Add a errotype message to the list		/*{{{*/
+bool GlobalError::Insert(MsgType const &type, const char *Description,...)
 {
 {
-   va_list args;
-   va_start(args,Description);
+	va_list args;
+	va_start(args,Description);
+	return Insert(type, Description, args);
+}
+									/*}}}*/
+// GlobalError::Insert - Insert a new item at the end			/*{{{*/
+bool GlobalError::Insert(MsgType type, const char* Description,
+			 va_list &args) {
+	char S[400];
+	vsnprintf(S,sizeof(S),Description,args);
+
+	Item const m(S, type);
+	Messages.push_back(m);
 
 
-   // sprintf the description
-   char S[400];
-   vsnprintf(S,sizeof(S),Description,args);
-   snprintf(S + strlen(S),sizeof(S) - strlen(S),
-	    " - %s (%i: %s)",Function,errno,strerror(errno));
+	if (type == ERROR || type == FATAL)
+		PendingFlag = true;
 
 
-   // Put it on the list
-   Item *Itm = new Item;
-   Itm->Text = S;
-   Itm->Error = false;
-   Insert(Itm);
+	if (type == FATAL || type == DEBUG)
+		std::clog << m << std::endl;
 
 
-   return false;
+	return false;
 }
 }
 									/*}}}*/
 									/*}}}*/
-// GlobalError::Error - Add an error to the list			/*{{{*/
-// ---------------------------------------------------------------------
-/* Just vsprintfs and pushes */
-bool GlobalError::Error(const char *Description,...)
-{
-   va_list args;
-   va_start(args,Description);
+// GlobalError::PopMessage - Pulls a single message out			/*{{{*/
+bool GlobalError::PopMessage(std::string &Text) {
+	if (Messages.empty() == true)
+		return false;
+
+	Item const msg = Messages.front();
+	Messages.pop_front();
 
 
-   // sprintf the description
-   char S[400];
-   vsnprintf(S,sizeof(S),Description,args);
+	bool const Ret = (msg.Type == ERROR || msg.Type == FATAL);
+	Text = msg.Text;
+	if (PendingFlag == false || Ret == false)
+		return Ret;
 
 
-   // Put it on the list
-   Item *Itm = new Item;
-   Itm->Text = S;
-   Itm->Error = true;
-   Insert(Itm);
-   
-   PendingFlag = true;
-   
-   return false;
+	// check if another error message is pending
+	for (std::list<Item>::const_iterator m = Messages.begin();
+	     m != Messages.end(); m++)
+		if (m->Type == ERROR || m->Type == FATAL)
+			return Ret;
+
+	PendingFlag = false;
+	return Ret;
 }
 }
 									/*}}}*/
 									/*}}}*/
-// GlobalError::Warning - Add a warning to the list			/*{{{*/
-// ---------------------------------------------------------------------
-/* This doesn't set the pending error flag */
-bool GlobalError::Warning(const char *Description,...)
-{
-   va_list args;
-   va_start(args,Description);
+// GlobalError::DumpErrors - Dump all of the errors/warns to cerr	/*{{{*/
+void GlobalError::DumpErrors(std::ostream &out, MsgType const &threshold,
+			     bool const &mergeStack) {
+	if (mergeStack == true)
+		for (std::list<MsgStack>::const_reverse_iterator s = Stacks.rbegin();
+		     s != Stacks.rend(); ++s)
+			Messages.insert(Messages.begin(), s->Messages.begin(), s->Messages.end());
 
 
-   // sprintf the description
-   char S[400];
-   vsnprintf(S,sizeof(S),Description,args);
+	for (std::list<Item>::const_iterator m = Messages.begin();
+	     m != Messages.end(); m++)
+		if (m->Type >= threshold)
+			out << (*m) << std::endl;
+	Discard();
+}
+									/*}}}*/
+// GlobalError::Discard - Discard					/*{{{*/
+void GlobalError::Discard() {
+	Messages.clear();
+	PendingFlag = false;
+};
+									/*}}}*/
+// GlobalError::empty - does our error list include anything?		/*{{{*/
+bool GlobalError::empty(MsgType const &trashhold) const {
+	if (PendingFlag == true)
+		return false;
 
 
-   // Put it on the list
-   Item *Itm = new Item;
-   Itm->Text = S;
-   Itm->Error = false;
-   Insert(Itm);
-   
-   return false;
+	if (Messages.empty() == true)
+		return true;
+
+	for (std::list<Item>::const_iterator m = Messages.begin();
+	     m != Messages.end(); m++)
+		if (m->Type >= trashhold)
+			return false;
+
+	return true;
 }
 }
 									/*}}}*/
 									/*}}}*/
-// GlobalError::PopMessage - Pulls a single message out			/*{{{*/
-// ---------------------------------------------------------------------
-/* This should be used in a loop checking empty() each cycle. It returns
-   true if the message is an error. */
-bool GlobalError::PopMessage(string &Text)
-{
-   if (List == 0)
-      return false;
-      
-   bool Ret = List->Error;
-   Text = List->Text;
-   Item *Old = List;
-   List = List->Next;
-   delete Old;
-   
-   // This really should check the list to see if only warnings are left..
-   if (List == 0)
-      PendingFlag = false;
-   
-   return Ret;
+// GlobalError::PushToStack						/*{{{*/
+void GlobalError::PushToStack() {
+	MsgStack pack(Messages, PendingFlag);
+	Stacks.push_back(pack);
+	Discard();
 }
 }
 									/*}}}*/
 									/*}}}*/
-// GlobalError::DumpErrors - Dump all of the errors/warns to cerr	/*{{{*/
-// ---------------------------------------------------------------------
-/* */
-void GlobalError::DumpErrors()
-{
-   // Print any errors or warnings found
-   string Err;
-   while (empty() == false)
-   {
-      bool Type = PopMessage(Err);
-      if (Type == true)
-	 cerr << "E: " << Err << endl;
-      else
-	 cerr << "W: " << Err << endl;
-   }
-}
-									/*}}}*/
-// GlobalError::Discard - Discard									/*{{{*/
-// ---------------------------------------------------------------------
-/* */
-void GlobalError::Discard()
-{
-   while (List != 0)
-   {
-      Item *Old = List;
-      List = List->Next;
-      delete Old;
-   }
-   
-   PendingFlag = false;
-};
+// GlobalError::RevertToStack						/*{{{*/
+void GlobalError::RevertToStack() {
+	Discard();
+	MsgStack pack = Stacks.back();
+	Messages = pack.Messages;
+	PendingFlag = pack.PendingFlag;
+	Stacks.pop_back();
+}
 									/*}}}*/
 									/*}}}*/
-// GlobalError::Insert - Insert a new item at the end			/*{{{*/
-// ---------------------------------------------------------------------
-/* */
-void GlobalError::Insert(Item *Itm)
-{
-   Item **End = &List;
-   for (Item *I = List; I != 0; I = I->Next)
-      End = &I->Next;
-   Itm->Next = *End;
-   *End = Itm;
+// GlobalError::MergeWithStack						/*{{{*/
+void GlobalError::MergeWithStack() {
+	MsgStack pack = Stacks.back();
+	Messages.insert(Messages.begin(), pack.Messages.begin(), pack.Messages.end());
+	PendingFlag = PendingFlag || pack.PendingFlag;
+	Stacks.pop_back();
 }
 }
 									/*}}}*/
 									/*}}}*/

+ 263 - 29
apt-pkg/contrib/error.h

@@ -42,43 +42,277 @@
 
 
 #include <apt-pkg/macros.h>
 #include <apt-pkg/macros.h>
 
 
+#include <iostream>
+#include <list>
 #include <string>
 #include <string>
 
 
-class GlobalError
+#include <stdarg.h>
+
+class GlobalError							/*{{{*/
 {
 {
-   struct Item
-   {
-      std::string Text;
-      bool Error;
-      Item *Next;
-   };
-   
-   Item *List;
-   bool PendingFlag;
-   void Insert(Item *I);
-   
-   public:
+public:									/*{{{*/
+	/** \brief a message can have one of following severity */
+	enum MsgType {
+		/** \brief Message will be printed instantly as it is likely that
+			this error will lead to a complete crash */
+		FATAL = 40,
+		/** \brief An error does hinder the correct execution and should be corrected */
+		ERROR = 30,
+		/** \brief indicates problem that can lead to errors later on */
+		WARNING = 20,
+		/** \brief deprecation warnings, old fallback behavior, … */
+		NOTICE = 10,
+		/** \brief for developers only in areas it is hard to print something directly */
+		DEBUG = 0
+	};
 
 
-   // Call to generate an error from a library call.
-   bool Errno(const char *Function,const char *Description,...) __like_printf_2 __cold;
-   bool WarningE(const char *Function,const char *Description,...) __like_printf_2 __cold;
+	/** \brief add a fatal error message with errno to the list
+	 *
+	 *  \param Function name of the function generating the error
+	 *  \param Description format string for the error message
+	 *
+	 *  \return \b false
+	 */
+	bool FatalE(const char *Function,const char *Description,...) __like_printf(3) __cold;
 
 
-   /* A warning should be considered less severe than an error, and may be
-      ignored by the client. */
-   bool Error(const char *Description,...) __like_printf_1 __cold;
-   bool Warning(const char *Description,...) __like_printf_1 __cold;
+	/** \brief add an Error message with errno to the list
+	 *
+	 *  \param Function name of the function generating the error
+	 *  \param Description format string for the error message
+	 *
+	 *  \return \b false
+	 */
+	bool Errno(const char *Function,const char *Description,...) __like_printf(3) __cold;
 
 
-   // Simple accessors
-   inline bool PendingError() {return PendingFlag;};
-   inline bool empty() {return List == 0;};
-   bool PopMessage(std::string &Text);
-   void Discard();
+	/** \brief add a warning message with errno to the list
+	 *
+	 *  A warning should be considered less severe than an error and
+	 *  may be ignored by the client.
+	 *
+	 *  \param Function Name of the function generates the warning.
+	 *  \param Description Format string for the warning message.
+	 *
+	 *  \return \b false
+	 */
+	bool WarningE(const char *Function,const char *Description,...) __like_printf(3) __cold;
 
 
-   // Usefull routine to dump to cerr
-   void DumpErrors();
-   
-   GlobalError();
+	/** \brief add a notice message with errno to the list
+	 *
+	 *  \param Function name of the function generating the error
+	 *  \param Description format string for the error message
+	 *
+	 *  \return \b false
+	 */
+	bool NoticeE(const char *Function,const char *Description,...) __like_printf(3) __cold;
+
+	/** \brief add a debug message with errno to the list
+	 *
+	 *  \param Function name of the function generating the error
+	 *  \param Description format string for the error message
+	 *
+	 *  \return \b false
+	 */
+	bool DebugE(const char *Function,const char *Description,...) __like_printf(3) __cold;
+
+	/** \brief adds an errno message with the given type
+	 *
+	 * \param type of the error message
+	 * \param Function which failed
+	 * \param Description of the error
+	 */
+	bool InsertErrno(MsgType const &type, const char* Function,
+			 const char* Description,...) __like_printf(4) __cold;
+
+	/** \brief add an fatal error message to the list
+	 *
+	 *  Most of the stuff we consider as "error" is also "fatal" for
+	 *  the user as the application will not have the expected result,
+	 *  but a fatal message here means that it gets printed directly
+	 *  to stderr in addiction to adding it to the list as the error
+	 *  leads sometimes to crashes and a maybe duplicated message
+	 *  is better than "Segfault" as the only displayed text
+	 *
+	 *  \param Description Format string for the fatal error message.
+	 *
+	 *  \return \b false
+	 */
+	bool Fatal(const char *Description,...) __like_printf(2) __cold;
+
+	/** \brief add an Error message to the list
+	 *
+	 *  \param Description Format string for the error message.
+	 *
+	 *  \return \b false
+	 */
+	bool Error(const char *Description,...) __like_printf(2) __cold;
+
+	/** \brief add a warning message to the list
+	 *
+	 *  A warning should be considered less severe than an error and
+	 *  may be ignored by the client.
+	 *
+	 *  \param Description Format string for the message
+	 *
+	 *  \return \b false
+	 */
+	bool Warning(const char *Description,...) __like_printf(2) __cold;
+
+	/** \brief add a notice message to the list
+	 *
+	 *  A notice should be considered less severe than an error or a
+	 *  warning and can be ignored by the client without further problems
+	 *  for some times, but he should consider fixing the problem.
+	 *  This error type can be used for e.g. deprecation warnings of options.
+	 *
+	 *  \param Description Format string for the message
+	 *
+	 *  \return \b false
+	 */
+	bool Notice(const char *Description,...) __like_printf(2) __cold;
+
+	/** \brief add a debug message to the list
+	 *
+	 *  \param Description Format string for the message
+	 *
+	 *  \return \b false
+	 */
+	bool Debug(const char *Description,...) __like_printf(2) __cold;
+
+	/** \brief adds an error message with the given type
+	 *
+	 * \param type of the error message
+	 * \param Description of the error
+	 */
+	bool Insert(MsgType const &type, const char* Description,...) __like_printf(3) __cold;
+
+	/** \brief is an error in the list?
+	 *
+	 *  \return \b true if an error is included in the list, \b false otherwise
+	 */
+	inline bool PendingError() const {return PendingFlag;};
+
+	/** \brief is the list empty?
+	 *
+	 *  The default checks if the list is empty or contains only notices,
+	 *  if you want to check if also no notices happend set the parameter
+	 *  flag to \b false.
+	 *
+	 *  \param WithoutNotice does notices count, default is \b true, so no
+	 *
+	 *  \return \b true if an the list is empty, \b false otherwise
+	 */
+	bool empty(MsgType const &trashhold = WARNING) const;
+
+	/** \brief returns and removes the first (or last) message in the list
+	 *
+	 *  \param[out] Text message of the first/last item
+	 *
+	 *  \return \b true if the message was an error, \b false otherwise
+	 */
+	bool PopMessage(std::string &Text);
+
+	/** \brief clears the list of messages */
+	void Discard();
+
+	/** \brief outputs the list of messages to the given stream
+	 *
+	 *  Note that all messages are discarded, also the notices
+	 *  displayed or not.
+	 *
+	 *  \param[out] out output stream to write the messages in
+	 *  \param threshold minimim level considered
+         *  \param mergeStack 
+	 */
+	void DumpErrors(std::ostream &out, MsgType const &threshold = WARNING,
+			bool const &mergeStack = true);
+
+	/** \brief dumps the list of messages to std::cerr
+	 *
+	 *  Note that all messages are discarded, also the notices
+	 *  displayed or not.
+	 *
+	 *  \param threshold minimum level printed
+	 */
+	void inline DumpErrors(MsgType const &threshold) {
+		DumpErrors(std::cerr, threshold);
+	}
+
+        // mvo: we do this instead of using a default parameter in the
+        //      previous declaration to avoid a (subtle) API break for
+        //      e.g. sigc++ and mem_fun0
+	/** \brief dumps the messages of type WARNING or higher to std::cerr
+	 *
+	 *  Note that all messages are discarded, displayed or not.
+	 *
+	 */
+	void inline DumpErrors() {
+                DumpErrors(WARNING);
+	}
+
+	/** \brief put the current Messages into the stack
+	 *
+	 *  All "old" messages will be pushed into a stack to
+	 *  them later back, but for now the Message query will be
+	 *  empty and performs as no messages were present before.
+	 *
+	 * The stack can be as deep as you want - all stack operations
+	 * will only operate on the last element in the stack.
+	 */
+	void PushToStack();
+
+	/** \brief throw away all current messages */
+	void RevertToStack();
+
+	/** \brief merge current and stack together */
+	void MergeWithStack();
+
+	/** \brief return the deep of the stack */
+	size_t StackCount() const {
+		return Stacks.size();
+	}
+
+	GlobalError();
+									/*}}}*/
+private:								/*{{{*/
+	struct Item {
+		std::string Text;
+		MsgType Type;
+
+		Item(char const *Text, MsgType const &Type) :
+			Text(Text), Type(Type) {};
+
+		friend std::ostream& operator<< (std::ostream &out, Item i) {
+			switch(i.Type) {
+			case FATAL:
+			case ERROR: out << "E"; break;
+			case WARNING: out << "W"; break;
+			case NOTICE: out << "N"; break;
+			case DEBUG: out << "D"; break;
+			}
+			return out << ": " << i.Text;
+		}
+	};
+
+	std::list<Item> Messages;
+	bool PendingFlag;
+
+	struct MsgStack {
+		std::list<Item> const Messages;
+		bool const PendingFlag;
+
+		MsgStack(std::list<Item> const &Messages, bool const &Pending) :
+			 Messages(Messages), PendingFlag(Pending) {};
+	};
+
+	std::list<MsgStack> Stacks;
+
+	bool InsertErrno(MsgType type, const char* Function,
+			 const char* Description, va_list &args);
+	bool Insert(MsgType type, const char* Description,
+			 va_list &args);
+									/*}}}*/
 };
 };
+									/*}}}*/
 
 
 // The 'extra-ansi' syntax is used to help with collisions. 
 // The 'extra-ansi' syntax is used to help with collisions. 
 GlobalError *_GetErrorObj();
 GlobalError *_GetErrorObj();

+ 146 - 18
apt-pkg/contrib/fileutl.cc

@@ -11,6 +11,7 @@
    Most of this source is placed in the Public Domain, do with it what 
    Most of this source is placed in the Public Domain, do with it what 
    you will
    you will
    It was originally written by Jason Gunthorpe <jgg@debian.org>.
    It was originally written by Jason Gunthorpe <jgg@debian.org>.
+   FileFd gzip support added by Martin Pitt <martin.pitt@canonical.com>
    
    
    The exception is RunScripts() it is under the GPLv2
    The exception is RunScripts() it is under the GPLv2
 
 
@@ -18,6 +19,7 @@
 									/*}}}*/
 									/*}}}*/
 // Include Files							/*{{{*/
 // Include Files							/*{{{*/
 #include <apt-pkg/fileutl.h>
 #include <apt-pkg/fileutl.h>
+#include <apt-pkg/strutl.h>
 #include <apt-pkg/error.h>
 #include <apt-pkg/error.h>
 #include <apt-pkg/sptr.h>
 #include <apt-pkg/sptr.h>
 #include <apt-pkg/configuration.h>
 #include <apt-pkg/configuration.h>
@@ -26,6 +28,7 @@
 
 
 #include <cstdlib>
 #include <cstdlib>
 #include <cstring>
 #include <cstring>
+#include <cstdio>
 
 
 #include <iostream>
 #include <iostream>
 #include <unistd.h>
 #include <unistd.h>
@@ -197,15 +200,61 @@ bool FileExists(string File)
    return true;
    return true;
 }
 }
 									/*}}}*/
 									/*}}}*/
+// DirectoryExists - Check if a directory exists and is really one	/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool DirectoryExists(string const &Path)
+{
+   struct stat Buf;
+   if (stat(Path.c_str(),&Buf) != 0)
+      return false;
+   return ((Buf.st_mode & S_IFDIR) != 0);
+}
+									/*}}}*/
+// CreateDirectory - poor man's mkdir -p guarded by a parent directory	/*{{{*/
+// ---------------------------------------------------------------------
+/* This method will create all directories needed for path in good old
+   mkdir -p style but refuses to do this if Parent is not a prefix of
+   this Path. Example: /var/cache/ and /var/cache/apt/archives are given,
+   so it will create apt/archives if /var/cache exists - on the other
+   hand if the parent is /var/lib the creation will fail as this path
+   is not a parent of the path to be generated. */
+bool CreateDirectory(string const &Parent, string const &Path)
+{
+   if (Parent.empty() == true || Path.empty() == true)
+      return false;
+
+   if (DirectoryExists(Path) == true)
+      return true;
+
+   if (DirectoryExists(Parent) == false)
+      return false;
+
+   // we are not going to create directories "into the blue"
+   if (Path.find(Parent, 0) != 0)
+      return false;
+
+   vector<string> const dirs = VectorizeString(Path.substr(Parent.size()), '/');
+   string progress = Parent;
+   for (vector<string>::const_iterator d = dirs.begin(); d != dirs.end(); ++d)
+   {
+      if (d->empty() == true)
+	 continue;
+
+      progress.append("/").append(*d);
+      if (DirectoryExists(progress) == true)
+	 continue;
+
+      if (mkdir(progress.c_str(), 0755) != 0)
+	 return false;
+   }
+   return true;
+}
+									/*}}}*/
 // GetListOfFilesInDir - returns a vector of files in the given dir	/*{{{*/
 // GetListOfFilesInDir - returns a vector of files in the given dir	/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /* If an extension is given only files with this extension are included
 /* If an extension is given only files with this extension are included
    in the returned vector, otherwise every "normal" file is included. */
    in the returned vector, otherwise every "normal" file is included. */
-std::vector<string> GetListOfFilesInDir(string const &Dir, string const &Ext,
-					bool const &SortList)
-{
-   return GetListOfFilesInDir(Dir, Ext, SortList, false);
-}
 std::vector<string> GetListOfFilesInDir(string const &Dir, string const &Ext,
 std::vector<string> GetListOfFilesInDir(string const &Dir, string const &Ext,
 					bool const &SortList, bool const &AllowNoExt)
 					bool const &SortList, bool const &AllowNoExt)
 {
 {
@@ -234,6 +283,7 @@ std::vector<string> GetListOfFilesInDir(string const &Dir, std::vector<string> c
    }
    }
 
 
    std::vector<string> List;
    std::vector<string> List;
+   Configuration::MatchAgainstConfig SilentIgnore("Dir::Ignore-Files-Silently");
    DIR *D = opendir(Dir.c_str());
    DIR *D = opendir(Dir.c_str());
    if (D == 0) 
    if (D == 0) 
    {
    {
@@ -259,6 +309,7 @@ std::vector<string> GetListOfFilesInDir(string const &Dir, std::vector<string> c
 	    {
 	    {
 	       if (Debug == true)
 	       if (Debug == true)
 		  std::clog << "Bad file: " << Ent->d_name << " → no extension" << std::endl;
 		  std::clog << "Bad file: " << Ent->d_name << " → no extension" << std::endl;
+	       _error->Notice("Ignoring file '%s' in directory '%s' as it has no filename extension", Ent->d_name, Dir.c_str());
 	       continue;
 	       continue;
 	    }
 	    }
 	 }
 	 }
@@ -266,6 +317,8 @@ std::vector<string> GetListOfFilesInDir(string const &Dir, std::vector<string> c
 	 {
 	 {
 	    if (Debug == true)
 	    if (Debug == true)
 	       std::clog << "Bad file: " << Ent->d_name << " → bad extension »" << flExtension(Ent->d_name) << "«" << std::endl;
 	       std::clog << "Bad file: " << Ent->d_name << " → bad extension »" << flExtension(Ent->d_name) << "«" << std::endl;
+	    if (SilentIgnore.Match(Ent->d_name) == false)
+	       _error->Notice("Ignoring file '%s' in directory '%s' as it has an invalid filename extension", Ent->d_name, Dir.c_str());
 	    continue;
 	    continue;
 	 }
 	 }
       }
       }
@@ -604,13 +657,25 @@ bool FileFd::Open(string FileName,OpenMode Mode, unsigned long Perms)
       case ReadOnly:
       case ReadOnly:
       iFd = open(FileName.c_str(),O_RDONLY);
       iFd = open(FileName.c_str(),O_RDONLY);
       break;
       break;
+
+      case ReadOnlyGzip:
+      iFd = open(FileName.c_str(),O_RDONLY);
+      if (iFd > 0) {
+	 gz = gzdopen (iFd, "r");
+	 if (gz == NULL) {
+	     close (iFd);
+	     iFd = -1;
+	 }
+      }
+      break;
       
       
       case WriteEmpty:
       case WriteEmpty:
       {
       {
-	 struct stat Buf;
-	 if (lstat(FileName.c_str(),&Buf) == 0 && S_ISLNK(Buf.st_mode))
-	    unlink(FileName.c_str());
-	 iFd = open(FileName.c_str(),O_RDWR | O_CREAT | O_TRUNC,Perms);
+	 Flags |= Replace;
+	 char *name = strdup((FileName + ".XXXXXX").c_str());
+	 TemporaryFileName = string(mktemp(name));
+	 iFd = open(TemporaryFileName.c_str(),O_RDWR | O_CREAT | O_EXCL,Perms);
+	 free(name);
 	 break;
 	 break;
       }
       }
       
       
@@ -635,6 +700,24 @@ bool FileFd::Open(string FileName,OpenMode Mode, unsigned long Perms)
    SetCloseExec(iFd,true);
    SetCloseExec(iFd,true);
    return true;
    return true;
 }
 }
+
+bool FileFd::OpenDescriptor(int Fd, OpenMode Mode, bool AutoClose)
+{
+   Close();
+   Flags = (AutoClose) ? FileFd::AutoClose : 0;
+   iFd = Fd;
+   if (Mode == ReadOnlyGzip) {
+      gz = gzdopen (iFd, "r");
+      if (gz == NULL) {
+	 if (AutoClose)
+	    close (iFd);
+	 return _error->Errno("gzdopen",_("Could not open file descriptor %d"),
+			      Fd);
+      }
+   }
+   this->FileName = "";
+   return true;
+}
 									/*}}}*/
 									/*}}}*/
 // FileFd::~File - Closes the file					/*{{{*/
 // FileFd::~File - Closes the file					/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
@@ -658,7 +741,10 @@ bool FileFd::Read(void *To,unsigned long Size,unsigned long *Actual)
    
    
    do
    do
    {
    {
-      Res = read(iFd,To,Size);
+      if (gz != NULL)
+         Res = gzread(gz,To,Size);
+      else
+         Res = read(iFd,To,Size);
       if (Res < 0 && errno == EINTR)
       if (Res < 0 && errno == EINTR)
 	 continue;
 	 continue;
       if (Res < 0)
       if (Res < 0)
@@ -697,7 +783,10 @@ bool FileFd::Write(const void *From,unsigned long Size)
    errno = 0;
    errno = 0;
    do
    do
    {
    {
-      Res = write(iFd,From,Size);
+      if (gz != NULL)
+         Res = gzwrite(gz,From,Size);
+      else
+         Res = write(iFd,From,Size);
       if (Res < 0 && errno == EINTR)
       if (Res < 0 && errno == EINTR)
 	 continue;
 	 continue;
       if (Res < 0)
       if (Res < 0)
@@ -723,7 +812,12 @@ bool FileFd::Write(const void *From,unsigned long Size)
 /* */
 /* */
 bool FileFd::Seek(unsigned long To)
 bool FileFd::Seek(unsigned long To)
 {
 {
-   if (lseek(iFd,To,SEEK_SET) != (signed)To)
+   int res;
+   if (gz)
+      res = gzseek(gz,To,SEEK_SET);
+   else
+      res = lseek(iFd,To,SEEK_SET);
+   if (res != (signed)To)
    {
    {
       Flags |= Fail;
       Flags |= Fail;
       return _error->Error("Unable to seek to %lu",To);
       return _error->Error("Unable to seek to %lu",To);
@@ -737,7 +831,12 @@ bool FileFd::Seek(unsigned long To)
 /* */
 /* */
 bool FileFd::Skip(unsigned long Over)
 bool FileFd::Skip(unsigned long Over)
 {
 {
-   if (lseek(iFd,Over,SEEK_CUR) < 0)
+   int res;
+   if (gz)
+      res = gzseek(gz,Over,SEEK_CUR);
+   else
+      res = lseek(iFd,Over,SEEK_CUR);
+   if (res < 0)
    {
    {
       Flags |= Fail;
       Flags |= Fail;
       return _error->Error("Unable to seek ahead %lu",Over);
       return _error->Error("Unable to seek ahead %lu",Over);
@@ -751,6 +850,11 @@ bool FileFd::Skip(unsigned long Over)
 /* */
 /* */
 bool FileFd::Truncate(unsigned long To)
 bool FileFd::Truncate(unsigned long To)
 {
 {
+   if (gz)
+   {
+      Flags |= Fail;
+      return _error->Error("Truncating gzipped files is not implemented (%s)", FileName.c_str());
+   }
    if (ftruncate(iFd,To) != 0)
    if (ftruncate(iFd,To) != 0)
    {
    {
       Flags |= Fail;
       Flags |= Fail;
@@ -765,7 +869,11 @@ bool FileFd::Truncate(unsigned long To)
 /* */
 /* */
 unsigned long FileFd::Tell()
 unsigned long FileFd::Tell()
 {
 {
-   off_t Res = lseek(iFd,0,SEEK_CUR);
+   off_t Res;
+   if (gz)
+     Res = gztell(gz);
+   else
+     Res = lseek(iFd,0,SEEK_CUR);
    if (Res == (off_t)-1)
    if (Res == (off_t)-1)
       _error->Errno("lseek","Failed to determine the current file position");
       _error->Errno("lseek","Failed to determine the current file position");
    return Res;
    return Res;
@@ -776,6 +884,7 @@ unsigned long FileFd::Tell()
 /* */
 /* */
 unsigned long FileFd::Size()
 unsigned long FileFd::Size()
 {
 {
+   //TODO: For gz, do we need the actual file size here or the uncompressed length?
    struct stat Buf;
    struct stat Buf;
    if (fstat(iFd,&Buf) != 0)
    if (fstat(iFd,&Buf) != 0)
       return _error->Errno("fstat","Unable to determine the file size");
       return _error->Errno("fstat","Unable to determine the file size");
@@ -789,14 +898,33 @@ bool FileFd::Close()
 {
 {
    bool Res = true;
    bool Res = true;
    if ((Flags & AutoClose) == AutoClose)
    if ((Flags & AutoClose) == AutoClose)
-      if (iFd >= 0 && close(iFd) != 0)
-	 Res &= _error->Errno("close",_("Problem closing the file"));
+   {
+      if (gz != NULL) {
+	 int const e = gzclose(gz);
+	 // gzdopen() on empty files always fails with "buffer error" here, ignore that
+	 if (e != 0 && e != Z_BUF_ERROR)
+	    Res &= _error->Errno("close",_("Problem closing the gzip file %s"), FileName.c_str());
+      } else
+	 if (iFd > 0 && close(iFd) != 0)
+	    Res &= _error->Errno("close",_("Problem closing the file %s"), FileName.c_str());
+   }
+
+   if ((Flags & Replace) == Replace && iFd >= 0) {
+      if (rename(TemporaryFileName.c_str(), FileName.c_str()) != 0)
+	 Res &= _error->Errno("rename",_("Problem renaming the file %s to %s"), TemporaryFileName.c_str(), FileName.c_str());
+
+      FileName = TemporaryFileName; // for the unlink() below.
+   }
+
    iFd = -1;
    iFd = -1;
-   
+   gz = NULL;
+
    if ((Flags & Fail) == Fail && (Flags & DelOnFail) == DelOnFail &&
    if ((Flags & Fail) == Fail && (Flags & DelOnFail) == DelOnFail &&
        FileName.empty() == false)
        FileName.empty() == false)
       if (unlink(FileName.c_str()) != 0)
       if (unlink(FileName.c_str()) != 0)
-	 Res &= _error->WarningE("unlnk",_("Problem unlinking the file"));
+	 Res &= _error->WarningE("unlnk",_("Problem unlinking the file %s"), FileName.c_str());
+
+
    return Res;
    return Res;
 }
 }
 									/*}}}*/
 									/*}}}*/

+ 18 - 10
apt-pkg/contrib/fileutl.h

@@ -21,10 +21,16 @@
 #ifndef PKGLIB_FILEUTL_H
 #ifndef PKGLIB_FILEUTL_H
 #define PKGLIB_FILEUTL_H
 #define PKGLIB_FILEUTL_H
 
 
+#include <apt-pkg/macros.h>
 
 
 #include <string>
 #include <string>
 #include <vector>
 #include <vector>
 
 
+#include <zlib.h>
+
+/* Define this for python-apt */
+#define APT_HAS_GZIP 1
+
 using std::string;
 using std::string;
 
 
 class FileFd
 class FileFd
@@ -33,12 +39,14 @@ class FileFd
    int iFd;
    int iFd;
  
  
    enum LocalFlags {AutoClose = (1<<0),Fail = (1<<1),DelOnFail = (1<<2),
    enum LocalFlags {AutoClose = (1<<0),Fail = (1<<1),DelOnFail = (1<<2),
-                    HitEof = (1<<3)};
+                    HitEof = (1<<3), Replace = (1<<4) };
    unsigned long Flags;
    unsigned long Flags;
    string FileName;
    string FileName;
-   
+   string TemporaryFileName;
+   gzFile gz;
+
    public:
    public:
-   enum OpenMode {ReadOnly,WriteEmpty,WriteExists,WriteAny,WriteTemp};
+   enum OpenMode {ReadOnly,WriteEmpty,WriteExists,WriteAny,WriteTemp,ReadOnlyGzip};
    
    
    inline bool Read(void *To,unsigned long Size,bool AllowEof)
    inline bool Read(void *To,unsigned long Size,bool AllowEof)
    {
    {
@@ -55,6 +63,7 @@ class FileFd
    unsigned long Tell();
    unsigned long Tell();
    unsigned long Size();
    unsigned long Size();
    bool Open(string FileName,OpenMode Mode,unsigned long Perms = 0666);
    bool Open(string FileName,OpenMode Mode,unsigned long Perms = 0666);
+   bool OpenDescriptor(int Fd, OpenMode Mode, bool AutoClose=false);
    bool Close();
    bool Close();
    bool Sync();
    bool Sync();
    
    
@@ -69,12 +78,12 @@ class FileFd
    inline string &Name() {return FileName;};
    inline string &Name() {return FileName;};
    
    
    FileFd(string FileName,OpenMode Mode,unsigned long Perms = 0666) : iFd(-1), 
    FileFd(string FileName,OpenMode Mode,unsigned long Perms = 0666) : iFd(-1), 
-            Flags(0) 
+            Flags(0), gz(NULL)
    {
    {
       Open(FileName,Mode,Perms);
       Open(FileName,Mode,Perms);
    };
    };
-   FileFd(int Fd = -1) : iFd(Fd), Flags(AutoClose) {};
-   FileFd(int Fd,bool) : iFd(Fd), Flags(0) {};
+   FileFd(int Fd = -1) : iFd(Fd), Flags(AutoClose), gz(NULL) {};
+   FileFd(int Fd,bool) : iFd(Fd), Flags(0), gz(NULL) {};
    virtual ~FileFd();
    virtual ~FileFd();
 };
 };
 
 
@@ -82,11 +91,10 @@ bool RunScripts(const char *Cnf);
 bool CopyFile(FileFd &From,FileFd &To);
 bool CopyFile(FileFd &From,FileFd &To);
 int GetLock(string File,bool Errors = true);
 int GetLock(string File,bool Errors = true);
 bool FileExists(string File);
 bool FileExists(string File);
-// FIXME: next ABI-Break: merge the two method-headers
-std::vector<string> GetListOfFilesInDir(string const &Dir, string const &Ext,
-					bool const &SortList);
+bool DirectoryExists(string const &Path) __attrib_const;
+bool CreateDirectory(string const &Parent, string const &Path);
 std::vector<string> GetListOfFilesInDir(string const &Dir, string const &Ext,
 std::vector<string> GetListOfFilesInDir(string const &Dir, string const &Ext,
-					bool const &SortList, bool const &AllowNoExt);
+					bool const &SortList, bool const &AllowNoExt=false);
 std::vector<string> GetListOfFilesInDir(string const &Dir, std::vector<string> const &Ext,
 std::vector<string> GetListOfFilesInDir(string const &Dir, std::vector<string> const &Ext,
 					bool const &SortList);
 					bool const &SortList);
 string SafeGetCWD();
 string SafeGetCWD();

+ 18 - 16
apt-pkg/contrib/macros.h

@@ -56,33 +56,35 @@
 
 
 // some nice optional GNUC features
 // some nice optional GNUC features
 #if __GNUC__ >= 3
 #if __GNUC__ >= 3
-        #define __must_check    __attribute__ ((warn_unused_result))
-        #define __deprecated    __attribute__ ((deprecated))
-        /* likely() and unlikely() can be used to mark boolean expressions
-           as (not) likely true which will help the compiler to optimise */
-        #define likely(x)       __builtin_expect (!!(x), 1)
-        #define unlikely(x)     __builtin_expect (!!(x), 0)
+	#define __must_check	__attribute__ ((warn_unused_result))
+	#define __deprecated	__attribute__ ((deprecated))
+	#define __attrib_const	__attribute__ ((__const__))
+	/* likely() and unlikely() can be used to mark boolean expressions
+	   as (not) likely true which will help the compiler to optimise */
+	#define likely(x)	__builtin_expect (!!(x), 1)
+	#define unlikely(x)	__builtin_expect (!!(x), 0)
 #else
 #else
-        #define __must_check    /* no warn_unused_result */
-        #define __deprecated    /* no deprecated */
-        #define likely(x)       (x)
-        #define unlikely(x)     (x)
+	#define __must_check	/* no warn_unused_result */
+	#define __deprecated	/* no deprecated */
+	#define __attrib_const	/* no const attribute */
+	#define likely(x)	(x)
+	#define unlikely(x)	(x)
 #endif
 #endif
 
 
 // cold functions are unlikely() to be called
 // cold functions are unlikely() to be called
 #if (__GNUC__ == 4 && __GNUC_MINOR__ >= 3) || __GNUC__ > 4
 #if (__GNUC__ == 4 && __GNUC_MINOR__ >= 3) || __GNUC__ > 4
-        #define __cold  __attribute__ ((__cold__))
+	#define __cold	__attribute__ ((__cold__))
+	#define __hot	__attribute__ ((__hot__))
 #else
 #else
-        #define __cold  /* no cold marker */
+	#define __cold	/* no cold marker */
+	#define __hot	/* no hot marker */
 #endif
 #endif
 
 
 #ifdef __GNUG__
 #ifdef __GNUG__
 // Methods have a hidden this parameter that is visible to this attribute
 // Methods have a hidden this parameter that is visible to this attribute
-	#define __like_printf_1 __attribute__ ((format (printf, 2, 3)))
-	#define __like_printf_2 __attribute__ ((format (printf, 3, 4)))
+	#define __like_printf(n)	__attribute__((format(printf, n, n + 1)))
 #else
 #else
-	#define __like_printf_1
-	#define __like_printf_2
+	#define __like_printf(n)	/* no like-printf */
 #endif
 #endif
 
 
 #endif
 #endif

+ 82 - 23
apt-pkg/contrib/mmap.cc

@@ -27,6 +27,7 @@
 #include <unistd.h>
 #include <unistd.h>
 #include <fcntl.h>
 #include <fcntl.h>
 #include <stdlib.h>
 #include <stdlib.h>
+#include <errno.h>
 
 
 #include <cstring>
 #include <cstring>
    									/*}}}*/
    									/*}}}*/
@@ -35,7 +36,7 @@
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /* */
 /* */
 MMap::MMap(FileFd &F,unsigned long Flags) : Flags(Flags), iSize(0),
 MMap::MMap(FileFd &F,unsigned long Flags) : Flags(Flags), iSize(0),
-                     Base(0)
+                     Base(0), SyncToFd(NULL)
 {
 {
    if ((Flags & NoImmMap) != NoImmMap)
    if ((Flags & NoImmMap) != NoImmMap)
       Map(F);
       Map(F);
@@ -45,7 +46,7 @@ MMap::MMap(FileFd &F,unsigned long Flags) : Flags(Flags), iSize(0),
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /* */
 /* */
 MMap::MMap(unsigned long Flags) : Flags(Flags), iSize(0),
 MMap::MMap(unsigned long Flags) : Flags(Flags), iSize(0),
-                     Base(0)
+                     Base(0), SyncToFd(NULL)
 {
 {
 }
 }
 									/*}}}*/
 									/*}}}*/
@@ -78,7 +79,24 @@ bool MMap::Map(FileFd &Fd)
    // Map it.
    // Map it.
    Base = mmap(0,iSize,Prot,Map,Fd.Fd(),0);
    Base = mmap(0,iSize,Prot,Map,Fd.Fd(),0);
    if (Base == (void *)-1)
    if (Base == (void *)-1)
-      return _error->Errno("mmap",_("Couldn't make mmap of %lu bytes"),iSize);
+   {
+      if (errno == ENODEV || errno == EINVAL)
+      {
+	 // The filesystem doesn't support this particular kind of mmap.
+	 // So we allocate a buffer and read the whole file into it.
+	 int const dupped_fd = dup(Fd.Fd());
+	 if (dupped_fd == -1)
+	    return _error->Errno("mmap", _("Couldn't duplicate file descriptor %i"), Fd.Fd());
+
+	 Base = new unsigned char[iSize];
+	 SyncToFd = new FileFd (dupped_fd);
+	 if (!SyncToFd->Seek(0L) || !SyncToFd->Read(Base, iSize))
+	    return false;
+      }
+      else
+	 return _error->Errno("mmap",_("Couldn't make mmap of %lu bytes"),
+	                      iSize);
+     }
 
 
    return true;
    return true;
 }
 }
@@ -93,10 +111,19 @@ bool MMap::Close(bool DoSync)
    
    
    if (DoSync == true)
    if (DoSync == true)
       Sync();
       Sync();
-   
-   if (munmap((char *)Base,iSize) != 0)
-      _error->Warning("Unable to munmap");
-   
+
+   if (SyncToFd != NULL)
+   {
+      delete[] (char *)Base;
+      delete SyncToFd;
+      SyncToFd = NULL;
+   }
+   else
+   {
+      if (munmap((char *)Base, iSize) != 0)
+	 _error->WarningE("mmap", _("Unable to close mmap"));
+   }
+
    iSize = 0;
    iSize = 0;
    Base = 0;
    Base = 0;
    return true;
    return true;
@@ -113,8 +140,18 @@ bool MMap::Sync()
    
    
 #ifdef _POSIX_SYNCHRONIZED_IO   
 #ifdef _POSIX_SYNCHRONIZED_IO   
    if ((Flags & ReadOnly) != ReadOnly)
    if ((Flags & ReadOnly) != ReadOnly)
-      if (msync((char *)Base,iSize,MS_SYNC) < 0)
-	 return _error->Errno("msync","Unable to write mmap");
+   {
+      if (SyncToFd != NULL)
+      {
+	 if (!SyncToFd->Seek(0) || !SyncToFd->Write(Base, iSize))
+	    return false;
+      }
+      else
+      {
+	 if (msync((char *)Base, iSize, MS_SYNC) < 0)
+	    return _error->Errno("msync", _("Unable to synchronize mmap"));
+      }
+   }
 #endif   
 #endif   
    return true;
    return true;
 }
 }
@@ -130,8 +167,19 @@ bool MMap::Sync(unsigned long Start,unsigned long Stop)
 #ifdef _POSIX_SYNCHRONIZED_IO
 #ifdef _POSIX_SYNCHRONIZED_IO
    unsigned long PSize = sysconf(_SC_PAGESIZE);
    unsigned long PSize = sysconf(_SC_PAGESIZE);
    if ((Flags & ReadOnly) != ReadOnly)
    if ((Flags & ReadOnly) != ReadOnly)
-      if (msync((char *)Base+(int)(Start/PSize)*PSize,Stop - Start,MS_SYNC) < 0)
-	 return _error->Errno("msync","Unable to write mmap");
+   {
+      if (SyncToFd != 0)
+      {
+	 if (!SyncToFd->Seek(0) ||
+	     !SyncToFd->Write (((char *)Base)+Start, Stop-Start))
+	    return false;
+      }
+      else
+      {
+	 if (msync((char *)Base+(int)(Start/PSize)*PSize,Stop - Start,MS_SYNC) < 0)
+	    return _error->Errno("msync", _("Unable to synchronize mmap"));
+      }
+   }
 #endif   
 #endif   
    return true;
    return true;
 }
 }
@@ -177,22 +225,22 @@ DynamicMMap::DynamicMMap(unsigned long Flags,unsigned long const &WorkSpace,
 
 
 	// disable Moveable if we don't grow
 	// disable Moveable if we don't grow
 	if (Grow == 0)
 	if (Grow == 0)
-		Flags &= ~Moveable;
+		this->Flags &= ~Moveable;
 
 
 #ifndef __linux__
 #ifndef __linux__
 	// kfreebsd doesn't have mremap, so we use the fallback
 	// kfreebsd doesn't have mremap, so we use the fallback
-	if ((Flags & Moveable) == Moveable)
-		Flags |= Fallback;
+	if ((this->Flags & Moveable) == Moveable)
+		this->Flags |= Fallback;
 #endif
 #endif
 
 
 #ifdef _POSIX_MAPPED_FILES
 #ifdef _POSIX_MAPPED_FILES
-	if ((Flags & Fallback) != Fallback) {
+	if ((this->Flags & Fallback) != Fallback) {
 		// Set the permissions.
 		// Set the permissions.
 		int Prot = PROT_READ;
 		int Prot = PROT_READ;
 		int Map = MAP_PRIVATE | MAP_ANONYMOUS;
 		int Map = MAP_PRIVATE | MAP_ANONYMOUS;
-		if ((Flags & ReadOnly) != ReadOnly)
+		if ((this->Flags & ReadOnly) != ReadOnly)
 			Prot |= PROT_WRITE;
 			Prot |= PROT_WRITE;
-		if ((Flags & Public) == Public)
+		if ((this->Flags & Public) == Public)
 			Map = MAP_SHARED | MAP_ANONYMOUS;
 			Map = MAP_SHARED | MAP_ANONYMOUS;
 
 
 		// use anonymous mmap() to get the memory
 		// use anonymous mmap() to get the memory
@@ -249,7 +297,7 @@ unsigned long DynamicMMap::RawAllocate(unsigned long Size,unsigned long Aln)
    {
    {
       if(!Grow())
       if(!Grow())
       {
       {
-	 _error->Error(_("Dynamic MMap ran out of room. Please increase the size "
+	 _error->Fatal(_("Dynamic MMap ran out of room. Please increase the size "
 			 "of APT::Cache-Limit. Current value: %lu. (man 5 apt.conf)"), WorkSpace);
 			 "of APT::Cache-Limit. Current value: %lu. (man 5 apt.conf)"), WorkSpace);
 	 return 0;
 	 return 0;
       }
       }
@@ -266,7 +314,7 @@ unsigned long DynamicMMap::Allocate(unsigned long ItemSize)
    // Look for a matching pool entry
    // Look for a matching pool entry
    Pool *I;
    Pool *I;
    Pool *Empty = 0;
    Pool *Empty = 0;
-   for (I = Pools; I != Pools + PoolCount; I++)
+   for (I = Pools; I != Pools + PoolCount; ++I)
    {
    {
       if (I->ItemSize == 0)
       if (I->ItemSize == 0)
 	 Empty = I;
 	 Empty = I;
@@ -294,7 +342,11 @@ unsigned long DynamicMMap::Allocate(unsigned long ItemSize)
    {
    {
       const unsigned long size = 20*1024;
       const unsigned long size = 20*1024;
       I->Count = size/ItemSize;
       I->Count = size/ItemSize;
+      Pool* oldPools = Pools;
       Result = RawAllocate(size,ItemSize);
       Result = RawAllocate(size,ItemSize);
+      if (Pools != oldPools)
+	 I += Pools - oldPools;
+
       // Does the allocation failed ?
       // Does the allocation failed ?
       if (Result == 0 && _error->PendingError())
       if (Result == 0 && _error->PendingError())
 	 return 0;
 	 return 0;
@@ -317,7 +369,7 @@ unsigned long DynamicMMap::WriteString(const char *String,
    if (Len == (unsigned long)-1)
    if (Len == (unsigned long)-1)
       Len = strlen(String);
       Len = strlen(String);
 
 
-   unsigned long Result = RawAllocate(Len+1,0);
+   unsigned long const Result = RawAllocate(Len+1,0);
 
 
    if (Result == 0 && _error->PendingError())
    if (Result == 0 && _error->PendingError())
       return 0;
       return 0;
@@ -344,19 +396,25 @@ unsigned long DynamicMMap::WriteString(const char *String,
    the nearly impossible 4 to grow it before it finally give up: Never say never. */
    the nearly impossible 4 to grow it before it finally give up: Never say never. */
 bool DynamicMMap::Grow() {
 bool DynamicMMap::Grow() {
 	if (Limit != 0 && WorkSpace >= Limit)
 	if (Limit != 0 && WorkSpace >= Limit)
-		return _error->Error(_("The size of a MMap has already reached the defined limit of %lu bytes,"
-		                       "abort the try to grow the MMap."), Limit);
+		return _error->Error(_("Unable to increase the size of the MMap as the "
+		                       "limit of %lu bytes is already reached."), Limit);
+	if (GrowFactor <= 0)
+		return _error->Error(_("Unable to increase size of the MMap as automatic growing is disabled by user."));
 
 
-	unsigned long const newSize = WorkSpace + 1024*1024;
+	unsigned long const newSize = WorkSpace + GrowFactor;
 
 
 	if(Fd != 0) {
 	if(Fd != 0) {
 		Fd->Seek(newSize - 1);
 		Fd->Seek(newSize - 1);
 		char C = 0;
 		char C = 0;
 		Fd->Write(&C,sizeof(C));
 		Fd->Write(&C,sizeof(C));
 	}
 	}
+
+	unsigned long const poolOffset = Pools - ((Pool*) Base);
+
 	if ((Flags & Fallback) != Fallback) {
 	if ((Flags & Fallback) != Fallback) {
 #if defined(_POSIX_MAPPED_FILES) && defined(__linux__)
 #if defined(_POSIX_MAPPED_FILES) && defined(__linux__)
    #ifdef MREMAP_MAYMOVE
    #ifdef MREMAP_MAYMOVE
+
 		if ((Flags & Moveable) == Moveable)
 		if ((Flags & Moveable) == Moveable)
 			Base = mremap(Base, WorkSpace, newSize, MREMAP_MAYMOVE);
 			Base = mremap(Base, WorkSpace, newSize, MREMAP_MAYMOVE);
 		else
 		else
@@ -377,6 +435,7 @@ bool DynamicMMap::Grow() {
 			return false;
 			return false;
 	}
 	}
 
 
+	Pools =(Pool*) Base + poolOffset;
 	WorkSpace = newSize;
 	WorkSpace = newSize;
 	return true;
 	return true;
 }
 }

+ 5 - 0
apt-pkg/contrib/mmap.h

@@ -44,6 +44,11 @@ class MMap
    unsigned long iSize;
    unsigned long iSize;
    void *Base;
    void *Base;
 
 
+   // In case mmap can not be used, we keep a dup of the file
+   // descriptor that should have been mmaped so that we can write to
+   // the file in Sync().
+   FileFd *SyncToFd;
+
    bool Map(FileFd &Fd);
    bool Map(FileFd &Fd);
    bool Close(bool DoSync = true);
    bool Close(bool DoSync = true);
    
    

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

@@ -198,7 +198,8 @@ bool ParseQuoteWord(const char *&String,string &Res)
    char *I;
    char *I;
    for (I = Buffer; I < Buffer + sizeof(Buffer) && Start != C; I++)
    for (I = Buffer; I < Buffer + sizeof(Buffer) && Start != C; I++)
    {
    {
-      if (*Start == '%' && Start + 2 < C)
+      if (*Start == '%' && Start + 2 < C &&
+	  isxdigit(Start[1]) && isxdigit(Start[2]))
       {
       {
 	 Tmp[0] = Start[1];
 	 Tmp[0] = Start[1];
 	 Tmp[1] = Start[2];
 	 Tmp[1] = Start[2];
@@ -273,7 +274,8 @@ string QuoteString(const string &Str, const char *Bad)
    for (string::const_iterator I = Str.begin(); I != Str.end(); I++)
    for (string::const_iterator I = Str.begin(); I != Str.end(); I++)
    {
    {
       if (strchr(Bad,*I) != 0 || isprint(*I) == 0 || 
       if (strchr(Bad,*I) != 0 || isprint(*I) == 0 || 
-	  *I <= 0x20 || *I >= 0x7F)
+	  *I == 0x25 || // percent '%' char
+	  *I <= 0x20 || *I >= 0x7F) // control chars
       {
       {
 	 char Buf[10];
 	 char Buf[10];
 	 sprintf(Buf,"%%%02x",(int)*I);
 	 sprintf(Buf,"%%%02x",(int)*I);
@@ -289,11 +291,17 @@ string QuoteString(const string &Str, const char *Bad)
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /* This undoes QuoteString */
 /* This undoes QuoteString */
 string DeQuoteString(const string &Str)
 string DeQuoteString(const string &Str)
+{
+   return DeQuoteString(Str.begin(),Str.end());
+}
+string DeQuoteString(string::const_iterator const &begin,
+			string::const_iterator const &end)
 {
 {
    string Res;
    string Res;
-   for (string::const_iterator I = Str.begin(); I != Str.end(); I++)
+   for (string::const_iterator I = begin; I != end; I++)
    {
    {
-      if (*I == '%' && I + 2 < Str.end())
+      if (*I == '%' && I + 2 < end &&
+	  isxdigit(I[1]) && isxdigit(I[2]))
       {
       {
 	 char Tmp[3];
 	 char Tmp[3];
 	 Tmp[0] = I[1];
 	 Tmp[0] = I[1];
@@ -566,7 +574,7 @@ int stringcmp(string::const_iterator A,string::const_iterator AEnd,
 int stringcasecmp(const char *A,const char *AEnd,const char *B,const char *BEnd)
 int stringcasecmp(const char *A,const char *AEnd,const char *B,const char *BEnd)
 {
 {
    for (; A != AEnd && B != BEnd; A++, B++)
    for (; A != AEnd && B != BEnd; A++, B++)
-      if (toupper(*A) != toupper(*B))
+      if (tolower_ascii(*A) != tolower_ascii(*B))
 	 break;
 	 break;
 
 
    if (A == AEnd && B == BEnd)
    if (A == AEnd && B == BEnd)
@@ -575,7 +583,7 @@ int stringcasecmp(const char *A,const char *AEnd,const char *B,const char *BEnd)
       return 1;
       return 1;
    if (B == BEnd)
    if (B == BEnd)
       return -1;
       return -1;
-   if (toupper(*A) < toupper(*B))
+   if (tolower_ascii(*A) < tolower_ascii(*B))
       return -1;
       return -1;
    return 1;
    return 1;
 }
 }
@@ -584,7 +592,7 @@ int stringcasecmp(string::const_iterator A,string::const_iterator AEnd,
 		  const char *B,const char *BEnd)
 		  const char *B,const char *BEnd)
 {
 {
    for (; A != AEnd && B != BEnd; A++, B++)
    for (; A != AEnd && B != BEnd; A++, B++)
-      if (toupper(*A) != toupper(*B))
+      if (tolower_ascii(*A) != tolower_ascii(*B))
 	 break;
 	 break;
 
 
    if (A == AEnd && B == BEnd)
    if (A == AEnd && B == BEnd)
@@ -593,7 +601,7 @@ int stringcasecmp(string::const_iterator A,string::const_iterator AEnd,
       return 1;
       return 1;
    if (B == BEnd)
    if (B == BEnd)
       return -1;
       return -1;
-   if (toupper(*A) < toupper(*B))
+   if (tolower_ascii(*A) < tolower_ascii(*B))
       return -1;
       return -1;
    return 1;
    return 1;
 }
 }
@@ -601,7 +609,7 @@ int stringcasecmp(string::const_iterator A,string::const_iterator AEnd,
 		  string::const_iterator B,string::const_iterator BEnd)
 		  string::const_iterator B,string::const_iterator BEnd)
 {
 {
    for (; A != AEnd && B != BEnd; A++, B++)
    for (; A != AEnd && B != BEnd; A++, B++)
-      if (toupper(*A) != toupper(*B))
+      if (tolower_ascii(*A) != tolower_ascii(*B))
 	 break;
 	 break;
 
 
    if (A == AEnd && B == BEnd)
    if (A == AEnd && B == BEnd)
@@ -610,7 +618,7 @@ int stringcasecmp(string::const_iterator A,string::const_iterator AEnd,
       return 1;
       return 1;
    if (B == BEnd)
    if (B == BEnd)
       return -1;
       return -1;
-   if (toupper(*A) < toupper(*B))
+   if (tolower_ascii(*A) < tolower_ascii(*B))
       return -1;
       return -1;
    return 1;
    return 1;
 }
 }
@@ -789,28 +797,28 @@ bool ReadMessages(int Fd, vector<string> &List)
 // MonthConv - Converts a month string into a number			/*{{{*/
 // MonthConv - Converts a month string into a number			/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /* This was lifted from the boa webserver which lifted it from 'wn-v1.07'
 /* This was lifted from the boa webserver which lifted it from 'wn-v1.07'
-   Made it a bit more robust with a few touppers though. */
+   Made it a bit more robust with a few tolower_ascii though. */
 static int MonthConv(char *Month)
 static int MonthConv(char *Month)
 {
 {
-   switch (toupper(*Month)) 
+   switch (tolower_ascii(*Month)) 
    {
    {
-      case 'A':
-      return toupper(Month[1]) == 'P'?3:7;
-      case 'D':
+      case 'a':
+      return tolower_ascii(Month[1]) == 'p'?3:7;
+      case 'd':
       return 11;
       return 11;
-      case 'F':
+      case 'f':
       return 1;
       return 1;
-      case 'J':
-      if (toupper(Month[1]) == 'A')
+      case 'j':
+      if (tolower_ascii(Month[1]) == 'a')
 	 return 0;
 	 return 0;
-      return toupper(Month[2]) == 'N'?5:6;
-      case 'M':
-      return toupper(Month[2]) == 'R'?2:4;
-      case 'N':
+      return tolower_ascii(Month[2]) == 'n'?5:6;
+      case 'm':
+      return tolower_ascii(Month[2]) == 'r'?2:4;
+      case 'n':
       return 10;
       return 10;
-      case 'O':
+      case 'o':
       return 9;
       return 9;
-      case 'S':
+      case 's':
       return 8;
       return 8;
 
 
       // Pretend it is January..
       // Pretend it is January..
@@ -819,34 +827,70 @@ 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).
    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)
 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
 #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;
+   setlocale (LC_ALL,"C");
+   bool const invalid =
+   // Sun, 06 Nov 1994 08:49:37 GMT  ; RFC 822, updated by RFC 1123
+      (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);
+   setlocale (LC_ALL,"");
+   if (invalid == true)
+      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				/*{{{*/
 // StrToTime - Converts a string into a time_t				/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /* This handles all 3 populare time formats including RFC 1123, RFC 1036
 /* This handles all 3 populare time formats including RFC 1123, RFC 1036
@@ -1000,12 +1044,12 @@ bool TokSplitString(char Tok,char *Input,char **List,
    return true;
    return true;
 }
 }
 									/*}}}*/
 									/*}}}*/
-// ExplodeString - Split a string up into a vector			/*{{{*/
+// VectorizeString - Split a string up into a vector of strings		/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /* This can be used to split a given string up into a vector, so the
 /* This can be used to split a given string up into a vector, so the
    propose is the same as in the method above and this one is a bit slower
    propose is the same as in the method above and this one is a bit slower
-   also, but the advantage is that we an iteratable vector */
-vector<string> ExplodeString(string const &haystack, char const &split)
+   also, but the advantage is that we have an iteratable vector */
+vector<string> VectorizeString(string const &haystack, char const &split)
 {
 {
    string::const_iterator start = haystack.begin();
    string::const_iterator start = haystack.begin();
    string::const_iterator end = start;
    string::const_iterator end = start;
@@ -1133,10 +1177,13 @@ char *safe_snprintf(char *Buffer,char *End,const char *Format,...)
 
 
 // tolower_ascii - tolower() function that ignores the locale		/*{{{*/
 // tolower_ascii - tolower() function that ignores the locale		/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
-/* */
-int tolower_ascii(int c)
+/* This little function is the most called method we have and tries
+   therefore to do the absolut minimum - and is noteable faster than
+   standard tolower/toupper and as a bonus avoids problems with different
+   locales - we only operate on ascii chars anyway. */
+int tolower_ascii(int const c)
 {
 {
-   if (c >= 'A' and c <= 'Z')
+   if (c >= 'A' && c <= 'Z')
       return c + 32;
       return c + 32;
    return c;
    return c;
 }
 }
@@ -1235,9 +1282,10 @@ void URI::CopyFrom(const string &U)
    else
    else
    {
    {
       Host.assign(At+1,SingleSlash);
       Host.assign(At+1,SingleSlash);
-      User.assign(FirstColon,SecondColon);
+      // username and password must be encoded (RFC 3986)
+      User.assign(DeQuoteString(FirstColon,SecondColon));
       if (SecondColon < At)
       if (SecondColon < At)
-	 Password.assign(SecondColon+1,At);
+	 Password.assign(DeQuoteString(SecondColon+1,At));
    }   
    }   
    
    
    // Now we parse the RFC 2732 [] hostnames.
    // Now we parse the RFC 2732 [] hostnames.

+ 11 - 17
apt-pkg/contrib/strutl.h

@@ -25,19 +25,12 @@
 #include <iostream>
 #include <iostream>
 #include <time.h>
 #include <time.h>
 
 
+#include "macros.h"
+
 using std::string;
 using std::string;
 using std::vector;
 using std::vector;
 using std::ostream;
 using std::ostream;
 
 
-#ifdef __GNUG__
-// Methods have a hidden this parameter that is visible to this attribute
-#define APT_FORMAT2 __attribute__ ((format (printf, 2, 3)))
-#define APT_FORMAT3 __attribute__ ((format (printf, 3, 4)))
-#else
-#define APT_FORMAT2
-#define APT_FORMAT3
-#endif    
-
 bool UTF8ToCodeset(const char *codeset, const string &orig, string *dest);
 bool UTF8ToCodeset(const char *codeset, const string &orig, string *dest);
 char *_strstrip(char *String);
 char *_strstrip(char *String);
 char *_strtabexpand(char *String,size_t Len);
 char *_strtabexpand(char *String,size_t Len);
@@ -45,13 +38,16 @@ bool ParseQuoteWord(const char *&String,string &Res);
 bool ParseCWord(const char *&String,string &Res);
 bool ParseCWord(const char *&String,string &Res);
 string QuoteString(const string &Str,const char *Bad);
 string QuoteString(const string &Str,const char *Bad);
 string DeQuoteString(const string &Str);
 string DeQuoteString(const string &Str);
+string DeQuoteString(string::const_iterator const &begin, string::const_iterator const &end);
 string SizeToStr(double Bytes);
 string SizeToStr(double Bytes);
 string TimeToStr(unsigned long Sec);
 string TimeToStr(unsigned long Sec);
 string Base64Encode(const string &Str);
 string Base64Encode(const string &Str);
 string OutputInDepth(const unsigned long Depth, const char* Separator="  ");
 string OutputInDepth(const unsigned long Depth, const char* Separator="  ");
 string URItoFileName(const string &URI);
 string URItoFileName(const string &URI);
 string TimeRFC1123(time_t Date);
 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);
 string LookupTag(const string &Message,const char *Tag,const char *Default = 0);
 int StringToBool(const string &Text,int Default = -1);
 int StringToBool(const string &Text,int Default = -1);
 bool ReadMessages(int Fd, vector<string> &List);
 bool ReadMessages(int Fd, vector<string> &List);
@@ -59,12 +55,12 @@ bool StrToNum(const char *Str,unsigned long &Res,unsigned Len,unsigned Base = 0)
 bool Hex2Num(const string &Str,unsigned char *Num,unsigned int Length);
 bool Hex2Num(const string &Str,unsigned char *Num,unsigned int Length);
 bool TokSplitString(char Tok,char *Input,char **List,
 bool TokSplitString(char Tok,char *Input,char **List,
 		    unsigned long ListMax);
 		    unsigned long ListMax);
-vector<string> ExplodeString(string const &haystack, char const &split);
-void ioprintf(ostream &out,const char *format,...) APT_FORMAT2;
-void strprintf(string &out,const char *format,...) APT_FORMAT2;
-char *safe_snprintf(char *Buffer,char *End,const char *Format,...) APT_FORMAT3;
+vector<string> VectorizeString(string const &haystack, char const &split) __attrib_const;
+void ioprintf(ostream &out,const char *format,...) __like_printf(2);
+void strprintf(string &out,const char *format,...) __like_printf(2);
+char *safe_snprintf(char *Buffer,char *End,const char *Format,...) __like_printf(3);
 bool CheckDomainList(const string &Host, const string &List);
 bool CheckDomainList(const string &Host, const string &List);
-int tolower_ascii(int c);
+int tolower_ascii(int const c) __attrib_const __hot;
 
 
 #define APT_MKSTRCMP(name,func) \
 #define APT_MKSTRCMP(name,func) \
 inline int name(const char *A,const char *B) {return func(A,A+strlen(A),B,B+strlen(B));}; \
 inline int name(const char *A,const char *B) {return func(A,A+strlen(A),B,B+strlen(B));}; \
@@ -144,6 +140,4 @@ struct RxChoiceList
 unsigned long RegexChoice(RxChoiceList *Rxs,const char **ListBegin,
 unsigned long RegexChoice(RxChoiceList *Rxs,const char **ListBegin,
 		      const char **ListEnd);
 		      const char **ListEnd);
 
 
-#undef APT_FORMAT2
-
 #endif
 #endif

+ 62 - 0
apt-pkg/contrib/weakptr.h

@@ -0,0 +1,62 @@
+/* weakptr.h - An object which supports weak pointers.
+ *
+ * Copyright (C) 2010 Julian Andres Klode <jak@debian.org>
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#ifndef WEAK_POINTER_H
+#define WEAK_POINTER_H
+
+#include <set>
+/**
+ * Class for objects providing support for weak pointers.
+ *
+ * This class allows for the registration of certain pointers as weak,
+ * which will cause them to be set to NULL when the destructor of the
+ * object is called.
+ */
+class WeakPointable {
+private:
+    std::set<WeakPointable**> pointers;
+
+public:
+
+    /**
+     * Add a new weak pointer.
+     */
+    inline void AddWeakPointer(WeakPointable** weakptr) {
+       pointers.insert(weakptr);
+    }
+
+    /**
+     * Remove the weak pointer from the list of weak pointers.
+     */
+    inline void RemoveWeakPointer(WeakPointable **weakptr) {
+       pointers.erase(weakptr);
+    }
+
+    /**
+     * Deconstruct the object, set all weak pointers to NULL.
+     */
+    ~WeakPointable() {
+        std::set<WeakPointable**>::iterator iter = pointers.begin();
+        while (iter != pointers.end())
+            **(iter++) = NULL;
+    }
+};
+
+#endif // WEAK_POINTER_H

+ 52 - 21
apt-pkg/deb/debindexfile.cc

@@ -63,9 +63,13 @@ string debSourcesIndex::SourceInfo(pkgSrcRecords::Parser const &Record,
 /* */
 /* */
 pkgSrcRecords::Parser *debSourcesIndex::CreateSrcParser() const
 pkgSrcRecords::Parser *debSourcesIndex::CreateSrcParser() const
 {
 {
-   string SourcesURI = URItoFileName(IndexURI("Sources"));
-   return new debSrcRecordParser(_config->FindDir("Dir::State::lists") +
-				 SourcesURI,this);
+   string SourcesURI = _config->FindDir("Dir::State::lists") + 
+      URItoFileName(IndexURI("Sources"));
+   string SourcesURIgzip = SourcesURI + ".gz";
+   if (!FileExists(SourcesURI) && FileExists(SourcesURIgzip))
+      SourcesURI = SourcesURIgzip;
+
+   return new debSrcRecordParser(SourcesURI,this);
 }
 }
 									/*}}}*/
 									/*}}}*/
 // SourcesIndex::Describe - Give a descriptive path to the index	/*{{{*/
 // SourcesIndex::Describe - Give a descriptive path to the index	/*{{{*/
@@ -106,8 +110,14 @@ string debSourcesIndex::Info(const char *Type) const
 /* */
 /* */
 inline string debSourcesIndex::IndexFile(const char *Type) const
 inline string debSourcesIndex::IndexFile(const char *Type) const
 {
 {
-   return URItoFileName(IndexURI(Type));
+   string s = URItoFileName(IndexURI(Type));
+   string sgzip = s + ".gz";
+   if (!FileExists(s) && FileExists(sgzip))
+       return sgzip;
+   else
+       return s;
 }
 }
+
 string debSourcesIndex::IndexURI(const char *Type) const
 string debSourcesIndex::IndexURI(const char *Type) const
 {
 {
    string Res;
    string Res;
@@ -149,9 +159,12 @@ unsigned long debSourcesIndex::Size() const
 // PackagesIndex::debPackagesIndex - Contructor				/*{{{*/
 // PackagesIndex::debPackagesIndex - Contructor				/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /* */
 /* */
-debPackagesIndex::debPackagesIndex(string URI,string Dist,string Section,bool Trusted) : 
-                  pkgIndexFile(Trusted), URI(URI), Dist(Dist), Section(Section)
+debPackagesIndex::debPackagesIndex(string const &URI, string const &Dist, string const &Section,
+					bool const &Trusted, string const &Arch) :
+                  pkgIndexFile(Trusted), URI(URI), Dist(Dist), Section(Section), Architecture(Arch)
 {
 {
+	if (Architecture == "native")
+		Architecture = _config->Find("APT::Architecture");
 }
 }
 									/*}}}*/
 									/*}}}*/
 // PackagesIndex::ArchiveInfo - Short version of the archive url	/*{{{*/
 // PackagesIndex::ArchiveInfo - Short version of the archive url	/*{{{*/
@@ -171,6 +184,8 @@ string debPackagesIndex::ArchiveInfo(pkgCache::VerIterator Ver) const
    Res += " ";
    Res += " ";
    Res += Ver.ParentPkg().Name();
    Res += Ver.ParentPkg().Name();
    Res += " ";
    Res += " ";
+   if (Dist[Dist.size() - 1] != '/')
+      Res.append(Ver.Arch()).append(" ");
    Res += Ver.VerStr();
    Res += Ver.VerStr();
    return Res;
    return Res;
 }
 }
@@ -204,6 +219,8 @@ string debPackagesIndex::Info(const char *Type) const
    else
    else
       Info += Dist + '/' + Section;   
       Info += Dist + '/' + Section;   
    Info += " ";
    Info += " ";
+   if (Dist[Dist.size() - 1] != '/')
+      Info += Architecture + " ";
    Info += Type;
    Info += Type;
    return Info;
    return Info;
 }
 }
@@ -213,7 +230,12 @@ string debPackagesIndex::Info(const char *Type) const
 /* */
 /* */
 inline string debPackagesIndex::IndexFile(const char *Type) const
 inline string debPackagesIndex::IndexFile(const char *Type) const
 {
 {
-   return _config->FindDir("Dir::State::lists") + URItoFileName(IndexURI(Type));
+   string s =_config->FindDir("Dir::State::lists") + URItoFileName(IndexURI(Type));
+   string sgzip = s + ".gz";
+   if (!FileExists(s) && FileExists(sgzip))
+       return sgzip;
+   else
+       return s;
 }
 }
 string debPackagesIndex::IndexURI(const char *Type) const
 string debPackagesIndex::IndexURI(const char *Type) const
 {
 {
@@ -227,7 +249,7 @@ string debPackagesIndex::IndexURI(const char *Type) const
    }
    }
    else
    else
       Res = URI + "dists/" + Dist + '/' + Section +
       Res = URI + "dists/" + Dist + '/' + Section +
-      "/binary-" + _config->Find("APT::Architecture") + '/';
+      "/binary-" + Architecture + '/';
    
    
    Res += Type;
    Res += Type;
    return Res;
    return Res;
@@ -255,21 +277,23 @@ unsigned long debPackagesIndex::Size() const
 // PackagesIndex::Merge - Load the index file into a cache		/*{{{*/
 // 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");
    string PackageFile = IndexFile("Packages");
-   FileFd Pkg(PackageFile,FileFd::ReadOnly);
-   debListParser Parser(&Pkg);
+   FileFd Pkg(PackageFile,FileFd::ReadOnlyGzip);
+   debListParser Parser(&Pkg, Architecture);
+
    if (_error->PendingError() == true)
    if (_error->PendingError() == true)
       return _error->Error("Problem opening %s",PackageFile.c_str());
       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);
    ::URI Tmp(URI);
    if (Gen.SelectFile(PackageFile,Tmp.Host,*this) == false)
    if (Gen.SelectFile(PackageFile,Tmp.Host,*this) == false)
       return _error->Error("Problem with SelectFile %s",PackageFile.c_str());
       return _error->Error("Problem with SelectFile %s",PackageFile.c_str());
 
 
    // Store the IMS information
    // Store the IMS information
    pkgCache::PkgFileIterator File = Gen.GetCurFile();
    pkgCache::PkgFileIterator File = Gen.GetCurFile();
+   pkgCacheGenerator::Dynamic<pkgCache::PkgFileIterator> DynFile(File);
    struct stat St;
    struct stat St;
    if (fstat(Pkg.Fd(),&St) != 0)
    if (fstat(Pkg.Fd(),&St) != 0)
       return _error->Errno("fstat","Failed to stat");
       return _error->Errno("fstat","Failed to stat");
@@ -340,7 +364,12 @@ debTranslationsIndex::debTranslationsIndex(string URI,string Dist,string Section
 /* */
 /* */
 inline string debTranslationsIndex::IndexFile(const char *Type) const
 inline string debTranslationsIndex::IndexFile(const char *Type) const
 {
 {
-   return _config->FindDir("Dir::State::lists") + URItoFileName(IndexURI(Type));
+   string s =_config->FindDir("Dir::State::lists") + URItoFileName(IndexURI(Type));
+   string sgzip = s + ".gz";
+   if (!FileExists(s) && FileExists(sgzip))
+       return sgzip;
+   else
+       return s;
 }
 }
 string debTranslationsIndex::IndexURI(const char *Type) const
 string debTranslationsIndex::IndexURI(const char *Type) const
 {
 {
@@ -438,18 +467,19 @@ unsigned long debTranslationsIndex::Size() const
 // TranslationsIndex::Merge - Load the index file into a cache		/*{{{*/
 // 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
    // Check the translation file, if in use
    string TranslationFile = IndexFile(Language);
    string TranslationFile = IndexFile(Language);
    if (TranslationsAvailable() && FileExists(TranslationFile))
    if (TranslationsAvailable() && FileExists(TranslationFile))
    {
    {
-     FileFd Trans(TranslationFile,FileFd::ReadOnly);
+     FileFd Trans(TranslationFile,FileFd::ReadOnlyGzip);
      debListParser TransParser(&Trans);
      debListParser TransParser(&Trans);
      if (_error->PendingError() == true)
      if (_error->PendingError() == true)
        return false;
        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)
      if (Gen.SelectFile(TranslationFile,string(),*this) == false)
        return _error->Error("Problem with SelectFile %s",TranslationFile.c_str());
        return _error->Error("Problem with SelectFile %s",TranslationFile.c_str());
 
 
@@ -522,16 +552,17 @@ unsigned long debStatusIndex::Size() const
 // StatusIndex::Merge - Load the index file into a cache		/*{{{*/
 // 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);
+   FileFd Pkg(File,FileFd::ReadOnlyGzip);
    if (_error->PendingError() == true)
    if (_error->PendingError() == true)
       return false;
       return false;
    debListParser Parser(&Pkg);
    debListParser Parser(&Pkg);
    if (_error->PendingError() == true)
    if (_error->PendingError() == true)
       return false;
       return false;
-   
-   Prog.SubProgress(0,File);
+
+   if (Prog != NULL)
+      Prog->SubProgress(0,File);
    if (Gen.SelectFile(File,string(),*this,pkgCache::Flag::NotSource) == false)
    if (Gen.SelectFile(File,string(),*this,pkgCache::Flag::NotSource) == false)
       return _error->Error("Problem with SelectFile %s",File.c_str());
       return _error->Error("Problem with SelectFile %s",File.c_str());
 
 

+ 6 - 4
apt-pkg/deb/debindexfile.h

@@ -35,7 +35,7 @@ class debStatusIndex : public pkgIndexFile
    virtual bool Exists() const;
    virtual bool Exists() const;
    virtual bool HasPackages() const {return true;};
    virtual bool HasPackages() const {return true;};
    virtual unsigned long Size() 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;
    virtual pkgCache::PkgFileIterator FindInCache(pkgCache &Cache) const;
 
 
    debStatusIndex(string File);
    debStatusIndex(string File);
@@ -46,6 +46,7 @@ class debPackagesIndex : public pkgIndexFile
    string URI;
    string URI;
    string Dist;
    string Dist;
    string Section;
    string Section;
+   string Architecture;
 
 
    string Info(const char *Type) const;
    string Info(const char *Type) const;
    string IndexFile(const char *Type) const;
    string IndexFile(const char *Type) const;
@@ -66,10 +67,11 @@ class debPackagesIndex : public pkgIndexFile
    virtual bool Exists() const;
    virtual bool Exists() const;
    virtual bool HasPackages() const {return true;};
    virtual bool HasPackages() const {return true;};
    virtual unsigned long Size() 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;
    virtual pkgCache::PkgFileIterator FindInCache(pkgCache &Cache) const;
 
 
-   debPackagesIndex(string URI,string Dist,string Section,bool Trusted);
+   debPackagesIndex(string const &URI, string const &Dist, string const &Section,
+			bool const &Trusted, string const &Arch = "native");
 };
 };
 
 
 class debTranslationsIndex : public pkgIndexFile
 class debTranslationsIndex : public pkgIndexFile
@@ -97,7 +99,7 @@ class debTranslationsIndex : public pkgIndexFile
    virtual bool Exists() const;
    virtual bool Exists() const;
    virtual bool HasPackages() const;
    virtual bool HasPackages() const;
    virtual unsigned long Size() 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;
    virtual pkgCache::PkgFileIterator FindInCache(pkgCache &Cache) const;
 
 
    debTranslationsIndex(string URI,string Dist,string Section, char const * const Language);
    debTranslationsIndex(string URI,string Dist,string Section, char const * const Language);

+ 204 - 56
apt-pkg/deb/deblistparser.cc

@@ -19,6 +19,7 @@
 #include <apt-pkg/md5.h>
 #include <apt-pkg/md5.h>
 #include <apt-pkg/macros.h>
 #include <apt-pkg/macros.h>
 
 
+#include <fnmatch.h>
 #include <ctype.h>
 #include <ctype.h>
 									/*}}}*/
 									/*}}}*/
 
 
@@ -31,10 +32,15 @@ static debListParser::WordList PrioList[] = {{"important",pkgCache::State::Impor
 
 
 // ListParser::debListParser - Constructor				/*{{{*/
 // ListParser::debListParser - Constructor				/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
-/* */
-debListParser::debListParser(FileFd *File) : Tags(File)
-{
-   Arch = _config->Find("APT::architecture");
+/* Provide an architecture and only this one and "all" will be accepted
+   in Step(), if no Architecture is given we will accept every arch
+   we would accept in general with checkArchitecture() */
+debListParser::debListParser(FileFd *File, string const &Arch) : Tags(File),
+				Arch(Arch) {
+   if (Arch == "native")
+      this->Arch = _config->Find("APT::Architecture");
+   Architectures = APT::Configuration::getArchitectures();
+   MultiArchEnabled = Architectures.size() > 1;
 }
 }
 									/*}}}*/
 									/*}}}*/
 // ListParser::UniqFindTagWrite - Find the tag and write a unq string	/*{{{*/
 // ListParser::UniqFindTagWrite - Find the tag and write a unq string	/*{{{*/
@@ -52,14 +58,41 @@ unsigned long debListParser::UniqFindTagWrite(const char *Tag)
 // ListParser::Package - Return the package name			/*{{{*/
 // ListParser::Package - Return the package name			/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /* This is to return the name of the package this section describes */
 /* This is to return the name of the package this section describes */
-string debListParser::Package()
-{
-   string Result = Section.FindS("Package");
-   if (Result.empty() == true)
+string debListParser::Package() {
+   string const Result = Section.FindS("Package");
+   if(unlikely(Result.empty() == true))
       _error->Error("Encountered a section with no Package: header");
       _error->Error("Encountered a section with no Package: header");
    return Result;
    return Result;
 }
 }
 									/*}}}*/
 									/*}}}*/
+// ListParser::Architecture - Return the package arch			/*{{{*/
+// ---------------------------------------------------------------------
+/* This will return the Architecture of the package this section describes
+   Note that architecture "all" packages will get the architecture of the
+   Packages file parsed here. */
+string debListParser::Architecture() {
+   string const Result = Section.FindS("Architecture");
+   if (Result.empty() == true || Result == "all")
+   {
+      if (Arch.empty() == true)
+	 /* FIXME: this is a problem for installed arch all
+	    packages as we don't know from which arch this
+	    package was installed - and therefore which
+	    dependency this package resolves. */
+	 return _config->Find("APT::Architecture");
+      else
+	 return Arch;
+   }
+   return Result;
+}
+									/*}}}*/
+// ListParser::ArchitectureAll						/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool debListParser::ArchitectureAll() {
+   return Section.FindS("Architecture") == "all";
+}
+									/*}}}*/
 // ListParser::Version - Return the version string			/*{{{*/
 // ListParser::Version - Return the version string			/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /* This is to return the string describing the version in debian form,
 /* This is to return the string describing the version in debian form,
@@ -73,17 +106,39 @@ string debListParser::Version()
 // ListParser::NewVersion - Fill in the version structure		/*{{{*/
 // ListParser::NewVersion - Fill in the version structure		/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /* */
 /* */
-bool debListParser::NewVersion(pkgCache::VerIterator Ver)
+bool debListParser::NewVersion(pkgCache::VerIterator &Ver)
 {
 {
    // Parse the section
    // Parse the section
    Ver->Section = UniqFindTagWrite("Section");
    Ver->Section = UniqFindTagWrite("Section");
-   Ver->Arch = UniqFindTagWrite("Architecture");
-   
+
+   // Parse multi-arch
+   if (Section.FindS("Architecture") == "all")
+      /* Arch all packages can't have a Multi-Arch field,
+         but we need a special treatment for them nonetheless */
+      Ver->MultiArch = pkgCache::Version::All;
+   else
+   {
+      string const MultiArch = Section.FindS("Multi-Arch");
+      if (MultiArch.empty() == true)
+	 Ver->MultiArch = pkgCache::Version::None;
+      else if (MultiArch == "same")
+	 Ver->MultiArch = pkgCache::Version::Same;
+      else if (MultiArch == "foreign")
+	 Ver->MultiArch = pkgCache::Version::Foreign;
+      else if (MultiArch == "allowed")
+	 Ver->MultiArch = pkgCache::Version::Allowed;
+      else
+      {
+	 _error->Warning("Unknown Multi-Arch type »%s« for package »%s«",
+			MultiArch.c_str(), Section.FindS("Package").c_str());
+	 Ver->MultiArch = pkgCache::Version::None;
+      }
+   }
+
    // Archive Size
    // Archive Size
-   Ver->Size = (unsigned)Section.FindI("Size");
-   
+   Ver->Size = Section.FindULL("Size");
    // Unpacked Size (in K)
    // Unpacked Size (in K)
-   Ver->InstalledSize = (unsigned)Section.FindI("Installed-Size");
+   Ver->InstalledSize = Section.FindULL("Installed-Size");
    Ver->InstalledSize *= 1024;
    Ver->InstalledSize *= 1024;
 
 
    // Priority
    // Priority
@@ -95,6 +150,24 @@ bool debListParser::NewVersion(pkgCache::VerIterator Ver)
 	 Ver->Priority = pkgCache::State::Extra;
 	 Ver->Priority = pkgCache::State::Extra;
    }
    }
 
 
+   if (Ver->MultiArch == pkgCache::Version::All)
+   {
+      /* We maintain a "pseudo" arch=all package for architecture all versions
+	 on which these versions can depend on. This pseudo package is many used
+	 for downloading/installing: The other pseudo-packages will degenerate
+	 to a NOP in the download/install step - this package will ensure that
+	 it is downloaded only one time and installed only one time -- even if
+	 the architecture bound versions coming in and out on regular basis. */
+      if (strcmp(Ver.Arch(true),"all") == 0)
+	 return true;
+      else if (MultiArchEnabled == true)
+      {
+	 // our pseudo packages have no size to not confuse the fetcher
+	 Ver->Size = 0;
+	 Ver->InstalledSize = 0;
+      }
+   }
+
    if (ParseDepends(Ver,"Depends",pkgCache::Dep::Depends) == false)
    if (ParseDepends(Ver,"Depends",pkgCache::Dep::Depends) == false)
       return false;
       return false;
    if (ParseDepends(Ver,"Pre-Depends",pkgCache::Dep::PreDepends) == false)
    if (ParseDepends(Ver,"Pre-Depends",pkgCache::Dep::PreDepends) == false)
@@ -178,13 +251,21 @@ MD5SumValue debListParser::Description_md5()
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /* This is called to update the package with any new information 
 /* This is called to update the package with any new information 
    that might be found in the section */
    that might be found in the section */
-bool debListParser::UsePackage(pkgCache::PkgIterator Pkg,
-			       pkgCache::VerIterator Ver)
+bool debListParser::UsePackage(pkgCache::PkgIterator &Pkg,
+			       pkgCache::VerIterator &Ver)
 {
 {
    if (Pkg->Section == 0)
    if (Pkg->Section == 0)
       Pkg->Section = UniqFindTagWrite("Section");
       Pkg->Section = UniqFindTagWrite("Section");
-   if (Section.FindFlag("Essential",Pkg->Flags,pkgCache::Flag::Essential) == false)
-      return false;
+
+   // Packages which are not from the "native" arch doesn't get the essential flag
+   // in the default "native" mode - it is also possible to mark "all" or "none".
+   // The "installed" mode is handled by ParseStatus(), See #544481 and friends.
+   string const static myArch = _config->Find("APT::Architecture");
+   string const static essential = _config->Find("pkgCacheGen::Essential", "native");
+   if ((essential == "native" && Pkg->Arch != 0 && myArch == Pkg.Arch()) ||
+       essential == "all")
+      if (Section.FindFlag("Essential",Pkg->Flags,pkgCache::Flag::Essential) == false)
+	 return false;
    if (Section.FindFlag("Important",Pkg->Flags,pkgCache::Flag::Important) == false)
    if (Section.FindFlag("Important",Pkg->Flags,pkgCache::Flag::Important) == false)
       return false;
       return false;
 
 
@@ -251,14 +332,20 @@ unsigned short debListParser::VersionHash()
    Some of the above are obsolete (I think?) flag = hold-* and 
    Some of the above are obsolete (I think?) flag = hold-* and 
    status = post-inst-failed, removal-failed at least.
    status = post-inst-failed, removal-failed at least.
  */
  */
-bool debListParser::ParseStatus(pkgCache::PkgIterator Pkg,
-				pkgCache::VerIterator Ver)
+bool debListParser::ParseStatus(pkgCache::PkgIterator &Pkg,
+				pkgCache::VerIterator &Ver)
 {
 {
    const char *Start;
    const char *Start;
    const char *Stop;
    const char *Stop;
    if (Section.Find("Status",Start,Stop) == false)
    if (Section.Find("Status",Start,Stop) == false)
       return true;
       return true;
-   
+
+   // UsePackage() is responsible for setting the flag in the default case
+   bool const static essential = _config->Find("pkgCacheGen::Essential", "") == "installed";
+   if (essential == true &&
+       Section.FindFlag("Essential",Pkg->Flags,pkgCache::Flag::Essential) == false)
+      return false;
+
    // Isolate the first word
    // Isolate the first word
    const char *I = Start;
    const char *I = Start;
    for(; I < Stop && *I != ' '; I++);
    for(; I < Stop && *I != ' '; I++);
@@ -387,6 +474,20 @@ const char *debListParser::ConvertRelation(const char *I,unsigned int &Op)
    return I;
    return I;
 }
 }
 
 
+/*
+ * CompleteArch:
+ *
+ * The complete architecture, consisting of <kernel>-<cpu>.
+ */
+static string CompleteArch(std::string& arch) {
+    if (arch == "armel")              return "linux-arm";
+    if (arch == "lpia")               return "linux-i386";
+    if (arch == "powerpcspe")         return "linux-powerpc";
+    if (arch == "uclibc-linux-armel") return "linux-arm";
+    if (arch == "uclinux-armel")      return "uclinux-arm";
+
+    return (arch.find("-") != string::npos) ? arch : "linux-" + arch;
+}
 									/*}}}*/
 									/*}}}*/
 // ListParser::ParseDepends - Parse a dependency element		/*{{{*/
 // ListParser::ParseDepends - Parse a dependency element		/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
@@ -460,6 +561,7 @@ const char *debListParser::ParseDepends(const char *Start,const char *Stop,
    if (ParseArchFlags == true)
    if (ParseArchFlags == true)
    {
    {
       string arch = _config->Find("APT::Architecture");
       string arch = _config->Find("APT::Architecture");
+      string completeArch = CompleteArch(arch);
 
 
       // Parse an architecture
       // Parse an architecture
       if (I != Stop && *I == '[')
       if (I != Stop && *I == '[')
@@ -487,8 +589,13 @@ const char *debListParser::ParseDepends(const char *Start,const char *Stop,
 	       I++;
 	       I++;
             }
             }
 
 
-	    if (stringcmp(arch,I,End) == 0)
+	    if (stringcmp(arch,I,End) == 0) {
 	       Found = true;
 	       Found = true;
+	    } else {
+	       std::string wildcard = SubstVar(string(I, End), "any", "*");
+	       if (fnmatch(wildcard.c_str(), completeArch.c_str(), 0) == 0)
+	          Found = true;
+	    }
 	    
 	    
 	    if (*End++ == ']') {
 	    if (*End++ == ']') {
 	       I = End;
 	       I = End;
@@ -527,15 +634,16 @@ const char *debListParser::ParseDepends(const char *Start,const char *Stop,
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /* This is the higher level depends parser. It takes a tag and generates
 /* This is the higher level depends parser. It takes a tag and generates
    a complete depends tree for the given version. */
    a complete depends tree for the given version. */
-bool debListParser::ParseDepends(pkgCache::VerIterator Ver,
+bool debListParser::ParseDepends(pkgCache::VerIterator &Ver,
 				 const char *Tag,unsigned int Type)
 				 const char *Tag,unsigned int Type)
 {
 {
    const char *Start;
    const char *Start;
    const char *Stop;
    const char *Stop;
    if (Section.Find(Tag,Start,Stop) == false)
    if (Section.Find(Tag,Start,Stop) == false)
       return true;
       return true;
-   
+
    string Package;
    string Package;
+   string const pkgArch = Ver.Arch(true);
    string Version;
    string Version;
    unsigned int Op;
    unsigned int Op;
 
 
@@ -544,8 +652,18 @@ bool debListParser::ParseDepends(pkgCache::VerIterator Ver,
       Start = ParseDepends(Start,Stop,Package,Version,Op);
       Start = ParseDepends(Start,Stop,Package,Version,Op);
       if (Start == 0)
       if (Start == 0)
 	 return _error->Error("Problem parsing dependency %s",Tag);
 	 return _error->Error("Problem parsing dependency %s",Tag);
-      
-      if (NewDepends(Ver,Package,Version,Op,Type) == false)
+
+      if (MultiArchEnabled == true &&
+	  (Type == pkgCache::Dep::Conflicts ||
+	   Type == pkgCache::Dep::DpkgBreaks ||
+	   Type == pkgCache::Dep::Replaces))
+      {
+	 for (std::vector<std::string>::const_iterator a = Architectures.begin();
+	      a != Architectures.end(); ++a)
+	    if (NewDepends(Ver,Package,*a,Version,Op,Type) == false)
+	       return false;
+      }
+      else if (NewDepends(Ver,Package,pkgArch,Version,Op,Type) == false)
 	 return false;
 	 return false;
       if (Start == Stop)
       if (Start == Stop)
 	 break;
 	 break;
@@ -556,33 +674,55 @@ bool debListParser::ParseDepends(pkgCache::VerIterator Ver,
 // ListParser::ParseProvides - Parse the provides list			/*{{{*/
 // ListParser::ParseProvides - Parse the provides list			/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /* */
 /* */
-bool debListParser::ParseProvides(pkgCache::VerIterator Ver)
+bool debListParser::ParseProvides(pkgCache::VerIterator &Ver)
 {
 {
    const char *Start;
    const char *Start;
    const char *Stop;
    const char *Stop;
-   if (Section.Find("Provides",Start,Stop) == false)
-      return true;
-   
-   string Package;
-   string Version;
-   unsigned int Op;
-
-   while (1)
+   if (Section.Find("Provides",Start,Stop) == true)
    {
    {
-      Start = ParseDepends(Start,Stop,Package,Version,Op);
-      if (Start == 0)
-	 return _error->Error("Problem parsing Provides line");
-      if (Op != pkgCache::Dep::NoOp) {
-	 _error->Warning("Ignoring Provides line with DepCompareOp for package %s", Package.c_str());
-      } else {
-	 if (NewProvides(Ver,Package,Version) == false)
-	    return false;
+      string Package;
+      string Version;
+      string const Arch = Ver.Arch(true);
+      unsigned int Op;
+
+      while (1)
+      {
+	 Start = ParseDepends(Start,Stop,Package,Version,Op);
+	 if (Start == 0)
+	    return _error->Error("Problem parsing Provides line");
+	 if (Op != pkgCache::Dep::NoOp) {
+	    _error->Warning("Ignoring Provides line with DepCompareOp for package %s", Package.c_str());
+	 } else {
+	    if (NewProvides(Ver, Package, Arch, Version) == false)
+	       return false;
+	 }
+
+	 if (Start == Stop)
+	    break;
       }
       }
+   }
 
 
-      if (Start == Stop)
-	 break;
+   if (Ver->MultiArch == pkgCache::Version::Allowed)
+   {
+      string const Package = string(Ver.ParentPkg().Name()).append(":").append("any");
+      NewProvides(Ver, Package, "any", Ver.VerStr());
    }
    }
-   
+
+   if (Ver->MultiArch != pkgCache::Version::Foreign)
+      return true;
+
+   if (MultiArchEnabled == false)
+      return true;
+
+   string const Package = Ver.ParentPkg().Name();
+   string const Version = Ver.VerStr();
+   for (std::vector<string>::const_iterator a = Architectures.begin();
+	a != Architectures.end(); ++a)
+   {
+      if (NewProvides(Ver, Package, *a, Version) == false)
+	 return false;
+   }
+
    return true;
    return true;
 }
 }
 									/*}}}*/
 									/*}}}*/
@@ -613,16 +753,23 @@ bool debListParser::Step()
       /* See if this is the correct Architecture, if it isn't then we
       /* See if this is the correct Architecture, if it isn't then we
          drop the whole section. A missing arch tag only happens (in theory)
          drop the whole section. A missing arch tag only happens (in theory)
          inside the Status file, so that is a positive return */
          inside the Status file, so that is a positive return */
-      const char *Start;
-      const char *Stop;
-      if (Section.Find("Architecture",Start,Stop) == false)
+      string const Architecture = Section.FindS("Architecture");
+      if (Architecture.empty() == true)
 	 return true;
 	 return true;
 
 
-      if (stringcmp(Arch,Start,Stop) == 0)
-	 return true;
+      if (Arch.empty() == true || Arch == "any" || MultiArchEnabled == false)
+      {
+	 if (APT::Configuration::checkArchitecture(Architecture) == true)
+	    return true;
+      }
+      else
+      {
+	 if (Architecture == Arch)
+	    return true;
 
 
-      if (stringcmp(Start,Stop,"all") == 0)
-	 return true;
+	 if (Architecture == "all")
+	    return true;
+      }
 
 
       iOffset = Tags.Offset();
       iOffset = Tags.Offset();
    }   
    }   
@@ -632,7 +779,7 @@ bool debListParser::Step()
 // ListParser::LoadReleaseInfo - Load the release information		/*{{{*/
 // ListParser::LoadReleaseInfo - Load the release information		/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /* */
 /* */
-bool debListParser::LoadReleaseInfo(pkgCache::PkgFileIterator FileI,
+bool debListParser::LoadReleaseInfo(pkgCache::PkgFileIterator &FileI,
 				    FileFd &File, string component)
 				    FileFd &File, string component)
 {
 {
    pkgTagFile Tags(&File, File.Size() + 256); // XXX
    pkgTagFile Tags(&File, File.Size() + 256); // XXX
@@ -640,8 +787,9 @@ bool debListParser::LoadReleaseInfo(pkgCache::PkgFileIterator FileI,
    if (Tags.Step(Section) == false)
    if (Tags.Step(Section) == false)
       return false;
       return false;
 
 
-   //mvo: I don't think we need to fill that in (it's unused since apt-0.6)
-   //FileI->Architecture = WriteUniqString(Arch);
+   // FIXME: Do we need it now for multi-arch?
+   // mvo: I don't think we need to fill that in (it's unused since apt-0.6)
+//    FileI->Architecture = WriteUniqString(Arch);
    
    
    // apt-secure does no longer download individual (per-section) Release
    // apt-secure does no longer download individual (per-section) Release
    // file. to provide Component pinning we use the section name now
    // file. to provide Component pinning we use the section name now

+ 13 - 9
apt-pkg/deb/deblistparser.h

@@ -32,12 +32,14 @@ class debListParser : public pkgCacheGenerator::ListParser
    pkgTagSection Section;
    pkgTagSection Section;
    unsigned long iOffset;
    unsigned long iOffset;
    string Arch;
    string Arch;
-   
+   std::vector<std::string> Architectures;
+   bool MultiArchEnabled;
+
    unsigned long UniqFindTagWrite(const char *Tag);
    unsigned long UniqFindTagWrite(const char *Tag);
-   bool ParseStatus(pkgCache::PkgIterator Pkg,pkgCache::VerIterator Ver);
-   bool ParseDepends(pkgCache::VerIterator Ver,const char *Tag,
+   bool ParseStatus(pkgCache::PkgIterator &Pkg,pkgCache::VerIterator &Ver);
+   bool ParseDepends(pkgCache::VerIterator &Ver,const char *Tag,
 		     unsigned int Type);
 		     unsigned int Type);
-   bool ParseProvides(pkgCache::VerIterator Ver);
+   bool ParseProvides(pkgCache::VerIterator &Ver);
    static bool GrabWord(string Word,WordList *List,unsigned char &Out);
    static bool GrabWord(string Word,WordList *List,unsigned char &Out);
    
    
    public:
    public:
@@ -46,20 +48,22 @@ class debListParser : public pkgCacheGenerator::ListParser
       
       
    // These all operate against the current section
    // These all operate against the current section
    virtual string Package();
    virtual string Package();
+   virtual string Architecture();
+   virtual bool ArchitectureAll();
    virtual string Version();
    virtual string Version();
-   virtual bool NewVersion(pkgCache::VerIterator Ver);
+   virtual bool NewVersion(pkgCache::VerIterator &Ver);
    virtual string Description();
    virtual string Description();
    virtual string DescriptionLanguage();
    virtual string DescriptionLanguage();
    virtual MD5SumValue Description_md5();
    virtual MD5SumValue Description_md5();
    virtual unsigned short VersionHash();
    virtual unsigned short VersionHash();
-   virtual bool UsePackage(pkgCache::PkgIterator Pkg,
-			   pkgCache::VerIterator Ver);
+   virtual bool UsePackage(pkgCache::PkgIterator &Pkg,
+			   pkgCache::VerIterator &Ver);
    virtual unsigned long Offset() {return iOffset;};
    virtual unsigned long Offset() {return iOffset;};
    virtual unsigned long Size() {return Section.size();};
    virtual unsigned long Size() {return Section.size();};
 
 
    virtual bool Step();
    virtual bool Step();
    
    
-   bool LoadReleaseInfo(pkgCache::PkgFileIterator FileI,FileFd &File,
+   bool LoadReleaseInfo(pkgCache::PkgFileIterator &FileI,FileFd &File,
 			string section);
 			string section);
    
    
    static const char *ParseDepends(const char *Start,const char *Stop,
    static const char *ParseDepends(const char *Start,const char *Stop,
@@ -68,7 +72,7 @@ class debListParser : public pkgCacheGenerator::ListParser
 			    bool const &StripMultiArch = false);
 			    bool const &StripMultiArch = false);
    static const char *ConvertRelation(const char *I,unsigned int &Op);
    static const char *ConvertRelation(const char *I,unsigned int &Op);
 
 
-   debListParser(FileFd *File);
+   debListParser(FileFd *File, string const &Arch = "");
 };
 };
 
 
 #endif
 #endif

+ 194 - 110
apt-pkg/deb/debmetaindex.cc

@@ -8,9 +8,11 @@
 #include <apt-pkg/aptconfiguration.h>
 #include <apt-pkg/aptconfiguration.h>
 #include <apt-pkg/error.h>
 #include <apt-pkg/error.h>
 
 
+#include <set>
+
 using namespace std;
 using namespace std;
 
 
-string debReleaseIndex::Info(const char *Type, const string Section) const
+string debReleaseIndex::Info(const char *Type, string const &Section, string const &Arch) const
 {
 {
    string Info = ::URI::SiteOnly(URI) + ' ';
    string Info = ::URI::SiteOnly(URI) + ' ';
    if (Dist[Dist.size() - 1] == '/')
    if (Dist[Dist.size() - 1] == '/')
@@ -19,7 +21,11 @@ string debReleaseIndex::Info(const char *Type, const string Section) const
          Info += Dist;
          Info += Dist;
    }
    }
    else
    else
-      Info += Dist + '/' + Section;   
+   {
+      Info += Dist + '/' + Section;
+      if (Arch.empty() != true)
+	 Info += " " + Arch;
+   }
    Info += " ";
    Info += " ";
    Info += Type;
    Info += Type;
    return Info;
    return Info;
@@ -61,16 +67,21 @@ string debReleaseIndex::MetaIndexURI(const char *Type) const
    return Res;
    return Res;
 }
 }
 
 
-string debReleaseIndex::IndexURISuffix(const char *Type, const string Section) const
+string debReleaseIndex::IndexURISuffix(const char *Type, string const &Section, string const &Arch) const
 {
 {
    string Res ="";
    string Res ="";
    if (Dist[Dist.size() - 1] != '/')
    if (Dist[Dist.size() - 1] != '/')
-      Res += Section + "/binary-" + _config->Find("APT::Architecture") + '/';
+   {
+      if (Arch == "native")
+	 Res += Section + "/binary-" + _config->Find("APT::Architecture") + '/';
+      else
+	 Res += Section + "/binary-" + Arch + '/';
+   }
    return Res + Type;
    return Res + Type;
 }
 }
    
    
 
 
-string debReleaseIndex::IndexURI(const char *Type, const string Section) const
+string debReleaseIndex::IndexURI(const char *Type, string const &Section, string const &Arch) const
 {
 {
    if (Dist[Dist.size() - 1] == '/')
    if (Dist[Dist.size() - 1] == '/')
    {
    {
@@ -82,10 +93,10 @@ string debReleaseIndex::IndexURI(const char *Type, const string Section) const
       return Res + Type;
       return Res + Type;
    }
    }
    else
    else
-      return URI + "dists/" + Dist + '/' + IndexURISuffix(Type, Section);
+      return URI + "dists/" + Dist + '/' + IndexURISuffix(Type, Section, Arch);
  }
  }
 
 
-string debReleaseIndex::SourceIndexURISuffix(const char *Type, const string Section) const
+string debReleaseIndex::SourceIndexURISuffix(const char *Type, const string &Section) const
 {
 {
    string Res ="";
    string Res ="";
    if (Dist[Dist.size() - 1] != '/')
    if (Dist[Dist.size() - 1] != '/')
@@ -93,7 +104,7 @@ string debReleaseIndex::SourceIndexURISuffix(const char *Type, const string Sect
    return Res + Type;
    return Res + Type;
 }
 }
 
 
-string debReleaseIndex::SourceIndexURI(const char *Type, const string Section) const
+string debReleaseIndex::SourceIndexURI(const char *Type, const string &Section) const
 {
 {
    string Res;
    string Res;
    if (Dist[Dist.size() - 1] == '/')
    if (Dist[Dist.size() - 1] == '/')
@@ -108,44 +119,61 @@ string debReleaseIndex::SourceIndexURI(const char *Type, const string Section) c
       return URI + "dists/" + Dist + "/" + SourceIndexURISuffix(Type, Section);
       return URI + "dists/" + Dist + "/" + SourceIndexURISuffix(Type, Section);
 }
 }
 
 
-debReleaseIndex::debReleaseIndex(string URI,string Dist)
-{
-   this->URI = URI;
-   this->Dist = Dist;
-   this->Indexes = NULL;
-   this->Type = "deb";
+debReleaseIndex::debReleaseIndex(string const &URI, string const &Dist) {
+	this->URI = URI;
+	this->Dist = Dist;
+	this->Indexes = NULL;
+	this->Type = "deb";
 }
 }
 
 
-debReleaseIndex::~debReleaseIndex()
-{
-   for (vector<const debSectionEntry *>::const_iterator I = SectionEntries.begin();
-	I != SectionEntries.end(); I++)
-      delete *I;
+debReleaseIndex::~debReleaseIndex() {
+	for (map<string, vector<debSectionEntry const*> >::const_iterator A = ArchEntries.begin();
+	     A != ArchEntries.end(); ++A)
+		for (vector<const debSectionEntry *>::const_iterator S = A->second.begin();
+		     S != A->second.end(); ++S)
+			delete *S;
 }
 }
 
 
-vector <struct IndexTarget *>* debReleaseIndex::ComputeIndexTargets() const
-{
-   vector <struct IndexTarget *>* IndexTargets = new vector <IndexTarget *>;
-   for (vector <const debSectionEntry *>::const_iterator I = SectionEntries.begin();
-	I != SectionEntries.end();
-	I++)
-   {
-      IndexTarget * Target = new IndexTarget();
-      Target->ShortDesc = (*I)->IsSrc ? "Sources" : "Packages";
-      Target->MetaKey
-	= (*I)->IsSrc ? SourceIndexURISuffix(Target->ShortDesc.c_str(), (*I)->Section)
-	              : IndexURISuffix(Target->ShortDesc.c_str(), (*I)->Section);
-      Target->URI 
-	= (*I)->IsSrc ? SourceIndexURI(Target->ShortDesc.c_str(), (*I)->Section)
-	              : IndexURI(Target->ShortDesc.c_str(), (*I)->Section);
-      
-      Target->Description = Info (Target->ShortDesc.c_str(), (*I)->Section);
-      IndexTargets->push_back (Target);
-   }
-   return IndexTargets;
+vector <struct IndexTarget *>* debReleaseIndex::ComputeIndexTargets() const {
+	vector <struct IndexTarget *>* IndexTargets = new vector <IndexTarget *>;
+
+	map<string, vector<debSectionEntry const*> >::const_iterator const src = ArchEntries.find("source");
+	if (src != ArchEntries.end()) {
+		vector<debSectionEntry const*> const SectionEntries = src->second;
+		for (vector<debSectionEntry const*>::const_iterator I = SectionEntries.begin();
+		     I != SectionEntries.end(); ++I) {
+			IndexTarget * Target = new IndexTarget();
+			Target->ShortDesc = "Sources";
+			Target->MetaKey = SourceIndexURISuffix(Target->ShortDesc.c_str(), (*I)->Section);
+			Target->URI = SourceIndexURI(Target->ShortDesc.c_str(), (*I)->Section);
+			Target->Description = Info (Target->ShortDesc.c_str(), (*I)->Section);
+			IndexTargets->push_back (Target);
+		}
+	}
+
+	// Only source release
+	if (IndexTargets->empty() == false && ArchEntries.size() == 1)
+		return IndexTargets;
+
+	for (map<string, vector<debSectionEntry const*> >::const_iterator a = ArchEntries.begin();
+	     a != ArchEntries.end(); ++a) {
+		if (a->first == "source")
+			continue;
+		for (vector <const debSectionEntry *>::const_iterator I = a->second.begin();
+		     I != a->second.end(); ++I) {
+			IndexTarget * Target = new IndexTarget();
+			Target->ShortDesc = "Packages";
+			Target->MetaKey = IndexURISuffix(Target->ShortDesc.c_str(), (*I)->Section, a->first);
+			Target->URI = IndexURI(Target->ShortDesc.c_str(), (*I)->Section, a->first);
+			Target->Description = Info (Target->ShortDesc.c_str(), (*I)->Section, a->first);
+			IndexTargets->push_back (Target);
+		}
+	}
+
+	return IndexTargets;
 }
 }
 									/*}}}*/
 									/*}}}*/
-bool debReleaseIndex::GetIndexes(pkgAcquire *Owner, bool GetAll) const
+bool debReleaseIndex::GetIndexes(pkgAcquire *Owner, bool const &GetAll) const
 {
 {
    // special case for --print-uris
    // special case for --print-uris
    if (GetAll) {
    if (GetAll) {
@@ -170,24 +198,28 @@ bool debReleaseIndex::GetIndexes(pkgAcquire *Owner, bool GetAll) const
 		     ComputeIndexTargets(),
 		     ComputeIndexTargets(),
 		     new indexRecords (Dist));
 		     new indexRecords (Dist));
 
 
-   // Queue the translations
-   std::vector<std::string> const lang = APT::Configuration::getLanguages(true);
-   for (vector<const debSectionEntry *>::const_iterator I = SectionEntries.begin(); 
-	I != SectionEntries.end(); I++) {
-
-      if((*I)->IsSrc)
-	 continue;
-
-      for (vector<string>::const_iterator l = lang.begin();
-		l != lang.end(); l++)
-      {
-	if (*l == "none") continue;
-	debTranslationsIndex i = debTranslationsIndex(URI,Dist,(*I)->Section,(*l).c_str());
-	i.GetIndexes(Owner);
-      }
-   }
-
-   return true;
+	// Queue the translations
+	std::vector<std::string> const lang = APT::Configuration::getLanguages(true);
+	map<string, set<string> > sections;
+	for (map<string, vector<debSectionEntry const*> >::const_iterator a = ArchEntries.begin();
+	     a != ArchEntries.end(); ++a) {
+		if (a->first == "source")
+			continue;
+		for (vector<debSectionEntry const*>::const_iterator I = a->second.begin();
+		     I != a->second.end(); I++)
+			sections[(*I)->Section].insert(lang.begin(), lang.end());
+	}
+
+	for (map<string, set<string> >::const_iterator s = sections.begin();
+	     s != sections.end(); ++s)
+		for (set<string>::const_iterator l = s->second.begin();
+		     l != s->second.end(); l++) {
+			if (*l == "none") continue;
+			debTranslationsIndex i = debTranslationsIndex(URI,Dist,s->first,(*l).c_str());
+			i.GetIndexes(Owner);
+		}
+
+	return true;
 }
 }
 
 
 bool debReleaseIndex::IsTrusted() const
 bool debReleaseIndex::IsTrusted() const
@@ -204,73 +236,123 @@ bool debReleaseIndex::IsTrusted() const
    return false;
    return false;
 }
 }
 
 
-vector <pkgIndexFile *> *debReleaseIndex::GetIndexFiles()
-{
-   if (Indexes != NULL)
-      return Indexes;
-
-   Indexes = new vector <pkgIndexFile*>;
-   std::vector<std::string> const lang = APT::Configuration::getLanguages(true);
-   for (vector<const debSectionEntry *>::const_iterator I = SectionEntries.begin(); 
-	I != SectionEntries.end(); I++) {
-      if ((*I)->IsSrc)
-         Indexes->push_back(new debSourcesIndex (URI, Dist, (*I)->Section, IsTrusted()));
-      else 
-      {
-         Indexes->push_back(new debPackagesIndex (URI, Dist, (*I)->Section, IsTrusted()));
-
-	 for (vector<string>::const_iterator l = lang.begin();
-		l != lang.end(); l++) {
-	    if (*l == "none") continue;
-	    Indexes->push_back(new debTranslationsIndex(URI,Dist,(*I)->Section,(*l).c_str()));
-	 }
-      }
-   }
+vector <pkgIndexFile *> *debReleaseIndex::GetIndexFiles() {
+	if (Indexes != NULL)
+		return Indexes;
+
+	Indexes = new vector <pkgIndexFile*>;
+	map<string, vector<debSectionEntry const*> >::const_iterator const src = ArchEntries.find("source");
+	if (src != ArchEntries.end()) {
+		vector<debSectionEntry const*> const SectionEntries = src->second;
+		for (vector<debSectionEntry const*>::const_iterator I = SectionEntries.begin();
+		     I != SectionEntries.end(); I++)
+			Indexes->push_back(new debSourcesIndex (URI, Dist, (*I)->Section, IsTrusted()));
+	}
+
+	// Only source release
+	if (Indexes->empty() == false && ArchEntries.size() == 1)
+		return Indexes;
+
+	std::vector<std::string> const lang = APT::Configuration::getLanguages(true);
+	map<string, set<string> > sections;
+	for (map<string, vector<debSectionEntry const*> >::const_iterator a = ArchEntries.begin();
+	     a != ArchEntries.end(); ++a) {
+		if (a->first == "source")
+			continue;
+		for (vector<debSectionEntry const*>::const_iterator I = a->second.begin();
+		     I != a->second.end(); I++) {
+			Indexes->push_back(new debPackagesIndex (URI, Dist, (*I)->Section, IsTrusted(), a->first));
+			sections[(*I)->Section].insert(lang.begin(), lang.end());
+		}
+	}
+
+	for (map<string, set<string> >::const_iterator s = sections.begin();
+	     s != sections.end(); ++s)
+		for (set<string>::const_iterator l = s->second.begin();
+		     l != s->second.end(); l++) {
+			if (*l == "none") continue;
+			Indexes->push_back(new debTranslationsIndex(URI,Dist,s->first,(*l).c_str()));
+		}
+
+	return Indexes;
+}
 
 
-   return Indexes;
+void debReleaseIndex::PushSectionEntry(vector<string> const &Archs, const debSectionEntry *Entry) {
+	for (vector<string>::const_iterator a = Archs.begin();
+	     a != Archs.end(); ++a)
+		ArchEntries[*a].push_back(new debSectionEntry(Entry->Section, Entry->IsSrc));
+	delete Entry;
 }
 }
 
 
-void debReleaseIndex::PushSectionEntry(const debSectionEntry *Entry)
-{
-   SectionEntries.push_back(Entry);
+void debReleaseIndex::PushSectionEntry(string const &Arch, const debSectionEntry *Entry) {
+	ArchEntries[Arch].push_back(Entry);
 }
 }
 
 
-debReleaseIndex::debSectionEntry::debSectionEntry (string Section, bool IsSrc): Section(Section)
-{
-   this->IsSrc = IsSrc;
+void debReleaseIndex::PushSectionEntry(const debSectionEntry *Entry) {
+	if (Entry->IsSrc == true)
+		PushSectionEntry("source", Entry);
+	else {
+		for (map<string, vector<const debSectionEntry *> >::iterator a = ArchEntries.begin();
+		     a != ArchEntries.end(); ++a) {
+			a->second.push_back(Entry);
+		}
+	}
 }
 }
 
 
+debReleaseIndex::debSectionEntry::debSectionEntry (string const &Section,
+		bool const &IsSrc): Section(Section), IsSrc(IsSrc)
+{}
+
 class debSLTypeDebian : public pkgSourceList::Type
 class debSLTypeDebian : public pkgSourceList::Type
 {
 {
    protected:
    protected:
 
 
-   bool CreateItemInternal(vector<metaIndex *> &List,string URI,
-			   string Dist,string Section,
-			   bool IsSrc) const
+   bool CreateItemInternal(vector<metaIndex *> &List, string const &URI,
+			   string const &Dist, string const &Section,
+			   bool const &IsSrc, map<string, string> const &Options) const
    {
    {
-      for (vector<metaIndex *>::const_iterator I = List.begin(); 
+      map<string, string>::const_iterator const arch = Options.find("arch");
+      vector<string> const Archs =
+		(arch != Options.end()) ? VectorizeString(arch->second, ',') :
+				APT::Configuration::getArchitectures();
+
+      for (vector<metaIndex *>::const_iterator I = List.begin();
 	   I != List.end(); I++)
 	   I != List.end(); I++)
       {
       {
-	 // This check insures that there will be only one Release file
-	 // queued for all the Packages files and Sources files it
-	 // corresponds to.
-		if (strcmp((*I)->GetType(), "deb") == 0)
+	 // We only worry about debian entries here
+	 if (strcmp((*I)->GetType(), "deb") != 0)
+	    continue;
+
+	 debReleaseIndex *Deb = (debReleaseIndex *) (*I);
+	 /* This check insures that there will be only one Release file
+	    queued for all the Packages files and Sources files it
+	    corresponds to. */
+	 if (Deb->GetURI() == URI && Deb->GetDist() == Dist)
 	 {
 	 {
-	    debReleaseIndex *Deb = (debReleaseIndex *) (*I);
-	    // This check insures that there will be only one Release file
-	    // queued for all the Packages files and Sources files it
-	    // corresponds to.
-	    if (Deb->GetURI() == URI && Deb->GetDist() == Dist)
+	    if (IsSrc == true)
+	       Deb->PushSectionEntry("source", new debReleaseIndex::debSectionEntry(Section, IsSrc));
+	    else
 	    {
 	    {
-	       Deb->PushSectionEntry(new debReleaseIndex::debSectionEntry(Section, IsSrc));
-	       return true;
+	       if (Dist[Dist.size() - 1] == '/')
+		  Deb->PushSectionEntry("any", new debReleaseIndex::debSectionEntry(Section, IsSrc));
+	       else
+		  Deb->PushSectionEntry(Archs, new debReleaseIndex::debSectionEntry(Section, IsSrc));
 	    }
 	    }
+	    return true;
 	 }
 	 }
       }
       }
       // No currently created Release file indexes this entry, so we create a new one.
       // No currently created Release file indexes this entry, so we create a new one.
       // XXX determine whether this release is trusted or not
       // XXX determine whether this release is trusted or not
-      debReleaseIndex *Deb = new debReleaseIndex(URI,Dist);
-      Deb->PushSectionEntry (new debReleaseIndex::debSectionEntry(Section, IsSrc));
+      debReleaseIndex *Deb = new debReleaseIndex(URI, Dist);
+      if (IsSrc == true)
+	 Deb->PushSectionEntry ("source", new debReleaseIndex::debSectionEntry(Section, IsSrc));
+      else
+      {
+	 if (Dist[Dist.size() - 1] == '/')
+	    Deb->PushSectionEntry ("any", new debReleaseIndex::debSectionEntry(Section, IsSrc));
+	 else
+	    Deb->PushSectionEntry (Archs, new debReleaseIndex::debSectionEntry(Section, IsSrc));
+      }
       List.push_back(Deb);
       List.push_back(Deb);
       return true;
       return true;
    }
    }
@@ -280,10 +362,11 @@ class debSLTypeDeb : public debSLTypeDebian
 {
 {
    public:
    public:
 
 
-   bool CreateItem(vector<metaIndex *> &List,string URI,
-		   string Dist,string Section) const
+   bool CreateItem(vector<metaIndex *> &List, string const &URI,
+		   string const &Dist, string const &Section,
+		   std::map<string, string> const &Options) const
    {
    {
-      return CreateItemInternal(List, URI, Dist, Section, false);
+      return CreateItemInternal(List, URI, Dist, Section, false, Options);
    }
    }
 
 
    debSLTypeDeb()
    debSLTypeDeb()
@@ -297,10 +380,11 @@ class debSLTypeDebSrc : public debSLTypeDebian
 {
 {
    public:
    public:
 
 
-   bool CreateItem(vector<metaIndex *> &List,string URI,
-		   string Dist,string Section) const 
+   bool CreateItem(vector<metaIndex *> &List, string const &URI,
+		   string const &Dist, string const &Section,
+		   std::map<string, string> const &Options) const
    {
    {
-      return CreateItemInternal(List, URI, Dist, Section, true);
+      return CreateItemInternal(List, URI, Dist, Section, true, Options);
    }
    }
    
    
    debSLTypeDebSrc()
    debSLTypeDebSrc()

+ 16 - 12
apt-pkg/deb/debmetaindex.h

@@ -5,40 +5,44 @@
 #include <apt-pkg/metaindex.h>
 #include <apt-pkg/metaindex.h>
 #include <apt-pkg/sourcelist.h>
 #include <apt-pkg/sourcelist.h>
 
 
+#include <map>
+
 class debReleaseIndex : public metaIndex {
 class debReleaseIndex : public metaIndex {
    public:
    public:
 
 
    class debSectionEntry
    class debSectionEntry
    {
    {
       public:
       public:
-      debSectionEntry (string Section, bool IsSrc);
-      bool IsSrc;
-      string Section;
+      debSectionEntry (string const &Section, bool const &IsSrc);
+      string const Section;
+      bool const IsSrc;
    };
    };
 
 
    private:
    private:
-   vector <const debSectionEntry *> SectionEntries;
+   std::map<string, vector<debSectionEntry const*> > ArchEntries;
 
 
    public:
    public:
 
 
-   debReleaseIndex(string URI, string Dist);
+   debReleaseIndex(string const &URI, string const &Dist);
    ~debReleaseIndex();
    ~debReleaseIndex();
 
 
-   virtual string ArchiveURI(string File) const {return URI + File;};
-   virtual bool GetIndexes(pkgAcquire *Owner, bool GetAll=false) const;
+   virtual string ArchiveURI(string const &File) const {return URI + File;};
+   virtual bool GetIndexes(pkgAcquire *Owner, bool const &GetAll=false) const;
    vector <struct IndexTarget *>* ComputeIndexTargets() const;
    vector <struct IndexTarget *>* ComputeIndexTargets() const;
-   string Info(const char *Type, const string Section) const;
+   string Info(const char *Type, string const &Section, string const &Arch="") const;
    string MetaIndexInfo(const char *Type) const;
    string MetaIndexInfo(const char *Type) const;
    string MetaIndexFile(const char *Types) const;
    string MetaIndexFile(const char *Types) const;
    string MetaIndexURI(const char *Type) const;
    string MetaIndexURI(const char *Type) const;
-   string IndexURI(const char *Type, const string Section) const;
-   string IndexURISuffix(const char *Type, const string Section) const;
-   string SourceIndexURI(const char *Type, const string Section) const;
-   string SourceIndexURISuffix(const char *Type, const string Section) const;
+   string IndexURI(const char *Type, string const &Section, string const &Arch="native") const;
+   string IndexURISuffix(const char *Type, string const &Section, string const &Arch="native") const;
+   string SourceIndexURI(const char *Type, const string &Section) const;
+   string SourceIndexURISuffix(const char *Type, const string &Section) const;
    virtual vector <pkgIndexFile *> *GetIndexFiles();
    virtual vector <pkgIndexFile *> *GetIndexFiles();
 
 
    virtual bool IsTrusted() const;
    virtual bool IsTrusted() const;
 
 
+   void PushSectionEntry(vector<string> const &Archs, const debSectionEntry *Entry);
+   void PushSectionEntry(string const &Arch, const debSectionEntry *Entry);
    void PushSectionEntry(const debSectionEntry *Entry);
    void PushSectionEntry(const debSectionEntry *Entry);
 };
 };
 
 

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

@@ -19,7 +19,7 @@
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /* */
 /* */
 debRecordParser::debRecordParser(string FileName,pkgCache &Cache) : 
 debRecordParser::debRecordParser(string FileName,pkgCache &Cache) : 
-                  File(FileName,FileFd::ReadOnly), 
+                  File(FileName,FileFd::ReadOnlyGzip), 
                   Tags(&File, std::max(Cache.Head().MaxVerFileSize, 
                   Tags(&File, std::max(Cache.Head().MaxVerFileSize, 
 				       Cache.Head().MaxDescFileSize) + 200)
 				       Cache.Head().MaxDescFileSize) + 200)
 {
 {

+ 1 - 1
apt-pkg/deb/debsrcrecords.h

@@ -48,7 +48,7 @@ class debSrcRecordParser : public pkgSrcRecords::Parser
    virtual bool Files(vector<pkgSrcRecords::File> &F);
    virtual bool Files(vector<pkgSrcRecords::File> &F);
 
 
    debSrcRecordParser(string const &File,pkgIndexFile const *Index) 
    debSrcRecordParser(string const &File,pkgIndexFile const *Index) 
-      : Parser(Index), Fd(File,FileFd::ReadOnly), Tags(&Fd,102400), 
+      : Parser(Index), Fd(File,FileFd::ReadOnlyGzip), Tags(&Fd,102400), 
         Buffer(0), BufSize(0) {}
         Buffer(0), BufSize(0) {}
    ~debSrcRecordParser();
    ~debSrcRecordParser();
 };
 };

+ 9 - 3
apt-pkg/deb/debsystem.cc

@@ -18,7 +18,6 @@
 #include <apt-pkg/error.h>
 #include <apt-pkg/error.h>
 #include <apt-pkg/fileutl.h>
 #include <apt-pkg/fileutl.h>
 #include <apti18n.h>
 #include <apti18n.h>
-    
 #include <sys/types.h>
 #include <sys/types.h>
 #include <unistd.h>
 #include <unistd.h>
 #include <dirent.h>
 #include <dirent.h>
@@ -79,8 +78,15 @@ bool debSystem::Lock()
    {
    {
       close(LockFD);
       close(LockFD);
       LockFD = -1;
       LockFD = -1;
+      const char *cmd;
+      if (getenv("SUDO_USER") != NULL)
+	 cmd = "sudo dpkg --configure -a";
+      else
+	 cmd = "dpkg --configure -a";
+      // TRANSLATORS: the %s contains the recovery command, usually
+      //              dpkg --configure -a
       return _error->Error(_("dpkg was interrupted, you must manually "
       return _error->Error(_("dpkg was interrupted, you must manually "
-                             "run 'dpkg --configure -a' to correct the problem. "));
+                             "run '%s' to correct the problem. "), cmd);
    }
    }
 
 
 	 LockCount++;
 	 LockCount++;
@@ -158,7 +164,7 @@ bool debSystem::Initialize(Configuration &Cnf)
    /* These really should be jammed into a generic 'Local Database' engine
    /* These really should be jammed into a generic 'Local Database' engine
       which is yet to be determined. The functions in pkgcachegen should
       which is yet to be determined. The functions in pkgcachegen should
       be the only users of these */
       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::State::status","/var/lib/dpkg/status");
    Cnf.CndSet("Dir::Bin::dpkg","/usr/bin/dpkg");
    Cnf.CndSet("Dir::Bin::dpkg","/usr/bin/dpkg");
 
 

+ 16 - 2
apt-pkg/deb/debversion.cc

@@ -190,8 +190,22 @@ int debVersioningSystem::DoCmpVersion(const char *A,const char *AEnd,
       dlhs++;
       dlhs++;
    if (drhs != rhs)
    if (drhs != rhs)
       drhs++;
       drhs++;
-   
-   return CmpFragment(dlhs,AEnd,drhs,BEnd);
+
+   // no debian revision need to be treated like -0
+   if (*(dlhs-1) == '-' && *(drhs-1) == '-')
+      return CmpFragment(dlhs,AEnd,drhs,BEnd);
+   else if (*(dlhs-1) == '-')
+   {
+      const char* null = "0";
+      return CmpFragment(dlhs,AEnd,null, null+1);
+   }
+   else if (*(drhs-1) == '-')
+   {
+      const char* null = "0";
+      return CmpFragment(null, null+1, drhs, BEnd);
+   }
+   else
+      return 0;
 }
 }
 									/*}}}*/
 									/*}}}*/
 // debVS::CheckDep - Check a single dependency				/*{{{*/
 // debVS::CheckDep - Check a single dependency				/*{{{*/

+ 311 - 27
apt-pkg/deb/dpkgpm.cc

@@ -12,6 +12,7 @@
 #include <apt-pkg/error.h>
 #include <apt-pkg/error.h>
 #include <apt-pkg/configuration.h>
 #include <apt-pkg/configuration.h>
 #include <apt-pkg/depcache.h>
 #include <apt-pkg/depcache.h>
+#include <apt-pkg/pkgrecords.h>
 #include <apt-pkg/strutl.h>
 #include <apt-pkg/strutl.h>
 #include <apti18n.h>
 #include <apti18n.h>
 #include <apt-pkg/fileutl.h>
 #include <apt-pkg/fileutl.h>
@@ -20,10 +21,12 @@
 #include <stdlib.h>
 #include <stdlib.h>
 #include <fcntl.h>
 #include <fcntl.h>
 #include <sys/select.h>
 #include <sys/select.h>
+#include <sys/stat.h>
 #include <sys/types.h>
 #include <sys/types.h>
 #include <sys/wait.h>
 #include <sys/wait.h>
 #include <signal.h>
 #include <signal.h>
 #include <errno.h>
 #include <errno.h>
+#include <string.h>
 #include <stdio.h>
 #include <stdio.h>
 #include <string.h>
 #include <string.h>
 #include <algorithm>
 #include <algorithm>
@@ -50,6 +53,7 @@ namespace
     std::make_pair("configure", N_("Configuring %s")),
     std::make_pair("configure", N_("Configuring %s")),
     std::make_pair("remove",    N_("Removing %s")),
     std::make_pair("remove",    N_("Removing %s")),
     std::make_pair("purge",    N_("Completely removing %s")),
     std::make_pair("purge",    N_("Completely removing %s")),
+    std::make_pair("disappear", N_("Noting disappearance of %s")),
     std::make_pair("trigproc",  N_("Running post-installation trigger %s"))
     std::make_pair("trigproc",  N_("Running post-installation trigger %s"))
   };
   };
 
 
@@ -105,7 +109,7 @@ ionice(int PID)
 /* */
 /* */
 pkgDPkgPM::pkgDPkgPM(pkgDepCache *Cache) 
 pkgDPkgPM::pkgDPkgPM(pkgDepCache *Cache) 
    : pkgPackageManager(Cache), dpkgbuf_pos(0),
    : pkgPackageManager(Cache), dpkgbuf_pos(0),
-     term_out(NULL), PackagesDone(0), PackagesTotal(0)
+     term_out(NULL), history_out(NULL), PackagesDone(0), PackagesTotal(0)
 {
 {
 }
 }
 									/*}}}*/
 									/*}}}*/
@@ -124,7 +128,19 @@ bool pkgDPkgPM::Install(PkgIterator Pkg,string File)
    if (File.empty() == true || Pkg.end() == true)
    if (File.empty() == true || Pkg.end() == true)
       return _error->Error("Internal Error, No file name for %s",Pkg.Name());
       return _error->Error("Internal Error, No file name for %s",Pkg.Name());
 
 
-   List.push_back(Item(Item::Install,Pkg,File));
+   // If the filename string begins with DPkg::Chroot-Directory, return the
+   // substr that is within the chroot so dpkg can access it.
+   string const chrootdir = _config->FindDir("DPkg::Chroot-Directory","/");
+   if (chrootdir != "/" && File.find(chrootdir) == 0)
+   {
+      size_t len = chrootdir.length();
+      if (chrootdir.at(len - 1) == '/')
+        len--;
+      List.push_back(Item(Item::Install,Pkg,File.substr(len)));
+   }
+   else
+      List.push_back(Item(Item::Install,Pkg,File));
+
    return true;
    return true;
 }
 }
 									/*}}}*/
 									/*}}}*/
@@ -341,7 +357,6 @@ bool pkgDPkgPM::RunScriptsWithPkgs(const char *Cnf)
 
 
    return true;
    return true;
 }
 }
-
 									/*}}}*/
 									/*}}}*/
 // DPkgPM::DoStdin - Read stdin and pass to slave pty			/*{{{*/
 // DPkgPM::DoStdin - Read stdin and pass to slave pty			/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
@@ -407,11 +422,12 @@ void pkgDPkgPM::ProcessDpkgStatusLine(int OutStatusFd, char *line)
       'processing: install: pkg'
       'processing: install: pkg'
       'processing: configure: pkg'
       'processing: configure: pkg'
       'processing: remove: pkg'
       'processing: remove: pkg'
-      'processing: purge: pkg' - but for apt is it a ignored "unknown" action
+      'processing: purge: pkg'
+      'processing: disappear: pkg'
       'processing: trigproc: trigger'
       'processing: trigproc: trigger'
 	    
 	    
    */
    */
-   char* list[5];
+   char* list[6];
    //        dpkg sends multiline error messages sometimes (see
    //        dpkg sends multiline error messages sometimes (see
    //        #374195 for a example. we should support this by
    //        #374195 for a example. we should support this by
    //        either patching dpkg to not send multiline over the
    //        either patching dpkg to not send multiline over the
@@ -454,11 +470,22 @@ void pkgDPkgPM::ProcessDpkgStatusLine(int OutStatusFd, char *line)
 	 write(OutStatusFd, status.str().c_str(), status.str().size());
 	 write(OutStatusFd, status.str().c_str(), status.str().size());
       if (Debug == true)
       if (Debug == true)
 	 std::clog << "send: '" << status.str() << "'" << endl;
 	 std::clog << "send: '" << status.str() << "'" << endl;
+
+      if (strncmp(action, "disappear", strlen("disappear")) == 0)
+	 handleDisappearAction(pkg_or_trigger);
       return;
       return;
    }
    }
 
 
    if(strncmp(action,"error",strlen("error")) == 0)
    if(strncmp(action,"error",strlen("error")) == 0)
    {
    {
+      // urgs, sometime has ":" in its error string so that we
+      // end up with the error message split between list[3]
+      // and list[4], e.g. the message: 
+      // "failed in buffer_write(fd) (10, ret=-1): backend dpkg-deb ..."
+      // concat them again
+      if( list[4] != NULL )
+	 list[3][strlen(list[3])] = ':';
+
       status << "pmerror:" << list[1]
       status << "pmerror:" << list[1]
 	     << ":"  << (PackagesDone/float(PackagesTotal)*100.0) 
 	     << ":"  << (PackagesDone/float(PackagesTotal)*100.0) 
 	     << ":" << list[3]
 	     << ":" << list[3]
@@ -467,6 +494,8 @@ void pkgDPkgPM::ProcessDpkgStatusLine(int OutStatusFd, char *line)
 	 write(OutStatusFd, status.str().c_str(), status.str().size());
 	 write(OutStatusFd, status.str().c_str(), status.str().size());
       if (Debug == true)
       if (Debug == true)
 	 std::clog << "send: '" << status.str() << "'" << endl;
 	 std::clog << "send: '" << status.str() << "'" << endl;
+      pkgFailures++;
+      WriteApportReport(list[1], list[3]);
       return;
       return;
    }
    }
    else if(strncmp(action,"conffile",strlen("conffile")) == 0)
    else if(strncmp(action,"conffile",strlen("conffile")) == 0)
@@ -513,6 +542,51 @@ void pkgDPkgPM::ProcessDpkgStatusLine(int OutStatusFd, char *line)
 		<< " action: " << action << endl;
 		<< " 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						/*{{{*/
 // DPkgPM::DoDpkgStatusFd						/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /*
 /*
@@ -551,67 +625,76 @@ void pkgDPkgPM::DoDpkgStatusFd(int statusfd, int OutStatusFd)
 }
 }
 									/*}}}*/
 									/*}}}*/
 // DPkgPM::WriteHistoryTag						/*{{{*/
 // 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							/*{{{*/
 // DPkgPM::OpenLog							/*{{{*/
 bool pkgDPkgPM::OpenLog()
 bool pkgDPkgPM::OpenLog()
 {
 {
-   string logdir = _config->FindDir("Dir::Log");
+   string const logdir = _config->FindDir("Dir::Log");
    if(not FileExists(logdir))
    if(not FileExists(logdir))
       return _error->Error(_("Directory '%s' missing"), logdir.c_str());
       return _error->Error(_("Directory '%s' missing"), logdir.c_str());
 
 
    // get current time
    // get current time
    char timestr[200];
    char timestr[200];
-   time_t t = time(NULL);
-   struct tm *tmp = localtime(&t);
+   time_t const t = time(NULL);
+   struct tm const * const tmp = localtime(&t);
    strftime(timestr, sizeof(timestr), "%F  %T", tmp);
    strftime(timestr, sizeof(timestr), "%F  %T", tmp);
 
 
    // open terminal log
    // open terminal log
-   string logfile_name = flCombine(logdir,
+   string const logfile_name = flCombine(logdir,
 				   _config->Find("Dir::Log::Terminal"));
 				   _config->Find("Dir::Log::Terminal"));
    if (!logfile_name.empty())
    if (!logfile_name.empty())
    {
    {
       term_out = fopen(logfile_name.c_str(),"a");
       term_out = fopen(logfile_name.c_str(),"a");
       if (term_out == NULL)
       if (term_out == NULL)
-	 return _error->WarningE(_("Could not open file '%s'"), logfile_name.c_str());
-
+	 return _error->WarningE("OpenLog", _("Could not open file '%s'"), logfile_name.c_str());
+      setvbuf(term_out, NULL, _IONBF, 0);
       chmod(logfile_name.c_str(), 0600);
       chmod(logfile_name.c_str(), 0600);
       fprintf(term_out, "\nLog started: %s\n", timestr);
       fprintf(term_out, "\nLog started: %s\n", timestr);
    }
    }
 
 
-   // write 
-   string history_name = flCombine(logdir,
+   // write your history
+   string const history_name = flCombine(logdir,
 				   _config->Find("Dir::Log::History"));
 				   _config->Find("Dir::Log::History"));
    if (!history_name.empty())
    if (!history_name.empty())
    {
    {
       history_out = fopen(history_name.c_str(),"a");
       history_out = fopen(history_name.c_str(),"a");
+      if (history_out == NULL)
+	 return _error->WarningE("OpenLog", _("Could not open file '%s'"), history_name.c_str());
       chmod(history_name.c_str(), 0644);
       chmod(history_name.c_str(), 0644);
       fprintf(history_out, "\nStart-Date: %s\n", timestr);
       fprintf(history_out, "\nStart-Date: %s\n", timestr);
       string remove, purge, install, upgrade, downgrade;
       string remove, purge, install, upgrade, downgrade;
       for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
       for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
       {
       {
 	 if (Cache[I].NewInstall())
 	 if (Cache[I].NewInstall())
-	    install += I.Name() + string(" (") + Cache[I].CandVersion + string("), ");
+	 {
+	    install += I.FullName(false) + string(" (") + Cache[I].CandVersion;
+	    if (Cache[I].Flags & pkgCache::Flag::Auto)
+	       install+= ", automatic";
+	    install += string("), ");
+	 }
 	 else if (Cache[I].Upgrade())
 	 else if (Cache[I].Upgrade())
-	    upgrade += I.Name() + string(" (") + Cache[I].CurVersion + string(", ") + Cache[I].CandVersion + string("), ");
+	    upgrade += I.FullName(false) + string(" (") + Cache[I].CurVersion + string(", ") + Cache[I].CandVersion + string("), ");
 	 else if (Cache[I].Downgrade())
 	 else if (Cache[I].Downgrade())
-	    downgrade += I.Name() + string(" (") + Cache[I].CurVersion + string(", ") + Cache[I].CandVersion + string("), ");
+	    downgrade += I.FullName(false) + string(" (") + Cache[I].CurVersion + string(", ") + Cache[I].CandVersion + string("), ");
 	 else if (Cache[I].Delete())
 	 else if (Cache[I].Delete())
 	 {
 	 {
 	    if ((Cache[I].iFlags & pkgDepCache::Purge) == pkgDepCache::Purge)
 	    if ((Cache[I].iFlags & pkgDepCache::Purge) == pkgDepCache::Purge)
-	       purge += I.Name() + string(" (") + Cache[I].CurVersion + string("), ");	    
+	       purge += I.FullName(false) + string(" (") + Cache[I].CurVersion + string("), ");	    
 	    else
 	    else
-	       remove += I.Name() + string(" (") + Cache[I].CurVersion + string("), ");	    
+	       remove += I.FullName(false) + string(" (") + Cache[I].CurVersion + string("), ");	    
 	 }
 	 }
       }
       }
+      if (_config->Exists("Commandline::AsString") == true)
+	 WriteHistoryTag("Commandline", _config->Find("Commandline::AsString"));
       WriteHistoryTag("Install", install);
       WriteHistoryTag("Install", install);
       WriteHistoryTag("Upgrade", upgrade);
       WriteHistoryTag("Upgrade", upgrade);
       WriteHistoryTag("Downgrade",downgrade);
       WriteHistoryTag("Downgrade",downgrade);
@@ -642,11 +725,27 @@ bool pkgDPkgPM::CloseLog()
 
 
    if(history_out)
    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, "Error: %s\n", dpkg_error.c_str());
       fprintf(history_out, "End-Date: %s\n", timestr);
       fprintf(history_out, "End-Date: %s\n", timestr);
       fclose(history_out);
       fclose(history_out);
    }
    }
+   history_out = NULL;
 
 
    return true;
    return true;
 }
 }
@@ -894,6 +993,8 @@ bool pkgDPkgPM::Go(int OutStatusFd)
 	 {
 	 {
 	    if((*I).Pkg.end() == true)
 	    if((*I).Pkg.end() == true)
 	       continue;
 	       continue;
+	    if (I->Op == Item::Configure && disappearedPkgs.find(I->Pkg.Name()) != disappearedPkgs.end())
+	       continue;
 	    Args[n++] = I->Pkg.Name();
 	    Args[n++] = I->Pkg.Name();
 	    Size += strlen(Args[n-1]);
 	    Size += strlen(Args[n-1]);
 	 }	 
 	 }	 
@@ -1151,3 +1252,186 @@ void pkgDPkgPM::Reset()
    List.erase(List.begin(),List.end());
    List.erase(List.begin(),List.end());
 }
 }
 									/*}}}*/
 									/*}}}*/
+// pkgDpkgPM::WriteApportReport - write out error report pkg failure	/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+void pkgDPkgPM::WriteApportReport(const char *pkgpath, const char *errormsg) 
+{
+   string pkgname, reportfile, srcpkgname, pkgver, arch;
+   string::size_type pos;
+   FILE *report;
+
+   if (_config->FindB("Dpkg::ApportFailureReport", false) == false)
+   {
+      std::clog << "configured to not write apport reports" << std::endl;
+      return;
+   }
+
+   // only report the first errors
+   if(pkgFailures > _config->FindI("APT::Apport::MaxReports", 3))
+   {
+      std::clog << _("No apport report written because MaxReports is reached already") << std::endl;
+      return;
+   }
+
+   // check if its not a follow up error 
+   const char *needle = dgettext("dpkg", "dependency problems - leaving unconfigured");
+   if(strstr(errormsg, needle) != NULL) {
+      std::clog << _("No apport report written because the error message indicates its a followup error from a previous failure.") << std::endl;
+      return;
+   }
+
+   // do not report disk-full failures 
+   if(strstr(errormsg, strerror(ENOSPC)) != NULL) {
+      std::clog << _("No apport report written because the error message indicates a disk full error") << std::endl;
+      return;
+   }
+
+   // do not report out-of-memory failures 
+   if(strstr(errormsg, strerror(ENOMEM)) != NULL) {
+      std::clog << _("No apport report written because the error message indicates a out of memory error") << std::endl;
+      return;
+   }
+
+   // do not report dpkg I/O errors
+   // XXX - this message is localized, but this only matches the English version.  This is better than nothing.
+   if(strstr(errormsg, "short read in buffer_copy (")) {
+      std::clog << _("No apport report written because the error message indicates a dpkg I/O error") << std::endl;
+      return;
+   }
+
+   // get the pkgname and reportfile
+   pkgname = flNotDir(pkgpath);
+   pos = pkgname.find('_');
+   if(pos != string::npos)
+      pkgname = pkgname.substr(0, pos);
+
+   // find the package versin and source package name
+   pkgCache::PkgIterator Pkg = Cache.FindPkg(pkgname);
+   if (Pkg.end() == true)
+      return;
+   pkgCache::VerIterator Ver = Cache.GetCandidateVer(Pkg);
+   if (Ver.end() == true)
+      return;
+   pkgver = Ver.VerStr() == NULL ? "unknown" : Ver.VerStr();
+   pkgRecords Recs(Cache);
+   pkgRecords::Parser &Parse = Recs.Lookup(Ver.FileList());
+   srcpkgname = Parse.SourcePkg();
+   if(srcpkgname.empty())
+      srcpkgname = pkgname;
+
+   // if the file exists already, we check:
+   // - if it was reported already (touched by apport). 
+   //   If not, we do nothing, otherwise
+   //    we overwrite it. This is the same behaviour as apport
+   // - if we have a report with the same pkgversion already
+   //   then we skip it
+   reportfile = flCombine("/var/crash",pkgname+".0.crash");
+   if(FileExists(reportfile))
+   {
+      struct stat buf;
+      char strbuf[255];
+
+      // check atime/mtime
+      stat(reportfile.c_str(), &buf);
+      if(buf.st_mtime > buf.st_atime)
+	 return;
+
+      // check if the existing report is the same version
+      report = fopen(reportfile.c_str(),"r");
+      while(fgets(strbuf, sizeof(strbuf), report) != NULL)
+      {
+	 if(strstr(strbuf,"Package:") == strbuf)
+	 {
+	    char pkgname[255], version[255];
+	    if(sscanf(strbuf, "Package: %s %s", pkgname, version) == 2)
+	       if(strcmp(pkgver.c_str(), version) == 0)
+	       {
+		  fclose(report);
+		  return;
+	       }
+	 }
+      }
+      fclose(report);
+   }
+
+   // now write the report
+   arch = _config->Find("APT::Architecture");
+   report = fopen(reportfile.c_str(),"w");
+   if(report == NULL)
+      return;
+   if(_config->FindB("DPkgPM::InitialReportOnly",false) == true)
+      chmod(reportfile.c_str(), 0);
+   else
+      chmod(reportfile.c_str(), 0600);
+   fprintf(report, "ProblemType: Package\n");
+   fprintf(report, "Architecture: %s\n", arch.c_str());
+   time_t now = time(NULL);
+   fprintf(report, "Date: %s" , ctime(&now));
+   fprintf(report, "Package: %s %s\n", pkgname.c_str(), pkgver.c_str());
+   fprintf(report, "SourcePackage: %s\n", srcpkgname.c_str());
+   fprintf(report, "ErrorMessage:\n %s\n", errormsg);
+
+   // ensure that the log is flushed
+   if(term_out)
+      fflush(term_out);
+
+   // attach terminal log it if we have it
+   string logfile_name = _config->FindFile("Dir::Log::Terminal");
+   if (!logfile_name.empty())
+   {
+      FILE *log = NULL;
+      char buf[1024];
+
+      fprintf(report, "DpkgTerminalLog:\n");
+      log = fopen(logfile_name.c_str(),"r");
+      if(log != NULL)
+      {
+	 while( fgets(buf, sizeof(buf), log) != NULL)
+	    fprintf(report, " %s", buf);
+	 fclose(log);
+      }
+   }
+
+   // log the ordering 
+   const char *ops_str[] = {"Install", "Configure","Remove","Purge"};
+   fprintf(report, "AptOrdering:\n");
+   for (vector<Item>::iterator I = List.begin(); I != List.end(); I++)
+      fprintf(report, " %s: %s\n", (*I).Pkg.Name(), ops_str[(*I).Op]);
+
+   // attach dmesg log (to learn about segfaults)
+   if (FileExists("/bin/dmesg"))
+   {
+      FILE *log = NULL;
+      char buf[1024];
+
+      fprintf(report, "Dmesg:\n");
+      log = popen("/bin/dmesg","r");
+      if(log != NULL)
+      {
+	 while( fgets(buf, sizeof(buf), log) != NULL)
+	    fprintf(report, " %s", buf);
+	 fclose(log);
+      }
+   }
+
+   // attach df -l log (to learn about filesystem status)
+   if (FileExists("/bin/df"))
+   {
+      FILE *log = NULL;
+      char buf[1024];
+
+      fprintf(report, "Df:\n");
+      log = popen("/bin/df -l","r");
+      if(log != NULL)
+      {
+	 while( fgets(buf, sizeof(buf), log) != NULL)
+	    fprintf(report, " %s", buf);
+	 fclose(log);
+      }
+   }
+
+   fclose(report);
+
+}
+									/*}}}*/

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

@@ -32,7 +32,23 @@ class pkgDPkgPM : public pkgPackageManager
    FILE *history_out;
    FILE *history_out;
    string dpkg_error;
    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:
    protected:
+   int pkgFailures;
 
 
    // progress reporting
    // progress reporting
    struct DpkgState 
    struct DpkgState 
@@ -49,6 +65,7 @@ class pkgDPkgPM : public pkgPackageManager
    // the int is the state that is already done (e.g. a package that is
    // the int is the state that is already done (e.g. a package that is
    // going to be install is already in state "half-installed")
    // going to be install is already in state "half-installed")
    map<string,unsigned int> PackageOpsDone;
    map<string,unsigned int> PackageOpsDone;
+
    // progress reporting
    // progress reporting
    unsigned int PackagesDone;
    unsigned int PackagesDone;
    unsigned int PackagesTotal;
    unsigned int PackagesTotal;
@@ -68,7 +85,10 @@ class pkgDPkgPM : public pkgPackageManager
    // Helpers
    // Helpers
    bool RunScriptsWithPkgs(const char *Cnf);
    bool RunScriptsWithPkgs(const char *Cnf);
    bool SendV2Pkgs(FILE *F);
    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);
 
 
    // dpkg log
    // dpkg log
    bool OpenLog();
    bool OpenLog();

+ 499 - 135
apt-pkg/depcache.cc

@@ -17,6 +17,7 @@
 #include <apt-pkg/fileutl.h>
 #include <apt-pkg/fileutl.h>
 #include <apt-pkg/strutl.h>
 #include <apt-pkg/strutl.h>
 #include <apt-pkg/configuration.h>
 #include <apt-pkg/configuration.h>
+#include <apt-pkg/aptconfiguration.h>
 #include <apt-pkg/pkgsystem.h>
 #include <apt-pkg/pkgsystem.h>
 #include <apt-pkg/tagfile.h>
 #include <apt-pkg/tagfile.h>
 
 
@@ -164,34 +165,46 @@ bool pkgDepCache::Init(OpProgress *Prog)
 bool pkgDepCache::readStateFile(OpProgress *Prog)			/*{{{*/
 bool pkgDepCache::readStateFile(OpProgress *Prog)			/*{{{*/
 {
 {
    FileFd state_file;
    FileFd state_file;
-   string state = _config->FindDir("Dir::State") + "extended_states";
+   string const state = _config->FindFile("Dir::State::extended_states");
    if(FileExists(state)) {
    if(FileExists(state)) {
       state_file.Open(state, FileFd::ReadOnly);
       state_file.Open(state, FileFd::ReadOnly);
-      int file_size = state_file.Size();
+      int const file_size = state_file.Size();
       if(Prog != NULL)
       if(Prog != NULL)
 	 Prog->OverallProgress(0, file_size, 1, 
 	 Prog->OverallProgress(0, file_size, 1, 
 			       _("Reading state information"));
 			       _("Reading state information"));
 
 
       pkgTagFile tagfile(&state_file);
       pkgTagFile tagfile(&state_file);
       pkgTagSection section;
       pkgTagSection section;
-      int amt=0;
-      bool debug_autoremove=_config->FindB("Debug::pkgAutoRemove",false);
+      int amt = 0;
+      bool const debug_autoremove = _config->FindB("Debug::pkgAutoRemove",false);
       while(tagfile.Step(section)) {
       while(tagfile.Step(section)) {
-	 string pkgname = section.FindS("Package");
-	 pkgCache::PkgIterator pkg=Cache->FindPkg(pkgname);
-	 // Silently ignore unknown packages and packages with no actual
-	 // version.
-	 if(!pkg.end() && !pkg.VersionList().end()) {
-	    short reason = section.FindI("Auto-Installed", 0);
-	    if(reason > 0)
-	       PkgState[pkg->ID].Flags  |= Flag::Auto;
-	    if(debug_autoremove)
-	       std::clog << "Auto-Installed : " << pkgname << std::endl;
-	    amt+=section.size();
-	    if(Prog != NULL)
-	       Prog->OverallProgress(amt, file_size, 1, 
-				     _("Reading state information"));
+	 string const pkgname = section.FindS("Package");
+	 string pkgarch = section.FindS("Architecture");
+	 if (pkgarch.empty() == true)
+	    pkgarch = "any";
+	 pkgCache::PkgIterator pkg = Cache->FindPkg(pkgname, pkgarch);
+	 // Silently ignore unknown packages and packages with no actual version.
+	 if(pkg.end() == true || pkg->VersionList == 0)
+	    continue;
+
+	 short const reason = section.FindI("Auto-Installed", 0);
+	 if(reason > 0)
+	 {
+	    PkgState[pkg->ID].Flags |= Flag::Auto;
+	    if (unlikely(debug_autoremove))
+	       std::clog << "Auto-Installed : " << pkg.FullName() << std::endl;
+	    if (pkgarch == "any")
+	    {
+	       pkgCache::GrpIterator G = pkg.Group();
+	       for (pkg = G.NextPkg(pkg); pkg.end() != true; pkg = G.NextPkg(pkg))
+		  if (pkg->VersionList != 0)
+		     PkgState[pkg->ID].Flags |= Flag::Auto;
+	    }
 	 }
 	 }
+	 amt += section.size();
+	 if(Prog != NULL)
+	    Prog->OverallProgress(amt, file_size, 1, 
+				  _("Reading state information"));
       }
       }
       if(Prog != NULL)
       if(Prog != NULL)
 	 Prog->OverallProgress(file_size, file_size, 1,
 	 Prog->OverallProgress(file_size, file_size, 1,
@@ -203,13 +216,13 @@ bool pkgDepCache::readStateFile(OpProgress *Prog)			/*{{{*/
 									/*}}}*/
 									/*}}}*/
 bool pkgDepCache::writeStateFile(OpProgress *prog, bool InstalledOnly)	/*{{{*/
 bool pkgDepCache::writeStateFile(OpProgress *prog, bool InstalledOnly)	/*{{{*/
 {
 {
-   bool debug_autoremove = _config->FindB("Debug::pkgAutoRemove",false);
+   bool const debug_autoremove = _config->FindB("Debug::pkgAutoRemove",false);
    
    
    if(debug_autoremove)
    if(debug_autoremove)
       std::clog << "pkgDepCache::writeStateFile()" << std::endl;
       std::clog << "pkgDepCache::writeStateFile()" << std::endl;
 
 
    FileFd StateFile;
    FileFd StateFile;
-   string 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 it does not exist, create a empty one
    if(!FileExists(state)) 
    if(!FileExists(state)) 
@@ -224,7 +237,7 @@ bool pkgDepCache::writeStateFile(OpProgress *prog, bool InstalledOnly)	/*{{{*/
 			   state.c_str());
 			   state.c_str());
 
 
    FILE *OutFile;
    FILE *OutFile;
-   string outfile = state + ".tmp";
+   string const outfile = state + ".tmp";
    if((OutFile = fopen(outfile.c_str(),"w")) == NULL)
    if((OutFile = fopen(outfile.c_str(),"w")) == NULL)
       return _error->Error(_("Failed to write temporary StateFile %s"),
       return _error->Error(_("Failed to write temporary StateFile %s"),
 			   outfile.c_str());
 			   outfile.c_str());
@@ -235,46 +248,72 @@ bool pkgDepCache::writeStateFile(OpProgress *prog, bool InstalledOnly)	/*{{{*/
    std::set<string> pkgs_seen;
    std::set<string> pkgs_seen;
    const char *nullreorderlist[] = {0};
    const char *nullreorderlist[] = {0};
    while(tagfile.Step(section)) {
    while(tagfile.Step(section)) {
-	 string pkgname = section.FindS("Package");
+	 string const pkgname = section.FindS("Package");
+	 string pkgarch = section.FindS("Architecture");
+	 if (pkgarch.empty() == true)
+	    pkgarch = "native";
 	 // Silently ignore unknown packages and packages with no actual
 	 // Silently ignore unknown packages and packages with no actual
 	 // version.
 	 // version.
-	 pkgCache::PkgIterator pkg=Cache->FindPkg(pkgname);
+	 pkgCache::PkgIterator pkg = Cache->FindPkg(pkgname, pkgarch);
 	 if(pkg.end() || pkg.VersionList().end()) 
 	 if(pkg.end() || pkg.VersionList().end()) 
 	    continue;
 	    continue;
-	 bool newAuto = (PkgState[pkg->ID].Flags & Flag::Auto);
+	 StateCache const &P = PkgState[pkg->ID];
+	 bool newAuto = (P.Flags & Flag::Auto);
+	 // skip not installed or now-removed ones if requested
+	 if (InstalledOnly && (
+	     (pkg->CurrentVer == 0 && P.Mode != ModeInstall) ||
+	     (pkg->CurrentVer != 0 && P.Mode == ModeDelete)))
+	 {
+	    // The section is obsolete if it contains no other tag
+	    unsigned int const count = section.Count();
+	    if (count < 2 ||
+		(count == 2 && section.Exists("Auto-Installed")) ||
+		(count == 3 && section.Exists("Auto-Installed") && section.Exists("Architecture")))
+	       continue;
+	    else
+	       newAuto = false;
+	 }
 	 if(_config->FindB("Debug::pkgAutoRemove",false))
 	 if(_config->FindB("Debug::pkgAutoRemove",false))
 	    std::clog << "Update existing AutoInstall info: " 
 	    std::clog << "Update existing AutoInstall info: " 
-		      << pkg.Name() << std::endl;
-	 TFRewriteData rewrite[2];
-	 rewrite[0].Tag = "Auto-Installed";
-	 rewrite[0].Rewrite = newAuto ? "1" : "0";
+		      << pkg.FullName() << std::endl;
+	 TFRewriteData rewrite[3];
+	 rewrite[0].Tag = "Architecture";
+	 rewrite[0].Rewrite = pkg.Arch();
 	 rewrite[0].NewTag = 0;
 	 rewrite[0].NewTag = 0;
-	 rewrite[1].Tag = 0;
+	 rewrite[1].Tag = "Auto-Installed";
+	 rewrite[1].Rewrite = newAuto ? "1" : "0";
+	 rewrite[1].NewTag = 0;
+	 rewrite[2].Tag = 0;
 	 TFRewrite(OutFile, section, nullreorderlist, rewrite);
 	 TFRewrite(OutFile, section, nullreorderlist, rewrite);
 	 fprintf(OutFile,"\n");
 	 fprintf(OutFile,"\n");
-	 pkgs_seen.insert(pkgname);
+	 pkgs_seen.insert(pkg.FullName());
    }
    }
    
    
    // then write the ones we have not seen yet
    // then write the ones we have not seen yet
    std::ostringstream ostr;
    std::ostringstream ostr;
    for(pkgCache::PkgIterator pkg=Cache->PkgBegin(); !pkg.end(); pkg++) {
    for(pkgCache::PkgIterator pkg=Cache->PkgBegin(); !pkg.end(); pkg++) {
-      if(PkgState[pkg->ID].Flags & Flag::Auto) {
-	 if (pkgs_seen.find(pkg.Name()) != pkgs_seen.end()) {
+      StateCache const &P = PkgState[pkg->ID];
+      if(P.Flags & Flag::Auto) {
+	 if (pkgs_seen.find(pkg.FullName()) != pkgs_seen.end()) {
 	    if(debug_autoremove)
 	    if(debug_autoremove)
-	       std::clog << "Skipping already written " << pkg.Name() << std::endl;
+	       std::clog << "Skipping already written " << pkg.FullName() << std::endl;
 	    continue;
 	    continue;
 	 }
 	 }
-         // skip not installed ones if requested
-         if(InstalledOnly && pkg->CurrentVer == 0)
-            continue;
+	 // skip not installed ones if requested
+	 if (InstalledOnly && (
+	     (pkg->CurrentVer == 0 && P.Mode != ModeInstall) ||
+	     (pkg->CurrentVer != 0 && P.Mode == ModeDelete)))
+	    continue;
+	 const char* const pkgarch = pkg.Arch();
+	 if (strcmp(pkgarch, "all") == 0)
+	    continue;
 	 if(debug_autoremove)
 	 if(debug_autoremove)
-	    std::clog << "Writing new AutoInstall: " 
-		      << pkg.Name() << std::endl;
+	    std::clog << "Writing new AutoInstall: " << pkg.FullName() << std::endl;
 	 ostr.str(string(""));
 	 ostr.str(string(""));
-	 ostr << "Package: " << pkg.Name() 
+	 ostr << "Package: " << pkg.Name()
+	      << "\nArchitecture: " << pkgarch
 	      << "\nAuto-Installed: 1\n\n";
 	      << "\nAuto-Installed: 1\n\n";
 	 fprintf(OutFile,"%s",ostr.str().c_str());
 	 fprintf(OutFile,"%s",ostr.str().c_str());
-	 fprintf(OutFile,"\n");
       }
       }
    }
    }
    fclose(OutFile);
    fclose(OutFile);
@@ -299,7 +338,7 @@ bool pkgDepCache::CheckDep(DepIterator Dep,int Type,PkgIterator &Res)
    /* Check simple depends. A depends -should- never self match but 
    /* Check simple depends. A depends -should- never self match but 
       we allow it anyhow because dpkg does. Technically it is a packaging
       we allow it anyhow because dpkg does. Technically it is a packaging
       bug. Conflicts may never self match */
       bug. Conflicts may never self match */
-   if (Dep.TargetPkg() != Dep.ParentPkg() || 
+   if (Dep.TargetPkg()->Group != Dep.ParentPkg()->Group ||
        (Dep->Type != Dep::Conflicts && Dep->Type != Dep::DpkgBreaks && Dep->Type != Dep::Obsoletes))
        (Dep->Type != Dep::Conflicts && Dep->Type != Dep::DpkgBreaks && Dep->Type != Dep::Obsoletes))
    {
    {
       PkgIterator Pkg = Dep.TargetPkg();
       PkgIterator Pkg = Dep.TargetPkg();
@@ -328,9 +367,9 @@ bool pkgDepCache::CheckDep(DepIterator Dep,int Type,PkgIterator &Res)
    PkgIterator Pkg = Dep.ParentPkg();
    PkgIterator Pkg = Dep.ParentPkg();
    for (; P.end() != true; P++)
    for (; P.end() != true; P++)
    {
    {
-      /* Provides may never be applied against the same package if it is
-         a conflicts. See the comment above. */
-      if (P.OwnerPkg() == Pkg &&
+      /* Provides may never be applied against the same package (or group)
+         if it is a conflicts. See the comment above. */
+      if (P.OwnerPkg()->Group == Pkg->Group &&
 	  (Dep->Type == Dep::Conflicts || Dep->Type == Dep::DpkgBreaks))
 	  (Dep->Type == Dep::Conflicts || Dep->Type == Dep::DpkgBreaks))
 	 continue;
 	 continue;
       
       
@@ -368,8 +407,11 @@ bool pkgDepCache::CheckDep(DepIterator Dep,int Type,PkgIterator &Res)
 									/*}}}*/
 									/*}}}*/
 // DepCache::AddSizes - Add the packages sizes to the counters		/*{{{*/
 // 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];
    StateCache &P = PkgState[Pkg->ID];
    
    
@@ -383,8 +425,8 @@ void pkgDepCache::AddSizes(const PkgIterator &Pkg,signed long Mult)
    // Compute the size data
    // Compute the size data
    if (P.NewInstall() == true)
    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;
       return;
    }
    }
    
    
@@ -393,9 +435,9 @@ void pkgDepCache::AddSizes(const PkgIterator &Pkg,signed long Mult)
        (P.InstallVer != (Version *)Pkg.CurrentVer() || 
        (P.InstallVer != (Version *)Pkg.CurrentVer() || 
 	(P.iFlags & ReInstall) == ReInstall) && P.InstallVer != 0)
 	(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;
       return;
    }
    }
    
    
@@ -403,14 +445,80 @@ void pkgDepCache::AddSizes(const PkgIterator &Pkg,signed long Mult)
    if (Pkg.State() == pkgCache::PkgIterator::NeedsUnpack &&
    if (Pkg.State() == pkgCache::PkgIterator::NeedsUnpack &&
        P.Delete() == false)
        P.Delete() == false)
    {
    {
-      iDownloadSize += (signed)(Mult*P.InstVerIter(*this)->Size);
+      iDownloadSize += (signed long long)(Mult*P.InstVerIter(*this)->Size);
       return;
       return;
    }
    }
    
    
    // Removing
    // Removing
    if (Pkg->CurrentVer != 0 && P.InstallVer == 0)
    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;
       return;
    }   
    }   
 }
 }
@@ -596,6 +704,107 @@ void pkgDepCache::UpdateVerState(PkgIterator Pkg)
    }
    }
 }
 }
 									/*}}}*/
 									/*}}}*/
+// DepCache::RemovePseudoInstalledPkg - MultiArch helper for Update()	/*{{{*/
+// ---------------------------------------------------------------------
+/* We "install" arch all packages for all archs if it is installed. Many
+   of these will be broken. This method will look at these broken Pkg and
+   "remove" it. */
+bool pkgDepCache::RemovePseudoInstalledPkg(PkgIterator &Pkg, std::set<unsigned long> &recheck) {
+   if (unlikely(Pkg->CurrentVer == 0))
+      return false;
+
+   VerIterator V = Pkg.CurrentVer();
+   if (V->MultiArch != Version::All)
+      return false;
+
+   // Never ever kill an "all" package - they have no dependency so they can't be broken
+   if (strcmp(Pkg.Arch(),"all") == 0)
+      return false;
+
+   unsigned char const CurDepState = VersionState(V.DependsList(),DepInstall,DepInstMin,DepInstPolicy);
+   if ((CurDepState & DepInstMin) == DepInstMin) {
+      // okay, the package isn't broken, but is the package also required?
+      // If it has no real dependencies, no installed rdepends and doesn't
+      // provide something of value, we will kill it as not required.
+      // These pseudopackages have otherwise interesting effects if they get
+      // a new dependency in a newer version…
+      for (pkgCache::DepIterator D = V.DependsList();
+	   D.end() != true; ++D)
+	 if (D.IsCritical() == true && D.ParentPkg()->Group != Pkg->Group)
+	    return false;
+      for (DepIterator D = Pkg.RevDependsList(); D.end() != true; ++D)
+      {
+	 if (D.IsCritical() == false)
+	    continue;
+	 PkgIterator const P = D.ParentPkg();
+	 if (P->Group == Pkg->Group)
+	    continue;
+	 if (P->CurrentVer != 0)
+	    return false;
+      }
+      for (PrvIterator Prv = V.ProvidesList(); Prv.end() != true; Prv++)
+	 for (DepIterator d = Prv.ParentPkg().RevDependsList();
+	      d.end() != true; ++d)
+	 {
+	    PkgIterator const P = d.ParentPkg();
+	    if (P->CurrentVer != 0 &&
+	        P->Group != Pkg->Group)
+	       return false;
+	 }
+   }
+
+   // Dependencies for this arch all package are not statisfied
+   // so we installed it only for our convenience: get right of it now.
+   RemoveSizes(Pkg);
+   RemoveStates(Pkg);
+
+   Pkg->CurrentVer = 0;
+   PkgState[Pkg->ID].InstallVer = 0;
+
+   AddStates(Pkg);
+   Update(Pkg);
+   AddSizes(Pkg);
+
+   // After the remove previously satisfied pseudo pkg could be now
+   // no longer satisfied, so we need to recheck the reverse dependencies
+   for (DepIterator d = Pkg.RevDependsList(); d.end() != true; ++d)
+   {
+      PkgIterator const P = d.ParentPkg();
+      if (P->CurrentVer != 0)
+	 recheck.insert(P.Index());
+   }
+
+   for (DepIterator d = V.DependsList(); d.end() != true; ++d)
+   {
+      PkgIterator const P = d.TargetPkg();
+      for (PrvIterator Prv = P.ProvidesList(); Prv.end() != true; ++Prv)
+      {
+	 PkgIterator const O = Prv.OwnerPkg();
+	 if (O->CurrentVer != 0)
+	    recheck.insert(O.Index());
+      }
+
+      if (P->CurrentVer != 0)
+	 recheck.insert(P.Index());
+   }
+
+   for (PrvIterator Prv = V.ProvidesList(); Prv.end() != true; Prv++)
+   {
+      for (DepIterator d = Prv.ParentPkg().RevDependsList();
+	   d.end() != true; ++d)
+      {
+	 PkgIterator const P = d.ParentPkg();
+	 if (P->CurrentVer == 0)
+	    continue;
+
+	    recheck.insert(P.Index());
+      }
+   }
+
+
+   return true;
+}
+									/*}}}*/
 // DepCache::Update - Figure out all the state information		/*{{{*/
 // DepCache::Update - Figure out all the state information		/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /* This will figure out the state of all the packages and all the 
 /* This will figure out the state of all the packages and all the 
@@ -609,9 +818,13 @@ void pkgDepCache::Update(OpProgress *Prog)
    iKeepCount = 0;
    iKeepCount = 0;
    iBrokenCount = 0;
    iBrokenCount = 0;
    iBadCount = 0;
    iBadCount = 0;
-   
+
+   std::set<unsigned long> recheck;
+
    // Perform the depends pass
    // Perform the depends pass
    int Done = 0;
    int Done = 0;
+   bool const checkMultiArch = APT::Configuration::getArchitectures().size() > 1;
+   unsigned long killed = 0;
    for (PkgIterator I = PkgBegin(); I.end() != true; I++,Done++)
    for (PkgIterator I = PkgBegin(); I.end() != true; I++,Done++)
    {
    {
       if (Prog != 0 && Done%20 == 0)
       if (Prog != 0 && Done%20 == 0)
@@ -619,7 +832,7 @@ void pkgDepCache::Update(OpProgress *Prog)
       for (VerIterator V = I.VersionList(); V.end() != true; V++)
       for (VerIterator V = I.VersionList(); V.end() != true; V++)
       {
       {
 	 unsigned char Group = 0;
 	 unsigned char Group = 0;
-	 
+
 	 for (DepIterator D = V.DependsList(); D.end() != true; D++)
 	 for (DepIterator D = V.DependsList(); D.end() != true; D++)
 	 {
 	 {
 	    // Build the dependency state.
 	    // Build the dependency state.
@@ -637,21 +850,158 @@ void pkgDepCache::Update(OpProgress *Prog)
 		D->Type == Dep::DpkgBreaks ||
 		D->Type == Dep::DpkgBreaks ||
 		D->Type == Dep::Obsoletes)
 		D->Type == Dep::Obsoletes)
 	       State = ~State;
 	       State = ~State;
-	 }	 
+	 }
       }
       }
 
 
-      // Compute the pacakge dependency state and size additions
+      // Compute the package dependency state and size additions
       AddSizes(I);
       AddSizes(I);
       UpdateVerState(I);
       UpdateVerState(I);
       AddStates(I);
       AddStates(I);
+
+      if (checkMultiArch != true || I->CurrentVer == 0)
+	 continue;
+
+      VerIterator const V = I.CurrentVer();
+      if (V->MultiArch != Version::All)
+	 continue;
+
+      recheck.insert(I.Index());
+      --Done; // no progress if we need to recheck the package
+   }
+
+   if (checkMultiArch == true) {
+      /* FIXME: recheck breaks proper progress reporting as we don't know
+		how many packages we need to recheck. To lower the effect
+		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();) {
+	    if (Prog != 0 && Done%20 == 0)
+	       Prog->Progress(Done);
+	    PkgIterator P = PkgIterator(*Cache, Cache->PkgP + *p);
+	    if (RemovePseudoInstalledPkg(P, recheck) == true) {
+	       ++killed;
+	       ++Done;
+	    }
+	    recheck.erase(p++);
+	 }
+
+      /* Okay, we have killed a great amount of pseudopackages -
+	 we have killed so many that we have now arch "all" packages
+	 without an installed pseudo package, but we NEED an installed
+	 pseudo package, so we will search now for a pseudo package
+	 we can install without breaking everything. */
+      for (GrpIterator G = Cache->GrpBegin(); G.end() != true; ++G)
+      {
+	 PkgIterator P = G.FindPkg("all");
+	 if (P.end() == true)
+	    continue;
+	 if (P->CurrentVer == 0)
+	    continue;
+	 bool installed = false;
+	 for (P = G.FindPkg("any"); P.end() != true; P = G.NextPkg(P))
+	 {
+	    if (strcmp(P.Arch(), "all") == 0)
+	       continue;
+	    if (P->CurrentVer == 0)
+	       continue;
+	    installed = true;
+	    break;
+	 }
+	 if (installed == false)
+	    recheck.insert(G.Index());
+      }
+
+      while (recheck.empty() != true)
+      {
+	 std::set<unsigned long>::const_iterator g = recheck.begin();
+	 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());
+      }
    }
    }
 
 
-   if (Prog != 0)      
+   if (Prog != 0)
       Prog->Progress(Done);
       Prog->Progress(Done);
 
 
    readStateFile(Prog);
    readStateFile(Prog);
 }
 }
 									/*}}}*/
 									/*}}}*/
+// DepCache::ReInstallPseudoForGroup - MultiArch helper for Update()	/*{{{*/
+// ---------------------------------------------------------------------
+/* RemovePseudoInstalledPkg() is very successful. It even kills packages
+   to an amount that no pseudo package is left, but we need a pseudo package
+   for upgrading senarios so we need to reinstall one pseudopackage which
+   doesn't break everything. Thankfully we can't have architecture depending
+   negative dependencies so this problem is already eliminated */
+bool pkgDepCache::ReInstallPseudoForGroup(pkgCache::PkgIterator const &P, std::set<unsigned long> &recheck)
+{
+   if (P->CurrentVer != 0)
+      return true;
+   // recursive call for packages which provide this package
+   for (pkgCache::PrvIterator Prv = P.ProvidesList(); Prv.end() != true; ++Prv)
+      ReInstallPseudoForGroup(Prv.OwnerPkg(), recheck);
+   // check if we actually need to look at this group
+   unsigned long const G = P->Group;
+   std::set<unsigned long>::const_iterator Pi = recheck.find(G);
+   if (Pi == recheck.end())
+      return true;
+   recheck.erase(Pi); // remove here, so we can't fall into an endless loop
+   if (unlikely(ReInstallPseudoForGroup(G, recheck) == false))
+   {
+      recheck.insert(G);
+      return false;
+   }
+   return true;
+}
+bool pkgDepCache::ReInstallPseudoForGroup(unsigned long const &G, std::set<unsigned long> &recheck)
+{
+   std::vector<std::string> static const Archs = APT::Configuration::getArchitectures();
+   pkgCache::GrpIterator Grp(*Cache, Cache->GrpP + G);
+   if (unlikely(Grp.end() == true))
+      return false;
+   for (std::vector<std::string>::const_iterator a = Archs.begin();
+        a != Archs.end(); ++a)
+   {
+      pkgCache::PkgIterator P = Grp.FindPkg(*a);
+      if (P.end() == true)
+	 continue;
+      pkgCache::VerIterator allV = Grp.FindPkg("all").CurrentVer();
+      for (VerIterator V = P.VersionList(); V.end() != true; ++V)
+      {
+	 // search for the same version as the all package
+	 if (allV->Hash != V->Hash || strcmp(allV.VerStr(),V.VerStr()) != 0)
+	    continue;
+	 unsigned char const CurDepState = VersionState(V.DependsList(),DepInstall,DepInstMin,DepInstPolicy);
+	 // If it is broken, try to install dependencies first before retry
+	 if ((CurDepState & DepInstMin) != DepInstMin)
+	 {
+	    for (pkgCache::DepIterator D = V.DependsList(); D.end() != true; ++D)
+	    {
+	       if (D->Type != pkgCache::Dep::PreDepends && D->Type != pkgCache::Dep::Depends)
+		  continue;
+	       ReInstallPseudoForGroup(D.TargetPkg(), recheck);
+	    }
+	    unsigned char const CurDepState = VersionState(V.DependsList(),DepInstall,DepInstMin,DepInstPolicy);
+	    // if package ist still broken… try another arch
+	    if ((CurDepState & DepInstMin) != DepInstMin)
+	       break;
+	 }
+	 // dependencies satisfied: reinstall the package
+	 RemoveSizes(P);
+	 RemoveStates(P);
+	 P->CurrentVer = V.Index();
+	 PkgState[P->ID].InstallVer = V;
+	 AddStates(P);
+	 Update(P);
+	 AddSizes(P);
+	 return true;
+      }
+   }
+   return false;
+}
+									/*}}}*/
 // DepCache::Update - Update the deps list of a package	   		/*{{{*/
 // DepCache::Update - Update the deps list of a package	   		/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /* This is a helper for update that only does the dep portion of the scan. 
 /* This is a helper for update that only does the dep portion of the scan. 
@@ -813,6 +1163,10 @@ void pkgDepCache::MarkDelete(PkgIterator const &Pkg, bool rPurge,
    AddStates(Pkg);   
    AddStates(Pkg);   
    Update(Pkg);
    Update(Pkg);
    AddSizes(Pkg);
    AddSizes(Pkg);
+
+   // if we remove the pseudo package, we also need to remove the "real"
+   if (Pkg->CurrentVer != 0 && Pkg.CurrentVer().Pseudo() == true)
+      MarkDelete(Pkg.Group().FindPkg("all"), rPurge, Depth+1, FromUser);
 }
 }
 									/*}}}*/
 									/*}}}*/
 // DepCache::IsDeleteOk - check if it is ok to remove this package	/*{{{*/
 // DepCache::IsDeleteOk - check if it is ok to remove this package	/*{{{*/
@@ -901,6 +1255,10 @@ void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst,
    Update(Pkg);
    Update(Pkg);
    AddSizes(Pkg);
    AddSizes(Pkg);
 
 
+   // always trigger the install of the all package for a pseudo package
+   if (P.CandidateVerIter(*Cache).Pseudo() == true)
+      MarkInstall(Pkg.Group().FindPkg("all"), AutoInst, Depth, FromUser, ForceImportantDeps);
+
    if (AutoInst == false)
    if (AutoInst == false)
       return;
       return;
 
 
@@ -1099,6 +1457,9 @@ bool pkgDepCache::IsInstallOk(PkgIterator const &Pkg,bool AutoInst,
 /* */
 /* */
 void pkgDepCache::SetReInstall(PkgIterator const &Pkg,bool To)
 void pkgDepCache::SetReInstall(PkgIterator const &Pkg,bool To)
 {
 {
+   if (unlikely(Pkg.end() == true))
+      return;
+
    ActionGroup group(*this);
    ActionGroup group(*this);
 
 
    RemoveSizes(Pkg);
    RemoveSizes(Pkg);
@@ -1112,12 +1473,17 @@ void pkgDepCache::SetReInstall(PkgIterator const &Pkg,bool To)
    
    
    AddStates(Pkg);
    AddStates(Pkg);
    AddSizes(Pkg);
    AddSizes(Pkg);
+
+   if (unlikely(Pkg.CurrentVer().end() == true) || Pkg.CurrentVer().Pseudo() == false)
+      return;
+
+   SetReInstall(Pkg.Group().FindPkg("all"), To);
 }
 }
 									/*}}}*/
 									/*}}}*/
 // DepCache::SetCandidateVersion - Change the candidate version		/*{{{*/
 // DepCache::SetCandidateVersion - Change the candidate version		/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /* */
 /* */
-void pkgDepCache::SetCandidateVersion(VerIterator TargetVer)
+void pkgDepCache::SetCandidateVersion(VerIterator TargetVer, bool const &Pseudo)
 {
 {
    ActionGroup group(*this);
    ActionGroup group(*this);
 
 
@@ -1135,6 +1501,28 @@ void pkgDepCache::SetCandidateVersion(VerIterator TargetVer)
    AddStates(Pkg);
    AddStates(Pkg);
    Update(Pkg);
    Update(Pkg);
    AddSizes(Pkg);
    AddSizes(Pkg);
+
+   if (TargetVer.Pseudo() == false || Pseudo == false)
+      return;
+
+   // the version was pseudo: set all other pseudos also
+   pkgCache::GrpIterator Grp = Pkg.Group();
+   for (Pkg = Grp.FindPkg("any"); Pkg.end() == false; ++Pkg)
+   {
+      StateCache &P = PkgState[Pkg->ID];
+      if (TargetVer.SimilarVer(P.CandidateVerIter(*this)) == true ||
+	  (P.CandidateVerIter(*this).Pseudo() == false &&
+	   strcmp(Pkg.Arch(), "all") != 0))
+	 continue;
+
+      for (pkgCache::VerIterator Ver = Pkg.VersionList(); Ver.end() == false; ++Ver)
+      {
+	 if (TargetVer.SimilarVer(Ver) == false)
+	    continue;
+	 SetCandidateVersion(Ver, false);
+	 break;
+      }
+   }
 }
 }
 
 
 void pkgDepCache::MarkAuto(const PkgIterator &Pkg, bool Auto)
 void pkgDepCache::MarkAuto(const PkgIterator &Pkg, bool Auto)
@@ -1197,7 +1585,7 @@ const char *pkgDepCache::StateCache::StripEpoch(const char *Ver)
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /* The default just returns the highest available version that is not
 /* The default just returns the highest available version that is not
    a source and automatic. */
    a source and automatic. */
-pkgCache::VerIterator pkgDepCache::Policy::GetCandidateVer(PkgIterator Pkg)
+pkgCache::VerIterator pkgDepCache::Policy::GetCandidateVer(PkgIterator const &Pkg)
 {
 {
    /* Not source/not automatic versions cannot be a candidate version 
    /* Not source/not automatic versions cannot be a candidate version 
       unless they are already installed */
       unless they are already installed */
@@ -1232,7 +1620,7 @@ pkgCache::VerIterator pkgDepCache::Policy::GetCandidateVer(PkgIterator Pkg)
 // Policy::IsImportantDep - True if the dependency is important		/*{{{*/
 // Policy::IsImportantDep - True if the dependency is important		/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /* */
 /* */
-bool pkgDepCache::Policy::IsImportantDep(DepIterator Dep)
+bool pkgDepCache::Policy::IsImportantDep(DepIterator const &Dep)
 {
 {
    if(Dep.IsCritical())
    if(Dep.IsCritical())
       return true;
       return true;
@@ -1251,54 +1639,6 @@ bool pkgDepCache::Policy::IsImportantDep(DepIterator Dep)
    else if(Dep->Type == pkgCache::Dep::Suggests)
    else if(Dep->Type == pkgCache::Dep::Suggests)
      return _config->FindB("APT::Install-Suggests", false);
      return _config->FindB("APT::Install-Suggests", false);
 
 
-   return false;
-}
-									/*}}}*/
-pkgDepCache::DefaultRootSetFunc::DefaultRootSetFunc()			/*{{{*/
-  : constructedSuccessfully(false)
-{
-  Configuration::Item const *Opts;
-  Opts = _config->Tree("APT::NeverAutoRemove");
-  if (Opts != 0 && Opts->Child != 0)
-    {
-      Opts = Opts->Child;
-      for (; Opts != 0; Opts = Opts->Next)
-	{
-	  if (Opts->Value.empty() == true)
-	    continue;
-
-	  regex_t *p = new regex_t;
-	  if(regcomp(p,Opts->Value.c_str(),
-		     REG_EXTENDED | REG_ICASE | REG_NOSUB) != 0)
-	    {
-	      regfree(p);
-	      delete p;
-	      _error->Error("Regex compilation error for APT::NeverAutoRemove");
-	      return;
-	    }
-
-	  rootSetRegexp.push_back(p);
-	}
-    }
-
-  constructedSuccessfully = true;
-}
-									/*}}}*/
-pkgDepCache::DefaultRootSetFunc::~DefaultRootSetFunc()			/*{{{*/
-{
-  for(unsigned int i = 0; i < rootSetRegexp.size(); i++)
-    {
-      regfree(rootSetRegexp[i]);
-      delete rootSetRegexp[i];
-    }
-}
-									/*}}}*/
-bool pkgDepCache::DefaultRootSetFunc::InRootSet(const pkgCache::PkgIterator &pkg) /*{{{*/
-{
-   for(unsigned int i = 0; i < rootSetRegexp.size(); i++)
-      if (regexec(rootSetRegexp[i], pkg.Name(), 0, 0, 0) == 0)
-	 return true;
-
    return false;
    return false;
 }
 }
 									/*}}}*/
 									/*}}}*/
@@ -1339,7 +1679,7 @@ bool pkgDepCache::MarkRequired(InRootSetFunc &userFunc)
 
 
       // debug output
       // debug output
       if(debug_autoremove && PkgState[p->ID].Flags & Flag::Auto)
       if(debug_autoremove && PkgState[p->ID].Flags & Flag::Auto)
-  	 std::clog << "AutoDep: " << p.Name() << std::endl;
+  	 std::clog << "AutoDep: " << p.FullName() << std::endl;
    }
    }
 
 
    // init vars
    // init vars
@@ -1353,8 +1693,11 @@ bool pkgDepCache::MarkRequired(InRootSetFunc &userFunc)
    {
    {
       if(!(PkgState[p->ID].Flags & Flag::Auto) ||
       if(!(PkgState[p->ID].Flags & Flag::Auto) ||
 	  (p->Flags & Flag::Essential) ||
 	  (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)
 	 // the package is installed (and set to keep)
 	 if(PkgState[p->ID].Keep() && !p.CurrentVer().end())
 	 if(PkgState[p->ID].Keep() && !p.CurrentVer().end())
@@ -1373,13 +1716,18 @@ bool pkgDepCache::MarkRequired(InRootSetFunc &userFunc)
 // MarkPackage - mark a single package in Mark-and-Sweep		/*{{{*/
 // MarkPackage - mark a single package in Mark-and-Sweep		/*{{{*/
 void pkgDepCache::MarkPackage(const pkgCache::PkgIterator &pkg,
 void pkgDepCache::MarkPackage(const pkgCache::PkgIterator &pkg,
 			      const pkgCache::VerIterator &ver,
 			      const pkgCache::VerIterator &ver,
-			      bool follow_recommends,
-			      bool follow_suggests)
+			      bool const &follow_recommends,
+			      bool const &follow_suggests)
 {
 {
    pkgDepCache::StateCache &state = PkgState[pkg->ID];
    pkgDepCache::StateCache &state = PkgState[pkg->ID];
-   VerIterator currver            = pkg.CurrentVer();
-   VerIterator candver            = state.CandidateVerIter(*this);
-   VerIterator instver            = state.InstVerIter(*this);
+
+   // if we are marked already we are done
+   if(state.Marked)
+      return;
+
+   VerIterator const currver = pkg.CurrentVer();
+   VerIterator const candver = state.CandidateVerIter(*this);
+   VerIterator const instver = state.InstVerIter(*this);
 
 
 #if 0
 #if 0
    // If a package was garbage-collected but is now being marked, we
    // If a package was garbage-collected but is now being marked, we
@@ -1405,15 +1753,11 @@ void pkgDepCache::MarkPackage(const pkgCache::PkgIterator &pkg,
       !(ver == currver && instver.end() && !ver.end()))
       !(ver == currver && instver.end() && !ver.end()))
       return;
       return;
 
 
-   // if we are marked already we are done
-   if(state.Marked)
-      return;
+   bool const debug_autoremove = _config->FindB("Debug::pkgAutoRemove", false);
 
 
-   bool debug_autoremove = _config->FindB("Debug::pkgAutoRemove", false);
-   
    if(debug_autoremove)
    if(debug_autoremove)
      {
      {
-       std::clog << "Marking: " << pkg.Name();
+       std::clog << "Marking: " << pkg.FullName();
        if(!ver.end())
        if(!ver.end())
 	 std::clog << " " << ver.VerStr();
 	 std::clog << " " << ver.VerStr();
        if(!currver.end())
        if(!currver.end())
@@ -1425,8 +1769,31 @@ void pkgDepCache::MarkPackage(const pkgCache::PkgIterator &pkg,
 
 
    state.Marked=true;
    state.Marked=true;
 
 
-   if(!ver.end())
+   if(ver.end() == true)
+      return;
+
+   // If the version belongs to a Multi-Arch all package
+   // we will mark all others in this Group with this version also
+   if (ver->MultiArch == pkgCache::Version::All &&
+	strcmp(ver.Arch(true), "all") == 0)
    {
    {
+      GrpIterator G = pkg.Group();
+      const char* const VerStr = ver.VerStr();
+      for (PkgIterator P = G.FindPkg("any");
+	   P.end() != true; P = G.NextPkg(P))
+      {
+	 for (VerIterator V = P.VersionList();
+	      V.end() != true; ++V)
+	 {
+	    if (ver->Hash != V->Hash ||
+		strcmp(VerStr, V.VerStr()) != 0)
+	       continue;
+	    MarkPackage(P, V, follow_recommends, follow_suggests);
+	    break;
+	 }
+      }
+   }
+
      for(DepIterator d = ver.DependsList(); !d.end(); ++d)
      for(DepIterator d = ver.DependsList(); !d.end(); ++d)
      {
      {
 	if(d->Type == Dep::Depends ||
 	if(d->Type == Dep::Depends ||
@@ -1444,10 +1811,9 @@ void pkgDepCache::MarkPackage(const pkgCache::PkgIterator &pkg,
 	      {
 	      {
 		if(debug_autoremove)
 		if(debug_autoremove)
 		  {
 		  {
-		    std::clog << "Following dep: " << d.ParentPkg().Name()
+		    std::clog << "Following dep: " << d.ParentPkg().FullName()
 			      << " " << d.ParentVer().VerStr() << " "
 			      << " " << d.ParentVer().VerStr() << " "
-			      << d.DepType() << " "
-			      << d.TargetPkg().Name();
+			      << d.DepType() << " " << d.TargetPkg().FullName();
 		    if((d->CompareOp & ~pkgCache::Dep::Or) != pkgCache::Dep::NoOp)
 		    if((d->CompareOp & ~pkgCache::Dep::Or) != pkgCache::Dep::NoOp)
 		      {
 		      {
 			std::clog << " (" << d.CompType() << " "
 			std::clog << " (" << d.CompType() << " "
@@ -1455,7 +1821,7 @@ void pkgDepCache::MarkPackage(const pkgCache::PkgIterator &pkg,
 		      }
 		      }
 		    std::clog << std::endl;
 		    std::clog << std::endl;
 		  }
 		  }
-		 MarkPackage(V.ParentPkg(), V, 
+		 MarkPackage(V.ParentPkg(), V,
 			     follow_recommends, follow_suggests);
 			     follow_recommends, follow_suggests);
 	      }
 	      }
 	   }
 	   }
@@ -1468,17 +1834,16 @@ void pkgDepCache::MarkPackage(const pkgCache::PkgIterator &pkg,
 	      {
 	      {
 		if(debug_autoremove)
 		if(debug_autoremove)
 		  {
 		  {
-		    std::clog << "Following dep: " << d.ParentPkg().Name()
-			      << " " << d.ParentVer().VerStr() << " "
-			      << d.DepType() << " "
-			      << d.TargetPkg().Name();
+		    std::clog << "Following dep: " << d.ParentPkg().FullName() << " "
+			      << d.ParentVer().VerStr() << " "
+			      << d.DepType() << " " << d.TargetPkg().FullName() << " ";
 		    if((d->CompareOp & ~pkgCache::Dep::Or) != pkgCache::Dep::NoOp)
 		    if((d->CompareOp & ~pkgCache::Dep::Or) != pkgCache::Dep::NoOp)
 		      {
 		      {
 			std::clog << " (" << d.CompType() << " "
 			std::clog << " (" << d.CompType() << " "
 				  << d.TargetVer() << ")";
 				  << d.TargetVer() << ")";
 		      }
 		      }
 		    std::clog << ", provided by "
 		    std::clog << ", provided by "
-			      << prv.OwnerPkg().Name() << " "
+			      << prv.OwnerPkg().FullName() << " "
 			      << prv.OwnerVer().VerStr()
 			      << prv.OwnerVer().VerStr()
 			      << std::endl;
 			      << std::endl;
 		  }
 		  }
@@ -1489,7 +1854,6 @@ void pkgDepCache::MarkPackage(const pkgCache::PkgIterator &pkg,
 	   }
 	   }
 	}
 	}
      }
      }
-   }
 }
 }
 									/*}}}*/
 									/*}}}*/
 bool pkgDepCache::Sweep()						/*{{{*/
 bool pkgDepCache::Sweep()						/*{{{*/
@@ -1511,7 +1875,7 @@ bool pkgDepCache::Sweep()						/*{{{*/
      {
      {
 	state.Garbage=true;
 	state.Garbage=true;
 	if(debug_autoremove)
 	if(debug_autoremove)
-	   std::clog << "Garbage: " << p.Name() << std::endl;
+	   std::clog << "Garbage: " << p.FullName() << std::endl;
      }
      }
   }   
   }   
 
 

+ 36 - 34
apt-pkg/depcache.h

@@ -38,14 +38,14 @@
 #ifndef PKGLIB_DEPCACHE_H
 #ifndef PKGLIB_DEPCACHE_H
 #define PKGLIB_DEPCACHE_H
 #define PKGLIB_DEPCACHE_H
 
 
-
+#include <apt-pkg/configuration.h>
 #include <apt-pkg/pkgcache.h>
 #include <apt-pkg/pkgcache.h>
 #include <apt-pkg/progress.h>
 #include <apt-pkg/progress.h>
-
-#include <regex.h>
+#include <apt-pkg/error.h>
 
 
 #include <vector>
 #include <vector>
 #include <memory>
 #include <memory>
+#include <set>
 
 
 class pkgDepCache : protected pkgCache::Namespace
 class pkgDepCache : protected pkgCache::Namespace
 {
 {
@@ -78,8 +78,8 @@ class pkgDepCache : protected pkgCache::Namespace
     */
     */
    void MarkPackage(const pkgCache::PkgIterator &pkg,
    void MarkPackage(const pkgCache::PkgIterator &pkg,
 		    const pkgCache::VerIterator &ver,
 		    const pkgCache::VerIterator &ver,
-		    bool follow_recommends,
-		    bool follow_suggests);
+		    bool const &follow_recommends,
+		    bool const &follow_suggests);
 
 
    /** \brief Update the Marked field of all packages.
    /** \brief Update the Marked field of all packages.
     *
     *
@@ -183,22 +183,13 @@ class pkgDepCache : protected pkgCache::Namespace
    /** \brief Returns \b true for packages matching a regular
    /** \brief Returns \b true for packages matching a regular
     *  expression in APT::NeverAutoRemove.
     *  expression in APT::NeverAutoRemove.
     */
     */
-   class DefaultRootSetFunc : public InRootSetFunc
+   class DefaultRootSetFunc : public InRootSetFunc, public Configuration::MatchAgainstConfig
    {
    {
-     std::vector<regex_t *> rootSetRegexp;
-     bool constructedSuccessfully;
-
    public:
    public:
-     DefaultRootSetFunc();
-     ~DefaultRootSetFunc();
-
-     /** \return \b true if the class initialized successfully, \b
-      *  false otherwise.  Used to avoid throwing an exception, since
-      *  APT classes generally don't.
-      */
-     bool wasConstructedSuccessfully() const { return constructedSuccessfully; }
+     DefaultRootSetFunc() : Configuration::MatchAgainstConfig("APT::NeverRemove") {};
+     virtual ~DefaultRootSetFunc() {};
 
 
-     bool InRootSet(const pkgCache::PkgIterator &pkg);
+     bool InRootSet(const pkgCache::PkgIterator &pkg) { return pkg.end() == true && Match(pkg.Name()); };
    };
    };
 
 
    struct StateCache
    struct StateCache
@@ -265,8 +256,8 @@ class pkgDepCache : protected pkgCache::Namespace
    {
    {
       public:
       public:
       
       
-      virtual VerIterator GetCandidateVer(PkgIterator Pkg);
-      virtual bool IsImportantDep(DepIterator Dep);
+      virtual VerIterator GetCandidateVer(PkgIterator const &Pkg);
+      virtual bool IsImportantDep(DepIterator const &Dep);
       
       
       virtual ~Policy() {};
       virtual ~Policy() {};
    };
    };
@@ -285,9 +276,11 @@ class pkgDepCache : protected pkgCache::Namespace
    pkgCache *Cache;
    pkgCache *Cache;
    StateCache *PkgState;
    StateCache *PkgState;
    unsigned char *DepState;
    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 iInstCount;
    unsigned long iDelCount;
    unsigned long iDelCount;
    unsigned long iKeepCount;
    unsigned long iKeepCount;
@@ -320,8 +313,9 @@ class pkgDepCache : protected pkgCache::Namespace
    void Update(PkgIterator const &P);
    void Update(PkgIterator const &P);
    
    
    // Count manipulators
    // 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);
    void AddStates(const PkgIterator &Pkg,int Add = 1);
    inline void RemoveStates(const PkgIterator &Pkg) {AddStates(Pkg,-1);};
    inline void RemoveStates(const PkgIterator &Pkg) {AddStates(Pkg,-1);};
    
    
@@ -330,14 +324,17 @@ class pkgDepCache : protected pkgCache::Namespace
    // Legacy.. We look like a pkgCache
    // Legacy.. We look like a pkgCache
    inline operator pkgCache &() {return *Cache;};
    inline operator pkgCache &() {return *Cache;};
    inline Header &Head() {return *Cache->HeaderP;};
    inline Header &Head() {return *Cache->HeaderP;};
+   inline GrpIterator GrpBegin() {return Cache->GrpBegin();};
    inline PkgIterator PkgBegin() {return Cache->PkgBegin();};
    inline PkgIterator PkgBegin() {return Cache->PkgBegin();};
+   inline GrpIterator FindGrp(string const &Name) {return Cache->FindGrp(Name);};
    inline PkgIterator FindPkg(string const &Name) {return Cache->FindPkg(Name);};
    inline PkgIterator FindPkg(string const &Name) {return Cache->FindPkg(Name);};
+   inline PkgIterator FindPkg(string const &Name, string const &Arch) {return Cache->FindPkg(Name, Arch);};
 
 
    inline pkgCache &GetCache() {return *Cache;};
    inline pkgCache &GetCache() {return *Cache;};
    inline pkgVersioningSystem &VS() {return *Cache->VS;};
    inline pkgVersioningSystem &VS() {return *Cache->VS;};
    
    
    // Policy implementation
    // Policy implementation
-   inline VerIterator GetCandidateVer(PkgIterator Pkg) {return LocalPolicy->GetCandidateVer(Pkg);};
+   inline VerIterator GetCandidateVer(PkgIterator const &Pkg) {return LocalPolicy->GetCandidateVer(Pkg);};
    inline bool IsImportantDep(DepIterator Dep) {return LocalPolicy->IsImportantDep(Dep);};
    inline bool IsImportantDep(DepIterator Dep) {return LocalPolicy->IsImportantDep(Dep);};
    inline Policy &GetPolicy() {return *LocalPolicy;};
    inline Policy &GetPolicy() {return *LocalPolicy;};
    
    
@@ -398,7 +395,7 @@ class pkgDepCache : protected pkgCache::Namespace
 		    bool ForceImportantDeps = false);
 		    bool ForceImportantDeps = false);
 
 
    void SetReInstall(PkgIterator const &Pkg,bool To);
    void SetReInstall(PkgIterator const &Pkg,bool To);
-   void SetCandidateVersion(VerIterator TargetVer);
+   void SetCandidateVersion(VerIterator TargetVer, bool const &Pseudo = true);
 
 
    /** Set the "is automatically installed" flag of Pkg. */
    /** Set the "is automatically installed" flag of Pkg. */
    void MarkAuto(const PkgIterator &Pkg, bool Auto);
    void MarkAuto(const PkgIterator &Pkg, bool Auto);
@@ -442,16 +439,13 @@ class pkgDepCache : protected pkgCache::Namespace
    virtual bool IsDeleteOk(const PkgIterator &Pkg,bool Purge = false,
    virtual bool IsDeleteOk(const PkgIterator &Pkg,bool Purge = false,
 			    unsigned long Depth = 0, bool FromUser = true);
 			    unsigned long Depth = 0, bool FromUser = true);
 
 
-   // This is for debuging
-   void Update(OpProgress *Prog = 0);
-
    // read persistent states
    // read persistent states
    bool readStateFile(OpProgress *prog);
    bool readStateFile(OpProgress *prog);
-   bool writeStateFile(OpProgress *prog, bool InstalledOnly=false);
+   bool writeStateFile(OpProgress *prog, bool InstalledOnly=true);
    
    
    // Size queries
    // 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 DelCount() {return iDelCount;};
    inline unsigned long KeepCount() {return iKeepCount;};
    inline unsigned long KeepCount() {return iKeepCount;};
    inline unsigned long InstCount() {return iInstCount;};
    inline unsigned long InstCount() {return iInstCount;};
@@ -460,9 +454,17 @@ class pkgDepCache : protected pkgCache::Namespace
    inline unsigned long BadCount() {return iBadCount;};
    inline unsigned long BadCount() {return iBadCount;};
 
 
    bool Init(OpProgress *Prog);
    bool Init(OpProgress *Prog);
-   
+   // Generate all state information
+   void Update(OpProgress *Prog = 0);
+
    pkgDepCache(pkgCache *Cache,Policy *Plcy = 0);
    pkgDepCache(pkgCache *Cache,Policy *Plcy = 0);
    virtual ~pkgDepCache();
    virtual ~pkgDepCache();
+
+   private:
+   // Helper for Update(OpProgress) to remove pseudoinstalled arch all packages
+   bool RemovePseudoInstalledPkg(PkgIterator &Pkg, std::set<unsigned long> &recheck);
+   bool ReInstallPseudoForGroup(unsigned long const &Grp, std::set<unsigned long> &recheck);
+   bool ReInstallPseudoForGroup(pkgCache::PkgIterator const &P, std::set<unsigned long> &recheck);
 };
 };
 
 
 #endif
 #endif

+ 108 - 41
apt-pkg/indexcopy.cc

@@ -27,6 +27,8 @@
 #include <sstream>
 #include <sstream>
 #include <unistd.h>
 #include <unistd.h>
 #include <sys/stat.h>
 #include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
 #include <stdio.h>
 #include <stdio.h>
 									/*}}}*/
 									/*}}}*/
 
 
@@ -590,66 +592,34 @@ bool SigVerify::CopyAndVerify(string CDROM,string Name,vector<string> &SigList,
       indexRecords *MetaIndex = new indexRecords;
       indexRecords *MetaIndex = new indexRecords;
       string prefix = *I; 
       string prefix = *I; 
 
 
+      string const releasegpg = *I+"Release.gpg";
+      string const release = *I+"Release";
+
       // a Release.gpg without a Release should never happen
       // a Release.gpg without a Release should never happen
-      if(!FileExists(*I+"Release"))
+      if(FileExists(release) == false)
       {
       {
 	 delete MetaIndex;
 	 delete MetaIndex;
 	 continue;
 	 continue;
       }
       }
 
 
-
-      // verify the gpg signature of "Release"
-      // gpg --verify "*I+Release.gpg", "*I+Release"
-      const char *Args[400];
-      unsigned int i = 0;
-
-      string gpgvpath = _config->Find("Dir::Bin::gpg", "/usr/bin/gpgv");
-      string pubringpath = _config->Find("Apt::GPGV::TrustedKeyring", "/etc/apt/trusted.gpg");
-      string releasegpg = *I+"Release.gpg";
-      string release = *I+"Release";
-
-      Args[i++] = gpgvpath.c_str();
-      Args[i++] = "--keyring";
-      Args[i++] = pubringpath.c_str();
-      Configuration::Item const *Opts;
-      Opts = _config->Tree("Acquire::gpgv::Options");
-      if (Opts != 0)
-      {
-         Opts = Opts->Child;
-	 for (; Opts != 0; Opts = Opts->Next)
-         {
-            if (Opts->Value.empty() == true)
-               continue;
-            Args[i++] = Opts->Value.c_str();
-	    if(i >= 390) { 
-	       _error->Error("Argument list from Acquire::gpgv::Options too long. Exiting.");
-	       return false;
-	    }
-         }
-      }
-      
-      Args[i++] = releasegpg.c_str();
-      Args[i++] = release.c_str();
-      Args[i++] = NULL;
-      
       pid_t pid = ExecFork();
       pid_t pid = ExecFork();
       if(pid < 0) {
       if(pid < 0) {
 	 _error->Error("Fork failed");
 	 _error->Error("Fork failed");
 	 return false;
 	 return false;
       }
       }
-      if(pid == 0) {
-	 execvp(gpgvpath.c_str(), (char**)Args);
-      }
+      if(pid == 0)
+	 RunGPGV(release, releasegpg);
+
       if(!ExecWait(pid, "gpgv")) {
       if(!ExecWait(pid, "gpgv")) {
 	 _error->Warning("Signature verification failed for: %s",
 	 _error->Warning("Signature verification failed for: %s",
-			 string(*I+"Release.gpg").c_str());
+			 releasegpg.c_str());
 	 // something went wrong, don't copy the Release.gpg
 	 // something went wrong, don't copy the Release.gpg
 	 // FIXME: delete any existing gpg file?
 	 // FIXME: delete any existing gpg file?
 	 continue;
 	 continue;
       }
       }
 
 
       // Open the Release file and add it to the MetaIndex
       // Open the Release file and add it to the MetaIndex
-      if(!MetaIndex->Load(*I+"Release"))
+      if(!MetaIndex->Load(release))
       {
       {
 	 _error->Error("%s",MetaIndex->ErrorText.c_str());
 	 _error->Error("%s",MetaIndex->ErrorText.c_str());
 	 return false;
 	 return false;
@@ -676,6 +646,103 @@ bool SigVerify::CopyAndVerify(string CDROM,string Name,vector<string> &SigList,
       CopyMetaIndex(CDROM, Name, prefix, "Release.gpg");
       CopyMetaIndex(CDROM, Name, prefix, "Release.gpg");
    }   
    }   
 
 
+   return true;
+}
+									/*}}}*/
+// SigVerify::RunGPGV - returns the command needed for verify		/*{{{*/
+// ---------------------------------------------------------------------
+/* Generating the commandline for calling gpgv is somehow complicated as
+   we need to add multiple keyrings and user supplied options. Also, as
+   the cdrom code currently can not use the gpgv method we have two places
+   these need to be done - so the place for this method is wrong but better
+   than code duplication… */
+bool SigVerify::RunGPGV(std::string const &File, std::string const &FileGPG,
+			int const &statusfd, int fd[2])
+{
+   string const gpgvpath = _config->Find("Dir::Bin::gpg", "/usr/bin/gpgv");
+   // FIXME: remove support for deprecated APT::GPGV setting
+   string const trustedFile = _config->FindFile("Dir::Etc::Trusted",
+		_config->Find("APT::GPGV::TrustedKeyring", "/etc/apt/trusted.gpg").c_str());
+   string const trustedPath = _config->FindDir("Dir::Etc::TrustedParts", "/etc/apt/trusted.gpg.d");
+
+   bool const Debug = _config->FindB("Debug::Acquire::gpgv", false);
+
+   if (Debug == true)
+   {
+      std::clog << "gpgv path: " << gpgvpath << std::endl;
+      std::clog << "Keyring file: " << trustedFile << std::endl;
+      std::clog << "Keyring path: " << trustedPath << std::endl;
+   }
+
+   std::vector<string> keyrings = GetListOfFilesInDir(trustedPath, "gpg", false);
+   if (FileExists(trustedFile) == true)
+      keyrings.push_back(trustedFile);
+
+   std::vector<const char *> Args;
+   Args.reserve(30);
+
+   if (keyrings.empty() == true)
+      return false;
+
+   Args.push_back(gpgvpath.c_str());
+   Args.push_back("--ignore-time-conflict");
+
+   if (statusfd != -1)
+   {
+      Args.push_back("--status-fd");
+      char fd[10];
+      snprintf(fd, sizeof(fd), "%i", statusfd);
+      Args.push_back(fd);
+   }
+
+   for (vector<string>::const_iterator K = keyrings.begin();
+	K != keyrings.end(); ++K)
+   {
+      Args.push_back("--keyring");
+      Args.push_back(K->c_str());
+   }
+
+   Configuration::Item const *Opts;
+   Opts = _config->Tree("Acquire::gpgv::Options");
+   if (Opts != 0)
+   {
+      Opts = Opts->Child;
+      for (; Opts != 0; Opts = Opts->Next)
+      {
+	 if (Opts->Value.empty() == true)
+	    continue;
+	 Args.push_back(Opts->Value.c_str());
+      }
+   }
+
+   Args.push_back(FileGPG.c_str());
+   Args.push_back(File.c_str());
+   Args.push_back(NULL);
+
+   if (Debug == true)
+   {
+      std::clog << "Preparing to exec: " << gpgvpath;
+      for (std::vector<const char *>::const_iterator a = Args.begin(); *a != NULL; ++a)
+	 std::clog << " " << *a;
+      std::clog << std::endl;
+   }
+
+   if (statusfd != -1)
+   {
+      int const nullfd = open("/dev/null", O_RDONLY);
+      close(fd[0]);
+      // Redirect output to /dev/null; we read from the status fd
+      dup2(nullfd, STDOUT_FILENO);
+      dup2(nullfd, STDERR_FILENO);
+      // Redirect the pipe to the status fd (3)
+      dup2(fd[1], statusfd);
+
+      putenv((char *)"LANG=");
+      putenv((char *)"LC_ALL=");
+      putenv((char *)"LC_MESSAGES=");
+   }
+
+   execvp(gpgvpath.c_str(), (char **) &Args[0]);
    return true;
    return true;
 }
 }
 									/*}}}*/
 									/*}}}*/

+ 9 - 0
apt-pkg/indexcopy.h

@@ -89,6 +89,15 @@ class SigVerify								/*{{{*/
  public:
  public:
    bool CopyAndVerify(string CDROM,string Name,vector<string> &SigList,
    bool CopyAndVerify(string CDROM,string Name,vector<string> &SigList,
 		      vector<string> PkgList,vector<string> SrcList);
 		      vector<string> PkgList,vector<string> SrcList);
+
+   /** \brief generates and run the command to verify a file with gpgv */
+   static bool RunGPGV(std::string const &File, std::string const &FileOut,
+		       int const &statusfd, int fd[2]);
+   inline static bool RunGPGV(std::string const &File, std::string const &FileOut,
+			      int const &statusfd = -1) {
+      int fd[2];
+      return RunGPGV(File, FileOut, statusfd, fd);
+   };
 };
 };
 									/*}}}*/
 									/*}}}*/
 
 

+ 6 - 2
apt-pkg/indexfile.h

@@ -74,8 +74,12 @@ class pkgIndexFile
    virtual bool Exists() const = 0;
    virtual bool Exists() const = 0;
    virtual bool HasPackages() const = 0;
    virtual bool HasPackages() const = 0;
    virtual unsigned long Size() 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;
    virtual pkgCache::PkgFileIterator FindInCache(pkgCache &Cache) const;
 
 
    static bool TranslationsAvailable();
    static bool TranslationsAvailable();

+ 47 - 3
apt-pkg/indexrecords.cc

@@ -7,8 +7,11 @@
 #include <apt-pkg/tagfile.h>
 #include <apt-pkg/tagfile.h>
 #include <apt-pkg/error.h>
 #include <apt-pkg/error.h>
 #include <apt-pkg/strutl.h>
 #include <apt-pkg/strutl.h>
+#include <apt-pkg/configuration.h>
 #include <apti18n.h>
 #include <apti18n.h>
 #include <sys/stat.h>
 #include <sys/stat.h>
+#include <clocale>
+
 									/*}}}*/
 									/*}}}*/
 string indexRecords::GetDist() const
 string indexRecords::GetDist() const
 {
 {
@@ -26,11 +29,21 @@ string indexRecords::GetExpectedDist() const
    return this->ExpectedDist;
    return this->ExpectedDist;
 }
 }
 
 
+time_t indexRecords::GetValidUntil() const
+{
+   return this->ValidUntil;
+}
+
 const indexRecords::checkSum *indexRecords::Lookup(const string MetaKey)
 const indexRecords::checkSum *indexRecords::Lookup(const string MetaKey)
 {
 {
    return Entries[MetaKey];
    return Entries[MetaKey];
 }
 }
 
 
+bool indexRecords::Exists(string const &MetaKey) const
+{
+   return Entries.count(MetaKey) == 1;
+}
+
 bool indexRecords::Load(const string Filename)				/*{{{*/
 bool indexRecords::Load(const string Filename)				/*{{{*/
 {
 {
    FileFd Fd(Filename, FileFd::ReadOnly);
    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());
       strprintf(ErrorText, _("No Hash entry in Release file %s"), Filename.c_str());
       return false;
       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;
    return true;
 }
 }
 									/*}}}*/
 									/*}}}*/
@@ -160,6 +204,6 @@ indexRecords::indexRecords()
 }
 }
 
 
 indexRecords::indexRecords(const string ExpectedDist) :
 indexRecords::indexRecords(const string ExpectedDist) :
-   ExpectedDist(ExpectedDist)
+   ExpectedDist(ExpectedDist), ValidUntil(0)
 {
 {
 }
 }

+ 6 - 0
apt-pkg/indexrecords.h

@@ -12,6 +12,7 @@
 
 
 #include <map>
 #include <map>
 #include <vector>
 #include <vector>
+#include <ctime>
 
 
 class indexRecords
 class indexRecords
 {
 {
@@ -25,6 +26,8 @@ class indexRecords
    string Dist;
    string Dist;
    string Suite;
    string Suite;
    string ExpectedDist;
    string ExpectedDist;
+   time_t ValidUntil;
+
    std::map<string,checkSum *> Entries;
    std::map<string,checkSum *> Entries;
 
 
    public:
    public:
@@ -34,10 +37,13 @@ class indexRecords
 
 
    // Lookup function
    // Lookup function
    virtual const checkSum *Lookup(const string MetaKey);
    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();
    std::vector<std::string> MetaKeys();
 
 
    virtual bool Load(string Filename);
    virtual bool Load(string Filename);
    string GetDist() const;
    string GetDist() const;
+   time_t GetValidUntil() const;
    virtual bool CheckDist(const string MaybeDist) const;
    virtual bool CheckDist(const string MaybeDist) const;
    string GetExpectedDist() const;
    string GetExpectedDist() const;
    virtual ~indexRecords(){};
    virtual ~indexRecords(){};

+ 8 - 2
apt-pkg/init.cc

@@ -51,6 +51,7 @@ bool pkgInitConfig(Configuration &Cnf)
        
        
    Cnf.Set("Dir::State::lists","lists/");
    Cnf.Set("Dir::State::lists","lists/");
    Cnf.Set("Dir::State::cdroms","cdroms.list");
    Cnf.Set("Dir::State::cdroms","cdroms.list");
+   Cnf.Set("Dir::State::mirrors","mirrors/");
    
    
    // Cache
    // Cache
    Cnf.Set("Dir::Cache","var/cache/apt/");
    Cnf.Set("Dir::Cache","var/cache/apt/");
@@ -77,6 +78,11 @@ bool pkgInitConfig(Configuration &Cnf)
    Cnf.Set("Dir::Log::Terminal","term.log");
    Cnf.Set("Dir::Log::Terminal","term.log");
    Cnf.Set("Dir::Log::History","history.log");
    Cnf.Set("Dir::Log::History","history.log");
 
 
+   Cnf.Set("Dir::Ignore-Files-Silently::", "~$");
+   Cnf.Set("Dir::Ignore-Files-Silently::", "\\.disabled$");
+   Cnf.Set("Dir::Ignore-Files-Silently::", "\\.bak$");
+   Cnf.Set("Dir::Ignore-Files-Silently::", "\\.dpkg-[a-z]+$");
+
    // Translation
    // Translation
    Cnf.Set("APT::Acquire::Translation", "environment");
    Cnf.Set("APT::Acquire::Translation", "environment");
 
 
@@ -94,10 +100,10 @@ bool pkgInitConfig(Configuration &Cnf)
 
 
    // Read the configuration parts dir
    // Read the configuration parts dir
    string Parts = Cnf.FindDir("Dir::Etc::parts");
    string Parts = Cnf.FindDir("Dir::Etc::parts");
-   if (FileExists(Parts) == true)
+   if (DirectoryExists(Parts) == true)
       Res &= ReadConfigDir(Cnf,Parts);
       Res &= ReadConfigDir(Cnf,Parts);
    else
    else
-      _error->WarningE("FileExists",_("Unable to read %s"),Parts.c_str());
+      _error->WarningE("DirectoryExists",_("Unable to read %s"),Parts.c_str());
 
 
    // Read the main config file
    // Read the main config file
    string FName = Cnf.FindFile("Dir::Etc::main");
    string FName = Cnf.FindFile("Dir::Etc::main");

+ 1 - 1
apt-pkg/init.h

@@ -22,7 +22,7 @@
 // Non-ABI-Breaks should only increase RELEASE number.
 // Non-ABI-Breaks should only increase RELEASE number.
 // See also buildlib/libversion.mak
 // See also buildlib/libversion.mak
 #define APT_PKG_MAJOR 4
 #define APT_PKG_MAJOR 4
-#define APT_PKG_MINOR 9
+#define APT_PKG_MINOR 10
 #define APT_PKG_RELEASE 0
 #define APT_PKG_RELEASE 0
     
     
 extern const char *pkgVersion;
 extern const char *pkgVersion;

+ 5 - 4
apt-pkg/makefile

@@ -14,7 +14,7 @@ include ../buildlib/libversion.mak
 LIBRARY=apt-pkg
 LIBRARY=apt-pkg
 MAJOR=$(LIBAPTPKG_MAJOR)
 MAJOR=$(LIBAPTPKG_MAJOR)
 MINOR=$(LIBAPTPKG_RELEASE)
 MINOR=$(LIBAPTPKG_RELEASE)
-SLIBS=$(PTHREADLIB) $(INTLLIBS) -lutil -ldl
+SLIBS=$(PTHREADLIB) $(INTLLIBS) -lutil -ldl -lz
 APT_DOMAIN:=libapt-pkg$(LIBAPTPKG_MAJOR)
 APT_DOMAIN:=libapt-pkg$(LIBAPTPKG_MAJOR)
 
 
 # Source code for the contributed non-core things
 # Source code for the contributed non-core things
@@ -25,7 +25,7 @@ SOURCE = contrib/mmap.cc contrib/error.cc contrib/strutl.cc \
 	 contrib/fileutl.cc 
 	 contrib/fileutl.cc 
 HEADERS = mmap.h error.h configuration.h fileutl.h  cmndline.h netrc.h\
 HEADERS = mmap.h error.h configuration.h fileutl.h  cmndline.h netrc.h\
 	  md5.h crc-16.h cdromutl.h strutl.h sptr.h sha1.h sha256.h hashes.h \
 	  md5.h crc-16.h cdromutl.h strutl.h sptr.h sha1.h sha256.h hashes.h \
-	  macros.h
+	  macros.h weakptr.h
 
 
 # Source code for the core main library
 # Source code for the core main library
 SOURCE+= pkgcache.cc version.cc depcache.cc \
 SOURCE+= pkgcache.cc version.cc depcache.cc \
@@ -35,14 +35,15 @@ SOURCE+= pkgcache.cc version.cc depcache.cc \
 	 srcrecords.cc cachefile.cc versionmatch.cc policy.cc \
 	 srcrecords.cc cachefile.cc versionmatch.cc policy.cc \
 	 pkgsystem.cc indexfile.cc pkgcachegen.cc acquire-item.cc \
 	 pkgsystem.cc indexfile.cc pkgcachegen.cc acquire-item.cc \
 	 indexrecords.cc vendor.cc vendorlist.cc cdrom.cc indexcopy.cc \
 	 indexrecords.cc vendor.cc vendorlist.cc cdrom.cc indexcopy.cc \
-	 aptconfiguration.cc
+	 aptconfiguration.cc cachefilter.cc cacheset.cc
 HEADERS+= algorithms.h depcache.h pkgcachegen.h cacheiterators.h \
 HEADERS+= algorithms.h depcache.h pkgcachegen.h cacheiterators.h \
 	  orderlist.h sourcelist.h packagemanager.h tagfile.h \
 	  orderlist.h sourcelist.h packagemanager.h tagfile.h \
 	  init.h pkgcache.h version.h progress.h pkgrecords.h \
 	  init.h pkgcache.h version.h progress.h pkgrecords.h \
 	  acquire.h acquire-worker.h acquire-item.h acquire-method.h \
 	  acquire.h acquire-worker.h acquire-item.h acquire-method.h \
 	  clean.h srcrecords.h cachefile.h versionmatch.h policy.h \
 	  clean.h srcrecords.h cachefile.h versionmatch.h policy.h \
 	  pkgsystem.h indexfile.h metaindex.h indexrecords.h vendor.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 \
+	  cachefilter.h cacheset.h
 
 
 # Source code for the debian specific components
 # Source code for the debian specific components
 # In theory the deb headers do not need to be exported..
 # In theory the deb headers do not need to be exported..

+ 2 - 2
apt-pkg/metaindex.h

@@ -33,8 +33,8 @@ class metaIndex
    virtual const char* GetType() const {return Type;}
    virtual const char* GetType() const {return Type;}
 
 
    // Interface for acquire
    // Interface for acquire
-   virtual string ArchiveURI(string /*File*/) const = 0;
-   virtual bool GetIndexes(pkgAcquire *Owner, bool GetAll=false) const = 0;
+   virtual string ArchiveURI(string const& /*File*/) const = 0;
+   virtual bool GetIndexes(pkgAcquire *Owner, bool const &GetAll=false) const = 0;
    
    
    virtual vector<pkgIndexFile *> *GetIndexFiles() = 0; 
    virtual vector<pkgIndexFile *> *GetIndexFiles() = 0; 
    virtual bool IsTrusted() const = 0;
    virtual bool IsTrusted() const = 0;

+ 89 - 6
apt-pkg/orderlist.cc

@@ -117,7 +117,8 @@ bool pkgOrderList::IsMissing(PkgIterator Pkg)
       return false;
       return false;
 
 
    // Skip Packages that need configure only.
    // Skip Packages that need configure only.
-   if (Pkg.State() == pkgCache::PkgIterator::NeedsConfigure && 
+   if ((Pkg.State() == pkgCache::PkgIterator::NeedsConfigure ||
+        Pkg.State() == pkgCache::PkgIterator::NeedsNothing) &&
        Cache[Pkg].Keep() == true)
        Cache[Pkg].Keep() == true)
       return false;
       return false;
 
 
@@ -126,6 +127,11 @@ bool pkgOrderList::IsMissing(PkgIterator Pkg)
    
    
    if (FileList[Pkg->ID].empty() == false)
    if (FileList[Pkg->ID].empty() == false)
       return false;
       return false;
+
+   // Missing Pseudo packages are missing if the real package is missing
+   if (pkgCache::VerIterator(Cache, Cache[Pkg].CandidateVer).Pseudo() == true)
+      return IsMissing(Pkg.Group().FindPkg("all"));
+
    return true;
    return true;
 }
 }
 									/*}}}*/
 									/*}}}*/
@@ -199,7 +205,7 @@ bool pkgOrderList::OrderCritical()
       {
       {
 	 PkgIterator P(Cache,*I);
 	 PkgIterator P(Cache,*I);
 	 if (IsNow(P) == true)
 	 if (IsNow(P) == true)
-	    clog << "  " << P.Name() << ' ' << IsMissing(P) << ',' << IsFlag(P,After) << endl;
+	    clog << "  " << P.FullName() << ' ' << IsMissing(P) << ',' << IsFlag(P,After) << endl;
       }
       }
    }
    }
 
 
@@ -272,7 +278,7 @@ bool pkgOrderList::OrderUnpack(string *FileList)
       {
       {
 	 PkgIterator P(Cache,*I);
 	 PkgIterator P(Cache,*I);
 	 if (IsNow(P) == true)
 	 if (IsNow(P) == true)
-	    clog << "  " << P.Name() << ' ' << IsMissing(P) << ',' << IsFlag(P,After) << endl;
+	    clog << "  " << P.FullName() << ' ' << IsMissing(P) << ',' << IsFlag(P,After) << endl;
       }
       }
    }
    }
 
 
@@ -543,7 +549,7 @@ bool pkgOrderList::VisitNode(PkgIterator Pkg)
    if (Debug == true)
    if (Debug == true)
    {
    {
       for (int j = 0; j != Depth; j++) clog << ' ';
       for (int j = 0; j != Depth; j++) clog << ' ';
-      clog << "Visit " << Pkg.Name() << endl;
+      clog << "Visit " << Pkg.FullName() << endl;
    }
    }
    
    
    Depth++;
    Depth++;
@@ -602,7 +608,7 @@ bool pkgOrderList::VisitNode(PkgIterator Pkg)
    if (Debug == true)
    if (Debug == true)
    {
    {
       for (int j = 0; j != Depth; j++) clog << ' ';
       for (int j = 0; j != Depth; j++) clog << ' ';
-      clog << "Leave " << Pkg.Name() << ' ' << IsFlag(Pkg,Added) << ',' << IsFlag(Pkg,AddPending) << endl;
+      clog << "Leave " << Pkg.FullName() << ' ' << IsFlag(Pkg,Added) << ',' << IsFlag(Pkg,AddPending) << endl;
    }
    }
    
    
    return true;
    return true;
@@ -880,13 +886,16 @@ bool pkgOrderList::DepRemove(DepIterator D)
 	    continue;
 	    continue;
 
 
 	 /* We wish to see if the dep on the parent package is okay
 	 /* We wish to see if the dep on the parent package is okay
-	    in the removed (install) state of the target pkg. */	 
+	    in the removed (install) state of the target pkg. */
+	 bool tryFixDeps = false;
 	 if (CheckDep(D) == true)
 	 if (CheckDep(D) == true)
 	 {
 	 {
 	    // We want to catch loops with the code below.
 	    // We want to catch loops with the code below.
 	    if (IsFlag(D.ParentPkg(),AddPending) == false)
 	    if (IsFlag(D.ParentPkg(),AddPending) == false)
 	       continue;
 	       continue;
 	 }
 	 }
+	 else
+	    tryFixDeps = true;
 
 
 	 // This is the loop detection
 	 // This is the loop detection
 	 if (IsFlag(D.ParentPkg(),Added) == true || 
 	 if (IsFlag(D.ParentPkg(),Added) == true || 
@@ -897,6 +906,80 @@ bool pkgOrderList::DepRemove(DepIterator D)
 	    continue;
 	    continue;
 	 }
 	 }
 
 
+	 if (tryFixDeps == true)
+	 {
+	    for (pkgCache::DepIterator F = D.ParentPkg().CurrentVer().DependsList();
+		 F.end() == false; ++F)
+	    {
+	       if (F->Type != pkgCache::Dep::Depends && F->Type != pkgCache::Dep::PreDepends)
+		  continue;
+	       // Check the Providers
+	       if (F.TargetPkg()->ProvidesList != 0)
+	       {
+		  pkgCache::PrvIterator Prov = F.TargetPkg().ProvidesList();
+		  for (; Prov.end() == false; ++Prov)
+		  {
+		     pkgCache::PkgIterator const P = Prov.OwnerPkg();
+		     if (IsFlag(P, InList) == true &&
+			 IsFlag(P, AddPending) == true &&
+			 IsFlag(P, Added) == false &&
+			 Cache[P].InstallVer == 0)
+			break;
+		  }
+		  if (Prov.end() == false)
+		     for (pkgCache::PrvIterator Prv = F.TargetPkg().ProvidesList();
+			  Prv.end() == false; ++Prv)
+		     {
+			pkgCache::PkgIterator const P = Prv.OwnerPkg();
+			if (IsFlag(P, InList) == true &&
+			    IsFlag(P, AddPending) == false &&
+			    Cache[P].InstallVer != 0 &&
+			    VisitNode(P) == true)
+			{
+			   Flag(P, Immediate);
+			   tryFixDeps = false;
+			   break;
+			}
+		     }
+		  if (tryFixDeps == false)
+		     break;
+	       }
+
+	       // Check for Or groups
+	       if ((F->CompareOp & pkgCache::Dep::Or) != pkgCache::Dep::Or)
+		  continue;
+	       // Lets see if the package is part of the Or group
+	       pkgCache::DepIterator S = F;
+	       for (; S.end() == false; ++S)
+	       {
+		  if (S.TargetPkg() == D.TargetPkg())
+		     break;
+		  if ((S->CompareOp & pkgCache::Dep::Or) != pkgCache::Dep::Or ||
+		      CheckDep(S)) // Or group is satisfied by another package
+		     for (;S.end() == false; ++S);
+	       }
+	       if (S.end() == true)
+		  continue;
+	       // skip to the end of the or group
+	       for (;S.end() == false && (S->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or; ++S);
+	       ++S;
+	       // The soon to be removed is part of the Or group
+	       // start again in the or group and find something which will serve as replacement
+	       for (; F.end() == false && F != S; ++F)
+	       {
+		  if (F.TargetPkg() == D.TargetPkg() ||
+		      IsFlag(F.TargetPkg(), InList) == false ||
+		      VisitNode(F.TargetPkg()) == false)
+		     continue;
+		  Flag(F.TargetPkg(), Immediate);
+		  tryFixDeps = false;
+		  break;
+	       }
+	       if (tryFixDeps == false)
+		  break;
+	    }
+	 }
+
 	 // Skip over missing files
 	 // Skip over missing files
 	 if (IsMissing(D.ParentPkg()) == true)
 	 if (IsMissing(D.ParentPkg()) == true)
 	    continue;
 	    continue;

+ 34 - 9
apt-pkg/packagemanager.cc

@@ -80,7 +80,10 @@ bool pkgPackageManager::GetArchives(pkgAcquire *Owner,pkgSourceList *Sources,
       // Skip already processed packages
       // Skip already processed packages
       if (List->IsNow(Pkg) == false)
       if (List->IsNow(Pkg) == false)
 	 continue;
 	 continue;
-	 
+
+      if (pkgCache::VerIterator(Cache, Cache[Pkg].CandidateVer).Pseudo() == true)
+	 continue;
+
       new pkgAcqArchive(Owner,Sources,Recs,Cache[Pkg].InstVerIter(Cache),
       new pkgAcqArchive(Owner,Sources,Recs,Cache[Pkg].InstVerIter(Cache),
 			FileNames[Pkg->ID]);
 			FileNames[Pkg->ID]);
    }
    }
@@ -277,8 +280,10 @@ bool pkgPackageManager::ConfigureAll()
    for (pkgOrderList::iterator I = OList.begin(); I != OList.end(); I++)
    for (pkgOrderList::iterator I = OList.begin(); I != OList.end(); I++)
    {
    {
       PkgIterator Pkg(Cache,*I);
       PkgIterator Pkg(Cache,*I);
-      
-      if (ConfigurePkgs == true && Configure(Pkg) == false)
+
+      if (ConfigurePkgs == true &&
+	  pkgCache::VerIterator(Cache, Cache[Pkg].CandidateVer).Pseudo() == false &&
+	  Configure(Pkg) == false)
 	 return false;
 	 return false;
       
       
       List->Flag(Pkg,pkgOrderList::Configured,pkgOrderList::States);
       List->Flag(Pkg,pkgOrderList::Configured,pkgOrderList::States);
@@ -313,7 +318,9 @@ bool pkgPackageManager::SmartConfigure(PkgIterator Pkg)
    {
    {
       PkgIterator Pkg(Cache,*I);
       PkgIterator Pkg(Cache,*I);
       
       
-      if (ConfigurePkgs == true && Configure(Pkg) == false)
+      if (ConfigurePkgs == true &&
+	  pkgCache::VerIterator(Cache, Cache[Pkg].CandidateVer).Pseudo() == false &&
+	  Configure(Pkg) == false)
 	 return false;
 	 return false;
       
       
       List->Flag(Pkg,pkgOrderList::Configured,pkgOrderList::States);
       List->Flag(Pkg,pkgOrderList::Configured,pkgOrderList::States);
@@ -465,7 +472,12 @@ bool pkgPackageManager::SmartRemove(PkgIterator Pkg)
       return true;
       return true;
 
 
    List->Flag(Pkg,pkgOrderList::Configured,pkgOrderList::States);
    List->Flag(Pkg,pkgOrderList::Configured,pkgOrderList::States);
-   return Remove(Pkg,(Cache[Pkg].iFlags & pkgDepCache::Purge) == pkgDepCache::Purge);
+
+   if (pkgCache::VerIterator(Cache, Cache[Pkg].CandidateVer).Pseudo() == false)
+      return Remove(Pkg,(Cache[Pkg].iFlags & pkgDepCache::Purge) == pkgDepCache::Purge);
+   else
+      return SmartRemove(Pkg.Group().FindPkg("all"));
+   return true;
 }
 }
 									/*}}}*/
 									/*}}}*/
 // PM::SmartUnPack - Install helper					/*{{{*/
 // PM::SmartUnPack - Install helper					/*{{{*/
@@ -579,10 +591,23 @@ bool pkgPackageManager::SmartUnPack(PkgIterator Pkg)
    for (PrvIterator P = Cache[Pkg].InstVerIter(Cache).ProvidesList(); 
    for (PrvIterator P = Cache[Pkg].InstVerIter(Cache).ProvidesList(); 
 	P.end() == false; P++)
 	P.end() == false; P++)
       CheckRConflicts(Pkg,P.ParentPkg().RevDependsList(),P.ProvideVersion());
       CheckRConflicts(Pkg,P.ParentPkg().RevDependsList(),P.ProvideVersion());
-   
-   if (Install(Pkg,FileNames[Pkg->ID]) == false)
-      return false;
-   
+
+   if (pkgCache::VerIterator(Cache, Cache[Pkg].CandidateVer).Pseudo() == false)
+   {
+      if(Install(Pkg,FileNames[Pkg->ID]) == false)
+         return false;
+   } else {
+      // Pseudo packages will not be unpacked - instead we will do this
+      // for the "real" package, but only once and if it is already
+      // configured we don't need to unpack it again…
+      PkgIterator const P = Pkg.Group().FindPkg("all");
+      if (List->IsFlag(P,pkgOrderList::UnPacked) != true &&
+	  List->IsFlag(P,pkgOrderList::Configured) != true &&
+	  P.State() != pkgCache::PkgIterator::NeedsNothing) {
+	 if (SmartUnPack(P) == false)
+	    return false;
+      }
+   }
    List->Flag(Pkg,pkgOrderList::UnPacked,pkgOrderList::States);
    List->Flag(Pkg,pkgOrderList::UnPacked,pkgOrderList::States);
    
    
    // Perform immedate configuration of the package.
    // Perform immedate configuration of the package.

+ 14 - 2
apt-pkg/packagemanager.h

@@ -28,6 +28,7 @@
 #include <iostream>
 #include <iostream>
 #include <apt-pkg/pkgcache.h>
 #include <apt-pkg/pkgcache.h>
 #include <apt-pkg/depcache.h>
 #include <apt-pkg/depcache.h>
+#include <set>
 
 
 using std::string;
 using std::string;
 
 
@@ -47,7 +48,15 @@ class pkgPackageManager : protected pkgCache::Namespace
    pkgDepCache &Cache;
    pkgDepCache &Cache;
    pkgOrderList *List;
    pkgOrderList *List;
    bool Debug;
    bool Debug;
-         
+
+   /** \brief saves packages dpkg let disappear
+
+       This way APT can retreat from trying to configure these
+       packages later on and a frontend can choose to display a
+       notice to inform the user about these disappears.
+   */
+   std::set<std::string> disappearedPkgs;
+
    bool DepAdd(pkgOrderList &Order,PkgIterator P,int Depth = 0);
    bool DepAdd(pkgOrderList &Order,PkgIterator P,int Depth = 0);
    void ImmediateAdd(PkgIterator P, bool UseInstallVer, unsigned const int &Depth = 0);
    void ImmediateAdd(PkgIterator P, bool UseInstallVer, unsigned const int &Depth = 0);
    virtual OrderResult OrderInstall();
    virtual OrderResult OrderInstall();
@@ -93,7 +102,10 @@ class pkgPackageManager : protected pkgCache::Namespace
    // stuff that needs to be done after the fork
    // stuff that needs to be done after the fork
    OrderResult DoInstallPostFork(int statusFd=-1);
    OrderResult DoInstallPostFork(int statusFd=-1);
    bool FixMissing();
    bool FixMissing();
-   
+
+   /** \brief returns all packages dpkg let disappear */
+   inline std::set<std::string> GetDisappearedPackages() { return disappearedPkgs; };
+
    pkgPackageManager(pkgDepCache *Cache);
    pkgPackageManager(pkgDepCache *Cache);
    virtual ~pkgPackageManager();
    virtual ~pkgPackageManager();
 };
 };

+ 231 - 46
apt-pkg/pkgcache.cc

@@ -55,6 +55,7 @@ pkgCache::Header::Header()
    Dirty = false;
    Dirty = false;
    
    
    HeaderSz = sizeof(pkgCache::Header);
    HeaderSz = sizeof(pkgCache::Header);
+   GroupSz = sizeof(pkgCache::Group);
    PackageSz = sizeof(pkgCache::Package);
    PackageSz = sizeof(pkgCache::Package);
    PackageFileSz = sizeof(pkgCache::PackageFile);
    PackageFileSz = sizeof(pkgCache::PackageFile);
    VersionSz = sizeof(pkgCache::Version);
    VersionSz = sizeof(pkgCache::Version);
@@ -64,6 +65,7 @@ pkgCache::Header::Header()
    VerFileSz = sizeof(pkgCache::VerFile);
    VerFileSz = sizeof(pkgCache::VerFile);
    DescFileSz = sizeof(pkgCache::DescFile);
    DescFileSz = sizeof(pkgCache::DescFile);
    
    
+   GroupCount = 0;
    PackageCount = 0;
    PackageCount = 0;
    VersionCount = 0;
    VersionCount = 0;
    DescriptionCount = 0;
    DescriptionCount = 0;
@@ -79,7 +81,8 @@ pkgCache::Header::Header()
    StringList = 0;
    StringList = 0;
    VerSysName = 0;
    VerSysName = 0;
    Architecture = 0;
    Architecture = 0;
-   memset(HashTable,0,sizeof(HashTable));
+   memset(PkgHashTable,0,sizeof(PkgHashTable));
+   memset(GrpHashTable,0,sizeof(GrpHashTable));
    memset(Pools,0,sizeof(Pools));
    memset(Pools,0,sizeof(Pools));
 }
 }
 									/*}}}*/
 									/*}}}*/
@@ -89,6 +92,7 @@ pkgCache::Header::Header()
 bool pkgCache::Header::CheckSizes(Header &Against) const
 bool pkgCache::Header::CheckSizes(Header &Against) const
 {
 {
    if (HeaderSz == Against.HeaderSz &&
    if (HeaderSz == Against.HeaderSz &&
+       GroupSz == Against.GroupSz &&
        PackageSz == Against.PackageSz &&
        PackageSz == Against.PackageSz &&
        PackageFileSz == Against.PackageFileSz &&
        PackageFileSz == Against.PackageFileSz &&
        VersionSz == Against.VersionSz &&
        VersionSz == Against.VersionSz &&
@@ -107,6 +111,7 @@ bool pkgCache::Header::CheckSizes(Header &Against) const
 /* */
 /* */
 pkgCache::pkgCache(MMap *Map, bool DoMap) : Map(*Map)
 pkgCache::pkgCache(MMap *Map, bool DoMap) : Map(*Map)
 {
 {
+   MultiArchEnabled = APT::Configuration::getArchitectures().size() > 1;
    if (DoMap == true)
    if (DoMap == true)
       ReMap();
       ReMap();
 }
 }
@@ -114,10 +119,11 @@ pkgCache::pkgCache(MMap *Map, bool DoMap) : Map(*Map)
 // Cache::ReMap - Reopen the cache file					/*{{{*/
 // Cache::ReMap - Reopen the cache file					/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /* If the file is already closed then this will open it open it. */
 /* If the file is already closed then this will open it open it. */
-bool pkgCache::ReMap()
+bool pkgCache::ReMap(bool const &Errorchecks)
 {
 {
    // Apply the typecasts.
    // Apply the typecasts.
    HeaderP = (Header *)Map.Data();
    HeaderP = (Header *)Map.Data();
+   GrpP = (Group *)Map.Data();
    PkgP = (Package *)Map.Data();
    PkgP = (Package *)Map.Data();
    VerFileP = (VerFile *)Map.Data();
    VerFileP = (VerFile *)Map.Data();
    DescFileP = (DescFile *)Map.Data();
    DescFileP = (DescFile *)Map.Data();
@@ -129,6 +135,9 @@ bool pkgCache::ReMap()
    StringItemP = (StringItem *)Map.Data();
    StringItemP = (StringItem *)Map.Data();
    StrP = (char *)Map.Data();
    StrP = (char *)Map.Data();
 
 
+   if (Errorchecks == false)
+      return true;
+
    if (Map.Size() == 0 || HeaderP == 0)
    if (Map.Size() == 0 || HeaderP == 0)
       return _error->Error(_("Empty package cache"));
       return _error->Error(_("Empty package cache"));
    
    
@@ -165,7 +174,7 @@ unsigned long pkgCache::sHash(const string &Str) const
    unsigned long Hash = 0;
    unsigned long Hash = 0;
    for (string::const_iterator I = Str.begin(); I != Str.end(); I++)
    for (string::const_iterator I = Str.begin(); I != Str.end(); I++)
       Hash = 5*Hash + tolower_ascii(*I);
       Hash = 5*Hash + tolower_ascii(*I);
-   return Hash % _count(HeaderP->HashTable);
+   return Hash % _count(HeaderP->PkgHashTable);
 }
 }
 
 
 unsigned long pkgCache::sHash(const char *Str) const
 unsigned long pkgCache::sHash(const char *Str) const
@@ -173,26 +182,82 @@ unsigned long pkgCache::sHash(const char *Str) const
    unsigned long Hash = 0;
    unsigned long Hash = 0;
    for (const char *I = Str; *I != 0; I++)
    for (const char *I = Str; *I != 0; I++)
       Hash = 5*Hash + tolower_ascii(*I);
       Hash = 5*Hash + tolower_ascii(*I);
-   return Hash % _count(HeaderP->HashTable);
+   return Hash % _count(HeaderP->PkgHashTable);
 }
 }
 
 
 									/*}}}*/
 									/*}}}*/
-// Cache::FindPkg - Locate a package by name				/*{{{*/
+// Cache::SingleArchFindPkg - Locate a package by name			/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
-/* Returns 0 on error, pointer to the package otherwise */
-pkgCache::PkgIterator pkgCache::FindPkg(const string &Name)
+/* Returns 0 on error, pointer to the package otherwise
+   The multiArch enabled methods will fallback to this one as it is (a bit)
+   faster for single arch environments and realworld is mostly singlearch… */
+pkgCache::PkgIterator pkgCache::SingleArchFindPkg(const string &Name)
 {
 {
    // Look at the hash bucket
    // Look at the hash bucket
-   Package *Pkg = PkgP + HeaderP->HashTable[Hash(Name)];
+   Package *Pkg = PkgP + HeaderP->PkgHashTable[Hash(Name)];
    for (; Pkg != PkgP; Pkg = PkgP + Pkg->NextPackage)
    for (; Pkg != PkgP; Pkg = PkgP + Pkg->NextPackage)
    {
    {
       if (Pkg->Name != 0 && StrP[Pkg->Name] == Name[0] &&
       if (Pkg->Name != 0 && StrP[Pkg->Name] == Name[0] &&
-	  stringcasecmp(Name,StrP + Pkg->Name) == 0)
-	 return PkgIterator(*this,Pkg);
+          stringcasecmp(Name,StrP + Pkg->Name) == 0)
+         return PkgIterator(*this,Pkg);
    }
    }
    return PkgIterator(*this,0);
    return PkgIterator(*this,0);
 }
 }
 									/*}}}*/
 									/*}}}*/
+// Cache::FindPkg - Locate a package by name				/*{{{*/
+// ---------------------------------------------------------------------
+/* Returns 0 on error, pointer to the package otherwise */
+pkgCache::PkgIterator pkgCache::FindPkg(const string &Name) {
+	if (MultiArchCache() == false)
+		return SingleArchFindPkg(Name);
+	size_t const found = Name.find(':');
+	if (found == string::npos)
+		return FindPkg(Name, "native");
+	string const Arch = Name.substr(found+1);
+	if (Arch == "any")
+		return FindPkg(Name, "any");
+	return FindPkg(Name.substr(0, found), Arch);
+}
+									/*}}}*/
+// Cache::FindPkg - Locate a package by name				/*{{{*/
+// ---------------------------------------------------------------------
+/* Returns 0 on error, pointer to the package otherwise */
+pkgCache::PkgIterator pkgCache::FindPkg(const string &Name, string const &Arch) {
+	if (MultiArchCache() == false) {
+		if (Arch == "native" || Arch == "all" || Arch == "any" ||
+		    Arch == _config->Find("APT::Architecture"))
+			return SingleArchFindPkg(Name);
+		else
+			return PkgIterator(*this,0);
+	}
+	/* We make a detour via the GrpIterator here as
+	   on a multi-arch environment a group is easier to
+	   find than a package (less entries in the buckets) */
+	pkgCache::GrpIterator Grp = FindGrp(Name);
+	if (Grp.end() == true)
+		return PkgIterator(*this,0);
+
+	return Grp.FindPkg(Arch);
+}
+									/*}}}*/
+// Cache::FindGrp - Locate a group by name				/*{{{*/
+// ---------------------------------------------------------------------
+/* Returns End-Pointer on error, pointer to the group otherwise */
+pkgCache::GrpIterator pkgCache::FindGrp(const string &Name) {
+	if (unlikely(Name.empty() == true))
+		return GrpIterator(*this,0);
+
+	// Look at the hash bucket for the group
+	Group *Grp = GrpP + HeaderP->GrpHashTable[sHash(Name)];
+	for (; Grp != GrpP; Grp = GrpP + Grp->Next) {
+		if (Grp->Name != 0 && StrP[Grp->Name] == Name[0] &&
+		    stringcasecmp(Name, StrP + Grp->Name) == 0)
+			return GrpIterator(*this, Grp);
+	}
+
+	return GrpIterator(*this,0);
+}
+									/*}}}*/
 // Cache::CompTypeDeb - Return a string describing the compare type	/*{{{*/
 // Cache::CompTypeDeb - Return a string describing the compare type	/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /* This returns a string representation of the dependency compare 
 /* This returns a string representation of the dependency compare 
@@ -242,11 +307,98 @@ const char *pkgCache::Priority(unsigned char Prio)
    return 0;
    return 0;
 }
 }
 									/*}}}*/
 									/*}}}*/
-// Bases for iterator classes						/*{{{*/
-void pkgCache::VerIterator::_dummy() {}
-void pkgCache::DepIterator::_dummy() {}
-void pkgCache::PrvIterator::_dummy() {}
-void pkgCache::DescIterator::_dummy() {}
+// GrpIterator::FindPkg - Locate a package by arch			/*{{{*/
+// ---------------------------------------------------------------------
+/* Returns an End-Pointer on error, pointer to the package otherwise */
+pkgCache::PkgIterator pkgCache::GrpIterator::FindPkg(string Arch) const {
+	if (unlikely(IsGood() == false || S->FirstPackage == 0))
+		return PkgIterator(*Owner, 0);
+
+	static string const myArch = _config->Find("APT::Architecture");
+	/* Most of the time the package for our native architecture is
+	   the one we add at first to the cache, but this would be the
+	   last one we check, so we do it now. */
+	if (Arch == "native" || Arch == myArch) {
+		Arch = myArch;
+		pkgCache::Package *Pkg = Owner->PkgP + S->LastPackage;
+		if (stringcasecmp(Arch, Owner->StrP + Pkg->Arch) == 0)
+			return PkgIterator(*Owner, Pkg);
+	}
+
+	/* If we accept any package we simply return the "first"
+	   package in this group (the last one added). */
+	if (Arch == "any")
+		return PkgIterator(*Owner, Owner->PkgP + S->FirstPackage);
+
+	/* Iterate over the list to find the matching arch
+	   unfortunately this list includes "package noise"
+	   (= different packages with same calculated hash),
+	   so we need to check the name also */
+	for (pkgCache::Package *Pkg = PackageList(); Pkg != Owner->PkgP;
+	     Pkg = Owner->PkgP + Pkg->NextPackage) {
+		if (S->Name == Pkg->Name &&
+		    stringcasecmp(Arch, Owner->StrP + Pkg->Arch) == 0)
+			return PkgIterator(*Owner, Pkg);
+		if ((Owner->PkgP + S->LastPackage) == Pkg)
+			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(bool const &PreferNonVirtual) const {
+	pkgCache::PkgIterator Pkg = FindPkg("native");
+	if (Pkg.end() == false && (PreferNonVirtual == false || Pkg->VersionList != 0))
+		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 && (PreferNonVirtual == false || Pkg->VersionList != 0))
+			return Pkg;
+	}
+
+	if (PreferNonVirtual == true)
+		return FindPreferredPkg(false);
+	return PkgIterator(*Owner, 0);
+}
+									/*}}}*/
+// GrpIterator::NextPkg - Locate the next package in the group		/*{{{*/
+// ---------------------------------------------------------------------
+/* Returns an End-Pointer on error, pointer to the package otherwise.
+   We can't simply ++ to the next as the next package of the last will
+   be from a different group (with the same hash value) */
+pkgCache::PkgIterator pkgCache::GrpIterator::NextPkg(pkgCache::PkgIterator const &LastPkg) const {
+	if (unlikely(IsGood() == false || S->FirstPackage == 0 ||
+	    LastPkg.end() == true))
+		return PkgIterator(*Owner, 0);
+
+	if (S->LastPackage == LastPkg.Index())
+		return PkgIterator(*Owner, 0);
+
+	return PkgIterator(*Owner, Owner->PkgP + LastPkg->NextPackage);
+}
+									/*}}}*/
+// GrpIterator::operator ++ - Postfix incr				/*{{{*/
+// ---------------------------------------------------------------------
+/* This will advance to the next logical group in the hash table. */
+void pkgCache::GrpIterator::operator ++(int) 
+{
+   // Follow the current links
+   if (S != Owner->GrpP)
+      S = Owner->GrpP + S->Next;
+
+   // Follow the hash table
+   while (S == Owner->GrpP && (HashIndex+1) < (signed)_count(Owner->HeaderP->GrpHashTable))
+   {
+      HashIndex++;
+      S = Owner->GrpP + Owner->HeaderP->GrpHashTable[HashIndex];
+   }
+};
 									/*}}}*/
 									/*}}}*/
 // PkgIterator::operator ++ - Postfix incr				/*{{{*/
 // PkgIterator::operator ++ - Postfix incr				/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
@@ -254,14 +406,14 @@ void pkgCache::DescIterator::_dummy() {}
 void pkgCache::PkgIterator::operator ++(int) 
 void pkgCache::PkgIterator::operator ++(int) 
 {
 {
    // Follow the current links
    // Follow the current links
-   if (Pkg != Owner->PkgP)
-      Pkg = Owner->PkgP + Pkg->NextPackage;
+   if (S != Owner->PkgP)
+      S = Owner->PkgP + S->NextPackage;
 
 
    // Follow the hash table
    // Follow the hash table
-   while (Pkg == Owner->PkgP && (HashIndex+1) < (signed)_count(Owner->HeaderP->HashTable))
+   while (S == Owner->PkgP && (HashIndex+1) < (signed)_count(Owner->HeaderP->PkgHashTable))
    {
    {
       HashIndex++;
       HashIndex++;
-      Pkg = Owner->PkgP + Owner->HeaderP->HashTable[HashIndex];
+      S = Owner->PkgP + Owner->HeaderP->PkgHashTable[HashIndex];
    }
    }
 };
 };
 									/*}}}*/
 									/*}}}*/
@@ -270,12 +422,12 @@ void pkgCache::PkgIterator::operator ++(int)
 /* By this we mean if it is either cleanly installed or cleanly removed. */
 /* By this we mean if it is either cleanly installed or cleanly removed. */
 pkgCache::PkgIterator::OkState pkgCache::PkgIterator::State() const
 pkgCache::PkgIterator::OkState pkgCache::PkgIterator::State() const
 {  
 {  
-   if (Pkg->InstState == pkgCache::State::ReInstReq ||
-       Pkg->InstState == pkgCache::State::HoldReInstReq)
+   if (S->InstState == pkgCache::State::ReInstReq ||
+       S->InstState == pkgCache::State::HoldReInstReq)
       return NeedsUnpack;
       return NeedsUnpack;
    
    
-   if (Pkg->CurrentState == pkgCache::State::UnPacked ||
-       Pkg->CurrentState == pkgCache::State::HalfConfigured)
+   if (S->CurrentState == pkgCache::State::UnPacked ||
+       S->CurrentState == pkgCache::State::HalfConfigured)
       // we leave triggers alone complettely. dpkg deals with
       // we leave triggers alone complettely. dpkg deals with
       // them in a hard-to-predict manner and if they get 
       // them in a hard-to-predict manner and if they get 
       // resolved by dpkg before apt run dpkg --configure on 
       // resolved by dpkg before apt run dpkg --configure on 
@@ -284,8 +436,8 @@ pkgCache::PkgIterator::OkState pkgCache::PkgIterator::State() const
       //Pkg->CurrentState == pkgCache::State::TriggersPending)
       //Pkg->CurrentState == pkgCache::State::TriggersPending)
       return NeedsConfigure;
       return NeedsConfigure;
    
    
-   if (Pkg->CurrentState == pkgCache::State::HalfInstalled ||
-       Pkg->InstState != pkgCache::State::Ok)
+   if (S->CurrentState == pkgCache::State::HalfInstalled ||
+       S->InstState != pkgCache::State::Ok)
       return NeedsUnpack;
       return NeedsUnpack;
       
       
    return NeedsNothing;
    return NeedsNothing;
@@ -332,7 +484,7 @@ operator<<(ostream& out, pkgCache::PkgIterator Pkg)
    string candidate = string(Pkg.CandVersion() == 0 ? "none" : Pkg.CandVersion());
    string candidate = string(Pkg.CandVersion() == 0 ? "none" : Pkg.CandVersion());
    string newest = string(Pkg.VersionList().end() ? "none" : Pkg.VersionList().VerStr());
    string newest = string(Pkg.VersionList().end() ? "none" : Pkg.VersionList().VerStr());
 
 
-   out << Pkg.Name() << " < " << current;
+   out << Pkg.Name() << " [ " << Pkg.Arch() << " ] < " << current;
    if (current != candidate)
    if (current != candidate)
       out << " -> " << candidate;
       out << " -> " << candidate;
    if ( newest != "none" && candidate != newest)
    if ( newest != "none" && candidate != newest)
@@ -341,17 +493,29 @@ operator<<(ostream& out, pkgCache::PkgIterator Pkg)
    return out;
    return out;
 }
 }
 									/*}}}*/
 									/*}}}*/
+// PkgIterator::FullName - Returns Name and (maybe) Architecture	/*{{{*/
+// ---------------------------------------------------------------------
+/* Returns a name:arch string */
+std::string pkgCache::PkgIterator::FullName(bool const &Pretty) const
+{
+   string fullname = Name();
+   if (Pretty == false ||
+       (strcmp(Arch(), "all") != 0 && _config->Find("APT::Architecture") != Arch()))
+      return fullname.append(":").append(Arch());
+   return fullname;
+}
+									/*}}}*/
 // DepIterator::IsCritical - Returns true if the dep is important	/*{{{*/
 // DepIterator::IsCritical - Returns true if the dep is important	/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /* Currently critical deps are defined as depends, predepends and
 /* Currently critical deps are defined as depends, predepends and
    conflicts (including dpkg's Breaks fields). */
    conflicts (including dpkg's Breaks fields). */
-bool pkgCache::DepIterator::IsCritical()
+bool pkgCache::DepIterator::IsCritical() const
 {
 {
-   if (Dep->Type == pkgCache::Dep::Conflicts ||
-       Dep->Type == pkgCache::Dep::DpkgBreaks ||
-       Dep->Type == pkgCache::Dep::Obsoletes ||
-       Dep->Type == pkgCache::Dep::Depends ||
-       Dep->Type == pkgCache::Dep::PreDepends)
+   if (S->Type == pkgCache::Dep::Conflicts ||
+       S->Type == pkgCache::Dep::DpkgBreaks ||
+       S->Type == pkgCache::Dep::Obsoletes ||
+       S->Type == pkgCache::Dep::Depends ||
+       S->Type == pkgCache::Dep::PreDepends)
       return true;
       return true;
    return false;
    return false;
 }
 }
@@ -369,7 +533,7 @@ bool pkgCache::DepIterator::IsCritical()
    In Conjunction with the DepCache the value of Result may not be 
    In Conjunction with the DepCache the value of Result may not be 
    super-good since the policy may have made it uninstallable. Using
    super-good since the policy may have made it uninstallable. Using
    AllTargets is better in this case. */
    AllTargets is better in this case. */
-bool pkgCache::DepIterator::SmartTargetPkg(PkgIterator &Result)
+bool pkgCache::DepIterator::SmartTargetPkg(PkgIterator &Result) const
 {
 {
    Result = TargetPkg();
    Result = TargetPkg();
    
    
@@ -418,7 +582,7 @@ bool pkgCache::DepIterator::SmartTargetPkg(PkgIterator &Result)
    provides. It includes every possible package-version that could satisfy
    provides. It includes every possible package-version that could satisfy
    the dependency. The last item in the list has a 0. The resulting pointer
    the dependency. The last item in the list has a 0. The resulting pointer
    must be delete [] 'd */
    must be delete [] 'd */
-pkgCache::Version **pkgCache::DepIterator::AllTargets()
+pkgCache::Version **pkgCache::DepIterator::AllTargets() const
 {
 {
    Version **Res = 0;
    Version **Res = 0;
    unsigned long Size =0;
    unsigned long Size =0;
@@ -430,12 +594,12 @@ pkgCache::Version **pkgCache::DepIterator::AllTargets()
       // Walk along the actual package providing versions
       // Walk along the actual package providing versions
       for (VerIterator I = DPkg.VersionList(); I.end() == false; I++)
       for (VerIterator I = DPkg.VersionList(); I.end() == false; I++)
       {
       {
-	 if (Owner->VS->CheckDep(I.VerStr(),Dep->CompareOp,TargetVer()) == false)
+	 if (Owner->VS->CheckDep(I.VerStr(),S->CompareOp,TargetVer()) == false)
 	    continue;
 	    continue;
 
 
-	 if ((Dep->Type == pkgCache::Dep::Conflicts ||
-	      Dep->Type == pkgCache::Dep::DpkgBreaks ||
-	      Dep->Type == pkgCache::Dep::Obsoletes) &&
+	 if ((S->Type == pkgCache::Dep::Conflicts ||
+	      S->Type == pkgCache::Dep::DpkgBreaks ||
+	      S->Type == pkgCache::Dep::Obsoletes) &&
 	     ParentPkg() == I.ParentPkg())
 	     ParentPkg() == I.ParentPkg())
 	    continue;
 	    continue;
 	 
 	 
@@ -447,12 +611,12 @@ pkgCache::Version **pkgCache::DepIterator::AllTargets()
       // Follow all provides
       // Follow all provides
       for (PrvIterator I = DPkg.ProvidesList(); I.end() == false; I++)
       for (PrvIterator I = DPkg.ProvidesList(); I.end() == false; I++)
       {
       {
-	 if (Owner->VS->CheckDep(I.ProvideVersion(),Dep->CompareOp,TargetVer()) == false)
+	 if (Owner->VS->CheckDep(I.ProvideVersion(),S->CompareOp,TargetVer()) == false)
 	    continue;
 	    continue;
 	 
 	 
-	 if ((Dep->Type == pkgCache::Dep::Conflicts ||
-	      Dep->Type == pkgCache::Dep::DpkgBreaks ||
-	      Dep->Type == pkgCache::Dep::Obsoletes) &&
+	 if ((S->Type == pkgCache::Dep::Conflicts ||
+	      S->Type == pkgCache::Dep::DpkgBreaks ||
+	      S->Type == pkgCache::Dep::Obsoletes) &&
 	     ParentPkg() == I.OwnerPkg())
 	     ParentPkg() == I.OwnerPkg())
 	    continue;
 	    continue;
 	 
 	 
@@ -490,7 +654,7 @@ void pkgCache::DepIterator::GlobOr(DepIterator &Start,DepIterator &End)
    End = *this;
    End = *this;
    for (bool LastOR = true; end() == false && LastOR == true;)
    for (bool LastOR = true; end() == false && LastOR == true;)
    {
    {
-      LastOR = (Dep->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or;
+      LastOR = (S->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or;
       (*this)++;
       (*this)++;
       if (LastOR == true)
       if (LastOR == true)
 	 End = (*this);
 	 End = (*this);
@@ -545,6 +709,23 @@ bool pkgCache::VerIterator::Automatic() const
    return false;
    return false;
 }
 }
 									/*}}}*/
 									/*}}}*/
+// VerIterator::Pseudo - Check if this version is a pseudo one		/*{{{*/
+// ---------------------------------------------------------------------
+/* Sometimes you have the need to express dependencies with versions
+   which doesn't really exist or exist multiply times for "different"
+   packages. We need these versions for dependency resolution but they
+   are a problem everytime we need to download/install something. */
+bool pkgCache::VerIterator::Pseudo() const
+{
+   if (S->MultiArch == pkgCache::Version::All &&
+	   strcmp(Arch(true),"all") != 0)
+   {
+	   GrpIterator const Grp = ParentPkg().Group();
+	   return (Grp->LastPackage != Grp->FirstPackage);
+   }
+   return false;
+}
+									/*}}}*/
 // VerIterator::NewestFile - Return the newest file version relation	/*{{{*/
 // VerIterator::NewestFile - Return the newest file version relation	/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /* This looks at the version numbers associated with all of the sources
 /* This looks at the version numbers associated with all of the sources
@@ -566,7 +747,7 @@ pkgCache::VerFileIterator pkgCache::VerIterator::NewestFile() const
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /* This describes the version from a release-centric manner. The output is a 
 /* This describes the version from a release-centric manner. The output is a 
    list of Label:Version/Archive */
    list of Label:Version/Archive */
-string pkgCache::VerIterator::RelStr()
+string pkgCache::VerIterator::RelStr() const
 {
 {
    bool First = true;
    bool First = true;
    string Res;
    string Res;
@@ -625,7 +806,9 @@ string pkgCache::VerIterator::RelStr()
 	 else
 	 else
 	    Res += File.Site();
 	    Res += File.Site();
       }      
       }      
-   }   
+   }
+   if (S->ParentPkg != 0)
+      Res.append(" [").append(Arch()).append("]");
    return Res;
    return Res;
 }
 }
 									/*}}}*/
 									/*}}}*/
@@ -640,7 +823,7 @@ bool pkgCache::PkgFileIterator::IsOk()
    if (stat(FileName(),&Buf) != 0)
    if (stat(FileName(),&Buf) != 0)
       return false;
       return false;
 
 
-   if (Buf.st_size != (signed)File->Size || Buf.st_mtime != File->mtime)
+   if (Buf.st_size != (signed)S->Size || Buf.st_mtime != S->mtime)
       return false;
       return false;
 
 
    return true;
    return true;
@@ -664,6 +847,8 @@ string pkgCache::PkgFileIterator::RelStr()
       Res = Res + (Res.empty() == true?"l=":",l=")  + Label();
       Res = Res + (Res.empty() == true?"l=":",l=")  + Label();
    if (Component() != 0)
    if (Component() != 0)
       Res = Res + (Res.empty() == true?"c=":",c=")  + Component();
       Res = Res + (Res.empty() == true?"c=":",c=")  + Component();
+   if (Architecture() != 0)
+      Res = Res + (Res.empty() == true?"b=":",b=")  + Architecture();
    return Res;
    return Res;
 }
 }
 									/*}}}*/
 									/*}}}*/

+ 422 - 91
apt-pkg/pkgcache.h

@@ -1,20 +1,75 @@
 // -*- mode: cpp; mode: fold -*-
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
 // Description								/*{{{*/
-// $Id: pkgcache.h,v 1.25 2001/07/01 22:28:24 jgg Exp $
-/* ######################################################################
-   
-   Cache - Structure definitions for the cache file
-   
-   Please see doc/apt-pkg/cache.sgml for a more detailed description of 
-   this format. Also be sure to keep that file up-to-date!!
-   
+/**\file pkgcache.h
+   \brief pkgCache - Structure definitions for the cache file
+
+   The goal of the cache file is two fold:
+   Firstly to speed loading and processing of the package file array and
+   secondly to reduce memory consumption of the package file array.
+
+   The implementation is aimed at an environment with many primary package
+   files, for instance someone that has a Package file for their CD-ROM, a
+   Package file for the latest version of the distribution on the CD-ROM and a
+   package file for the development version. Always present is the information
+   contained in the status file which might be considered a separate package
+   file.
+
+   Please understand, this is designed as a <b>Cache file</b> it is not meant to be
+   used on any system other than the one it was created for. It is not meant to
+   be authoritative either, i.e. if a system crash or software failure occurs it
+   must be perfectly acceptable for the cache file to be in an inconsistent
+   state. Furthermore at any time the cache file may be erased without losing
+   any information.
+
+   Also the structures and storage layout is optimized for use by the APT
+   and may not be suitable for all purposes. However it should be possible
+   to extend it with associate cache files that contain other information.
+
+   To keep memory use down the cache file only contains often used fields and
+   fields that are inexpensive to store, the Package file has a full list of
+   fields. Also the client may assume that all items are perfectly valid and
+   need not perform checks against their correctness. Removal of information
+   from the cache is possible, but blanks will be left in the file, and
+   unused strings will also be present. The recommended implementation is to
+   simply rebuild the cache each time any of the data files change. It is
+   possible to add a new package file to the cache without any negative side
+   effects.
+
+   <b>Note on Pointer access</b>
    Clients should always use the CacheIterators classes for access to the
    Clients should always use the CacheIterators classes for access to the
-   cache. They provide a simple STL-like method for traversing the links
-   of the datastructure.
-   
-   See pkgcachegen.h for information about generating cache structures.
-   
-   ##################################################################### */
+   cache and the data in it. They also provide a simple STL-like method for
+   traversing the links of the datastructure.
+
+   Every item in every structure is stored as the index to that structure.
+   What this means is that once the files is mmaped every data access has to
+   go through a fix up stage to get a real memory pointer. This is done
+   by taking the index, multiplying it by the type size and then adding
+   it to the start address of the memory block. This sounds complex, but
+   in C it is a single array dereference. Because all items are aligned to
+   their size and indexes are stored as multiples of the size of the structure
+   the format is immediately portable to all possible architectures - BUT the
+   generated files are -NOT-.
+
+   This scheme allows code like this to be written:
+   <example>
+     void *Map = mmap(...);
+     Package *PkgList = (Package *)Map;
+     Header *Head = (Header *)Map;
+     char *Strings = (char *)Map;
+     cout << (Strings + PkgList[Head->HashTable[0]]->Name) << endl;
+   </example>
+   Notice the lack of casting or multiplication. The net result is to return
+   the name of the first package in the first hash bucket, without error
+   checks.
+
+   The generator uses allocation pools to group similarly sized structures in
+   large blocks to eliminate any alignment overhead. The generator also
+   assures that no structures overlap and all indexes are unique. Although
+   at first glance it may seem like there is the potential for two structures
+   to exist at the same point the generator never allows this to happen.
+   (See the discussion of free space pools)
+
+   See \ref pkgcachegen.h for more information about generating cache structures. */
 									/*}}}*/
 									/*}}}*/
 #ifndef PKGLIB_PKGCACHE_H
 #ifndef PKGLIB_PKGCACHE_H
 #define PKGLIB_PKGCACHE_H
 #define PKGLIB_PKGCACHE_H
@@ -32,6 +87,7 @@ class pkgCache								/*{{{*/
    public:
    public:
    // Cache element predeclarations
    // Cache element predeclarations
    struct Header;
    struct Header;
+   struct Group;
    struct Package;
    struct Package;
    struct PackageFile;
    struct PackageFile;
    struct Version;
    struct Version;
@@ -43,6 +99,8 @@ class pkgCache								/*{{{*/
    struct DescFile;
    struct DescFile;
    
    
    // Iterators
    // Iterators
+   template<typename Str, typename Itr> class Iterator;
+   class GrpIterator;
    class PkgIterator;
    class PkgIterator;
    class VerIterator;
    class VerIterator;
    class DescIterator;
    class DescIterator;
@@ -51,14 +109,6 @@ class pkgCache								/*{{{*/
    class PkgFileIterator;
    class PkgFileIterator;
    class VerFileIterator;
    class VerFileIterator;
    class DescFileIterator;
    class DescFileIterator;
-   friend class PkgIterator;
-   friend class VerIterator;
-   friend class DescInterator;
-   friend class DepIterator;
-   friend class PrvIterator;
-   friend class PkgFileIterator;
-   friend class VerFileIterator;
-   friend class DescFileIterator;
    
    
    class Namespace;
    class Namespace;
    
    
@@ -71,12 +121,20 @@ class pkgCache								/*{{{*/
    {
    {
       enum DepType {Depends=1,PreDepends=2,Suggests=3,Recommends=4,
       enum DepType {Depends=1,PreDepends=2,Suggests=3,Recommends=4,
 	 Conflicts=5,Replaces=6,Obsoletes=7,DpkgBreaks=8,Enhances=9};
 	 Conflicts=5,Replaces=6,Obsoletes=7,DpkgBreaks=8,Enhances=9};
+      /** \brief available compare operators
+
+          The lower 4 bits are used to indicate what operator is being specified and
+          the upper 4 bits are flags. OR indicates that the next package is
+          or'd with the current package. */
       enum DepCompareOp {Or=0x10,NoOp=0,LessEq=0x1,GreaterEq=0x2,Less=0x3,
       enum DepCompareOp {Or=0x10,NoOp=0,LessEq=0x1,GreaterEq=0x2,Less=0x3,
 	 Greater=0x4,Equals=0x5,NotEquals=0x6};
 	 Greater=0x4,Equals=0x5,NotEquals=0x6};
    };
    };
    
    
    struct State
    struct State
    {
    {
+      /** \brief priority of a package version
+
+          Zero is used for unparsable or absent Priority fields. */
       enum VerPriority {Important=1,Required=2,Standard=3,Optional=4,Extra=5};
       enum VerPriority {Important=1,Required=2,Standard=3,Optional=4,Extra=5};
       enum PkgSelectedState {Unknown=0,Install=1,Hold=2,DeInstall=3,Purge=4};
       enum PkgSelectedState {Unknown=0,Install=1,Hold=2,DeInstall=3,Purge=4};
       enum PkgInstState {Ok=0,ReInstReq=1,HoldInst=2,HoldReInstReq=3};
       enum PkgInstState {Ok=0,ReInstReq=1,HoldInst=2,HoldReInstReq=3};
@@ -104,6 +162,7 @@ class pkgCache								/*{{{*/
    
    
    // Pointers to the arrays of items
    // Pointers to the arrays of items
    Header *HeaderP;
    Header *HeaderP;
+   Group *GrpP;
    Package *PkgP;
    Package *PkgP;
    VerFile *VerFileP;
    VerFile *VerFileP;
    DescFile *DescFileP;
    DescFile *DescFileP;
@@ -115,7 +174,7 @@ class pkgCache								/*{{{*/
    StringItem *StringItemP;
    StringItem *StringItemP;
    char *StrP;
    char *StrP;
 
 
-   virtual bool ReMap();
+   virtual bool ReMap(bool const &Errorchecks = true);
    inline bool Sync() {return Map.Sync();};
    inline bool Sync() {return Map.Sync();};
    inline MMap &GetMap() {return Map;};
    inline MMap &GetMap() {return Map;};
    inline void *DataEnd() {return ((unsigned char *)Map.Data()) + Map.Size();};
    inline void *DataEnd() {return ((unsigned char *)Map.Data()) + Map.Size();};
@@ -124,17 +183,24 @@ class pkgCache								/*{{{*/
    inline unsigned long Hash(const string &S) const {return sHash(S);};
    inline unsigned long Hash(const string &S) const {return sHash(S);};
    inline unsigned long Hash(const char *S) const {return sHash(S);};
    inline unsigned long Hash(const char *S) const {return sHash(S);};
 
 
-   // Usefull transformation things
+   // Useful transformation things
    const char *Priority(unsigned char Priority);
    const char *Priority(unsigned char Priority);
    
    
    // Accessors
    // Accessors
+   GrpIterator FindGrp(const string &Name);
    PkgIterator FindPkg(const string &Name);
    PkgIterator FindPkg(const string &Name);
+   PkgIterator FindPkg(const string &Name, const string &Arch);
+
    Header &Head() {return *HeaderP;};
    Header &Head() {return *HeaderP;};
+   inline GrpIterator GrpBegin();
+   inline GrpIterator GrpEnd();
    inline PkgIterator PkgBegin();
    inline PkgIterator PkgBegin();
    inline PkgIterator PkgEnd();
    inline PkgIterator PkgEnd();
    inline PkgFileIterator FileBegin();
    inline PkgFileIterator FileBegin();
    inline PkgFileIterator FileEnd();
    inline PkgFileIterator FileEnd();
 
 
+   inline bool MultiArchCache() const { return MultiArchEnabled; };
+
    // Make me a function
    // Make me a function
    pkgVersioningSystem *VS;
    pkgVersioningSystem *VS;
    
    
@@ -145,19 +211,40 @@ class pkgCache								/*{{{*/
    
    
    pkgCache(MMap *Map,bool DoMap = true);
    pkgCache(MMap *Map,bool DoMap = true);
    virtual ~pkgCache() {};
    virtual ~pkgCache() {};
+
+private:
+   bool MultiArchEnabled;
+   PkgIterator SingleArchFindPkg(const string &Name);
 };
 };
 									/*}}}*/
 									/*}}}*/
 // Header structure							/*{{{*/
 // Header structure							/*{{{*/
 struct pkgCache::Header
 struct pkgCache::Header
 {
 {
-   // Signature information
+   /** \brief Signature information
+
+       This must contain the hex value 0x98FE76DC which is designed to
+       verify that the system loading the image has the same byte order
+       and byte size as the system saving the image */
    unsigned long Signature;
    unsigned long Signature;
+   /** These contain the version of the cache file */
    short MajorVersion;
    short MajorVersion;
    short MinorVersion;
    short MinorVersion;
+   /** \brief indicates if the cache should be erased
+
+       Dirty is true if the cache file was opened for reading, the client
+       expects to have written things to it and have not fully synced it.
+       The file should be erased and rebuilt if it is true. */
    bool Dirty;
    bool Dirty;
-   
-   // Size of structure values
+
+   /** \brief Size of structure values
+
+       All *Sz variables contains the sizeof() that particular structure.
+       It is used as an extra consistency check on the structure of the file.
+
+       If any of the size values do not exactly match what the client expects
+       then the client should refuse the load the file. */
    unsigned short HeaderSz;
    unsigned short HeaderSz;
+   unsigned short GroupSz;
    unsigned short PackageSz;
    unsigned short PackageSz;
    unsigned short PackageFileSz;
    unsigned short PackageFileSz;
    unsigned short VersionSz;
    unsigned short VersionSz;
@@ -166,8 +253,13 @@ struct pkgCache::Header
    unsigned short ProvidesSz;
    unsigned short ProvidesSz;
    unsigned short VerFileSz;
    unsigned short VerFileSz;
    unsigned short DescFileSz;
    unsigned short DescFileSz;
-   
-   // Structure counts
+
+   /** \brief Structure counts
+
+       These indicate the number of each structure contained in the cache.
+       PackageCount is especially useful for generating user state structures.
+       See Package::Id for more info. */
+   unsigned long GroupCount;
    unsigned long PackageCount;
    unsigned long PackageCount;
    unsigned long VersionCount;
    unsigned long VersionCount;
    unsigned long DescriptionCount;
    unsigned long DescriptionCount;
@@ -176,154 +268,393 @@ struct pkgCache::Header
    unsigned long VerFileCount;
    unsigned long VerFileCount;
    unsigned long DescFileCount;
    unsigned long DescFileCount;
    unsigned long ProvidesCount;
    unsigned long ProvidesCount;
-   
-   // Offsets
-   map_ptrloc FileList;              // struct PackageFile
-   map_ptrloc StringList;            // struct StringItem
-   map_ptrloc VerSysName;            // StringTable
-   map_ptrloc Architecture;          // StringTable
+
+   /** \brief index of the first PackageFile structure
+
+       The PackageFile structures are singly linked lists that represent
+       all package files that have been merged into the cache. */
+   map_ptrloc FileList;
+   /** \brief index of the first StringItem structure
+
+       The cache contains a list of all the unique strings (StringItems).
+       The parser reads this list into memory so it can match strings
+       against it.*/
+   map_ptrloc StringList;
+   /** \brief String representing the version system used */
+   map_ptrloc VerSysName;
+   /** \brief Architecture(s) the cache was built against */
+   map_ptrloc Architecture;
+   /** \brief The maximum size of a raw entry from the original Package file */
    unsigned long MaxVerFileSize;
    unsigned long MaxVerFileSize;
+   /** \brief The maximum size of a raw entry from the original Translation file */
    unsigned long MaxDescFileSize;
    unsigned long MaxDescFileSize;
 
 
-   /* Allocation pools, there should be one of these for each structure
-      excluding the header */
-   DynamicMMap::Pool Pools[8];
+   /** \brief The Pool structures manage the allocation pools that the generator uses
+
+       Start indicates the first byte of the pool, Count is the number of objects
+       remaining in the pool and ItemSize is the structure size (alignment factor)
+       of the pool. An ItemSize of 0 indicates the pool is empty. There should be
+       the same number of pools as there are structure types. The generator
+       stores this information so future additions can make use of any unused pool
+       blocks. */
+   DynamicMMap::Pool Pools[9];
    
    
-   // Rapid package name lookup
-   map_ptrloc HashTable[2*1048];
+   /** \brief hash tables providing rapid group/package name lookup
+
+       Each group/package name is inserted into the hash table using pkgCache::Hash(const &string)
+       By iterating over each entry in the hash table it is possible to iterate over
+       the entire list of packages. Hash Collisions are handled with a singly linked
+       list of packages based at the hash item. The linked list contains only
+       packages that match the hashing function.
+       In the PkgHashTable is it possible that multiple packages have the same name -
+       these packages are stored as a sequence in the list.
+
+       Beware: The Hashmethod assumes that the hash table sizes are equal */
+   map_ptrloc PkgHashTable[2*1048];
+   map_ptrloc GrpHashTable[2*1048];
 
 
    bool CheckSizes(Header &Against) const;
    bool CheckSizes(Header &Against) const;
    Header();
    Header();
 };
 };
 									/*}}}*/
 									/*}}}*/
-struct pkgCache::Package						/*{{{*/
+// Group structure							/*{{{*/
+/** \brief groups architecture depending packages together
+
+    On or more packages with the same name form a group, so we have
+    a simple way to access a package built for different architectures
+    Group exists in a singly linked list of group records starting at
+    the hash index of the name in the pkgCache::Header::GrpHashTable */
+struct pkgCache::Group
 {
 {
-   // Pointers
-   map_ptrloc Name;              // Stringtable
+   /** \brief Name of the group */
+   map_ptrloc Name;		// StringItem
+
+   // Linked List
+   /** \brief Link to the first package which belongs to the group */
+   map_ptrloc FirstPackage;	// Package
+   /** \brief Link to the last package which belongs to the group */
+   map_ptrloc LastPackage;	// Package
+   /** \brief Link to the next Group */
+   map_ptrloc Next;		// Group
+   /** \brief unique sequel ID */
+   unsigned int ID;
+
+};
+									/*}}}*/
+// Package structure							/*{{{*/
+/** \brief contains information for a single unique package
+
+    There can be any number of versions of a given package.
+    Package exists in a singly linked list of package records starting at
+    the hash index of the name in the pkgCache::Header::PkgHashTable
+
+    A package can be created for every architecture so package names are
+    not unique, but it is garanteed that packages with the same name
+    are sequencel ordered in the list. Packages with the same name can be
+    accessed with the Group.
+*/
+struct pkgCache::Package
+{
+   /** \brief Name of the package */
+   map_ptrloc Name;              // StringItem
+   /** \brief Architecture of the package */
+   map_ptrloc Arch;              // StringItem
+   /** \brief Base of a singly linked list of versions
+
+       Each structure represents a unique version of the package.
+       The version structures contain links into PackageFile and the
+       original text file as well as detailed information about the size
+       and dependencies of the specific package. In this way multiple
+       versions of a package can be cleanly handled by the system.
+       Furthermore, this linked list is guaranteed to be sorted
+       from Highest version to lowest version with no duplicate entries. */
    map_ptrloc VersionList;       // Version
    map_ptrloc VersionList;       // Version
+   /** \brief index to the installed version */
    map_ptrloc CurrentVer;        // Version
    map_ptrloc CurrentVer;        // Version
-   map_ptrloc Section;           // StringTable (StringItem)
-      
-   // Linked list 
+   /** \brief indicates the deduced section
+
+       Should be the index to the string "Unknown" or to the section
+       of the last parsed item. */
+   map_ptrloc Section;           // StringItem
+   /** \brief index of the group this package belongs to */
+   map_ptrloc Group;             // Group the Package belongs to
+
+   // Linked list
+   /** \brief Link to the next package in the same bucket */
    map_ptrloc NextPackage;       // Package
    map_ptrloc NextPackage;       // Package
+   /** \brief List of all dependencies on this package */
    map_ptrloc RevDepends;        // Dependency
    map_ptrloc RevDepends;        // Dependency
+   /** \brief List of all "packages" this package provide */
    map_ptrloc ProvidesList;      // Provides
    map_ptrloc ProvidesList;      // Provides
 
 
    // Install/Remove/Purge etc
    // Install/Remove/Purge etc
+   /** \brief state that the user wishes the package to be in */
    unsigned char SelectedState;     // What
    unsigned char SelectedState;     // What
+   /** \brief installation state of the package
+
+       This should be "ok" but in case the installation failed
+       it will be different.
+   */
    unsigned char InstState;         // Flags
    unsigned char InstState;         // Flags
+   /** \brief indicates if the package is installed */
    unsigned char CurrentState;      // State
    unsigned char CurrentState;      // State
-   
+
+   /** \brief unique sequel ID
+
+       ID is a unique value from 0 to Header->PackageCount assigned by the generator.
+       This allows clients to create an array of size PackageCount and use it to store
+       state information for the package map. For instance the status file emitter uses
+       this to track which packages have been emitted already. */
    unsigned int ID;
    unsigned int ID;
+   /** \brief some useful indicators of the package's state */
    unsigned long Flags;
    unsigned long Flags;
 };
 };
 									/*}}}*/
 									/*}}}*/
-struct pkgCache::PackageFile						/*{{{*/
+// Package File structure						/*{{{*/
+/** \brief stores information about the files used to generate the cache
+
+    Package files are referenced by Version structures to be able to know
+    after the generation still from which Packages file includes this Version
+    as we need this information later on e.g. for pinning. */
+struct pkgCache::PackageFile
 {
 {
-   // Names
-   map_ptrloc FileName;        // Stringtable
-   map_ptrloc Archive;         // Stringtable
-   map_ptrloc Codename;        // Stringtable
-   map_ptrloc Component;       // Stringtable
-   map_ptrloc Version;         // Stringtable
-   map_ptrloc Origin;          // Stringtable
-   map_ptrloc Label;           // Stringtable
-   map_ptrloc Architecture;    // Stringtable
-   map_ptrloc Site;            // Stringtable
-   map_ptrloc IndexType;       // Stringtable
-   unsigned long Size;            
+   /** \brief physical disk file that this PackageFile represents */
+   map_ptrloc FileName;        // StringItem
+   /** \brief the release information
+
+       Please see the files document for a description of what the
+       release information means. */
+   map_ptrloc Archive;         // StringItem
+   map_ptrloc Codename;        // StringItem
+   map_ptrloc Component;       // StringItem
+   map_ptrloc Version;         // StringItem
+   map_ptrloc Origin;          // StringItem
+   map_ptrloc Label;           // StringItem
+   map_ptrloc Architecture;    // StringItem
+   /** \brief The site the index file was fetched from */
+   map_ptrloc Site;            // StringItem
+   /** \brief indicates what sort of index file this is
+
+       @TODO enumerate at least the possible indexes */
+   map_ptrloc IndexType;       // StringItem
+   /** \brief Size of the file
+
+       Used together with the modification time as a
+       simple check to ensure that the Packages
+       file has not been altered since Cache generation. */
+   unsigned long Size;
+   /** \brief Modification time for the file */
+   time_t mtime;
+
+   /* @TODO document PackageFile::Flags */
    unsigned long Flags;
    unsigned long Flags;
-   
+
    // Linked list
    // Linked list
+   /** \brief Link to the next PackageFile in the Cache */
    map_ptrloc NextFile;        // PackageFile
    map_ptrloc NextFile;        // PackageFile
+   /** \brief unique sequel ID */
    unsigned int ID;
    unsigned int ID;
-   time_t mtime;                  // Modification time for the file
 };
 };
 									/*}}}*/
 									/*}}}*/
-struct pkgCache::VerFile						/*{{{*/
+// VerFile structure							/*{{{*/
+/** \brief associates a version with a PackageFile
+
+    This allows a full description of all Versions in all files
+    (and hence all sources) under consideration. */
+struct pkgCache::VerFile
 {
 {
+   /** \brief index of the package file that this version was found in */
    map_ptrloc File;           // PackageFile
    map_ptrloc File;           // PackageFile
+   /** \brief next step in the linked list */
    map_ptrloc NextFile;       // PkgVerFile
    map_ptrloc NextFile;       // PkgVerFile
+   /** \brief position in the package file */
    map_ptrloc Offset;         // File offset
    map_ptrloc Offset;         // File offset
+   /* @TODO document pkgCache::VerFile::Size */
    unsigned long Size;
    unsigned long Size;
 };
 };
 									/*}}}*/
 									/*}}}*/
-struct pkgCache::DescFile						/*{{{*/
+// DescFile structure							/*{{{*/
+/** \brief associates a description with a Translation file */
+struct pkgCache::DescFile
 {
 {
+   /** \brief index of the file that this description was found in */
    map_ptrloc File;           // PackageFile
    map_ptrloc File;           // PackageFile
+   /** \brief next step in the linked list */
    map_ptrloc NextFile;       // PkgVerFile
    map_ptrloc NextFile;       // PkgVerFile
+   /** \brief position in the file */
    map_ptrloc Offset;         // File offset
    map_ptrloc Offset;         // File offset
+   /* @TODO document pkgCache::DescFile::Size */
    unsigned long Size;
    unsigned long Size;
 };
 };
 									/*}}}*/
 									/*}}}*/
-struct pkgCache::Version						/*{{{*/
+// Version structure							/*{{{*/
+/** \brief information for a single version of a package
+
+    The version list is always sorted from highest version to lowest
+    version by the generator. Equal version numbers are either merged
+    or handled as separate versions based on the Hash value. */
+struct pkgCache::Version
 {
 {
-   map_ptrloc VerStr;            // Stringtable
-   map_ptrloc Section;           // StringTable (StringItem)
-   map_ptrloc Arch;              // StringTable
-      
-   // Lists
+   /** \brief complete version string */
+   map_ptrloc VerStr;            // StringItem
+   /** \brief section this version is filled in */
+   map_ptrloc Section;           // StringItem
+   /** \brief stores the MultiArch capabilities of this version
+
+       None is the default and doesn't trigger special behaviour,
+       Foreign means that this version can fulfill dependencies even
+       if it is built for another architecture as the requester.
+       Same indicates that builds for different architectures can
+       be co-installed on the system and All is the marker for a
+       version with the Architecture: all. */
+   enum {None, All, Foreign, Same, Allowed} MultiArch;
+
+   /** \brief references all the PackageFile's that this version came from
+
+       FileList can be used to determine what distribution(s) the Version
+       applies to. If FileList is 0 then this is a blank version.
+       The structure should also have a 0 in all other fields excluding
+       pkgCache::Version::VerStr and Possibly pkgCache::Version::NextVer. */
    map_ptrloc FileList;          // VerFile
    map_ptrloc FileList;          // VerFile
+   /** \brief next (lower or equal) version in the linked list */
    map_ptrloc NextVer;           // Version
    map_ptrloc NextVer;           // Version
+   /** \brief next description in the linked list */
    map_ptrloc DescriptionList;   // Description
    map_ptrloc DescriptionList;   // Description
+   /** \brief base of the dependency list */
    map_ptrloc DependsList;       // Dependency
    map_ptrloc DependsList;       // Dependency
+   /** \brief links to the owning package
+
+       This allows reverse dependencies to determine the package */
    map_ptrloc ParentPkg;         // Package
    map_ptrloc ParentPkg;         // Package
+   /** \brief list of pkgCache::Provides */
    map_ptrloc ProvidesList;      // Provides
    map_ptrloc ProvidesList;      // Provides
-   
-   map_ptrloc Size;              // These are the .deb size
-   map_ptrloc InstalledSize;
+
+   /** \brief archive size for this version
+
+       For Debian this is the size of the .deb file. */
+   unsigned long long Size;      // These are the .deb size
+   /** \brief uncompressed size for this version */
+   unsigned long long InstalledSize;
+   /** \brief characteristic value representing this version
+
+       No two packages in existence should have the same VerStr
+       and Hash with different contents. */
    unsigned short Hash;
    unsigned short Hash;
+   /** \brief unique sequel ID */
    unsigned int ID;
    unsigned int ID;
+   /** \brief parsed priority value */
    unsigned char Priority;
    unsigned char Priority;
 };
 };
 									/*}}}*/
 									/*}}}*/
-struct pkgCache::Description						/*{{{*/
+// Description structure						/*{{{*/
+/** \brief datamember of a linked list of available description for a version */
+struct pkgCache::Description
 {
 {
-   // Language Code store the description translation language code. If
-   // the value has a 0 lenght then this is readed using the Package
-   // file else the Translation-CODE are used.
-   map_ptrloc language_code;     // StringTable
-   map_ptrloc md5sum;            // StringTable
+   /** \brief Language code of this description (translation)
+
+       If the value has a 0 length then this is read using the Package
+       file else the Translation-CODE file is used. */
+   map_ptrloc language_code;     // StringItem
+   /** \brief MD5sum of the original description
+
+       Used to map Translations of a description to a version
+       and to check that the Translation is up-to-date. */
+   map_ptrloc md5sum;            // StringItem
 
 
-   // Linked list 
+   /* @TODO document pkgCache::Description::FileList */
    map_ptrloc FileList;          // DescFile
    map_ptrloc FileList;          // DescFile
+   /** \brief next translation for this description */
    map_ptrloc NextDesc;          // Description
    map_ptrloc NextDesc;          // Description
+   /** \brief the text is a description of this package */
    map_ptrloc ParentPkg;         // Package
    map_ptrloc ParentPkg;         // Package
 
 
+   /** \brief unique sequel ID */
    unsigned int ID;
    unsigned int ID;
 };
 };
 									/*}}}*/
 									/*}}}*/
-struct pkgCache::Dependency						/*{{{*/
+// Dependency structure							/*{{{*/
+/** \brief information for a single dependency record
+
+    The records are split up like this to ease processing by the client.
+    The base of the linked list is pkgCache::Version::DependsList.
+    All forms of dependencies are recorded here including Depends,
+    Recommends, Suggests, Enhances, Conflicts, Replaces and Breaks. */
+struct pkgCache::Dependency
 {
 {
-   map_ptrloc Version;         // Stringtable
+   /** \brief string of the version the dependency is applied against */
+   map_ptrloc Version;         // StringItem
+   /** \brief index of the package this depends applies to
+
+       The generator will - if the package does not already exist -
+       create a blank (no version records) package. */
    map_ptrloc Package;         // Package
    map_ptrloc Package;         // Package
+   /** \brief next dependency of this version */
    map_ptrloc NextDepends;     // Dependency
    map_ptrloc NextDepends;     // Dependency
+   /** \brief next reverse dependency of this package */
    map_ptrloc NextRevDepends;  // Dependency
    map_ptrloc NextRevDepends;  // Dependency
+   /** \brief version of the package which has the reverse depends */
    map_ptrloc ParentVer;       // Version
    map_ptrloc ParentVer;       // Version
-   
-   // Specific types of depends
-   map_ptrloc ID;   
+
+   /** \brief unique sequel ID */
+   map_ptrloc ID;
+   /** \brief Dependency type - Depends, Recommends, Conflicts, etc */
    unsigned char Type;
    unsigned char Type;
+   /** \brief comparison operator specified on the depends line
+
+       If the high bit is set then it is a logical OR with the previous record. */
    unsigned char CompareOp;
    unsigned char CompareOp;
 };
 };
 									/*}}}*/
 									/*}}}*/
-struct pkgCache::Provides						/*{{{*/
+// Provides structure							/*{{{*/
+/** \brief handles virtual packages
+
+    When a Provides: line is encountered a new provides record is added
+    associating the package with a virtual package name.
+    The provides structures are linked off the package structures.
+    This simplifies the analysis of dependencies and other aspects A provides
+    refers to a specific version of a specific package, not all versions need to
+    provide that provides.*/
+struct pkgCache::Provides
 {
 {
-   map_ptrloc ParentPkg;        // Pacakge
+   /** \brief index of the package providing this */
+   map_ptrloc ParentPkg;        // Package
+   /** \brief index of the version this provide line applies to */
    map_ptrloc Version;          // Version
    map_ptrloc Version;          // Version
-   map_ptrloc ProvideVersion;   // Stringtable
+   /** \brief version in the provides line (if any)
+
+       This version allows dependencies to depend on specific versions of a
+       Provides, as well as allowing Provides to override existing packages.
+       This is experimental. Note that Debian doesn't allow versioned provides */
+   map_ptrloc ProvideVersion;   // StringItem
+   /** \brief next provides (based of package) */
    map_ptrloc NextProvides;     // Provides
    map_ptrloc NextProvides;     // Provides
+   /** \brief next provides (based of version) */
    map_ptrloc NextPkgProv;      // Provides
    map_ptrloc NextPkgProv;      // Provides
 };
 };
 									/*}}}*/
 									/*}}}*/
-struct pkgCache::StringItem						/*{{{*/
+// StringItem structure							/*{{{*/
+/** \brief used for generating single instances of strings
+
+    Some things like Section Name are are useful to have as unique tags.
+    It is part of a linked list based at pkgCache::Header::StringList
+
+    All strings are simply inlined any place in the file that is natural
+    for the writer. The client should make no assumptions about the positioning
+    of strings. All StringItems should be null-terminated. */
+struct pkgCache::StringItem
 {
 {
-   map_ptrloc String;        // Stringtable
+   /** \brief string this refers to */
+   map_ptrloc String;        // StringItem
+   /** \brief Next link in the chain */
    map_ptrloc NextItem;      // StringItem
    map_ptrloc NextItem;      // StringItem
 };
 };
 									/*}}}*/
 									/*}}}*/
 #include <apt-pkg/cacheiterators.h>
 #include <apt-pkg/cacheiterators.h>
 
 
+inline pkgCache::GrpIterator pkgCache::GrpBegin() 
+       {return GrpIterator(*this);};
+inline pkgCache::GrpIterator pkgCache::GrpEnd() 
+       {return GrpIterator(*this,GrpP);};
 inline pkgCache::PkgIterator pkgCache::PkgBegin() 
 inline pkgCache::PkgIterator pkgCache::PkgBegin() 
        {return PkgIterator(*this);};
        {return PkgIterator(*this);};
 inline pkgCache::PkgIterator pkgCache::PkgEnd() 
 inline pkgCache::PkgIterator pkgCache::PkgEnd() 
@@ -337,7 +668,7 @@ inline pkgCache::PkgFileIterator pkgCache::FileEnd()
 class pkgCache::Namespace						/*{{{*/
 class pkgCache::Namespace						/*{{{*/
 {   
 {   
    public:
    public:
-
+   typedef pkgCache::GrpIterator GrpIterator;
    typedef pkgCache::PkgIterator PkgIterator;
    typedef pkgCache::PkgIterator PkgIterator;
    typedef pkgCache::VerIterator VerIterator;
    typedef pkgCache::VerIterator VerIterator;
    typedef pkgCache::DescIterator DescIterator;
    typedef pkgCache::DescIterator DescIterator;

Разлика између датотеке није приказан због своје велике величине
+ 460 - 139
apt-pkg/pkgcachegen.cc


+ 50 - 16
apt-pkg/pkgcachegen.h

@@ -23,6 +23,8 @@
 #include <apt-pkg/pkgcache.h>
 #include <apt-pkg/pkgcache.h>
 #include <apt-pkg/md5.h>
 #include <apt-pkg/md5.h>
 
 
+#include <vector>
+
 class pkgSourceList;
 class pkgSourceList;
 class OpProgress;
 class OpProgress;
 class MMap;
 class MMap;
@@ -31,16 +33,32 @@ class pkgIndexFile;
 class pkgCacheGenerator							/*{{{*/
 class pkgCacheGenerator							/*{{{*/
 {
 {
    private:
    private:
-   
+
    pkgCache::StringItem *UniqHash[26];
    pkgCache::StringItem *UniqHash[26];
-   
+   map_ptrloc WriteStringInMap(std::string const &String) { return WriteStringInMap(String.c_str()); };
+   map_ptrloc WriteStringInMap(const char *String);
+   map_ptrloc WriteStringInMap(const char *String, const unsigned long &Len);
+   map_ptrloc AllocateInMap(const unsigned long &size);
+
    public:
    public:
    
    
    class ListParser;
    class ListParser;
    friend class ListParser;
    friend class ListParser;
-   
+
+   template<typename Iter> class Dynamic {
+      public:
+      static std::vector<Iter*> toReMap;
+      Dynamic(Iter &I) {
+	 toReMap.push_back(&I);
+      }
+
+      ~Dynamic() {
+	 toReMap.pop_back();
+      }
+   };
+
    protected:
    protected:
-   
+
    DynamicMMap &Map;
    DynamicMMap &Map;
    pkgCache Cache;
    pkgCache Cache;
    OpProgress *Progress;
    OpProgress *Progress;
@@ -51,9 +69,13 @@ class pkgCacheGenerator							/*{{{*/
    // Flag file dependencies
    // Flag file dependencies
    bool FoundFileDeps;
    bool FoundFileDeps;
    
    
-   bool NewPackage(pkgCache::PkgIterator &Pkg,const string &PkgName);
+   bool NewGroup(pkgCache::GrpIterator &Grp,const string &Name);
+   bool NewPackage(pkgCache::PkgIterator &Pkg,const string &Name, const string &Arch);
    bool NewFileVer(pkgCache::VerIterator &Ver,ListParser &List);
    bool NewFileVer(pkgCache::VerIterator &Ver,ListParser &List);
    bool NewFileDesc(pkgCache::DescIterator &Desc,ListParser &List);
    bool NewFileDesc(pkgCache::DescIterator &Desc,ListParser &List);
+   bool NewDepends(pkgCache::PkgIterator &Pkg, pkgCache::VerIterator &Ver,
+		   string const &Version, unsigned int const &Op,
+		   unsigned int const &Type, map_ptrloc *OldDepLast);
    unsigned long NewVersion(pkgCache::VerIterator &Ver,const string &VerStr,unsigned long Next);
    unsigned long NewVersion(pkgCache::VerIterator &Ver,const string &VerStr,unsigned long Next);
    map_ptrloc NewDescription(pkgCache::DescIterator &Desc,const string &Lang,const MD5SumValue &md5sum,map_ptrloc Next);
    map_ptrloc NewDescription(pkgCache::DescIterator &Desc,const string &Lang,const MD5SumValue &md5sum,map_ptrloc Next);
 
 
@@ -72,7 +94,15 @@ class pkgCacheGenerator							/*{{{*/
 
 
    bool HasFileDeps() {return FoundFileDeps;};
    bool HasFileDeps() {return FoundFileDeps;};
    bool MergeFileProvides(ListParser &List);
    bool MergeFileProvides(ListParser &List);
-      
+   bool FinishCache(OpProgress *Progress);
+
+   static bool MakeStatusCache(pkgSourceList &List,OpProgress *Progress,
+			MMap **OutMap = 0,bool AllowMem = false);
+   static bool MakeOnlyStatusCache(OpProgress *Progress,DynamicMMap **OutMap);
+   static DynamicMMap* CreateDynamicMMap(FileFd *CacheF, unsigned long Flags = 0);
+
+   void ReMap(void const * const oldMap, void const * const newMap);
+
    pkgCacheGenerator(DynamicMMap *Map,OpProgress *Progress);
    pkgCacheGenerator(DynamicMMap *Map,OpProgress *Progress);
    ~pkgCacheGenerator();
    ~pkgCacheGenerator();
 };
 };
@@ -94,26 +124,28 @@ class pkgCacheGenerator::ListParser
 
 
    inline unsigned long WriteUniqString(string S) {return Owner->WriteUniqString(S);};
    inline unsigned long WriteUniqString(string S) {return Owner->WriteUniqString(S);};
    inline unsigned long WriteUniqString(const char *S,unsigned int Size) {return Owner->WriteUniqString(S,Size);};
    inline unsigned long WriteUniqString(const char *S,unsigned int Size) {return Owner->WriteUniqString(S,Size);};
-   inline unsigned long WriteString(const string &S) {return Owner->Map.WriteString(S);};
-   inline unsigned long WriteString(const char *S,unsigned int Size) {return Owner->Map.WriteString(S,Size);};
-   bool NewDepends(pkgCache::VerIterator Ver,const string &Package,
+   inline unsigned long WriteString(const string &S) {return Owner->WriteStringInMap(S);};
+   inline unsigned long WriteString(const char *S,unsigned int Size) {return Owner->WriteStringInMap(S,Size);};
+   bool NewDepends(pkgCache::VerIterator &Ver,const string &Package, const string &Arch,
 		   const string &Version,unsigned int Op,
 		   const string &Version,unsigned int Op,
 		   unsigned int Type);
 		   unsigned int Type);
-   bool NewProvides(pkgCache::VerIterator Ver,const string &Package,
-		    const string &Version);
+   bool NewProvides(pkgCache::VerIterator &Ver,const string &PkgName,
+		    const string &PkgArch, const string &Version);
    
    
    public:
    public:
    
    
    // These all operate against the current section
    // These all operate against the current section
    virtual string Package() = 0;
    virtual string Package() = 0;
+   virtual string Architecture() = 0;
+   virtual bool ArchitectureAll() = 0;
    virtual string Version() = 0;
    virtual string Version() = 0;
-   virtual bool NewVersion(pkgCache::VerIterator Ver) = 0;
+   virtual bool NewVersion(pkgCache::VerIterator &Ver) = 0;
    virtual string Description() = 0;
    virtual string Description() = 0;
    virtual string DescriptionLanguage() = 0;
    virtual string DescriptionLanguage() = 0;
    virtual MD5SumValue Description_md5() = 0;
    virtual MD5SumValue Description_md5() = 0;
    virtual unsigned short VersionHash() = 0;
    virtual unsigned short VersionHash() = 0;
-   virtual bool UsePackage(pkgCache::PkgIterator Pkg,
-			   pkgCache::VerIterator Ver) = 0;
+   virtual bool UsePackage(pkgCache::PkgIterator &Pkg,
+			   pkgCache::VerIterator &Ver) = 0;
    virtual unsigned long Offset() = 0;
    virtual unsigned long Offset() = 0;
    virtual unsigned long Size() = 0;
    virtual unsigned long Size() = 0;
    
    
@@ -121,16 +153,18 @@ class pkgCacheGenerator::ListParser
    
    
    inline bool HasFileDeps() {return FoundFileDeps;};
    inline bool HasFileDeps() {return FoundFileDeps;};
    virtual bool CollectFileProvides(pkgCache &Cache,
    virtual bool CollectFileProvides(pkgCache &Cache,
-				    pkgCache::VerIterator Ver) {return true;};
+				    pkgCache::VerIterator &Ver) {return true;};
 
 
    ListParser() : FoundFileDeps(false) {};
    ListParser() : FoundFileDeps(false) {};
    virtual ~ListParser() {};
    virtual ~ListParser() {};
 };
 };
 									/*}}}*/
 									/*}}}*/
+
 bool pkgMakeStatusCache(pkgSourceList &List,OpProgress &Progress,
 bool pkgMakeStatusCache(pkgSourceList &List,OpProgress &Progress,
 			MMap **OutMap = 0,bool AllowMem = false);
 			MMap **OutMap = 0,bool AllowMem = false);
 bool pkgMakeOnlyStatusCache(OpProgress &Progress,DynamicMMap **OutMap);
 bool pkgMakeOnlyStatusCache(OpProgress &Progress,DynamicMMap **OutMap);
 
 
+
 #ifdef APT_COMPATIBILITY
 #ifdef APT_COMPATIBILITY
 #if APT_COMPATIBILITY != 986
 #if APT_COMPATIBILITY != 986
 #warning "Using APT_COMPATIBILITY"
 #warning "Using APT_COMPATIBILITY"
@@ -138,7 +172,7 @@ bool pkgMakeOnlyStatusCache(OpProgress &Progress,DynamicMMap **OutMap);
 MMap *pkgMakeStatusCacheMem(pkgSourceList &List,OpProgress &Progress)
 MMap *pkgMakeStatusCacheMem(pkgSourceList &List,OpProgress &Progress)
 {
 {
    MMap *Map = 0;
    MMap *Map = 0;
-   if (pkgMakeStatusCache(List,Progress,&Map,true) == false)
+   if (pkgCacheGenerator::MakeStatusCache(List,&Progress,&Map,true) == false)
       return 0;
       return 0;
    return Map;
    return Map;
 }
 }

+ 45 - 32
apt-pkg/policy.cc

@@ -115,7 +115,7 @@ bool pkgPolicy::InitDefaults()
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /* Evaluate the package pins and the default list to deteremine what the
 /* Evaluate the package pins and the default list to deteremine what the
    best package is. */
    best package is. */
-pkgCache::VerIterator pkgPolicy::GetCandidateVer(pkgCache::PkgIterator Pkg)
+pkgCache::VerIterator pkgPolicy::GetCandidateVer(pkgCache::PkgIterator const &Pkg)
 {
 {
    // Look for a package pin and evaluate it.
    // Look for a package pin and evaluate it.
    signed Max = GetPriority(Pkg);
    signed Max = GetPriority(Pkg);
@@ -147,6 +147,16 @@ pkgCache::VerIterator pkgPolicy::GetCandidateVer(pkgCache::PkgIterator Pkg)
     */
     */
    for (pkgCache::VerIterator Ver = Pkg.VersionList(); Ver.end() == false; Ver++)
    for (pkgCache::VerIterator Ver = Pkg.VersionList(); Ver.end() == false; Ver++)
    {
    {
+      /* Lets see if this version is the installed version */
+      bool instVer = (Pkg.CurrentVer() == Ver);
+      if (Ver.Pseudo() == true && instVer == false)
+      {
+	 pkgCache::PkgIterator const allPkg = Ver.ParentPkg().Group().FindPkg("all");
+	 if (allPkg->CurrentVer != 0 && allPkg.CurrentVer()->Hash == Ver->Hash &&
+	     strcmp(allPkg.CurVersion(), Ver.VerStr()) == 0)
+	    instVer = true;
+      }
+
       for (pkgCache::VerFileIterator VF = Ver.FileList(); VF.end() == false; VF++)
       for (pkgCache::VerFileIterator VF = Ver.FileList(); VF.end() == false; VF++)
       {
       {
 	 /* If this is the status file, and the current version is not the
 	 /* If this is the status file, and the current version is not the
@@ -155,9 +165,9 @@ pkgCache::VerIterator pkgPolicy::GetCandidateVer(pkgCache::PkgIterator Pkg)
 	    out bogus entries that may be due to config-file states, or
 	    out bogus entries that may be due to config-file states, or
 	    other. */
 	    other. */
 	 if ((VF.File()->Flags & pkgCache::Flag::NotSource) == pkgCache::Flag::NotSource &&
 	 if ((VF.File()->Flags & pkgCache::Flag::NotSource) == pkgCache::Flag::NotSource &&
-	     Pkg.CurrentVer() != Ver)
+	     instVer == false)
 	    continue;
 	    continue;
-	 	 	 
+
 	 signed Prio = PFPriority[VF.File()->ID];
 	 signed Prio = PFPriority[VF.File()->ID];
 	 if (Prio > Max)
 	 if (Prio > Max)
 	 {
 	 {
@@ -171,7 +181,7 @@ pkgCache::VerIterator pkgPolicy::GetCandidateVer(pkgCache::PkgIterator Pkg)
 	 }	 
 	 }	 
       }      
       }      
       
       
-      if (Pkg.CurrentVer() == Ver && Max < 1000)
+      if (instVer == true && Max < 1000)
       {
       {
 	 /* Elevate our current selection (or the status file itself)
 	 /* Elevate our current selection (or the status file itself)
 	    to the Pseudo-status priority. */
 	    to the Pseudo-status priority. */
@@ -189,6 +199,7 @@ pkgCache::VerIterator pkgPolicy::GetCandidateVer(pkgCache::PkgIterator Pkg)
    // will always be a candidate (Closes: #512318)
    // will always be a candidate (Closes: #512318)
    if (!Pref.IsGood() && MaxAlt > 0)
    if (!Pref.IsGood() && MaxAlt > 0)
        Pref = PrefAlt;
        Pref = PrefAlt;
+
    return Pref;
    return Pref;
 }
 }
 									/*}}}*/
 									/*}}}*/
@@ -201,49 +212,51 @@ pkgCache::VerIterator pkgPolicy::GetCandidateVer(pkgCache::PkgIterator Pkg)
 void pkgPolicy::CreatePin(pkgVersionMatch::MatchType Type,string Name,
 void pkgPolicy::CreatePin(pkgVersionMatch::MatchType Type,string Name,
 			  string Data,signed short Priority)
 			  string Data,signed short Priority)
 {
 {
-   Pin *P = 0;
-   
    if (Name.empty() == true)
    if (Name.empty() == true)
-      P = &*Defaults.insert(Defaults.end(),PkgPin());
-   else
    {
    {
-      // Get a spot to put the pin
-      pkgCache::PkgIterator Pkg = Cache->FindPkg(Name);
-      if (Pkg.end() == true)
+      Pin *P = &*Defaults.insert(Defaults.end(),PkgPin());
+      P->Type = Type;
+      P->Priority = Priority;
+      P->Data = Data;
+      return;
+   }
+
+   // Get a spot to put the pin
+   pkgCache::GrpIterator Grp = Cache->FindGrp(Name);
+   for (pkgCache::PkgIterator Pkg = Grp.FindPkg("any");
+	Pkg.end() != true; Pkg = Grp.NextPkg(Pkg))
+   {
+      Pin *P = 0;
+      if (Pkg.end() == false)
+	 P = Pins + Pkg->ID;
+      else
       {
       {
 	 // Check the unmatched table
 	 // Check the unmatched table
-	 for (vector<PkgPin>::iterator I = Unmatched.begin(); 
+	 for (vector<PkgPin>::iterator I = Unmatched.begin();
 	      I != Unmatched.end() && P == 0; I++)
 	      I != Unmatched.end() && P == 0; I++)
 	    if (I->Pkg == Name)
 	    if (I->Pkg == Name)
 	       P = &*I;
 	       P = &*I;
-	 
+
 	 if (P == 0)
 	 if (P == 0)
-	    P = &*Unmatched.insert(Unmatched.end(),PkgPin());      
+	    P = &*Unmatched.insert(Unmatched.end(),PkgPin());
       }
       }
-      else
-      {
-	 P = Pins + Pkg->ID;
-      }      
+      P->Type = Type;
+      P->Priority = Priority;
+      P->Data = Data;
    }
    }
-   
-   // Set..
-   P->Type = Type;
-   P->Priority = Priority;
-   P->Data = Data;
 }
 }
 									/*}}}*/
 									/*}}}*/
 // Policy::GetMatch - Get the matching version for a package pin	/*{{{*/
 // Policy::GetMatch - Get the matching version for a package pin	/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /* */
 /* */
-pkgCache::VerIterator pkgPolicy::GetMatch(pkgCache::PkgIterator Pkg)
+pkgCache::VerIterator pkgPolicy::GetMatch(pkgCache::PkgIterator const &Pkg)
 {
 {
    const Pin &PPkg = Pins[Pkg->ID];
    const Pin &PPkg = Pins[Pkg->ID];
-   if (PPkg.Type != pkgVersionMatch::None)
-   {
-      pkgVersionMatch Match(PPkg.Data,PPkg.Type);
-      return Match.Find(Pkg);
-   }
-   return pkgCache::VerIterator(*Pkg.Cache());
+   if (PPkg.Type == pkgVersionMatch::None)
+      return pkgCache::VerIterator(*Pkg.Cache());
+
+   pkgVersionMatch Match(PPkg.Data,PPkg.Type);
+   return Match.Find(Pkg);
 }
 }
 									/*}}}*/
 									/*}}}*/
 // Policy::GetPriority - Get the priority of the package pin		/*{{{*/
 // Policy::GetPriority - Get the priority of the package pin		/*{{{*/
@@ -288,9 +301,9 @@ bool ReadPinDir(pkgPolicy &Plcy,string Dir)
    if (Dir.empty() == true)
    if (Dir.empty() == true)
       Dir = _config->FindDir("Dir::Etc::PreferencesParts");
       Dir = _config->FindDir("Dir::Etc::PreferencesParts");
 
 
-   if (FileExists(Dir) == false)
+   if (DirectoryExists(Dir) == false)
    {
    {
-      _error->WarningE("FileExists",_("Unable to read %s"),Dir.c_str());
+      _error->WarningE("DirectoryExists",_("Unable to read %s"),Dir.c_str());
       return true;
       return true;
    }
    }
 
 

+ 3 - 3
apt-pkg/policy.h

@@ -72,11 +72,11 @@ class pkgPolicy : public pkgDepCache::Policy
    inline signed short GetPriority(pkgCache::PkgFileIterator const &File) 
    inline signed short GetPriority(pkgCache::PkgFileIterator const &File) 
        {return PFPriority[File->ID];};
        {return PFPriority[File->ID];};
    signed short GetPriority(pkgCache::PkgIterator const &Pkg);
    signed short GetPriority(pkgCache::PkgIterator const &Pkg);
-   pkgCache::VerIterator GetMatch(pkgCache::PkgIterator Pkg);
+   pkgCache::VerIterator GetMatch(pkgCache::PkgIterator const &Pkg);
 
 
    // Things for the cache interface.
    // Things for the cache interface.
-   virtual pkgCache::VerIterator GetCandidateVer(pkgCache::PkgIterator Pkg);
-   virtual bool IsImportantDep(pkgCache::DepIterator Dep) {return pkgDepCache::Policy::IsImportantDep(Dep);};
+   virtual pkgCache::VerIterator GetCandidateVer(pkgCache::PkgIterator const &Pkg);
+   virtual bool IsImportantDep(pkgCache::DepIterator const &Dep) {return pkgDepCache::Policy::IsImportantDep(Dep);};
    bool InitDefaults();
    bool InitDefaults();
    
    
    pkgPolicy(pkgCache *Owner);
    pkgPolicy(pkgCache *Owner);

+ 56 - 40
apt-pkg/sourcelist.cc

@@ -72,13 +72,58 @@ bool pkgSourceList::Type::FixupURI(string &URI) const
    Weird types may override this. */
    Weird types may override this. */
 bool pkgSourceList::Type::ParseLine(vector<metaIndex *> &List,
 bool pkgSourceList::Type::ParseLine(vector<metaIndex *> &List,
 				    const char *Buffer,
 				    const char *Buffer,
-				    unsigned long CurLine,
-				    string File) const
+				    unsigned long const &CurLine,
+				    string const &File) const
 {
 {
+   for (;Buffer != 0 && isspace(*Buffer); ++Buffer); // Skip whitespaces
+
+   // Parse option field if it exists
+   // e.g.: [ option1=value1 option2=value2 ]
+   map<string, string> Options;
+   if (Buffer != 0 && Buffer[0] == '[')
+   {
+      ++Buffer; // ignore the [
+      for (;Buffer != 0 && isspace(*Buffer); ++Buffer); // Skip whitespaces
+      while (*Buffer != ']')
+      {
+	 // get one option, e.g. option1=value1
+	 string option;
+	 if (ParseQuoteWord(Buffer,option) == false)
+	    return _error->Error(_("Malformed line %lu in source list %s ([option] unparseable)"),CurLine,File.c_str());
+
+	 if (option.length() < 3)
+	    return _error->Error(_("Malformed line %lu in source list %s ([option] too short)"),CurLine,File.c_str());
+
+	 // accept options even if the last has no space before the ]-end marker
+	 if (option.at(option.length()-1) == ']')
+	 {
+	    for (; *Buffer != ']'; --Buffer);
+	    option.resize(option.length()-1);
+	 }
+
+	 size_t const needle = option.find('=');
+	 if (needle == string::npos)
+	    return _error->Error(_("Malformed line %lu in source list %s ([%s] is not an assignment)"),CurLine,File.c_str(), option.c_str());
+
+	 string const key = string(option, 0, needle);
+	 string const value = string(option, needle + 1, option.length());
+
+	 if (key.empty() == true)
+	    return _error->Error(_("Malformed line %lu in source list %s ([%s] has no key)"),CurLine,File.c_str(), option.c_str());
+
+	 if (value.empty() == true)
+	    return _error->Error(_("Malformed line %lu in source list %s ([%s] key %s has no value)"),CurLine,File.c_str(),option.c_str(),key.c_str());
+
+	 Options[key] = value;
+      }
+      ++Buffer; // ignore the ]
+      for (;Buffer != 0 && isspace(*Buffer); ++Buffer); // Skip whitespaces
+   }
+
    string URI;
    string URI;
    string Dist;
    string Dist;
-   string Section;   
-   
+   string Section;
+
    if (ParseQuoteWord(Buffer,URI) == false)
    if (ParseQuoteWord(Buffer,URI) == false)
       return _error->Error(_("Malformed line %lu in source list %s (URI)"),CurLine,File.c_str());
       return _error->Error(_("Malformed line %lu in source list %s (URI)"),CurLine,File.c_str());
    if (ParseQuoteWord(Buffer,Dist) == false)
    if (ParseQuoteWord(Buffer,Dist) == false)
@@ -93,7 +138,7 @@ bool pkgSourceList::Type::ParseLine(vector<metaIndex *> &List,
       if (ParseQuoteWord(Buffer,Section) == true)
       if (ParseQuoteWord(Buffer,Section) == true)
 	 return _error->Error(_("Malformed line %lu in source list %s (absolute dist)"),CurLine,File.c_str());
 	 return _error->Error(_("Malformed line %lu in source list %s (absolute dist)"),CurLine,File.c_str());
       Dist = SubstVar(Dist,"$(ARCH)",_config->Find("APT::Architecture"));
       Dist = SubstVar(Dist,"$(ARCH)",_config->Find("APT::Architecture"));
-      return CreateItem(List,URI,Dist,Section);
+      return CreateItem(List, URI, Dist, Section, Options);
    }
    }
    
    
    // Grab the rest of the dists
    // Grab the rest of the dists
@@ -102,7 +147,7 @@ bool pkgSourceList::Type::ParseLine(vector<metaIndex *> &List,
    
    
    do
    do
    {
    {
-      if (CreateItem(List,URI,Dist,Section) == false)
+      if (CreateItem(List, URI, Dist, Section, Options) == false)
 	 return false;
 	 return false;
    }
    }
    while (ParseQuoteWord(Buffer,Section) == true);
    while (ParseQuoteWord(Buffer,Section) == true);
@@ -154,15 +199,15 @@ bool pkgSourceList::ReadMainList()
    
    
    if (FileExists(Main) == true)
    if (FileExists(Main) == true)
       Res &= ReadAppend(Main);
       Res &= ReadAppend(Main);
-   else if (FileExists(Parts) == false)
+   else if (DirectoryExists(Parts) == false)
       // Only warn if there are no sources.list.d.
       // Only warn if there are no sources.list.d.
-      _error->WarningE("FileExists",_("Unable to read %s"),Main.c_str());
+      _error->WarningE("DirectoryExists", _("Unable to read %s"), Parts.c_str());
 
 
-   if (FileExists(Parts) == true)
+   if (DirectoryExists(Parts) == true)
       Res &= ReadSourceDir(Parts);
       Res &= ReadSourceDir(Parts);
    else if (FileExists(Main) == false)
    else if (FileExists(Main) == false)
       // Only warn if there is no sources.list file.
       // Only warn if there is no sources.list file.
-      _error->WarningE("FileExists",_("Unable to read %s"),Parts.c_str());
+      _error->WarningE("FileExists", _("Unable to read %s"), Main.c_str());
 
 
    return Res;
    return Res;
 }
 }
@@ -239,36 +284,7 @@ bool pkgSourceList::ReadAppend(string File)
       if (Parse == 0)
       if (Parse == 0)
 	 return _error->Error(_("Type '%s' is not known on line %u in source list %s"),LineType.c_str(),CurLine,File.c_str());
 	 return _error->Error(_("Type '%s' is not known on line %u in source list %s"),LineType.c_str(),CurLine,File.c_str());
       
       
-      // Vendor name specified
-      if (C[0] == '[')
-      {
-	 string VendorID;
-	 
-	 if (ParseQuoteWord(C,VendorID) == false)
-	     return _error->Error(_("Malformed line %u in source list %s (vendor id)"),CurLine,File.c_str());
-
-	 if (VendorID.length() < 2 || VendorID.end()[-1] != ']')
-	     return _error->Error(_("Malformed line %u in source list %s (vendor id)"),CurLine,File.c_str());
-	 VendorID = string(VendorID,1,VendorID.size()-2);
-	 
-// 	 for (vector<const Vendor *>::const_iterator iter = VendorList.begin();
-// 	      iter != VendorList.end(); iter++) 
-// 	 {
-// 	    if ((*iter)->GetVendorID() == VendorID)
-// 	    {
-// 	      if (_config->FindB("Debug::sourceList", false)) 
-// 		std::cerr << "Comparing VendorID \"" << VendorID << "\" with \"" << (*iter)->GetVendorID() << '"' << std::endl;
-// 	       Verifier = *iter;
-// 	       break;
-// 	    }
-// 	 }
-
-// 	 if (Verifier == 0)
-// 	    return _error->Error(_("Unknown vendor ID '%s' in line %u of source list %s"),
-// 				 VendorID.c_str(),CurLine,File.c_str());
-      }
-
-      if (Parse->ParseLine(SrcList,C,CurLine,File) == false)
+      if (Parse->ParseLine(SrcList, C, CurLine, File) == false)
 	 return false;
 	 return false;
    }
    }
    return true;
    return true;

+ 5 - 3
apt-pkg/sourcelist.h

@@ -29,6 +29,7 @@
 
 
 #include <string>
 #include <string>
 #include <vector>
 #include <vector>
+#include <map>
 #include <apt-pkg/pkgcache.h>
 #include <apt-pkg/pkgcache.h>
 #include <apt-pkg/metaindex.h>
 #include <apt-pkg/metaindex.h>
 
 
@@ -57,9 +58,10 @@ class pkgSourceList
       bool FixupURI(string &URI) const;
       bool FixupURI(string &URI) const;
       virtual bool ParseLine(vector<metaIndex *> &List,
       virtual bool ParseLine(vector<metaIndex *> &List,
 			     const char *Buffer,
 			     const char *Buffer,
-			     unsigned long CurLine,string File) const;
-      virtual bool CreateItem(vector<metaIndex *> &List,string URI,
-			      string Dist,string Section) const = 0;
+			     unsigned long const &CurLine,string const &File) const;
+      virtual bool CreateItem(vector<metaIndex *> &List,string const &URI,
+			      string const &Dist,string const &Section,
+			      std::map<string, string> const &Options) const = 0;
       Type();
       Type();
       virtual ~Type() {};
       virtual ~Type() {};
    };
    };

+ 28 - 11
apt-pkg/tagfile.cc

@@ -193,17 +193,8 @@ bool pkgTagFile::Jump(pkgTagSection &Tag,unsigned long Offset)
 									/*}}}*/
 									/*}}}*/
 // TagSection::Scan - Scan for the end of the header information	/*{{{*/
 // TagSection::Scan - Scan for the end of the header information	/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
-/* This looks for the first double new line in the data stream. It also
-   indexes the tags in the section. This very simple hash function for the
-   last 8 letters gives very good performance on the debian package files */
-inline static unsigned long AlphaHash(const char *Text, const char *End = 0)
-{
-   unsigned long Res = 0;
-   for (; Text != End && *Text != ':' && *Text != 0; Text++)
-      Res = ((unsigned long)(*Text) & 0xDF) ^ (Res << 1);
-   return Res & 0xFF;
-}
-
+/* This looks for the first double new line in the data stream.
+   It also indexes the tags in the section. */
 bool pkgTagSection::Scan(const char *Start,unsigned long MaxLength)
 bool pkgTagSection::Scan(const char *Start,unsigned long MaxLength)
 {
 {
    const char *End = Start + MaxLength;
    const char *End = Start + MaxLength;
@@ -374,6 +365,30 @@ signed int pkgTagSection::FindI(const char *Tag,signed long Default) const
    return Result;
    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			/*{{{*/
 // TagSection::FindFlag - Locate a yes/no type flag			/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /* The bits marked in Flag are masked on/off in Flags */
 /* The bits marked in Flag are masked on/off in Flags */
@@ -418,6 +433,7 @@ static const char *iTFRewritePackageOrder[] = {
                           "Section",
                           "Section",
                           "Installed-Size",
                           "Installed-Size",
                           "Maintainer",
                           "Maintainer",
+                          "Original-Maintainer",
                           "Architecture",
                           "Architecture",
                           "Source",
                           "Source",
                           "Version",
                           "Version",
@@ -447,6 +463,7 @@ static const char *iTFRewriteSourceOrder[] = {"Package",
                                       "Priority",
                                       "Priority",
                                       "Section",
                                       "Section",
                                       "Maintainer",
                                       "Maintainer",
+				      "Original-Maintainer",
                                       "Build-Depends",
                                       "Build-Depends",
                                       "Build-Depends-Indep",
                                       "Build-Depends-Indep",
                                       "Build-Conflicts",
                                       "Build-Conflicts",

+ 15 - 1
apt-pkg/tagfile.h

@@ -33,7 +33,18 @@ class pkgTagSection
    unsigned int AlphaIndexes[0x100];
    unsigned int AlphaIndexes[0x100];
    
    
    unsigned int TagCount;
    unsigned int TagCount;
-     
+
+   /* This very simple hash function for the last 8 letters gives
+      very good performance on the debian package files */
+   inline static unsigned long AlphaHash(const char *Text, const char *End = 0)
+   {
+      unsigned long Res = 0;
+      for (; Text != End && *Text != ':' && *Text != 0; Text++)
+	 Res = ((unsigned long)(*Text) & 0xDF) ^ (Res << 1);
+      return Res & 0xFF;
+   }
+
+
    protected:
    protected:
    const char *Stop;
    const char *Stop;
 
 
@@ -46,6 +57,7 @@ class pkgTagSection
    bool Find(const char *Tag,unsigned &Pos) const;
    bool Find(const char *Tag,unsigned &Pos) const;
    string FindS(const char *Tag) const;
    string FindS(const char *Tag) const;
    signed int FindI(const char *Tag,signed long Default = 0) 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,
    bool FindFlag(const char *Tag,unsigned long &Flags,
 		 unsigned long Flag) const;
 		 unsigned long Flag) const;
    bool Scan(const char *Start,unsigned long MaxLength);
    bool Scan(const char *Start,unsigned long MaxLength);
@@ -54,6 +66,8 @@ class pkgTagSection
    virtual void TrimRecord(bool BeforeRecord, const char* &End);
    virtual void TrimRecord(bool BeforeRecord, const char* &End);
    
    
    inline unsigned int Count() const {return TagCount;};
    inline unsigned int Count() const {return TagCount;};
+   inline bool Exists(const char* const Tag) {return AlphaIndexes[AlphaHash(Tag)] != 0;}
+ 
    inline void Get(const char *&Start,const char *&Stop,unsigned int I) const
    inline void Get(const char *&Start,const char *&Stop,unsigned int I) const
                    {Start = Section + Indexes[I]; Stop = Section + Indexes[I+1];}
                    {Start = Section + Indexes[I]; Stop = Section + Indexes[I+1];}
 	    
 	    

+ 54 - 12
apt-pkg/versionmatch.cc

@@ -18,6 +18,10 @@
 
 
 #include <stdio.h>
 #include <stdio.h>
 #include <ctype.h>
 #include <ctype.h>
+#include <fnmatch.h>
+#include <sys/types.h>
+#include <regex.h>
+
 									/*}}}*/
 									/*}}}*/
 
 
 // VersionMatch::pkgVersionMatch - Constructor				/*{{{*/
 // VersionMatch::pkgVersionMatch - Constructor				/*{{{*/
@@ -100,6 +104,8 @@ pkgVersionMatch::pkgVersionMatch(string Data,MatchType Type) : Type(Type)
 	    RelLabel = Fragments[J]+2;
 	    RelLabel = Fragments[J]+2;
 	 else if (stringcasecmp(Fragments[J],Fragments[J]+2,"c=") == 0)
 	 else if (stringcasecmp(Fragments[J],Fragments[J]+2,"c=") == 0)
 	    RelComponent = Fragments[J]+2;
 	    RelComponent = Fragments[J]+2;
+	 else if (stringcasecmp(Fragments[J],Fragments[J]+2,"b=") == 0)
+	    RelArchitecture = Fragments[J]+2;
       }
       }
 
 
       if (RelVerStr.end()[-1] == '*')
       if (RelVerStr.end()[-1] == '*')
@@ -149,6 +155,8 @@ pkgCache::VerIterator pkgVersionMatch::Find(pkgCache::PkgIterator Pkg)
       {
       {
 	 if (MatchVer(Ver.VerStr(),VerStr,VerPrefixMatch) == true)
 	 if (MatchVer(Ver.VerStr(),VerStr,VerPrefixMatch) == true)
 	    return Ver;
 	    return Ver;
+	 if (ExpressionMatches(VerStr, Ver.VerStr()) == true)
+	    return Ver;
 	 continue;
 	 continue;
       }
       }
       
       
@@ -160,6 +168,36 @@ pkgCache::VerIterator pkgVersionMatch::Find(pkgCache::PkgIterator Pkg)
    // This will be Ended by now.
    // This will be Ended by now.
    return Ver;
    return Ver;
 }
 }
+
+#ifndef FNM_CASEFOLD
+#define FNM_CASEFOLD 0
+#endif
+
+bool pkgVersionMatch::ExpressionMatches(const char *pattern, const char *string)
+{
+   if (pattern[0] == '/') {
+      bool res = false;
+      size_t length = strlen(pattern);
+      if (pattern[length - 1] == '/') {
+	 regex_t preg;
+	 char *regex = strdup(pattern + 1);
+	 regex[length - 2] = '\0';
+	 if (regcomp(&preg, regex, REG_EXTENDED | REG_ICASE) != 0) {
+	    _error->Warning("Invalid regular expression: %s", regex);
+	 } else if (regexec(&preg, string, 0, NULL, 0) == 0) {
+	    res = true;
+	 }
+	 free(regex);
+	 regfree(&preg);
+	 return res;
+      }
+   }
+   return fnmatch(pattern, string, FNM_CASEFOLD) == 0;
+}
+bool pkgVersionMatch::ExpressionMatches(const std::string& pattern, const char *string)
+{
+    return ExpressionMatches(pattern.c_str(), string);
+}
 									/*}}}*/
 									/*}}}*/
 // VersionMatch::FileMatch - Match against an index file		/*{{{*/
 // VersionMatch::FileMatch - Match against an index file		/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
@@ -178,38 +216,42 @@ bool pkgVersionMatch::FileMatch(pkgCache::PkgFileIterator File)
       if (RelVerStr.empty() == true && RelOrigin.empty() == true &&
       if (RelVerStr.empty() == true && RelOrigin.empty() == true &&
 	  RelArchive.empty() == true && RelLabel.empty() == true &&
 	  RelArchive.empty() == true && RelLabel.empty() == true &&
 	  RelRelease.empty() == true && RelCodename.empty() == true &&
 	  RelRelease.empty() == true && RelCodename.empty() == true &&
-	  RelComponent.empty() == true)
+	  RelComponent.empty() == true && RelArchitecture.empty() == true)
 	 return false;
 	 return false;
 
 
       if (RelVerStr.empty() == false)
       if (RelVerStr.empty() == false)
 	 if (File->Version == 0 ||
 	 if (File->Version == 0 ||
-	     MatchVer(File.Version(),RelVerStr,RelVerPrefixMatch) == false)
+	     (MatchVer(File.Version(),RelVerStr,RelVerPrefixMatch) == false &&
+	      ExpressionMatches(RelVerStr, File.Version()) == false))
 	    return false;
 	    return false;
       if (RelOrigin.empty() == false)
       if (RelOrigin.empty() == false)
-	 if (File->Origin == 0 ||
-	     stringcasecmp(RelOrigin,File.Origin()) != 0)
+	 if (File->Origin == 0 || !ExpressionMatches(RelOrigin,File.Origin()))
 	    return false;
 	    return false;
       if (RelArchive.empty() == false)
       if (RelArchive.empty() == false)
 	 if (File->Archive == 0 ||
 	 if (File->Archive == 0 ||
-	     stringcasecmp(RelArchive,File.Archive()) != 0)
+	     !ExpressionMatches(RelArchive,File.Archive()))
             return false;
             return false;
       if (RelCodename.empty() == false)
       if (RelCodename.empty() == false)
 	 if (File->Codename == 0 ||
 	 if (File->Codename == 0 ||
-	     stringcasecmp(RelCodename,File.Codename()) != 0)
+	     !ExpressionMatches(RelCodename,File.Codename()))
             return false;
             return false;
       if (RelRelease.empty() == false)
       if (RelRelease.empty() == false)
 	 if ((File->Archive == 0 ||
 	 if ((File->Archive == 0 ||
-	     stringcasecmp(RelRelease,File.Archive()) != 0) &&
+	     !ExpressionMatches(RelRelease,File.Archive())) &&
              (File->Codename == 0 ||
              (File->Codename == 0 ||
-	      stringcasecmp(RelRelease,File.Codename()) != 0))
+	      !ExpressionMatches(RelRelease,File.Codename())))
 	       return false;
 	       return false;
       if (RelLabel.empty() == false)
       if (RelLabel.empty() == false)
 	 if (File->Label == 0 ||
 	 if (File->Label == 0 ||
-	     stringcasecmp(RelLabel,File.Label()) != 0)
+	     !ExpressionMatches(RelLabel,File.Label()))
 	    return false;
 	    return false;
       if (RelComponent.empty() == false)
       if (RelComponent.empty() == false)
 	 if (File->Component == 0 ||
 	 if (File->Component == 0 ||
-	     stringcasecmp(RelComponent,File.Component()) != 0)
+	     !ExpressionMatches(RelComponent,File.Component()))
+	    return false;
+      if (RelArchitecture.empty() == false)
+	 if (File->Architecture == 0 ||
+	     !ExpressionMatches(RelArchitecture,File.Architecture()))
 	    return false;
 	    return false;
       return true;
       return true;
    }
    }
@@ -217,12 +259,12 @@ bool pkgVersionMatch::FileMatch(pkgCache::PkgFileIterator File)
    if (Type == Origin)
    if (Type == Origin)
    {
    {
       if (OrSite.empty() == false) {
       if (OrSite.empty() == false) {
-	 if (File->Site == 0 || OrSite != File.Site())
+	 if (File->Site == 0 || !ExpressionMatches(OrSite, File.Site()))
 	    return false;
 	    return false;
       } else // so we are talking about file:// or status file
       } else // so we are talking about file:// or status file
 	 if (strcmp(File.Site(),"") == 0 && File->Archive != 0) // skip the status file
 	 if (strcmp(File.Site(),"") == 0 && File->Archive != 0) // skip the status file
 	    return false;
 	    return false;
-      return (OrSite == File.Site());		/* both strings match */
+      return (ExpressionMatches(OrSite, File.Site())); /* both strings match */
    }
    }
 
 
    return false;
    return false;

+ 4 - 0
apt-pkg/versionmatch.h

@@ -23,6 +23,7 @@
       Codename (n=) e.g. etch, lenny, squeeze, sid
       Codename (n=) e.g. etch, lenny, squeeze, sid
       Label (l=)
       Label (l=)
       Component (c=)
       Component (c=)
+      Binary Architecture (b=)
    If there are no equals signs in the string then it is scanned in short
    If there are no equals signs in the string then it is scanned in short
    form - if it starts with a number it is Version otherwise it is an
    form - if it starts with a number it is Version otherwise it is an
    Archive or a Codename.
    Archive or a Codename.
@@ -55,6 +56,7 @@ class pkgVersionMatch
    string RelArchive;
    string RelArchive;
    string RelLabel;
    string RelLabel;
    string RelComponent;
    string RelComponent;
+   string RelArchitecture;
    bool MatchAll;
    bool MatchAll;
    
    
    // Origin Matching
    // Origin Matching
@@ -65,6 +67,8 @@ class pkgVersionMatch
    enum MatchType {None = 0,Version,Release,Origin} Type;
    enum MatchType {None = 0,Version,Release,Origin} Type;
    
    
    bool MatchVer(const char *A,string B,bool Prefix);
    bool MatchVer(const char *A,string B,bool Prefix);
+   bool ExpressionMatches(const char *pattern, const char *string);
+   bool ExpressionMatches(const std::string& pattern, const char *string);
    bool FileMatch(pkgCache::PkgFileIterator File);
    bool FileMatch(pkgCache::PkgFileIterator File);
    pkgCache::VerIterator Find(pkgCache::PkgIterator Pkg);
    pkgCache::VerIterator Find(pkgCache::PkgIterator Pkg);
 			       
 			       

Разлика између датотеке није приказан због своје велике величине
+ 489 - 499
cmdline/apt-cache.cc


+ 7 - 9
cmdline/apt-cdrom.cc

@@ -147,7 +147,7 @@ bool DoAdd(CommandLine &)
    pkgCdrom cdrom;
    pkgCdrom cdrom;
    bool res = true;
    bool res = true;
 
 
-   bool AutoDetect = _config->FindB("Acquire::cdrom::AutoDetect");
+   bool AutoDetect = _config->FindB("Acquire::cdrom::AutoDetect", true);
    unsigned int count = 0;
    unsigned int count = 0;
    
    
    if (AutoDetect && UdevCdroms.Dlopen())
    if (AutoDetect && UdevCdroms.Dlopen())
@@ -266,20 +266,18 @@ int main(int argc,const char *argv[])					/*{{{*/
       return ShowHelp();
       return ShowHelp();
 
 
    // Deal with stdout not being a tty
    // Deal with stdout not being a tty
-   if (isatty(STDOUT_FILENO) && _config->FindI("quiet",0) < 1)
+   if (isatty(STDOUT_FILENO) && _config->FindI("quiet", -1) == -1)
       _config->Set("quiet","1");
       _config->Set("quiet","1");
    
    
    // Match the operation
    // Match the operation
    CmdL.DispatchArg(Cmds);
    CmdL.DispatchArg(Cmds);
 
 
    // Print any errors or warnings found during parsing
    // Print any errors or warnings found during parsing
-   if (_error->empty() == false)
-   {
-      bool Errors = _error->PendingError();
+   bool const Errors = _error->PendingError();
+   if (_config->FindI("quiet",0) > 0)
       _error->DumpErrors();
       _error->DumpErrors();
-      return Errors == true?100:0;
-   }
-   
-   return 0;
+   else
+      _error->DumpErrors(GlobalError::DEBUG);
+   return Errors == true ? 100 : 0;
 }
 }
 									/*}}}*/
 									/*}}}*/

+ 1 - 2
cmdline/apt-extracttemplates.cc

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

Разлика између датотеке није приказан због своје велике величине
+ 542 - 480
cmdline/apt-get.cc


+ 6 - 1
cmdline/apt-mark

@@ -8,7 +8,7 @@ import os.path
 try:
 try:
     import apt_pkg
     import apt_pkg
 except ImportError:
 except ImportError:
-    print "Error importing apt_pkg, is python-apt installed?"
+    print >> sys.stderr, "Error importing apt_pkg, is python-apt installed?"
     sys.exit(1)
     sys.exit(1)
     
     
 actions = { "markauto" : 1,
 actions = { "markauto" : 1,
@@ -68,6 +68,7 @@ if __name__ == "__main__":
     # option parsing
     # option parsing
     parser = OptionParser()
     parser = OptionParser()
     parser.usage = "%prog [options] {markauto|unmarkauto} packages..."
     parser.usage = "%prog [options] {markauto|unmarkauto} packages..."
+    parser.epilog = "apt-mark is deprecated, use apt-get markauto/unmarkauto."
     parser.add_option("-f", "--file", action="store", type="string",
     parser.add_option("-f", "--file", action="store", type="string",
                       dest="filename",
                       dest="filename",
                       help="read/write a different file")
                       help="read/write a different file")
@@ -76,6 +77,10 @@ if __name__ == "__main__":
                       help="print verbose status messages to stdout")
                       help="print verbose status messages to stdout")
     (options, args) = parser.parse_args()
     (options, args) = parser.parse_args()
 
 
+    if not args:
+        parser.print_help()
+        sys.exit(1)
+
     # get the state-file
     # get the state-file
     if not options.filename:
     if not options.filename:
         STATE_FILE = apt_pkg.config.find_dir("Dir::State") + "extended_states"
         STATE_FILE = apt_pkg.config.find_dir("Dir::State") + "extended_states"

+ 29 - 0
cmdline/apt-report-mirror-failure

@@ -0,0 +1,29 @@
+#!/usr/bin/python
+#
+# This is a stub that is meant to support failure reporting of 
+# mirrors to a central database
+#
+# its currently not used
+
+import sys
+import urllib
+import apt_pkg
+
+apt_pkg.init()
+url = apt_pkg.Config.find("Acquire::Mirror::ReportFailures", "")
+                          #"http://people.ubuntu.com:9000/mirror-failure")
+                          #"http://localhost:9000/mirror-failure")
+if not url:
+    sys.exit(0)
+
+print "Reporting mirror failure to '%s'" % url
+
+data = {}
+data['mirror'] = sys.argv[1]
+data['failurl'] = sys.argv[2]
+data['error'] = sys.argv[3]
+f = urllib.urlopen(url, urllib.urlencode(data))
+f.read()
+f.close()
+
+

+ 6 - 0
cmdline/makefile

@@ -58,3 +58,9 @@ SOURCE=apt-mark
 TO=$(BIN)
 TO=$(BIN)
 TARGET=program
 TARGET=program
 include $(COPY_H)
 include $(COPY_H)
+
+# The apt-report-mirror-failure program
+#SOURCE=apt-report-mirror-failure
+#TO=$(BIN)
+#TARGET=program
+#include $(COPY_H)

+ 5 - 1
configure.in

@@ -18,7 +18,7 @@ AC_CONFIG_AUX_DIR(buildlib)
 AC_CONFIG_HEADER(include/config.h:buildlib/config.h.in include/apti18n.h:buildlib/apti18n.h.in)
 AC_CONFIG_HEADER(include/config.h:buildlib/config.h.in include/apti18n.h:buildlib/apti18n.h.in)
 
 
 dnl -- SET THIS TO THE RELEASE VERSION --
 dnl -- SET THIS TO THE RELEASE VERSION --
-AC_DEFINE_UNQUOTED(VERSION,"0.7.25.4")
+AC_DEFINE_UNQUOTED(VERSION,"0.7.26~exp6")
 PACKAGE="apt"
 PACKAGE="apt"
 AC_DEFINE_UNQUOTED(PACKAGE,"$PACKAGE")
 AC_DEFINE_UNQUOTED(PACKAGE,"$PACKAGE")
 AC_SUBST(PACKAGE)
 AC_SUBST(PACKAGE)
@@ -83,6 +83,10 @@ AC_CHECK_LIB(curl, curl_easy_init,
 
 
 AC_SUBST(BDBLIB)
 AC_SUBST(BDBLIB)
 
 
+AC_CHECK_LIB(z, gzopen,
+	[AC_CHECK_HEADER(zlib.h, [], AC_MSG_ERROR([failed: zlib.h not found]))],
+	AC_MSG_ERROR([failed: Need libz]))
+
 dnl Converts the ARCH to be something singular for this general CPU family
 dnl Converts the ARCH to be something singular for this general CPU family
 dnl This is often the dpkg architecture string.
 dnl This is often the dpkg architecture string.
 dnl First check against the full canonical canoncial-system-type in $target
 dnl First check against the full canonical canoncial-system-type in $target

+ 2 - 1
debian/apt-doc.docs

@@ -1 +1,2 @@
-README.progress-reporting
+README.progress-reporting
+README.MultiArch

+ 19 - 4
debian/apt.conf.autoremove

@@ -1,9 +1,24 @@
 APT
 APT
 {
 {
-  NeverAutoRemove  
-  { 
-	"^linux-image.*";  
+  NeverAutoRemove
+  {
+	"^firmware-linux.*";
+	"^linux-firmware$";
+	"^linux-image.*";
+	"^kfreebsd-image.*";
 	"^linux-restricted-modules.*";
 	"^linux-restricted-modules.*";
-	"^kfreebsd-image.*";  
+	"^linux-ubuntu-modules-.*";
+  };
+
+  Never-MarkAuto-Sections
+  {
+	"metapackages";
+	"restricted/metapackages";
+	"universe/metapackages";
+	"multiverse/metapackages";
+	"oldlibs";
+	"restricted/oldlibs";
+	"universe/oldlibs";
+	"multiverse/oldlibs";
   };
   };
 };
 };

+ 1 - 0
debian/apt.dirs

@@ -9,6 +9,7 @@ etc/apt/trusted.gpg.d
 etc/logrotate.d
 etc/logrotate.d
 var/cache/apt/archives/partial
 var/cache/apt/archives/partial
 var/lib/apt/lists/partial
 var/lib/apt/lists/partial
+var/lib/apt/mirrors/partial
 var/lib/apt/periodic
 var/lib/apt/periodic
 var/log/apt
 var/log/apt
 usr/share/bug/apt
 usr/share/bug/apt

+ 489 - 14
debian/changelog

@@ -1,15 +1,420 @@
-apt (0.7.26~exp5) UNRELEASED; urgency=low
+apt (0.8.0~pre1) unstable; urgency=low
 
 
+  * merge of the debian-expermental-ma branch
+    
+
+ -- Michael Vogt <mvo@debian.org>  Fri, 30 Jul 2010 12:42:57 +0200
+
+apt (0.7.26~exp12) experimental; urgency=low
+
+  [ Michael Vogt ]
+  * debian/control:
+    - add dependency on zlib-dev for libapt-pkg-dev
+
+  [ David Kalnischkies ]
+  * apt-pkg/cacheset.cc:
+    - [ABI BREAK] add an ErrorType option to CacheSetHelper
+  * cmdline/apt-cache.cc:
+    - use Notice instead of Error in the CacheSetHelper messages
+      for compat reasons. Otherwise tools like sbuild blow up
+    - return success in show if a virtual package was given
+  * debian/control:
+    - remove libcurl3-gnutls-dev alternative as the package is gone
+    - increase needed version of libcurl4-gnutls-dev to >= 7.19.0
+      as we use CURLOPT_{ISSUERCERT,CRLFILE} (Closes: #589642)
+
+ -- Michael Vogt <mvo@debian.org>  Fri, 30 Jul 2010 11:55:48 +0200
+
+apt (0.7.26~exp11) experimental; urgency=low
+
+  [ Julian Andres Klode ]
+  * apt-pkg/deb/dpkgpm.cc:
+    - Write architecture information to history file.
+    - Add to history whether a change was automatic or not.
+  * apt-pkg/contrib/fileutl.cc:
+    - Add FileFd::OpenDescriptor() (needed for python-apt's #383617).
+  * cmdline/apt-get.cc:
+    - Support large filesystems by using statvfs64() instead of statvfs()
+      and statfs64() instead of statfs() (Closes: #590513).
+  * apt-pkg/cdrom.cc:
+    - Use link() instead of rename() for creating the CD database backup;
+      otherwise there would be a short time without any database.
+
+  [ David Kalnischkies ]
+  * apt-pkg/depcache.cc:
+    - handle "circular" conflicts for "all" packages correctly
+  * cmdline/apt-cache.cc:
+    - be able to omit dependency types in (r)depends (Closes: #319006)
+    - show in (r)depends the canidate per default instead of newest
+    - share the (r)depends code instead of codecopy
+  * apt-pkg/cacheset.cc:
+    - move them back to the library as they look stable now
+    - add a 'newest' pseudo target release as in pkg/newest
+  * apt-pkg/pkgcache.cc:
+    - prefer non-virtual packages in FindPreferredPkg (Closes: #590041)
+  * test/integration/*:
+    - add with bug#590041 testcase a small test "framework"
+  * apt-pkg/orderlist.cc:
+    - try to install another or-group member in DepRemove before
+      breaking the or group (Closes: #590438)
+    - configure also the replacement before remove by adding Immediate flag
+  
+  [ Michael Vogt ]
+  * apt-pkg/contrib/error.{cc,h}
+    - docstring cleanup
+    - add inline DumpError() to avoid subtle API break
+
+ -- Michael Vogt <mvo@debian.org>  Thu, 29 Jul 2010 16:40:58 +0200
+
+apt (0.7.26~exp10) experimental; urgency=low
+
+  [ David Kalnischkies ]
+  * apt-pkg/contrib/error.{cc,h}:
+    - remove constness of va_list parameter to fix build on amd64 and co
+      Thanks Eric Valette! (Closes: #588610)
+  * apt-pkg/deb/debmetaindex.cc:
+    - do not query each architecture for flat file archives
+    - fix typo preventing display of architecture in Info()
+  * methods/bzip2.cc:
+    - add a copycat of the old gzip.cc as we need it for bzip2 and lzma
+
+  [ Martin Pitt ]
+  * debian/rules:
+    - Make DEB_BUILD_OPTIONS=noopt actually work by passing the right
+      CXXFLAGS.
+  * apt-pkg/contrib/fileutl.{h,cc}:
+    - Add support for reading of gzipped files with the new "ReadOnlyGzip"
+      OpenMode. (Closes: #188407)
+    - Link against zlib (in apt-pkg/makefile) and add zlib build dependency.
+    - [ABI BREAK] This adds a new private member to FileFd, but its
+      initialization is in the public header file.
+  * configure.in:
+    - Check for zlib library and headers.
+  * apt-pkg/acquire-item.cc, apt-pkg/deb/debindexfile.cc,
+    apt-pkg/deb/debrecords.cc, apt-pkg/deb/debsrcrecords.h,
+    cmdline/apt-cache.cc:
+    - Open Packages, Sources, and Translations indexes in "ReadOnlyGzip" mode.
+  * apt-pkg/deb/debindexfile.cc:
+    - If we do not find uncompressed package/source/translation indexes, look
+      for gzip compressed ones.
+  * apt-pkg/acquire-item.cc:
+    - If the Acquire::GzipIndexes option is true and we download a gzipped
+      index file, keep it as it is (and rename to .gz) instead of
+      uncompressing it.
+  * doc/apt.conf.5.xml:
+    - Document the new Acquire::GzipIndexes option.
+  * doc/po/apt-doc.pot, doc/po/de.po:
+    - German translation of new Acquire::GzipIndexes option.
+  * Add test/test-indexes.sh:
+    - Test behaviour of index retrieval and usage, in particular with
+      uncompressed and gzip compressed indexes.
+  * methods/gzip.cc: With FileFd now being able to read gzipped files, there
+    is no need for the gzip method any more to spawn an external gzip process.
+    Rewrite it to use FileFd directly, which makes the code a lot simpler, and
+    also using less memory and overhead.
+
+ -- Michael Vogt <mvo@debian.org>  Mon, 12 Jul 2010 11:41:01 +0200
+
+apt (0.7.26~exp9) experimental; urgency=low
+
+  [ David Kalnischkies ]
+  * doc/apt.conf.5.xml:
+    - add and document APT::Cache-{Start,Grow,Limit} options for mmap control
+  * apt-pkg/contrib/fileutl.cc:
+    - do not fail von double close()
+
+ -- Michael Vogt <mvo@debian.org>  Fri, 09 Jul 2010 21:51:55 +0200
+
+apt (0.7.26~exp8) experimental; urgency=low
+
+  [ David Kalnischkies ]
+  * cmdline/cacheset.cc:
+    - doesn't include it in the library for now as it is too volatile
+    - get the candidate either from an already built depcache
+      or use the policy which is a bit faster than depcache generation
+    - get packages by task^ with FromTask()
+    - only print errors if all tries to get a package by string failed
+    - factor out code to get a single package FromName()
+    - check in Grouped* first without modifier interpretation
+  * cmdline/apt-get.cc:
+    - use the cachsets in the install commands
+    - make the specify order of packages irrelevant (Closes: #196021)
+  * apt-pkg/orderlist.cc:
+    - untouched packages are never missing
+  * apt-pkg/packagemanager.cc:
+    - packages that are not touched doesn't need to be unpacked
+  * debian/control:
+    - remove intltool's dependency as it is an ubuntu artefact
+  * apt-pkg/depcache.cc:
+    - SetCandidateVer for all pseudo packages
+    - SetReInstall for the "all" package of a pseudo package
+    - use the new MatchAgainstConfig for the DefaultRootSetFunc
+    - always mark the all package if a pseudo package is marked for install
+  * apt-pkg/contrib/error.{cc,h}:
+    - complete rewrite but use the same API
+    - add NOTICE and DEBUG as new types of a message
+    - add a simple stack handling to be able to delay error handling
+  * apt-pkg/aptconfiguration.cc:
+    - show a deprecation notice for APT::Acquire::Translation
+  * apt-pkg/contrib/configuration.{cc,h}:
+    - add a wrapper to match strings against configurable regex patterns
+  * apt-pkg/contrib/fileutl.cc:
+    - show notice about ignored file instead of being always silent
+    - add a Dir::Ignore-Files-Silently list option to control the notice
+  * apt-pkg/policy.h:
+    - add another round of const& madness as the previous round accidentally
+      NOT overrides the virtual GetCandidateVer() method (Closes: #587725)
+  * apt-pkg/pkgcachegen.{cc,h}:
+    - make the used MMap moveable (and therefore dynamic resizeable) by
+      applying (some) mad pointer magic (Closes: #195018)
+
+  [ Michael Vogt ]
+  * apt-pkg/deb/dpkgpm.cc:
+    - make the apt/term.log output unbuffered (thanks to Matt Zimmerman)
+
+  [ Julian Andres Klode ]
+  * methods/ftp.h:
+    - Handle different logins on the same server (Closes: #586904).
+  * apt-pkg/deb/deblistparser.cc:
+    - Handle architecture wildcards (Closes: #547724).
+  * apt-pkg/versionmatch.cc:
+    - Support matching pins by regular expressions or glob() like patterns,
+      regular expressions have to be put between to slashes; for example,
+      /.*/.
+  * apt-pkg/contrib/fileutl.cc:
+    - Make FileFd replace files atomically in WriteTemp mode (for cache, etc).
+  * debian/control:
+    - Set Standards-Version to 3.9.0
+
+ -- Michael Vogt <mvo@debian.org>  Fri, 09 Jul 2010 19:16:20 +0200
+
+apt (0.7.26~exp7) experimental; urgency=low
+
+  * apt-pkg/cachefile.h:
+    - make pkgPolicy public again, libapt-pkg-perl (and probably
+      others) get unhappy without that
+
+ -- Michael Vogt <mvo@debian.org>  Thu, 10 Jun 2010 15:33:24 +0200
+
+apt (0.7.26~exp6) experimental; urgency=low
+
+  [ Michael Vogt ]
+  * merge the remaining Ubuntu change:
+    - on gpg verification failure warn and restore the last known
+      good state
+    - on failure display the IP of the server (useful for servers
+      that use round robin DNS)
+    - support Original-Maintainer in RewritePackageOrder
+    - enable cdrom autodetection via libudev by default
+    - show message about Vcs in use when apt-get source is run for
+      packages maintained in a Vcs
+    - better support transitional packages with mark auto-installed. 
+      when the transitional package is in "oldlibs" the new package
+      is not marked auto installed (same is true for section
+      metapackages)
+    - provide new "deb mirror://archive.foo/mirrors.list sid main"
+      method expects a list of mirrors (generated on the server e.g.
+      via geoip) and will use that, including cycle on failure
+    - 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
+    - sent Last-Modified header also for Translation files
+  * 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
+  * apt-pkg/policy.cc:
+    - get the candidate right for a not-installed pseudo package if
+      his non-pseudo friend is installed
+  * apt-pkg/indexcopy.cc:
+    - move the gpg codecopy to a new method and use it also in methods/gpgv.cc
+
+ -- Michael Vogt <mvo@debian.org>  Thu, 10 Jun 2010 14:02:22 +0200
+
+apt (0.7.26~exp5) experimental; urgency=low
+
+  [ David Kalnischkies ]
+  * cmdline/apt-get.cc:
+    - rerun dpkg-source in source if --fix-broken is given (Closes: #576752)
+    - don't suggest held packages as they are installed (Closes: #578135)
+    - handle multiple --{tar,diff,dsc}-only options correctly
+    - show at the end of the install process a list of disappeared packages
+  * cmdline/apt-cache.cc:
+    - use GroupCount for package names in stats and add a package struct line
+  * methods/rred.cc:
+    - use the patchfile modification time instead of the one from the
+      "old" file - thanks to Philipp Weis for noticing! (Closes: #571541)
+  * debian/rules:
+    - remove targets referring to CVS or arch as they are useless
+    - use $(CURDIR) instead of $(pwd)
+    - use dpkg-buildflags if available for CXXFLAGS
+  * README.arch:
+    - remove the file completely as it has no use nowadays
+  * apt-pkg/depcache.cc:
+    - be doublesure that the killer query is empty before starting reinstall
+  * methods/gpgv.cc:
+    - remove the keyrings count limit by using vector magic
+  * contrib/mmap.cc:
+    - clarify "MMap reached size limit" error message, thanks Ivan Masár!
+  * doc/apt.ent
+    - add entities for the current oldstable/stable/testing codenames
+  * doc/sources.list.5.xml:
+    - use stable-codename instead of stable in the examples (Closes: #531492)
+  * doc/apt_preferences.5.xml:
+    - adapt some examples here to use current codenames as well
+    - add "NotAutomatic: yes" handling, thanks Osamu Aoki (Closes: #490347)
+  * debian/libapt-pkg-doc.doc-base.cache:
+    - remove yet another reference to the removed cache.sgml
+  * doc/apt-get.8.xml:
+    - do not say explicit target_release_{name,version,codename}, it should
+      be clear by itself and 'man' can break lines again (Closes: #566166)
+    - remove the gnome-apt reference as it is removed from unstable
+  * apt-pkg/deb/dpkgpm.cc:
+    - add 'disappear' to the known processing states, thanks Jonathan Nieder
+  * apt-pkg/packagemanager.h:
+    - export info about disappeared packages with GetDisappearedPackages()
+
+  [ Michael Vogt ]
+  * methods/http.{cc,h}:
+    - code cleanup, use enums instead of magic ints
+  
+  [ Jari Aalto ]
+  * debian/rules:
+    - spell out some less known options to reduce manpage consultation-rate
+    - Use POSIX command substitution: $(<command sequence>)
+    - Remove EOL whitespace (Closes: #577804)
+
+  [ Julian Andres Klode ]
+  * apt-pkg/acquire-item.cc:
+    - Fix pkgAcqFile::Custom600Headers() to always return something.
+  
+
+  [ Christian Perrier ]
   * Slovak translation update. Closes: #581159
   * Slovak translation update. Closes: #581159
   * Italian translation update. Closes: #581742
   * Italian translation update. Closes: #581742
 
 
- -- Christian Perrier <bubulle@debian.org>  Tue, 11 May 2010 19:52:00 +0200
+ -- Michael Vogt <mvo@debian.org>  Tue, 25 May 2010 16:01:42 +0200
+
+apt (0.7.26~exp4) experimental; urgency=low
+
+  [ David Kalnischkies ]
+  * apt-pkg/depcache.cc:
+    - rewrite the pseudo package reinstaller to be more intelligent
+      in his package choices
+  * apt-pkg/packagemanager.cc:
+    - don't try to "unpack" pseudo packages twice
+  * apt-pkg/contrib/fileutl.cc:
+    - add a parent-guarded "mkdir -p" as CreateDirectory()
+  * apt-pkg/acquire.{cc,h}:
+    - add a delayed constructor with Setup() for success reporting
+    - check for and create directories in Setup if needed instead of
+      error out unfriendly in the Constructor (Closes: #523920, #525783)
+    - optional handle a lock file in Setup()
+  * apt-pkg/acquire-item.cc:
+    - Acquire::ForceHash to force method for expected hash
+  * cmdline/apt-get.cc:
+    - remove the lock file handling and let Acquire take care of it instead
+    - display MD5Sum in --print-uris if not forced to use another method
+      instead of displaying the strongest available (Closes: #576420)
+    - regex for package names executed on Grp- not PkgIterator
+    - show non-candidates as fallback for virtual packages (Closes: #578385)
+    - set also "all" to this version for pseudo packages in TryToChangeVer
+  * apt-pkg/deb/dpkgpm.cc:
+    - remove Chroot-Directory from files passed to install commands.
+      Thanks to Kel Modderman for report & patch! (Closes: #577226)
+  * ftparchive/writer.cc:
+    - remove 999 chars Files and Checksums rewrite limit (Closes: #577759)
+  * cmdline/apt-cache.cc:
+    - align Installed and Candidate Version in policy so they can be compared
+      easier, thanks Ralf Gesellensetter for the pointer! (Closes: #578657)
+  * doc/apt.ent:
+    - Add a note about APT_CONFIG in the -c description (Closes: #578267)
+  * doc/po/de.po:
+    - correct typos in german apt_preferences manpage, thanks Chris Leick!
+  * apt-pkg/sourcelist.cc:
+    - be less strict and accept [option=value] as well
+  * apt-pkg/contrib/configuration.cc:
+    - error out if #clear directive has no argument
+  * doc/files.sgml:
+    - sync documentation with status quo, regarding files/directories in
+      use, extended_states and uri schemes.
+  * doc/cache.sgml:
+    - drop the file in favor of inplace documentation with doxygen
+  * apt-pkg/pkgcache.h:
+    - enhance the Groups ABI by providing a ID as the other structs does
+    - check also the size of the Group struct then checking for the others
 
 
-apt (0.7.26~exp4) unstable; urgency=low
+  [ Jari Aalto ]
+  * cmdline/apt-get.cc:
+    - replace backticks with single quotes around fix-broken command
+      in the broken packages message. (Closes: #577168)
+  * dselect/install:
+    - modernize if-statements not to use 'x' (Closes: #577117)
+    - replace backticks with POSIX $() (Closes: #577116)
 
 
+  [ Michael Vogt ]
   * [ Abi break ] apt-pkg/acquire-item.{cc,h}:
   * [ Abi break ] apt-pkg/acquire-item.{cc,h}:
     - add "IsIndexFile" to constructor of pkgAcqFile so that it sends
     - add "IsIndexFile" to constructor of pkgAcqFile so that it sends
       the right cache control headers
       the right cache control headers
+  * cmdline/apt-get.cc:
+    - fix crash when pkg.VersionList() is empty
   * apt-pkg/depcache.cc:
   * apt-pkg/depcache.cc:
     - fix incorrect std::cout usage for debug output
     - fix incorrect std::cout usage for debug output
   * test/libapt/getlanguages_test.cc:
   * test/libapt/getlanguages_test.cc:
@@ -18,11 +423,26 @@ apt (0.7.26~exp4) unstable; urgency=low
   * apt-pkg/deb/debrecords.cc:
   * apt-pkg/deb/debrecords.cc:
     - fix max tag buffer size (LP: #545336, closes: #578959)
     - fix max tag buffer size (LP: #545336, closes: #578959)
   * debian/rules:
   * debian/rules:
-    - install html doxygen in libapt-pkg-doc as well
+    - install html doxygen in libapt-pkg-doc 
+  * debian/control:
+    - build-depend on doxygen
 
 
- -- Michael Vogt <michael.vogt@ubuntu.com>  Tue, 04 May 2010 09:55:08 +0200
+  [ Julian Andres Klode ]
+  * apt-pkg/contrib/weakptr.h:
+    - add a class WeakPointable which allows one to register weak pointers to
+      an object which will be set to NULL when the object is deallocated.
+  * [ABI break] apt-pkg/acquire{-worker,-item,}.h:
+    - subclass pkgAcquire::{Worker,Item,ItemDesc} from WeakPointable.
+  * apt-pkg/pkgcache.cc:
+    - Merge fix from David to correct handling in single-arch environments.
+  * cmdline/apt-cache.cc:
+    - Add a showauto command to apt-cache.
+  * cmdline/apt-get.cc:
+    - Add apt-get markauto and unmarkauto commands.
 
 
-apt (0.7.26~exp3) UNRELEASED; urgency=low
+ -- Michael Vogt <mvo@debian.org>  Thu, 06 May 2010 09:32:54 +0200
+
+apt (0.7.26~exp3) experimental; urgency=low
 
 
   [ Christian Perrier ]
   [ Christian Perrier ]
   * German translation update. Closes: #571037
   * German translation update. Closes: #571037
@@ -32,6 +452,68 @@ apt (0.7.26~exp3) UNRELEASED; urgency=low
   * Add "manpages-pl (<< 20060617-3~)" to avoid file conflicts with
   * Add "manpages-pl (<< 20060617-3~)" to avoid file conflicts with
     that package that was providing some manpages for APT utilities.
     that package that was providing some manpages for APT utilities.
 
 
+  [ David Kalnischkies ]
+  * [BREAK] merge MultiArch-ABI. We don't support MultiArch,
+    but we support the usage of the new ABI so libapt users
+    can start to prepare for MultiArch (Closes: #536029)
+  * Ignore :qualifiers after package name in build dependencies
+    in the library by default, but try to honour them in apt-get
+    as we have some sort of MultiArch support ready (Closes: #558103)
+  * add translation of the manpages to PT (portuguese)
+    Thanks to Américo Monteiro!
+  * Switch to dpkg-source 3.0 (native) format
+  * apt-pkg/depcache.cc:
+    - remove Auto-Installed information from extended_states
+      together with the package itself (Closes: #572364)
+  * cmdline/apt-mark:
+    - don't crash if no arguments are given (Closes: #570962)
+  * debian/control:
+    - remove some years old and obsolete Replaces
+    - add automake/conf build-depends/conflicts as recommend by
+      the autotools-dev README (Closes: #572615)
+  * apt-pkg/contrib/mmap.{h,cc}:
+    - add char[] fallback for filesystems without shared writable
+      mmap() like JFFS2. Thanks to Marius Vollmer for writing
+      and to Loïc Minier for pointing to the patch! (Closes: #314334)
+  * doc/apt_preferences.5.xml:
+    - fix two typos and be more verbose in the novice warning.
+      Thanks to Osamu Aoki for pointing it out! (Closes: #567669)
+    - fix a=sid vs. n=sid typo, thanks Ansgar Burchardt!
+    - origin can be used to match a hostname (Closes: #352667)
+    - remove wrong pin-priority is optional remark (Closes: #574944)
+  * apt-pkg/deb/dpkgpm.cc:
+    - fix error message construction in OpenLog()
+    - if available store the Commandline in the history
+  * cmdline/apt-get.cc:
+    - add a --only-upgrade flag to install command (Closes: #572259)
+    - fix memory leaks in error conditions in DoSource()
+    - try version match in FindSrc first exact than fuzzy (LP: #551178)
+  * apt-pkg/contrib/cmndline.cc:
+    - save Commandline in Commandline::AsString for logging
+  * apt-pkg/deb/debversion.cc:
+    - consider absent of debian revision equivalent to 0 (Closes: #573592)
+  * doc/makefile, doc/*:
+    - generate subdirectories for building the manpages in on the fly
+      depending on the po files we have.
+  * apt-pkg/pkgcachegen.cc:
+    - merge versions correctly even if multiple different versions
+      with the same version number are available.
+      Thanks to Magnus Holmgren for the patch! (Closes: #351056)
+  * ftparchive/writer.cc:
+    - write LongDescriptions if they shouldn't be included in Packages
+      file into i18n/Translation-en by default.
+  * doc/po/de.po:
+    - correct a few typos in the german manpage translation.
+      Thanks to Chris Leick and Georg Koppen! (Closes: #574962)
+  * apt-pkg/contrib/strutl.cc:
+    - convert all toupper calls to tolower_ascii for a little speedup
+
+  [ Jean-Baptiste Lallement ]
+  * apt-pkg/contrib/strutl.cc:
+    - always escape '%' (LP: #130289) (Closes: #500560)
+    - unescape '%' sequence only if followed by 2 hex digit
+    - username/password are urlencoded in proxy string (RFC 3986)
+
   [ Julian Andres Klode ]
   [ Julian Andres Klode ]
   * cmdline/apt-cache.cc:
   * cmdline/apt-cache.cc:
     - Change behavior of showsrc to match the one of show (Closes: #512046).
     - Change behavior of showsrc to match the one of show (Closes: #512046).
@@ -64,7 +546,7 @@ apt (0.7.26~exp3) UNRELEASED; urgency=low
   * doc/examples/configure-index:
   * doc/examples/configure-index:
     - add missing Debug::pkgPackageManager option
     - add missing Debug::pkgPackageManager option
 
 
- -- Christian Perrier <bubulle@debian.org>  Wed, 24 Feb 2010 22:13:50 +0100
+ -- Michael Vogt <mvo@debian.org>  Thu, 01 Apr 2010 17:30:43 +0200
 
 
 apt (0.7.26~exp2) experimental; urgency=low
 apt (0.7.26~exp2) experimental; urgency=low
 
 
@@ -1464,13 +1946,6 @@ apt (0.7.6) unstable; urgency=low
 
 
  -- Otavio Salvador <otavio@debian.org>  Wed, 01 Aug 2007 19:49:51 -0300
  -- Otavio Salvador <otavio@debian.org>  Wed, 01 Aug 2007 19:49:51 -0300
 
 
-apt (0.7.6) unstable; urgency=low
-
-  * Applied patch from Aurelien Jarno <aurel32@debian.org> to fix wrong
-    directory downloading on non-linux architectures (closes: #435597)
-
- -- Otavio Salvador <otavio@debian.org>  Wed, 01 Aug 2007 19:49:51 -0300
-
 apt (0.7.5) unstable; urgency=low
 apt (0.7.5) unstable; urgency=low
 
 
   [ Otavio Salvador ]
   [ Otavio Salvador ]

+ 5 - 6
debian/control

@@ -5,14 +5,15 @@ Maintainer: APT Development Team <deity@lists.debian.org>
 Uploaders: Michael Vogt <mvo@debian.org>, Otavio Salvador <otavio@debian.org>,
 Uploaders: Michael Vogt <mvo@debian.org>, Otavio Salvador <otavio@debian.org>,
  Christian Perrier <bubulle@debian.org>, Daniel Burrows <dburrows@debian.org>,
  Christian Perrier <bubulle@debian.org>, Daniel Burrows <dburrows@debian.org>,
  Luca Bruno <lethalman88@gmail.com>, Julian Andres Klode <jak@debian.org>
  Luca Bruno <lethalman88@gmail.com>, Julian Andres Klode <jak@debian.org>
-Standards-Version: 3.8.4
-Build-Depends: debhelper (>= 5.0), libdb-dev, gettext (>= 0.12), libcurl4-gnutls-dev | libcurl3-gnutls-dev (>= 7.15.5), debiandoc-sgml, xsltproc, docbook-xsl, po4a (>= 0.34-2), autotools-dev
+Standards-Version: 3.9.0
+Build-Depends: debhelper (>= 5.0), libdb-dev, gettext (>= 0.12), libcurl4-gnutls-dev (>= 7.19.0), zlib1g-dev | libz-dev, debiandoc-sgml, xsltproc, docbook-xsl, po4a (>= 0.34-2), autotools-dev, autoconf, automake, doxygen
+Build-Conflicts: autoconf2.13, automake1.4
 Vcs-Bzr: http://bzr.debian.org/apt/debian-sid/
 Vcs-Bzr: http://bzr.debian.org/apt/debian-sid/
 
 
 Package: apt
 Package: apt
 Architecture: any
 Architecture: any
 Depends: ${shlibs:Depends}, debian-archive-keyring, ${misc:Depends}
 Depends: ${shlibs:Depends}, debian-archive-keyring, ${misc:Depends}
-Replaces: libapt-pkg-doc (<< 0.3.7), libapt-pkg-dev (<< 0.3.7), manpages-pl (<< 20060617-3~)
+Replaces: manpages-pl (<< 20060617-3~)
 Provides: ${libapt-pkg:provides}
 Provides: ${libapt-pkg:provides}
 Conflicts: python-apt (<< 0.7.93.2~)
 Conflicts: python-apt (<< 0.7.93.2~)
 Suggests: aptitude | synaptic | wajig, dpkg-dev, apt-doc, bzip2, lzma, python-apt
 Suggests: aptitude | synaptic | wajig, dpkg-dev, apt-doc, bzip2, lzma, python-apt
@@ -28,7 +29,6 @@ Package: apt-doc
 Architecture: all
 Architecture: all
 Priority: optional
 Priority: optional
 Depends: ${misc:Depends}
 Depends: ${misc:Depends}
-Replaces: apt (<< 0.5.4.9)
 Section: doc
 Section: doc
 Description: Documentation for APT
 Description: Documentation for APT
  This package contains the user guide and offline guide, for APT, an
  This package contains the user guide and offline guide, for APT, an
@@ -37,7 +37,7 @@ Description: Documentation for APT
 Package: libapt-pkg-dev
 Package: libapt-pkg-dev
 Architecture: any
 Architecture: any
 Priority: optional
 Priority: optional
-Depends: apt (= ${binary:Version}), apt-utils (= ${binary:Version}), ${libapt-pkg:provides}, ${libapt-inst:provides}, ${misc:Depends}
+Depends: apt (= ${binary:Version}), apt-utils (= ${binary:Version}), ${libapt-pkg:provides}, ${libapt-inst:provides}, ${misc:Depends}, zlib1g-dev | zlib-dev
 Section: libdevel
 Section: libdevel
 Description: Development files for APT's libapt-pkg and libapt-inst
 Description: Development files for APT's libapt-pkg and libapt-inst
  This package contains the header files and libraries for
  This package contains the header files and libraries for
@@ -60,7 +60,6 @@ Package: apt-utils
 Architecture: any
 Architecture: any
 Depends: ${shlibs:Depends}, ${misc:Depends}
 Depends: ${shlibs:Depends}, ${misc:Depends}
 Provides: ${libapt-inst:provides}
 Provides: ${libapt-inst:provides}
-Replaces: apt (<< 0.5.9)
 Description: APT utility programs
 Description: APT utility programs
  This package contains some APT utility programs such as apt-ftparchive,
  This package contains some APT utility programs such as apt-ftparchive,
  apt-sortpkgs and apt-extracttemplates.
  apt-sortpkgs and apt-extracttemplates.

+ 0 - 18
debian/libapt-pkg-doc.doc-base.cache

@@ -1,18 +0,0 @@
-Document: libapt-pkg-doc-cache
-Title: APT Cache Specification
-Author: Jason Gunthorpe
-Abstract: The APT Cache Specification describes the complete implementation
- and format of the APT Cache file. The APT Cache file is a way for APT to
- parse and store a large number of package files for display in the UI.
- It's primary design goal is to make display of a single package in the
- tree very fast by pre-linking important things like dependencies and
- provides. The specification doubles as documentation for one of the
- in-memory structures used by the package library and the APT GUI.
-Section: Debian
-
-Format: html
-Index: /usr/share/doc/libapt-pkg-doc/cache.html/index.html
-Files: /usr/share/doc/libapt-pkg-doc/cache.html/*.html
-
-Format: text
-Files: /usr/share/doc/libapt-pkg-doc/cache.text.gz

+ 37 - 81
debian/rules

@@ -27,10 +27,14 @@ endif
 # See below
 # See below
 -include build/environment.mak
 -include build/environment.mak
 
 
-ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS)))
-  export CXXFLAGS = -O0 -g -Wall
+ifneq (,$(shell which dpkg-buildflags))
+  export CXXFLAGS = $(shell dpkg-buildflags --get CXXFLAGS)
 else
 else
-  export CXXFLAGS = -O2 -g -Wall
+  ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS)))
+    export CXXFLAGS = -O0 -g -Wall
+  else
+    export CXXFLAGS = -O2 -g -Wall
+  endif
 endif
 endif
 
 
 # Default rule
 # Default rule
@@ -47,7 +51,7 @@ BASE=.
 ifdef BUILD
 ifdef BUILD
 BUILD_POSSIBLE := $(BUILD) $(BASE)/$(BUILD)
 BUILD_POSSIBLE := $(BUILD) $(BASE)/$(BUILD)
 else
 else
-BUILD_POSSIBLE := $(BASE) $(BASE)/build-$(shell uname -m) $(BASE)/build
+BUILD_POSSIBLE := $(BASE) $(BASE)/build-$(shell uname --machine) $(BASE)/build
 endif
 endif
 BUILDX:= $(foreach i,$(BUILD_POSSIBLE),$(wildcard $(i)/environment.mak*))
 BUILDX:= $(foreach i,$(BUILD_POSSIBLE),$(wildcard $(i)/environment.mak*))
 BUILDX:= $(patsubst %/,%,$(firstword $(dir $(BUILDX))))
 BUILDX:= $(patsubst %/,%,$(firstword $(dir $(BUILDX))))
@@ -82,9 +86,9 @@ LIBAPTPKG_PROVIDE=libapt-pkg$(LIBAPTPKG_MAJOR)
 LIBAPTINST_PROVIDE=libapt-inst$(LIBAPTINST_MAJOR)
 LIBAPTINST_PROVIDE=libapt-inst$(LIBAPTINST_MAJOR)
 
 
 debian/shlibs.local: apt-pkg/makefile
 debian/shlibs.local: apt-pkg/makefile
-	# We have 3 shlibs.local files.. One for 'apt', one for 'apt-utils' and
+	# We have 3 shlibs.local files: One for 'apt', one for 'apt-utils' and
 	# one for the rest of the packages. This ensures that each package gets
 	# one for the rest of the packages. This ensures that each package gets
-	# the right overrides.. 
+	# the right overrides
 	rm -rf $@ $@.apt $@.apt-utils
 	rm -rf $@ $@.apt $@.apt-utils
 	echo "libapt-pkg $(LIBAPTPKG_MAJOR)" > $@.apt
 	echo "libapt-pkg $(LIBAPTPKG_MAJOR)" > $@.apt
 
 
@@ -94,8 +98,8 @@ debian/shlibs.local: apt-pkg/makefile
 	echo "libapt-pkg $(LIBAPTPKG_MAJOR) $(LIBAPTPKG_PROVIDE)" > $@
 	echo "libapt-pkg $(LIBAPTPKG_MAJOR) $(LIBAPTPKG_PROVIDE)" > $@
 	echo "libapt-inst $(LIBAPTINST_MAJOR) $(LIBAPTINST_PROVIDE)" >> $@
 	echo "libapt-inst $(LIBAPTINST_MAJOR) $(LIBAPTINST_PROVIDE)" >> $@
 
 
-build: build/build-stamp	
-build-doc: build/build-doc-stamp	
+build: build/build-stamp
+build-doc: build/build-doc-stamp
 
 
 # Note that this is unconditionally done first as part of loading environment.mak
 # Note that this is unconditionally done first as part of loading environment.mak
 # The true is needed to force make to reload environment.mak after running
 # The true is needed to force make to reload environment.mak after running
@@ -108,7 +112,7 @@ build/configure-stamp: configure
 	dh_testdir
 	dh_testdir
 	-mkdir build
 	-mkdir build
 	cp COPYING debian/copyright
 	cp COPYING debian/copyright
-	cd build && CXXFLAGS="$(confcxxflags)" ../configure $(confflags)
+	cd build && CXXFLAGS="$(CXXFLAGS)" ../configure $(confflags)
 	touch $@
 	touch $@
 
 
 build/build-stamp: build/configure-stamp
 build/build-stamp: build/configure-stamp
@@ -123,10 +127,8 @@ build/build-doc-stamp: build/configure-stamp
 
 
 clean:
 clean:
 	dh_testdir
 	dh_testdir
-#	dh_testroot
-	[ -f Makefile ] && $(MAKE) clean
-	[ -f Makefile ] && $(MAKE) distclean
 
 
+	[ ! -f Makefile ] || $(MAKE) clean distclean
 	rm -rf build
 	rm -rf build
 
 
 	# Add here commands to clean up after the build process.
 	# Add here commands to clean up after the build process.
@@ -141,23 +143,20 @@ libapt-pkg-doc: build-doc debian/shlibs.local
 	dh_installdirs -p$@
 	dh_installdirs -p$@
 #
 #
 # libapt-pkg-doc install
 # libapt-pkg-doc install
-#	
-	dh_installdocs -p$@ $(BLD)/docs/cache* $(BLD)/docs/design* $(BLD)/docs/dpkg-tech* \
-                            $(BLD)/docs/files* $(BLD)/docs/method* \
-			    doc/libapt-pkg2_to_3.txt doc/style.txt \
-			    $(BLD)/doc/doxygen/html/*
+#
+	dh_installdocs -p$@ $(BLD)/docs/design* \
+			    $(BLD)/docs/dpkg-tech* \
+			    $(BLD)/docs/files* \
+			    $(BLD)/docs/method* \
+			    doc/libapt-pkg2_to_3.txt \
+			    doc/style.txt \
+			    $(BLD)/doc/doxygen/html
 	dh_installexamples -p$@
 	dh_installexamples -p$@
-#	dh_installmenu -p$@
-#	dh_installinit -p$@
-#	dh_installcron -p$@
-#	dh_installman -p$@
 
 
-#	dh_undocumented -p$@
 	dh_installchangelogs -p$@
 	dh_installchangelogs -p$@
 	dh_strip -p$@
 	dh_strip -p$@
 	dh_compress -p$@
 	dh_compress -p$@
 	dh_fixperms -p$@
 	dh_fixperms -p$@
-#	dh_suidregister -p$@
 	dh_installdeb -p$@
 	dh_installdeb -p$@
 	dh_gencontrol -p$@ -u -Vlibapt-pkg:provides=$(LIBAPTPKG_PROVIDE)
 	dh_gencontrol -p$@ -u -Vlibapt-pkg:provides=$(LIBAPTPKG_PROVIDE)
 	dh_md5sums -p$@
 	dh_md5sums -p$@
@@ -171,8 +170,10 @@ apt-doc: build-doc
 # apt-doc install
 # apt-doc install
 #
 #
 	# Copy the guides
 	# Copy the guides
-	dh_installdocs -p$@ $(BLD)/docs/guide*.text $(BLD)/docs/guide*.html \
-	               $(BLD)/docs/offline*.text $(BLD)/docs/offline*.html
+	dh_installdocs -p$@ $(BLD)/docs/guide*.text \
+			    $(BLD)/docs/guide*.html \
+			    $(BLD)/docs/offline*.text \
+			    $(BLD)/docs/offline*.html
 	dh_installchangelogs -p$@
 	dh_installchangelogs -p$@
 	dh_compress -p$@
 	dh_compress -p$@
 	dh_fixperms -p$@
 	dh_fixperms -p$@
@@ -215,7 +216,6 @@ apt: build build-doc debian/shlibs.local
 	cp debian/apt.logrotate debian/$@/etc/logrotate.d/apt
 	cp debian/apt.logrotate debian/$@/etc/logrotate.d/apt
 
 
 	cp debian/apt.conf.autoremove debian/$@/etc/apt/apt.conf.d/01autoremove
 	cp debian/apt.conf.autoremove debian/$@/etc/apt/apt.conf.d/01autoremove
-#	head -n 500 ChangeLog > debian/ChangeLog
 
 
 	# copy lintian override
 	# copy lintian override
 	cp share/lintian-overrides debian/$@/usr/share/lintian/overrides/apt
 	cp share/lintian-overrides debian/$@/usr/share/lintian/overrides/apt
@@ -225,6 +225,10 @@ apt: build build-doc debian/shlibs.local
 	rm -f build/po/*.pot
 	rm -f build/po/*.pot
 	rm -f po/*.pot
 	rm -f po/*.pot
 
 
+	# move the mirror failure script in place
+	#mv debian/$@/usr/bin/apt-report-mirror-failure \
+	#   debian/$@/usr/lib/apt/apt-report-mirror-failure \
+
 	dh_installexamples -p$@ $(BLD)/docs/examples/*
 	dh_installexamples -p$@ $(BLD)/docs/examples/*
 	dh_installman -p$@ $(wildcard $(patsubst %,doc/%.[158],$(apt_MANPAGES)) $(patsubst %,doc/*/%.*.[158],$(apt_MANPAGES)))
 	dh_installman -p$@ $(wildcard $(patsubst %,doc/%.[158],$(apt_MANPAGES)) $(patsubst %,doc/*/%.*.[158],$(apt_MANPAGES)))
 	dh_installcron -p$@
 	dh_installcron -p$@
@@ -233,9 +237,9 @@ apt: build build-doc debian/shlibs.local
 	dh_strip -p$@
 	dh_strip -p$@
 	dh_compress -p$@
 	dh_compress -p$@
 	dh_fixperms -p$@
 	dh_fixperms -p$@
-	dh_makeshlibs -p$@ -m$(LIBAPTPKG_MAJOR) -V '$(LIBAPTPKG_PROVIDE)'
+	dh_makeshlibs -p$@ --major=$(LIBAPTPKG_MAJOR) --version-info='$(LIBAPTPKG_PROVIDE)'
 	dh_installdeb -p$@
 	dh_installdeb -p$@
-	dh_shlibdeps -p$@ -l`pwd`/debian/apt/usr/lib:`pwd`/debian/$@/usr/lib -- -Ldebian/shlibs.local.apt
+	dh_shlibdeps -p$@ -l$(CURDIR)/debian/apt/usr/lib:$(CURDIR)/debian/$@/usr/lib -- -Ldebian/shlibs.local.apt
 	dh_gencontrol -p$@ -u -Vlibapt-pkg:provides=$(LIBAPTPKG_PROVIDE)
 	dh_gencontrol -p$@ -u -Vlibapt-pkg:provides=$(LIBAPTPKG_PROVIDE)
 	dh_md5sums -p$@
 	dh_md5sums -p$@
 	dh_builddeb -p$@
 	dh_builddeb -p$@
@@ -254,16 +258,11 @@ libapt-pkg-dev: build debian/shlibs.local
 	cp $(BLD)/include/apt-pkg/*.h debian/libapt-pkg-dev/usr/include/apt-pkg/
 	cp $(BLD)/include/apt-pkg/*.h debian/libapt-pkg-dev/usr/include/apt-pkg/
 
 
 	dh_installdocs -p$@
 	dh_installdocs -p$@
-#	dh_installmenu -p$@
-#	dh_installinit -p$@
-#	dh_installcron -p$@
-#	dh_installman -p$@
 
 
 	dh_installchangelogs -p$@
 	dh_installchangelogs -p$@
 	dh_strip -p$@
 	dh_strip -p$@
 	dh_compress -p$@
 	dh_compress -p$@
 	dh_fixperms -p$@
 	dh_fixperms -p$@
-#	dh_suidregister -p$@
 	dh_installdeb -p$@
 	dh_installdeb -p$@
 	dh_gencontrol -p$@ -u -Vlibapt-pkg:provides=$(LIBAPTPKG_PROVIDE) -Vlibapt-inst:provides=$(LIBAPTINST_PROVIDE)
 	dh_gencontrol -p$@ -u -Vlibapt-pkg:provides=$(LIBAPTPKG_PROVIDE) -Vlibapt-inst:provides=$(LIBAPTINST_PROVIDE)
 	dh_md5sums -p$@
 	dh_md5sums -p$@
@@ -291,9 +290,9 @@ apt-utils: build debian/shlibs.local
 	dh_strip -p$@
 	dh_strip -p$@
 	dh_compress -p$@
 	dh_compress -p$@
 	dh_fixperms -p$@
 	dh_fixperms -p$@
-	dh_makeshlibs -m$(LIBAPTINST_MAJOR) -V '$(LIBAPTINST_PROVIDE)' -p$@
+	dh_makeshlibs -p$@ --major=$(LIBAPTINST_MAJOR) --version-info='$(LIBAPTINST_PROVIDE)'
 	dh_installdeb -p$@
 	dh_installdeb -p$@
-	dh_shlibdeps -p$@ -l`pwd`/debian/apt/usr/lib:`pwd`/debian/$@/usr/lib -- -Ldebian/shlibs.local.apt-utils
+	dh_shlibdeps -p$@ -l$(CURDIR)/debian/apt/usr/lib:$(CURDIR)/debian/$@/usr/lib -- -Ldebian/shlibs.local.apt-utils
 	dh_gencontrol -p$@ -u -Vlibapt-inst:provides=$(LIBAPTINST_PROVIDE)
 	dh_gencontrol -p$@ -u -Vlibapt-inst:provides=$(LIBAPTINST_PROVIDE)
 	dh_md5sums -p$@
 	dh_md5sums -p$@
 	dh_builddeb -p$@
 	dh_builddeb -p$@
@@ -305,7 +304,7 @@ apt-transport-https: build debian/shlibs.local libapt-pkg-dev
 	dh_installdirs -p$@
 	dh_installdirs -p$@
 
 
 	# install the method
 	# install the method
-	mkdir -p debian/$@/usr/lib/apt/methods
+	mkdir --parents debian/$@/usr/lib/apt/methods
 	cp $(BLD)/bin/methods/https debian/$@/usr/lib/apt/methods
 	cp $(BLD)/bin/methods/https debian/$@/usr/lib/apt/methods
 
 
 	dh_installdocs -p$@ debian/apt-transport-https.README
 	dh_installdocs -p$@ debian/apt-transport-https.README
@@ -319,61 +318,18 @@ apt-transport-https: build debian/shlibs.local libapt-pkg-dev
 	dh_compress -p$@
 	dh_compress -p$@
 	dh_fixperms -p$@
 	dh_fixperms -p$@
 	dh_installdeb -p$@
 	dh_installdeb -p$@
-	dh_shlibdeps -p$@ -l`pwd`/debian/apt/usr/lib:`pwd`/debian/$@/usr/lib 
+	dh_shlibdeps -p$@ -l$(CURDIR)/debian/apt/usr/lib:$(CURDIR)/debian/$@/usr/lib
 	dh_gencontrol -p$@
 	dh_gencontrol -p$@
 	dh_md5sums -p$@
 	dh_md5sums -p$@
 	dh_builddeb -p$@
 	dh_builddeb -p$@
 
 
-source diff:
-	@echo >&2 'source and diff are obsolete - use dpkg-source -b'; false
-
-# Update from CVS
-l33ch: really-clean
-	cvs update
-	buildlib/mkChangeLog
-
-# Update from CVS and then configure for build
-super-l33ch: l33ch Makefile.in
-
 configure:
 configure:
 	$(MAKE) configure
 	$(MAKE) configure
 
 
-l33ch-stamp: super-l33ch
-	touch $@
-
 really-clean: clean
 really-clean: clean
-	-find -name Makefile.in -print0 | xargs -0r rm -f
+	-find . -name Makefile.in -print0 | xargs --null --no-run-if-empty -- rm -f
 	find -name ChangeLog | xargs rm -f
 	find -name ChangeLog | xargs rm -f
 	rm -f l33ch-stamp
 	rm -f l33ch-stamp
 
 
 binary: binary-indep binary-arch
 binary: binary-indep binary-arch
 .PHONY: build clean binary-indep binary-arch binary debian/shlibs.local
 .PHONY: build clean binary-indep binary-arch binary debian/shlibs.local
-
-
-# Done by the uploader.
-#cvs update.. 
-#edit debian/changelog
-# configure.in has the version automatically updated now.
-# edit configure.in
-# debian/rules cvs-build
-
-CVS_BUILDDIR=apt-$(APT_DEBVER)
-CVS_ROOT=$(shell cat CVS/Root)
-CVS_MODULE=$(shell cat CVS/Repository)
-cvs-build:
-	rm -rf debian/cvs-build
-	mkdir -p debian/cvs-build
-	(cd debian/cvs-build;cvs -d $(CVS_ROOT) export -r$(APT_CVSTAG) -d apt-$(APT_DEBVER) $(CVS_MODULE))
-	$(MAKE) -C debian/cvs-build/$(CVS_BUILDDIR) startup doc
-	(cd debian/cvs-build/$(CVS_BUILDDIR);$(DEB_BUILD_PROG))
-
-cvs-mkul:
-	-mkdir -p ../upload-$(APT_DEBVER)
-	cp `find debian/cvs-build -maxdepth 1 -type f` ../upload-$(APT_DEBVER)
-
-arch-build:
-	rm -rf debian/arch-build
-	mkdir -p debian/arch-build/apt-$(APT_DEBVER)
-	tar -c --exclude=arch-build --no-recursion -f - `bzr inventory` | (cd debian/arch-build/$(PKG)-$(APT_DEBVER);tar xf -)
-	$(MAKE) -C debian/arch-build/apt-$(APT_DEBVER) startup doc
-	(cd debian/arch-build/apt-$(APT_DEBVER); $(DEB_BUILD_PROG); dpkg-genchanges -S > ../apt_$(APT_DEBVER)_source.changes)

+ 1 - 0
debian/source/format

@@ -0,0 +1 @@
+3.0 (native)

+ 14 - 0
doc/apt-cache.8.xml

@@ -309,6 +309,20 @@ Reverse Provides:
      Configuration Item: <literal>APT::Cache::Important</literal>.</para></listitem>
      Configuration Item: <literal>APT::Cache::Important</literal>.</para></listitem>
      </varlistentry>
      </varlistentry>
 
 
+     <varlistentry><term><option>--no-pre-depends</option></term>
+		   <term><option>--no-depends</option></term>
+		   <term><option>--no-recommends</option></term>
+		   <term><option>--no-suggests</option></term>
+		   <term><option>--no-conflicts</option></term>
+		   <term><option>--no-breaks</option></term>
+		   <term><option>--no-replaces</option></term>
+		   <term><option>--no-enhances</option></term>
+		   <listitem><para>Per default the <literal>depends</literal> and
+     <literal>rdepends</literal> print all dependencies. This can be twicked with
+     these flags which will omit the specified dependency type.
+     Configuration Item: <literal>APT::Cache::Show<replaceable>DependencyType</replaceable></literal>
+     e.g. <literal>APT::Cache::ShowRecommends</literal>.</para></listitem>
+     </varlistentry>
      <varlistentry><term><option>-f</option></term><term><option>--full</option></term>
      <varlistentry><term><option>-f</option></term><term><option>--full</option></term>
      <listitem><para>Print full package records when searching. 
      <listitem><para>Print full package records when searching. 
      Configuration Item: <literal>APT::Cache::ShowFull</literal>.</para></listitem>
      Configuration Item: <literal>APT::Cache::ShowFull</literal>.</para></listitem>

+ 33 - 7
doc/apt-ftparchive.1.xml

@@ -122,7 +122,8 @@
      e.g. <literal>APT::FTPArchive::Release::Origin</literal>.  The supported fields
      e.g. <literal>APT::FTPArchive::Release::Origin</literal>.  The supported fields
      are: <literal>Origin</literal>, <literal>Label</literal>, <literal>Suite</literal>,
      are: <literal>Origin</literal>, <literal>Label</literal>, <literal>Suite</literal>,
      <literal>Version</literal>, <literal>Codename</literal>, <literal>Date</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>
      </varlistentry>
 
 
@@ -224,7 +225,13 @@
       This is similar to <literal>Packages::Compress</literal> 
       This is similar to <literal>Packages::Compress</literal> 
       except that it controls the compression for the Contents files.</para></listitem>
       except that it controls the compression for the Contents files.</para></listitem>
       </varlistentry>
       </varlistentry>
-      
+
+      <varlistentry><term>Translation::Compress</term>
+      <listitem><para>
+      This is similar to <literal>Packages::Compress</literal> 
+      except that it controls the compression for the Translation-en master file.</para></listitem>
+      </varlistentry>
+
       <varlistentry><term>DeLinkLimit</term>
       <varlistentry><term>DeLinkLimit</term>
       <listitem><para>
       <listitem><para>
       Specifies the number of kilobytes to delink (and 
       Specifies the number of kilobytes to delink (and 
@@ -238,6 +245,12 @@
       defaults to 0644. All index files are set to this mode with no regard 
       defaults to 0644. All index files are set to this mode with no regard 
       to the umask.</para></listitem>
       to the umask.</para></listitem>
       </varlistentry>
       </varlistentry>
+
+      <varlistentry><term>LongDescription</term>
+      <listitem><para>
+      Sets if long descriptions should be included in the Packages file or split
+      out into a master Translation-en file.</para></listitem>
+      </varlistentry>
      </variablelist>
      </variablelist>
    </refsect2>
    </refsect2>
    
    
@@ -289,7 +302,14 @@
       Sets the output Sources file. Defaults to 
       Sets the output Sources file. Defaults to 
       <filename>$(DIST)/$(SECTION)/source/Sources</filename></para></listitem>
       <filename>$(DIST)/$(SECTION)/source/Sources</filename></para></listitem>
       </varlistentry>
       </varlistentry>
-      
+
+      <varlistentry><term>Translation</term>
+      <listitem><para>
+      Set the output Translation-en master file with the long descriptions if they
+      should be not included in the Packages file. Defaults to
+      <filename>$(DIST)/$(SECTION)/i18n/Translation-en</filename></para></listitem>
+      </varlistentry>
+
       <varlistentry><term>InternalPrefix</term>
       <varlistentry><term>InternalPrefix</term>
       <listitem><para>
       <listitem><para>
       Sets the path prefix that causes a symlink to be
       Sets the path prefix that causes a symlink to be
@@ -344,7 +364,7 @@
      The <literal>Tree</literal> section takes a scope tag which sets the 
      The <literal>Tree</literal> section takes a scope tag which sets the 
      <literal>$(DIST)</literal> variable and defines the root of the tree 
      <literal>$(DIST)</literal> variable and defines the root of the tree 
      (the path is prefixed by <literal>ArchiveDir</literal>).
      (the path is prefixed by <literal>ArchiveDir</literal>).
-     Typically this is a setting such as <filename>dists/woody</filename>.</para>
+     Typically this is a setting such as <filename>dists/&stable-codename;</filename>.</para>
      <para>
      <para>
      All of the settings defined in the <literal>TreeDefault</literal> section can be
      All of the settings defined in the <literal>TreeDefault</literal> section can be
      use in a <literal>Tree</literal> section as well as three new variables.</para>
      use in a <literal>Tree</literal> section as well as three new variables.</para>
@@ -371,7 +391,13 @@ for i in Sections do
       architectures that appear under search section. The special architecture 
       architectures that appear under search section. The special architecture 
       'source' is used to indicate that this tree has a source archive.</para></listitem>
       'source' is used to indicate that this tree has a source archive.</para></listitem>
       </varlistentry>
       </varlistentry>
-      
+
+      <varlistentry><term>LongDescription</term>
+      <listitem><para>
+      Sets if long descriptions should be included in the Packages file or split
+      out into a master Translation-en file.</para></listitem>
+      </varlistentry>
+
       <varlistentry><term>BinOverride</term>
       <varlistentry><term>BinOverride</term>
       <listitem><para>
       <listitem><para>
       Sets the binary override file. The override file 
       Sets the binary override file. The override file 
@@ -568,8 +594,8 @@ for i in Sections do
      <listitem><para>
      <listitem><para>
      This configuration option defaults to "<literal>true</literal>" and should only be set to
      This configuration option defaults to "<literal>true</literal>" and should only be set to
      <literal>"false"</literal> if the Archive generated with &apt-ftparchive; also provides
      <literal>"false"</literal> if the Archive generated with &apt-ftparchive; also provides
-     <filename>Translation</filename> files. Note that it is currently not possible to create these
-     files with <command>apt-ftparchive</command>.
+     <filename>Translation</filename> files. Note that the <filename>Translation-en</filename>
+     master file can only be created in the generate command.
      </para></listitem>
      </para></listitem>
      </varlistentry>
      </varlistentry>
 
 

+ 14 - 21
doc/apt-get.8.xml

@@ -46,18 +46,10 @@
 	      </option>
 	      </option>
       </arg>
       </arg>
       <arg>
       <arg>
-		  <option>-t=</option>
-		  <group choice='req'>
-			  <arg choice='plain'>
-				  <replaceable>target_release_name</replaceable>
-			  </arg>
-			  <arg choice='plain'>
-				  <replaceable>target_release_number_expression</replaceable>
-			  </arg>
-			  <arg choice='plain'>
-				  <replaceable>target_release_codename</replaceable>
-			  </arg>
-		  </group>
+		<option>-t=</option>
+		<arg choice='plain'>
+			<replaceable>target_release</replaceable>
+		</arg>
       </arg>
       </arg>
 
 
       <group choice="req">
       <group choice="req">
@@ -73,10 +65,7 @@
 							=<replaceable>pkg_version_number</replaceable>
 							=<replaceable>pkg_version_number</replaceable>
 						</arg>
 						</arg>
 						<arg choice='plain'>
 						<arg choice='plain'>
-							/<replaceable>target_release_name</replaceable>
-						</arg>
-						<arg choice='plain'>
-							/<replaceable>target_release_codename</replaceable>
+							/<replaceable>target_release</replaceable>
 						</arg>
 						</arg>
 					</group>
 					</group>
 				</arg>
 				</arg>
@@ -92,10 +81,7 @@
 							=<replaceable>pkg_version_number</replaceable>
 							=<replaceable>pkg_version_number</replaceable>
 						</arg>
 						</arg>
 						<arg choice='plain'>
 						<arg choice='plain'>
-							/<replaceable>target_release_name</replaceable>
-						</arg>
-						<arg choice='plain'>
-							/<replaceable>target_release_codename</replaceable>
+							/<replaceable>target_release</replaceable>
 						</arg>
 						</arg>
 					</group>
 					</group>
 				</arg>
 				</arg>
@@ -126,7 +112,7 @@
    <para><command>apt-get</command> is the command-line tool for handling packages, and may be 
    <para><command>apt-get</command> is the command-line tool for handling packages, and may be 
    considered the user's "back-end" to other tools using the APT
    considered the user's "back-end" to other tools using the APT
    library.  Several "front-end" interfaces exist, such as &dselect;,
    library.  Several "front-end" interfaces exist, such as &dselect;,
-   &aptitude;, &synaptic;, &gnome-apt; and &wajig;.</para>
+   &aptitude;, &synaptic; and &wajig;.</para>
 
 
    <para>Unless the <option>-h</option>, or <option>--help</option> option is given, one of the
    <para>Unless the <option>-h</option>, or <option>--help</option> option is given, one of the
    commands below must be present.</para>
    commands below must be present.</para>
@@ -444,6 +430,13 @@
      Configuration Item: <literal>APT::Get::Upgrade</literal>.</para></listitem>
      Configuration Item: <literal>APT::Get::Upgrade</literal>.</para></listitem>
      </varlistentry>
      </varlistentry>
 
 
+     <varlistentry><term><option>--only-upgrade</option></term>
+     <listitem><para>Do not install new packages; When used in conjunction with <literal>install</literal>,
+     <literal>only-upgrade</literal> will prevent packages on the command line
+     from being upgraded if they are not already installed.
+     Configuration Item: <literal>APT::Get::Only-Upgrade</literal>.</para></listitem>
+     </varlistentry>
+
      <varlistentry><term><option>--force-yes</option></term>
      <varlistentry><term><option>--force-yes</option></term>
      <listitem><para>Force yes; This is a dangerous option that will cause apt to continue 
      <listitem><para>Force yes; This is a dangerous option that will cause apt to continue 
      without prompting if it is doing something potentially harmful. It 
      without prompting if it is doing something potentially harmful. It 

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

@@ -121,12 +121,7 @@
 
 
  <refsect1><title>Files</title>
  <refsect1><title>Files</title>
    <variablelist>
    <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>
    </variablelist>
  </refsect1>
  </refsect1>
 
 

+ 59 - 5
doc/apt.conf.5.xml

@@ -150,8 +150,9 @@ DPkg::Pre-Install-Pkgs {"/usr/sbin/dpkg-preconfigure --apt";};
      </varlistentry>
      </varlistentry>
      
      
      <varlistentry><term>Default-Release</term>
      <varlistentry><term>Default-Release</term>
-	 <listitem><para>Default release to install packages from if more than one
-	 version available. Contains release name, codename or release version. Examples: 'stable', 'testing', 'unstable', 'lenny', 'squeeze', '4.0', '5.0*'. See also &apt-preferences;.</para></listitem>
+     <listitem><para>Default release to install packages from if more than one
+     version available. Contains release name, codename or release version. Examples: 'stable', 'testing',
+     'unstable', '&stable-codename;', '&testing-codename;', '4.0', '5.0*'. See also &apt-preferences;.</para></listitem>
      </varlistentry>
      </varlistentry>
 
 
      <varlistentry><term>Ignore-Hold</term>
      <varlistentry><term>Ignore-Hold</term>
@@ -198,9 +199,20 @@ DPkg::Pre-Install-Pkgs {"/usr/sbin/dpkg-preconfigure --apt";};
      anything that those packages depend on.</para></listitem>
      anything that those packages depend on.</para></listitem>
      </varlistentry>
      </varlistentry>
 
 
-     <varlistentry><term>Cache-Limit</term>
-     <listitem><para>APT uses a fixed size memory mapped cache file to store the 'available'
-     information. This sets the size of that cache (in bytes).</para></listitem>
+     <varlistentry><term>Cache-Start, Cache-Grow and Cache-Limit</term>
+     <listitem><para>APT uses since version 0.7.26 a resizable memory mapped cache file to store the 'available'
+     information. <literal>Cache-Start</literal> acts as a hint to which size the Cache will grow
+     and is therefore the amount of memory APT will request at startup. The default value is
+     20971520 bytes (~20 MB). Note that these amount of space need to be available for APT
+     otherwise it will likely fail ungracefully, so for memory restricted devices these value should
+     be lowered while on systems with a lot of configured sources this might be increased.
+     <literal>Cache-Grow</literal> defines in byte with the default of 1048576 (~1 MB) how much
+     the Cache size will be increased in the event the space defined by <literal>Cache-Start</literal>
+     is not enough. These value will be applied again and again until either the cache is big
+     enough to store all information or the size of the cache reaches the <literal>Cache-Limit</literal>.
+     The default of <literal>Cache-Limit</literal> is 0 which stands for no limit.
+     If <literal>Cache-Grow</literal> is set to 0 the automatic grow of the cache is disabled.
+     </para></listitem>
      </varlistentry>
      </varlistentry>
 
 
      <varlistentry><term>Build-Essential</term>
      <varlistentry><term>Build-Essential</term>
@@ -229,6 +241,30 @@ DPkg::Pre-Install-Pkgs {"/usr/sbin/dpkg-preconfigure --apt";};
    and the URI handlers. 
    and the URI handlers. 
 
 
    <variablelist>
    <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>
      <varlistentry><term>PDiffs</term>
 	 <listitem><para>Try to download deltas called <literal>PDiffs</literal> for
 	 <listitem><para>Try to download deltas called <literal>PDiffs</literal> for
 	 Packages or Sources files instead of downloading whole ones. True
 	 Packages or Sources files instead of downloading whole ones. True
@@ -411,6 +447,15 @@ DPkg::Pre-Install-Pkgs {"/usr/sbin/dpkg-preconfigure --apt";};
      really prefer uncompressed files to support the usage of local mirrors.</para></listitem>
      really prefer uncompressed files to support the usage of local mirrors.</para></listitem>
      </varlistentry>
      </varlistentry>
 
 
+     <varlistentry><term>GzipIndexes</term>
+	 <listitem><para>
+	 When downloading <literal>gzip</literal> compressed indexes (Packages, Sources, or
+	 Translations), keep them gzip compressed locally instead of unpacking
+	 them. This saves quite a lot of disk space at the expense of more CPU
+	 requirements when building the local package caches. False by default.
+	 </para></listitem>
+     </varlistentry>
+
      <varlistentry><term>Languages</term>
      <varlistentry><term>Languages</term>
      <listitem><para>The Languages subsection controls which <filename>Translation</filename> files are downloaded
      <listitem><para>The Languages subsection controls which <filename>Translation</filename> files are downloaded
      and in which order APT tries to display the Description-Translations. APT will try to display the first
      and in which order APT tries to display the Description-Translations. APT will try to display the first
@@ -482,6 +527,15 @@ DPkg::Pre-Install-Pkgs {"/usr/sbin/dpkg-preconfigure --apt";};
      will be looked up in
      will be looked up in
      <filename>/tmp/staging/var/lib/dpkg/status</filename>.
      <filename>/tmp/staging/var/lib/dpkg/status</filename>.
    </para>
    </para>
+
+   <para>
+      The <literal>Ignore-Files-Silently</literal> list can be used to specify
+      which files APT should silently ignore while parsing the files in the
+      fragment directories. Per default a file which end with <literal>.disabled</literal>,
+      <literal>~</literal>, <literal>.bak</literal> or <literal>.dpkg-[a-z]+</literal>
+      is silently ignored. As seen in the last default value these patterns can use regular
+      expression syntax.
+   </para>
  </refsect1>
  </refsect1>
  
  
  <refsect1><title>APT in DSelect</title>
  <refsect1><title>APT in DSelect</title>

+ 22 - 9
doc/apt.ent

@@ -142,12 +142,6 @@
   </citerefentry>"
   </citerefentry>"
 >
 >
 
 
-<!ENTITY gnome-apt "<citerefentry>
-    <refentrytitle><command>gnome-apt</command></refentrytitle>
-    <manvolnum>1</manvolnum>
-  </citerefentry>"
->
-
 <!ENTITY wajig "<citerefentry>
 <!ENTITY wajig "<citerefentry>
     <refentrytitle><command>wajig</command></refentrytitle>
     <refentrytitle><command>wajig</command></refentrytitle>
     <manvolnum>1</manvolnum>
     <manvolnum>1</manvolnum>
@@ -261,7 +255,9 @@
       <term><option>--config-file</option></term>
       <term><option>--config-file</option></term>
      <listitem><para>Configuration File; Specify a configuration file to use. 
      <listitem><para>Configuration File; Specify a configuration file to use. 
      The program will read the default configuration file and then this 
      The program will read the default configuration file and then this 
-     configuration file. See &apt-conf; for syntax information.     
+     configuration file. If configuration settings need to be set before the
+     default configuration files are parsed specify a file with the <envar>APT_CONFIG</envar>
+     environment variable. See &apt-conf; for syntax information.
      </para>
      </para>
      </listitem>
      </listitem>
      </varlistentry>
      </varlistentry>
@@ -367,9 +363,19 @@
      </varlistentry>
      </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">
 <!ENTITY translation-title "TRANSLATION">
 
 
-<!-- TRANSLATOR: This is a placeholder. You should write here who has constributed
+<!-- TRANSLATOR: This is a placeholder. You should write here who has contributed
      to the translation in the past, who is responsible now and maybe further information
      to the translation in the past, who is responsible now and maybe further information
      specially related to your translation. -->
      specially related to your translation. -->
 <!ENTITY translation-holder "
 <!ENTITY translation-holder "
@@ -379,9 +385,16 @@
 ">
 ">
 
 
 <!-- TRANSLATOR: As a translation is allowed to have 20% of untranslated/fuzzy strings
 <!-- TRANSLATOR: As a translation is allowed to have 20% of untranslated/fuzzy strings
-     in a shipped manpage will maybe appear english parts. -->
+     in a shipped manpage newer/modified paragraphs will maybe appear in english in
+     the generated manpage. This sentence is therefore here to tell the reader that this
+     is not a mistake by the translator - obviously the target is that at least for stable
+     releases this sentence is not needed. :) -->
 <!ENTITY translation-english "
 <!ENTITY translation-english "
      Note that this translated document may contain untranslated parts.
      Note that this translated document may contain untranslated parts.
      This is done on purpose, to avoid losing content when the
      This is done on purpose, to avoid losing content when the
      translation is lagging behind the original content.
      translation is lagging behind the original content.
 ">
 ">
+
+<!ENTITY oldstable-codename "etch">
+<!ENTITY stable-codename "lenny">
+<!ENTITY testing-codename "squeeze">

+ 32 - 18
doc/apt_preferences.5.xml

@@ -59,6 +59,9 @@ APT will not questioning the preferences so wrong settings will therefore
 lead to uninstallable packages or wrong decisions while upgrading packages.
 lead to uninstallable packages or wrong decisions while upgrading packages.
 Even more problems will arise if multiply distribution releases are mixed
 Even more problems will arise if multiply distribution releases are mixed
 without a good understanding of the following paragraphs.
 without a good understanding of the following paragraphs.
+Packages included in a specific release aren't tested in and
+therefore doesn't always work as expected in older or newer releases or
+together with other packages from different releases.
 You have been warned.</para>
 You have been warned.</para>
 
 
 <para>Note that the files in the <filename>/etc/apt/preferences.d</filename>
 <para>Note that the files in the <filename>/etc/apt/preferences.d</filename>
@@ -94,6 +97,12 @@ APT::Default-Release "stable";
 algorithm to set the priorities of the versions of a package.  Assign:
 algorithm to set the priorities of the versions of a package.  Assign:
 
 
 <variablelist>
 <variablelist>
+<varlistentry>
+<term>priority 1</term>
+<listitem><simpara>to the versions coming from archives which in their <filename>Release</filename>
+files are marked as "NotAutomatic: yes" like the debian experimental archive.</simpara></listitem>
+</varlistentry>
+
 <varlistentry>
 <varlistentry>
 <term>priority 100</term>
 <term>priority 100</term>
 <listitem><simpara>to the version that is already installed (if any).</simpara></listitem>
 <listitem><simpara>to the version that is already installed (if any).</simpara></listitem>
@@ -113,7 +122,9 @@ algorithm to set the priorities of the versions of a package.  Assign:
 
 
 <para>If the target release has not been specified then APT simply assigns
 <para>If the target release has not been specified then APT simply assigns
 priority 100 to all installed package versions and priority 500 to all
 priority 100 to all installed package versions and priority 500 to all
-uninstalled package versions.</para>
+uninstalled package versions, expect versions coming from archives which
+in their <filename>Release</filename> files are marked as "NotAutomatic: yes" -
+these versions get the priority 1.</para>
 
 
 <para>APT then applies the following rules, listed in order of precedence,
 <para>APT then applies the following rules, listed in order of precedence,
 to determine which version of a package to install.
 to determine which version of a package to install.
@@ -192,8 +203,15 @@ Pin: origin ""
 Pin-Priority: 999
 Pin-Priority: 999
 </programlisting>
 </programlisting>
 
 
-<simpara>A note of caution: the keyword used here is "<literal>origin</literal>".
-This should not be confused with the Origin of a distribution as
+<simpara>A note of caution: the keyword used here is "<literal>origin</literal>"
+which can be used to match a hostname. The following record will assign a high priority
+to all versions available from the server identified by the hostname "ftp.de.debian.org"</simpara>
+<programlisting>
+Package: *
+Pin: origin "ftp.de.debian.org"
+Pin-Priority: 999
+</programlisting>
+<simpara>This should <emphasis>not</emphasis> be confused with the Origin of a distribution as
 specified in a <filename>Release</filename> file.  What follows the "Origin:" tag
 specified in a <filename>Release</filename> file.  What follows the "Origin:" tag
 in a <filename>Release</filename> file is not an Internet address
 in a <filename>Release</filename> file is not an Internet address
 but an author or vendor name, such as "Debian" or "Ximian".</simpara>
 but an author or vendor name, such as "Debian" or "Ximian".</simpara>
@@ -208,11 +226,11 @@ Pin-Priority: 50
 </programlisting>
 </programlisting>
 
 
 <simpara>The following record assigns a high priority to all package versions
 <simpara>The following record assigns a high priority to all package versions
-belonging to any distribution whose Codename is "<literal>squeeze</literal>".</simpara>
+belonging to any distribution whose Codename is "<literal>&testing-codename;</literal>".</simpara>
 
 
 <programlisting>
 <programlisting>
 Package: *
 Package: *
-Pin: release n=squeeze
+Pin: release n=&testing-codename;
 Pin-Priority: 900
 Pin-Priority: 900
 </programlisting>
 </programlisting>
 
 
@@ -345,7 +363,7 @@ APT priorities:
 <para>The <filename>Release</filename> file is normally found in the directory
 <para>The <filename>Release</filename> file is normally found in the directory
 <filename>.../dists/<replaceable>dist-name</replaceable></filename>:
 <filename>.../dists/<replaceable>dist-name</replaceable></filename>:
 for example, <filename>.../dists/stable/Release</filename>,
 for example, <filename>.../dists/stable/Release</filename>,
-or <filename>.../dists/woody/Release</filename>.
+or <filename>.../dists/&stable-codename;/Release</filename>.
 It consists of a single multi-line record which applies to <emphasis>all</emphasis> of
 It consists of a single multi-line record which applies to <emphasis>all</emphasis> of
 the packages in the directory tree below its parent.  Unlike the
 the packages in the directory tree below its parent.  Unlike the
 <filename>Packages</filename> file, nearly all of the lines in a <filename>Release</filename>
 <filename>Packages</filename> file, nearly all of the lines in a <filename>Release</filename>
@@ -373,14 +391,14 @@ Pin: release a=stable
 <term>the <literal>Codename:</literal> line</term>
 <term>the <literal>Codename:</literal> line</term>
 <listitem><simpara>names the codename to which all the packages
 <listitem><simpara>names the codename to which all the packages
 in the directory tree belong.  For example, the line
 in the directory tree belong.  For example, the line
-"Codename: squeeze"
+"Codename: &testing-codename;"
 specifies that all of the packages in the directory
 specifies that all of the packages in the directory
 tree below the parent of the <filename>Release</filename> file belong to a version named
 tree below the parent of the <filename>Release</filename> file belong to a version named
-<literal>squeeze</literal>.  Specifying this value in the APT preferences file
+<literal>&testing-codename;</literal>.  Specifying this value in the APT preferences file
 would require the line:
 would require the line:
 </simpara>
 </simpara>
 <programlisting>
 <programlisting>
-Pin: release n=squeeze
+Pin: release n=&testing-codename;
 </programlisting>
 </programlisting>
 </listitem>
 </listitem>
 </varlistentry>
 </varlistentry>
@@ -466,10 +484,6 @@ distribution.</para>
 <para>Each record in the APT preferences file can optionally begin with
 <para>Each record in the APT preferences file can optionally begin with
 one or more lines beginning with the word <literal>Explanation:</literal>.
 one or more lines beginning with the word <literal>Explanation:</literal>.
 This provides a place for comments.</para>
 This provides a place for comments.</para>
-
-<para>The <literal>Pin-Priority:</literal> line in each APT preferences record is
-optional.  If omitted, APT assigns a priority of 1 less than the last value
-specified on a line beginning with <literal>Pin-Priority: release ...</literal>.</para>
 </refsect2>
 </refsect2>
 </refsect1>
 </refsect1>
 
 
@@ -584,14 +598,14 @@ the example configurations above.
 
 
 <programlisting>
 <programlisting>
 Explanation: Uninstall or do not install any Debian-originated package versions
 Explanation: Uninstall or do not install any Debian-originated package versions
-Explanation: other than those in the distribution codenamed with squeeze or sid
+Explanation: other than those in the distribution codenamed with &testing-codename; or sid
 Package: *
 Package: *
-Pin: release n=squeeze
+Pin: release n=&testing-codename;
 Pin-Priority: 900
 Pin-Priority: 900
 
 
 Explanation: Debian unstable is always codenamed with sid
 Explanation: Debian unstable is always codenamed with sid
 Package: *
 Package: *
-Pin: release a=sid
+Pin: release n=sid
 Pin-Priority: 800
 Pin-Priority: 800
 
 
 Package: *
 Package: *
@@ -602,7 +616,7 @@ Pin-Priority: -10
 
 
 <para>With a suitable &sources-list; file and the above preferences file,
 <para>With a suitable &sources-list; file and the above preferences file,
 any of the following commands will cause APT to upgrade to the
 any of the following commands will cause APT to upgrade to the
-latest version(s) in the release codenamed with <literal>squeeze</literal>.
+latest version(s) in the release codenamed with <literal>&testing-codename;</literal>.
 
 
 <programlisting>
 <programlisting>
 apt-get install <replaceable>package-name</replaceable>
 apt-get install <replaceable>package-name</replaceable>
@@ -614,7 +628,7 @@ apt-get dist-upgrade
 <para>The following command will cause APT to upgrade the specified
 <para>The following command will cause APT to upgrade the specified
 package to the latest version from the <literal>sid</literal> distribution.
 package to the latest version from the <literal>sid</literal> distribution.
 Thereafter, <command>apt-get upgrade</command> will upgrade
 Thereafter, <command>apt-get upgrade</command> will upgrade
-the package to the most recent <literal>squeeze</literal> version if that is
+the package to the most recent <literal>&testing-codename;</literal> version if that is
 more recent than the installed version, otherwise, to the most recent
 more recent than the installed version, otherwise, to the most recent
 <literal>sid</literal> version if that is more recent than the installed
 <literal>sid</literal> version if that is more recent than the installed
 version.
 version.

+ 0 - 0
doc/cache.sgml


Неке датотеке нису приказане због велике количине промена