]> git.saurik.com Git - apt.git/commitdiff
merged patches from david (many thanks)
authorMichael Vogt <michael.vogt@ubuntu.com>
Mon, 14 Dec 2009 08:22:29 +0000 (09:22 +0100)
committerMichael Vogt <michael.vogt@ubuntu.com>
Mon, 14 Dec 2009 08:22:29 +0000 (09:22 +0100)
20 files changed:
apt-inst/makefile
apt-pkg/init.h
buildlib/library.mak
buildlib/libversion.mak
debian/apt.cron.daily
debian/changelog
debian/rules
doc/apt-ftparchive.1.xml
doc/apt-get.8.xml
doc/apt.conf.5.xml
doc/examples/configure-index
ftparchive/apt-ftparchive.cc
ftparchive/cachedb.cc
ftparchive/contents.cc
ftparchive/multicompress.cc
ftparchive/writer.cc
methods/connect.cc
methods/http.cc
methods/https.cc
methods/rred.cc

index c0ff3d8862eaac1bf48fa9028f1b9b6d1574d1f2..18637d749415cae0b63737a38e9b75da61c6f6d1 100644 (file)
@@ -11,7 +11,7 @@ include ../buildlib/defaults.mak
 
 # The library name
 LIBRARY=apt-inst
-MAJOR=1.2
+MAJOR=1.1
 MINOR=0
 SLIBS=$(PTHREADLIB) -lapt-pkg
 APT_DOMAIN:=libapt-inst$(MAJOR)
index f892e7ff458a426b36dddea7a7c85cae6a712593..f0757f644c9d3bb83d772ff7306338fc27f2b2c9 100644 (file)
@@ -21,9 +21,7 @@
 // reverse-dependencies of libapt-pkg against the new SONAME.
 // Non-ABI-Breaks should only increase RELEASE number.
 // See also buildlib/libversion.mak
-// FIXME: this needs to be changed to "4" (without quotes) on the next
-//        ABI break
-#define APT_PKG_MAJOR libc6.9-6-4
+#define APT_PKG_MAJOR 4
 #define APT_PKG_MINOR 8
 #define APT_PKG_RELEASE 0
     
index 029e8746319177124d6bb25ec3f6bac217dc51a4..2a4bb782a38af0d511c52cde58fe93c31606d27a 100644 (file)
 # See defaults.mak for information about LOCAL
 
 # Some local definitions
-LOCAL := lib$(LIBRARY).so.$(MAJOR).$(MINOR)
+LOCAL := lib$(LIBRARY)$(LIBEXT).so.$(MAJOR).$(MINOR)
 $(LOCAL)-OBJS := $(addprefix $(OBJ)/,$(addsuffix .opic,$(notdir $(basename $(SOURCE)))))
 $(LOCAL)-DEP := $(addprefix $(DEP)/,$(addsuffix .opic.d,$(notdir $(basename $(SOURCE)))))
 $(LOCAL)-HEADERS := $(addprefix $(INCLUDE)/,$(HEADERS))
-$(LOCAL)-SONAME := lib$(LIBRARY).so.$(MAJOR)
+$(LOCAL)-SONAME := lib$(LIBRARY)$(LIBEXT).so.$(MAJOR)
 $(LOCAL)-SLIBS := $(SLIBS)
 $(LOCAL)-LIBRARY := $(LIBRARY)
 
@@ -29,7 +29,7 @@ include $(PODOMAIN_H)
 
 # Install the command hooks
 headers: $($(LOCAL)-HEADERS)
-library: $(LIB)/lib$(LIBRARY).so $(LIB)/lib$(LIBRARY).so.$(MAJOR)
+library: $(LIB)/lib$(LIBRARY).so $(LIB)/lib$(LIBRARY)$(LIBEXT).so.$(MAJOR)
 clean: clean/$(LOCAL)
 veryclean: veryclean/$(LOCAL)
 
@@ -44,14 +44,14 @@ veryclean/$(LOCAL): clean/$(LOCAL)
        -rm -f $($(@F)-HEADERS) $(LIB)/lib$($(@F)-LIBRARY)*.so*
 
 # Build rules for the two symlinks
-.PHONY: $(LIB)/lib$(LIBRARY).so.$(MAJOR) $(LIB)/lib$(LIBRARY).so
-$(LIB)/lib$(LIBRARY).so.$(MAJOR): $(LIB)/lib$(LIBRARY).so.$(MAJOR).$(MINOR)
+.PHONY: $(LIB)/lib$(LIBRARY)$(LIBEXT).so.$(MAJOR) $(LIB)/lib$(LIBRARY).so
+$(LIB)/lib$(LIBRARY)$(LIBEXT).so.$(MAJOR): $(LIB)/lib$(LIBRARY)$(LIBEXT).so.$(MAJOR).$(MINOR)
        ln -sf $(<F) $@
-$(LIB)/lib$(LIBRARY).so: $(LIB)/lib$(LIBRARY).so.$(MAJOR).$(MINOR)
+$(LIB)/lib$(LIBRARY).so: $(LIB)/lib$(LIBRARY)$(LIBEXT).so.$(MAJOR).$(MINOR)
        ln -sf $(<F) $@
 
 # The binary build rule
-$(LIB)/lib$(LIBRARY).so.$(MAJOR).$(MINOR): $($(LOCAL)-HEADERS) $($(LOCAL)-OBJS)
+$(LIB)/lib$(LIBRARY)$(LIBEXT).so.$(MAJOR).$(MINOR): $($(LOCAL)-HEADERS) $($(LOCAL)-OBJS)
        -rm -f $(LIB)/lib$($(@F)-LIBRARY)*.so* 2> /dev/null
        echo Building shared library $@
        $(CXX) $(CXXFLAGS) $(LDFLAGS) $(PICFLAGS) $(LFLAGS) $(LFLAGS_SO)\
index 796c956e7becab3a7c3b999d85359a0384eca446..26ca86ced44ea15e79c6303dfc13b26a464dc95d 100644 (file)
@@ -12,3 +12,10 @@ LIBAPTPKG_RELEASE=$(shell grep -E '^\#define APT_PKG_RELEASE' $(BASE)/apt-pkg/in
 # The versionnumber is extracted from apt-inst/makefile - see also there.
 LIBAPTINST_MAJOR=$(shell egrep '^MAJOR=' $(BASE)/apt-inst/makefile |cut -d '=' -f 2)
 LIBAPTINST_MINOR=$(shell egrep '^MINOR=' $(BASE)/apt-inst/makefile |cut -d '=' -f 2)
+
+# FIXME: In previous releases this lovely variable includes
+# the detected libc and libdc++ version. As this is bogus we
+# want to drop this, but this a ABI break.
+# And we don't want to do this now. So we hardcode a value here,
+# and drop it later on (hopefully as fast as possible).
+LIBEXT=-libc6.9-6
index b6099ee75aa30cd22b8e2c8dcf56a17aff7238ad..e59b05ee484534bb0d74bb59718f8cf7fdba1593 100644 (file)
@@ -401,12 +401,16 @@ eval $(apt-config shell BackupArchiveInterval APT::Periodic::BackupArchiveInterv
 Debdelta=1
 eval $(apt-config shell Debdelta APT::Periodic::Download-Upgradeable-Packages-Debdelta)
 
-# check if we actually have to do anything
+# check if we actually have to do anything that requires locking the cache
 if [ $UpdateInterval -eq 0 ] &&
    [ $DownloadUpgradeableInterval -eq 0 ] &&
    [ $UnattendedUpgradeInterval -eq 0 ] &&
    [ $BackupArchiveInterval -eq 0 ] &&
    [ $AutocleanInterval -eq 0 ]; then
+
+    # check cache size
+    check_size_constraints
+
     exit 0
 fi
 
index 64e67670920fac55611fd841878c5f633fe0caaf..cd4573468c405627a27a7dacc4cdac005083f6a8 100644 (file)
@@ -13,8 +13,6 @@ apt (0.7.25) UNRELEASED; urgency=low
     Closes: #548571
   * German translation update by Holger Wansing
     Closes: #551534
-  * German translation of manpages by Chris Leick
-    Closes: #552606
   * Italian translation update by Milo Casagrande
     Closes: #555797
   * Simplified Chinese translation update by Aron Xu 
@@ -37,7 +35,7 @@ apt (0.7.25) UNRELEASED; urgency=low
   * apt-pkg/deb/dpkgpm.cc:
     - add "purge" to list of known actions
   * apt-pkg/init.h:
-    - add compatibilty with old ABI name until the next ABI break
+    - add compatibility with old ABI name until the next ABI break
 
   [ Brian Murray ]
   * apt-pkg/depcache.cc, apt-pkg/indexcopy.cc:
@@ -56,18 +54,21 @@ apt (0.7.25) UNRELEASED; urgency=low
   * doc/po4a.conf: activate translation of guide.sgml and offline.sgml
   * doc/apt.conf.5.xml:
     - provide a few more details about APT::Immediate-Configure
+    - briefly document the behaviour of the new https options
   * doc/sources.list.5.xml:
     - add note about additional apt-transport-methods
   * doc/apt-mark.8.xml:
     - correct showauto synopsis, thanks Andrew Schulman (Closes: #551440)
   * cmdline/apt-get.cc:
-    - source should displays his final pkg pick (Closes: #249383, #550952)
+    - source should display his final pkg pick (Closes: #249383, #550952)
     - source doesn't need the complete version for match (Closes: #245250)
     - source ignores versions/releases if not available (Closes: #377424)
     - only warn if (free) space overflows (Closes: #522238)
     - add --debian-only as alias for --diff-only
   * methods/connect.cc:
     - display also strerror of "wicked" getaddrinfo errors
+    - add AI_ADDRCONFIG to ai_flags as suggested by Aurelien Jarno
+      in response to Bernhard R. Link, thanks! (Closes: #505020)
   * buildlib/configure.mak, buildlib/config.{sub,guess}:
     - remove (outdated) config.{sub,guess} and use the ones provided
       by the new added build-dependency autotools-dev instead
@@ -81,21 +82,42 @@ apt (0.7.25) UNRELEASED; urgency=low
     - bump policy to 3.8.3 as we have no outdated manpages anymore
   * debian/NEWS:
     - fix a typo in 0.7.24: Allready -> Already (Closes: #557674)
-  * cmdline/apt-mark:
-    - print an error if a new state file can't be created,
-      thanks Carl Chenet! (Closes: #521289)
-    - print an error and exit if python-apt is not installed,
-      thanks Carl Chenet! (Closes: #521284)
   * ftparchive/writer.{cc,h}:
     - add APT::FTPArchive::LongDescription to be able to disable them
   * apt-pkg/deb/debsrcrecords.cc:
     - use "diff" filetype for .debian.tar.* files (Closes: #554898)
+  * methods/rred.cc:
+    - rewrite to be able to handle even big patch files
+    - adopt optional mmap+iovec patch from Morten Hustveit
+      (Closes: #463354) which should speed up a bit. Thanks!
+  * methods/http{,s}.cc
+    - add config setting for User-Agent to the Acquire group,
+      thanks Timothy J. Miller! (Closes: #355782)
+    - add https options which default to http ones (Closes: #557085)
+  * debian/apt.cron.daily:
+    - check cache size even if we do nothing else otherwise, thanks
+      Francesco Poli for patch(s) and patience! (Closes: #459344)
+  * ftparchive/*:
+    - fix a few typos in strings, comments and manpage,
+      thanks Karl Goetz! (Closes: #558757)
+
+  [ Carl Chenet ]
+  * cmdline/apt-mark:
+    - print an error if a new state file can't be created
+      (Closes: #521289) and
+    - exit nicely if python-apt is not installed (Closes: #521284)
 
   [ Chris Leick ]
+  * doc/de: German translation of manpages (Closes: #552606)
   * doc/ various manpages:
     - correct various errors, typos and oddities (Closes: #552535)
   * doc/apt-secure.8.xml:
     - replace literal with emphasis tags in Archive configuration
+  * doc/apt-ftparchive.1.xml:
+    - remove informalexample tag which hides the programlisting
+  * doc/apt-get.8.xml:
+    - change equivalent "for" to "to the" (purge command)
+    - clarify --fix-broken sentence about specifying packages
 
   [ Eugene V. Lyubimkin ]
   * apt-pkg/contib/strutl.h
index f69c0cffb7999b9dfcc5cb4dd5a20f3f51a5aa03..d01b57cd637aa84c1530b737b09b8196f6b918de 100755 (executable)
@@ -78,21 +78,21 @@ APT_UTILS=ftparchive sortpkgs extracttemplates
 include buildlib/libversion.mak
 
 # Determine which package we should provide in the control files
-LIBAPTPKG_PROVIDE=libapt-pkg-$(LIBAPTPKG_MAJOR)
-LIBAPTINST_PROVIDE=libapt-inst-$(LIBAPTINST_MAJOR)
+LIBAPTPKG_PROVIDE=libapt-pkg$(LIBEXT)-$(LIBAPTPKG_MAJOR)
+LIBAPTINST_PROVIDE=libapt-inst$(LIBEXT)-$(LIBAPTINST_MAJOR)
 
 debian/shlibs.local: apt-pkg/makefile
        # 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
        # the right overrides.. 
        rm -rf $@ $@.apt $@.apt-utils
-       echo "libapt-pkg $(LIBAPTPKG_MAJOR)" > $@.apt
+       echo "libapt-pkg$(LIBEXT) $(LIBAPTPKG_MAJOR)" > $@.apt
 
-       echo "libapt-pkg $(LIBAPTPKG_MAJOR) $(LIBAPTPKG_PROVIDE)" > $@.apt-utils
-       echo "libapt-inst $(LIBAPTINST_MAJOR)" >> $@.apt-utils
+       echo "libapt-pkg$(LIBEXT) $(LIBAPTPKG_MAJOR) $(LIBAPTPKG_PROVIDE)" > $@.apt-utils
+       echo "libapt-inst$(LIBEXT) $(LIBAPTINST_MAJOR)" >> $@.apt-utils
 
-       echo "libapt-pkg $(LIBAPTPKG_MAJOR) $(LIBAPTPKG_PROVIDE)" > $@
-       echo "libapt-inst $(LIBAPTINST_MAJOR) $(LIBAPTINST_PROVIDE)" >> $@
+       echo "libapt-pkg$(LIBEXT) $(LIBAPTPKG_MAJOR) $(LIBAPTPKG_PROVIDE)" > $@
+       echo "libapt-inst$(LIBEXT) $(LIBAPTINST_MAJOR) $(LIBAPTINST_PROVIDE)" >> $@
 
 build: build/build-stamp       
 build-doc: build/build-doc-stamp       
index d47df957acdcff191451788f580b24ccbdf32c34..c56ff235a27cd55657e547936f5648b6802c204f 100644 (file)
       
       <varlistentry><term>Sources</term>
       <listitem><para>
-      Sets the output Packages file. Defaults to 
+      Sets the output Sources file. Defaults to 
       <filename>$(DIST)/$(SECTION)/source/Sources</filename></para></listitem>
       </varlistentry>
       
      <para>
      When processing a <literal>Tree</literal> section <command>apt-ftparchive</command> 
      performs an operation similar to:
-<informalexample><programlisting>
+     <programlisting>
 for i in Sections do 
    for j in Architectures do
       Generate for DIST=scope SECTION=i ARCH=j
-</programlisting></informalexample></para>
+     </programlisting></para>
 
      <variablelist>     
       <varlistentry><term>Sections</term>
index d3c3772bde1256ec46ff770a5d1384ff61580b3e..3d22f262ca9b2b5c79a7dcc0bad6d12ad4ec2ef6 100644 (file)
      <varlistentry><term><option>-f</option></term><term><option>--fix-broken</option></term>
      <listitem><para>Fix; attempt to correct a system with broken dependencies in            
      place. This option, when used with install/remove, can omit any packages
-     to permit APT to deduce a likely solution. Any Package that are specified
-     must completely correct the problem. The option is sometimes necessary when 
+     to permit APT to deduce a likely solution. If packages are specified,
+     these have to completely correct the problem. The option is sometimes necessary when 
      running APT for the first time; APT itself does not allow broken package 
      dependencies to exist on a system. It is possible that a system's 
      dependency structure can be so corrupt as to require manual intervention 
      <varlistentry><term><option>--purge</option></term>
      <listitem><para>Use purge instead of remove for anything that would be removed.
      An asterisk ("*") will be displayed next to packages which are
-        scheduled to be purged. <option>remove --purge</option> is equivalent for
+        scheduled to be purged. <option>remove --purge</option> is equivalent to the
         <option>purge</option> command.
      Configuration Item: <literal>APT::Get::Purge</literal>.</para></listitem>
      </varlistentry>
index e2db9defbd6424bc2c1f4a6705f1fe8ced509023..d7ad51cfb4aa24f8dbd1d46e1bbca9cdf0a0de32 100644 (file)
@@ -275,13 +275,20 @@ DPkg::Pre-Install-Pkgs {"/usr/sbin/dpkg-preconfigure --apt";};
      <para>The used bandwidth can be limited with <literal>Acquire::http::Dl-Limit</literal>
      which accepts integer values in kilobyte. The default value is 0 which deactivates
      the limit and tries uses as much as possible of the bandwidth (Note that this option implicit
-     deactivates the download from multiple servers at the same time.)</para></listitem>
+     deactivates the download from multiple servers at the same time.)</para>
+
+     <para><literal>Acquire::http::User-Agent</literal> can be used to set a different
+     User-Agent for the http download method as some proxies allow access for clients
+     only if the client uses a known identifier.</para>
+     </listitem>
      </varlistentry>
 
      <varlistentry><term>https</term>
-        <listitem><para>HTTPS URIs. Cache-control and proxy options are the same as for
-        <literal>http</literal> method.
-        <literal>Pipeline-Depth</literal> option is not supported yet.</para>
+        <listitem><para>HTTPS URIs. Cache-control, Timeout, AllowRedirect, Dl-Limit and
+        proxy options are the same as for <literal>http</literal> method and will also
+        default to the options from the <literal>http</literal> method if they are not
+        explicitly set for https. <literal>Pipeline-Depth</literal> option is not
+        supported yet.</para>
 
         <para><literal>CaInfo</literal> suboption specifies place of file that
         holds info about trusted certificates.
index f5f9964609282e6d75c4ae562b192f0bc52da9b6..ced390447bbb0da40e20c1d9302051910319ba02 100644 (file)
@@ -191,19 +191,37 @@ Acquire
     Max-Age "86400";     // 1 Day age on index files
     No-Store "false";    // Prevent the cache from storing archives    
     Dl-Limit "7";        // 7Kb/sec maximum download rate
+    User-Agent "Debian APT-HTTP/1.3";
   };
 
-  // HTTPS method configuration:
-  // - uses the http proxy config 
-  // - uses the http cache-control values
-  // - uses the http Dl-Limit values
-  https 
+
+
+  // HTTPS method configuration: uses the http
+  // - proxy config
+  // - cache-control values
+  // - Dl-Limit, Timout, ... values
+  // if not set explicit for https
+  //
+  // see /usr/share/doc/apt/examples/apt-https-method-example.conf.gz
+  // for more examples
+  https
   {
        Verify-Peer "false";
        SslCert "/etc/apt/some.pem";
-        CaPath  "/etc/ssl/certs";
-        Verify-Host" "true";
-        AllowRedirect  "true";
+       CaPath  "/etc/ssl/certs";
+       Verify-Host" "true";
+       AllowRedirect  "true";
+
+       Timeout "120";
+       AllowRedirect  "true";
+
+       // Cache Control. Note these do not work with Squid 2.0.2
+       No-Cache "false";
+       Max-Age "86400";     // 1 Day age on index files
+       No-Store "false";    // Prevent the cache from storing archives
+       Dl-Limit "7";        // 7Kb/sec maximum download rate
+
+       User-Agent "Debian APT-CURL/1.0";
   };
 
   ftp
index d0dea7768288edee11aee9a72d2e4473f6ee20c8..5b6b3940c652ddb6924a91c741e0de20863f57f8 100644 (file)
@@ -3,7 +3,7 @@
 // $Id: apt-ftparchive.cc,v 1.8.2.3 2004/01/02 22:01:48 mdz Exp $
 /* ######################################################################
 
-   apt-scanpackages - Efficient work-alike for dpkg-scanpackages
+   apt-ftparchive - Efficient work-alike for dpkg-scanpackages
 
    Let contents be disabled from the conf
    
@@ -792,7 +792,7 @@ bool Generate(CommandLine &CmdL)
    if (_config->FindB("APT::FTPArchive::Contents",true) == false)
       return true;
    
-   c1out << "Done Packages, Starting contents." << endl;
+   c1out << "Packages done, Starting contents." << endl;
 
    // Sort the contents file list by date
    string ArchiveDir = Setup.FindDir("Dir::ArchiveDir");
index dfda827b6b0b362af8218f2b9d359d1b88876587..e02f0e1b6dd93b11de51a6093528030454466018 100644 (file)
@@ -69,7 +69,7 @@ bool CacheDB::ReadyDB(string DB)
       // apt 0.6.44
       if (err == EINVAL)
       {
-        _error->Error(_("DB format is invalid. If you upgraded from a older version of apt, please remove and re-create the database."));
+        _error->Error(_("DB format is invalid. If you upgraded from an older version of apt, please remove and re-create the database."));
       }
       if (err)
       {
@@ -83,7 +83,7 @@ bool CacheDB::ReadyDB(string DB)
    return true;
 }
                                                                        /*}}}*/
-// CacheDB::OpenFile - Open the filei                                  /*{{{*/
+// CacheDB::OpenFile - Open the file                                   /*{{{*/
 // ---------------------------------------------------------------------
 /* */
 bool CacheDB::OpenFile()
@@ -139,7 +139,7 @@ bool CacheDB::GetCurStat()
    
        if (DBLoaded)
        {
-               /* First see if thre is anything about it
+               /* First see if there is anything about it
                   in the database */
 
                /* Get the flags (and mtime) */
index 1f2cbcc3d2ff3ba78c58cb165bcd845665e7a2c5..fb1438f745bc1192aa026d371714da91e5a23ec7 100644 (file)
@@ -13,7 +13,7 @@
    removing the massive sort time overhead.
    
    By breaking all the pathnames into components and storing them 
-   separately a space savings is realized by not duplicating the string
+   separately a space saving is realized by not duplicating the string
    over and over again. Ultimately this saving is sacrificed to storage of
    the tree structure itself but the tree structure yields a speed gain
    in the sorting and processing. Ultimately it takes about 5 seconds to
index 2fc8efcbfe142e3882480d79b9b249be219e1aa3..16cef9769e7e36a495159874600a23e01ce6f0e0 100644 (file)
@@ -365,7 +365,7 @@ bool MultiCompress::CloseOld(int Fd,pid_t Proc)
 // MultiCompress::Child - The writer child                             /*{{{*/
 // ---------------------------------------------------------------------
 /* The child process forks a bunch of compression children and takes 
-   input on FD and passes it to all the compressor childer. On the way it
+   input on FD and passes it to all the compressor child. On the way it
    computes the MD5 of the raw data. After this the raw data in the 
    original files is compared to see if this data is new. If the data
    is new then the temp files are renamed, otherwise they are erased. */
index b2ebdca8a30190c6fda77cdc0fd7bcbf90a0fd3c..4e6c9a77ddab6d2049d83ab1334b773de3e4742c 100644 (file)
@@ -463,7 +463,7 @@ bool PackagesWriter::DoPackage(string FileName)
       SetTFRewriteData(Changes[End++], "Maintainer", NewMaint.c_str());
    
    /* Get rid of the Optional tag. This is an ugly, ugly, ugly hack that
-      dpkg-scanpackages does.. Well sort of. dpkg-scanpackages just does renaming
+      dpkg-scanpackages does. Well sort of. dpkg-scanpackages just does renaming
       but dpkg does this append bit. So we do the append bit, at least that way the
       status file and package file will remain similar. There are other transforms
       but optional is the only legacy one still in use for some lazy reason. */
index 74e670ebd417cf0467aed6a45ef596653ecc1659..adb16a19973c9341dfc9b38f0a311f913cac63a2 100644 (file)
@@ -158,6 +158,7 @@ bool Connect(string Host,int Port,const char *Service,int DefPort,int &Fd,
       struct addrinfo Hints;
       memset(&Hints,0,sizeof(Hints));
       Hints.ai_socktype = SOCK_STREAM;
+      Hints.ai_flags = AI_ADDRCONFIG;
       Hints.ai_protocol = 0;
       
       // if we couldn't resolve the host before, we don't try now
index 3b210f6b612153fd5a433e784956b28c22ce6677..2dae87a02be878cb3da87c0c18336a8633b2c743 100644 (file)
@@ -731,7 +731,8 @@ void HttpMethod::SendReq(FetchItem *Itm,CircleBuf &Out)
       Req += string("Authorization: Basic ") + 
           Base64Encode(Uri.User + ":" + Uri.Password) + "\r\n";
    }
-   Req += "User-Agent: Debian APT-HTTP/1.3 ("VERSION")\r\n\r\n";
+   Req += "User-Agent: " + _config->Find("Acquire::http::User-Agent",
+               "Debian APT-HTTP/1.3 ("VERSION")") + "\r\n\r\n";
    
    if (Debug == true)
       cerr << Req << endl;
index 86d7f3a6ba6542ed894292fbfc668789690f4949..5d8e63f47db3c2c265126ab4e3e119fc247b5df9 100644 (file)
@@ -1,4 +1,4 @@
-// -*- mode: cpp; mode: fold -*-
+//-*- mode: cpp; mode: fold -*-
 // Description                                                         /*{{{*/
 // $Id: http.cc,v 1.59 2004/05/08 19:42:35 mdz Exp $
 /* ######################################################################
@@ -57,54 +57,41 @@ HttpsMethod::progress_callback(void *clientp, double dltotal, double dlnow,
    return 0;
 }
 
-void HttpsMethod::SetupProxy()
+void HttpsMethod::SetupProxy()                                         /*{{{*/
 {
    URI ServerName = Queue->Uri;
 
-   // Determine the proxy setting
-   string SpecificProxy = _config->Find("Acquire::http::Proxy::" + ServerName.Host);
-   if (!SpecificProxy.empty())
-   {
-          if (SpecificProxy == "DIRECT")
-                  Proxy = "";
-          else
-                  Proxy = SpecificProxy;
-   }
-   else
-   {
-          string DefProxy = _config->Find("Acquire::http::Proxy");
-          if (!DefProxy.empty())
-          {
-                  Proxy = DefProxy;
-          }
-          else
-          {
-                  char* result = getenv("http_proxy");
-                  Proxy = result ? result : "";
-          }
-   }
-   
-   // Parse no_proxy, a , separated list of domains
-   if (getenv("no_proxy") != 0)
+   // Determine the proxy setting - try https first, fallback to http and use env at last
+   string UseProxy = _config->Find("Acquire::https::Proxy::" + ServerName.Host,
+                                  _config->Find("Acquire::http::Proxy::" + ServerName.Host).c_str());
+
+   if (UseProxy.empty() == true)
+      UseProxy = _config->Find("Acquire::https::Proxy", _config->Find("Acquire::http::Proxy").c_str());
+
+   // User want to use NO proxy, so nothing to setup
+   if (UseProxy == "DIRECT")
+      return;
+
+   if (UseProxy.empty() == false) 
    {
-      if (CheckDomainList(ServerName.Host,getenv("no_proxy")) == true)
-        Proxy = "";
+      // Parse no_proxy, a comma (,) separated list of domains we don't want to use
+      // a proxy for so we stop right here if it is in the list
+      if (getenv("no_proxy") != 0 && CheckDomainList(ServerName.Host,getenv("no_proxy")) == true)
+        return;
+   } else {
+      const char* result = getenv("http_proxy");
+      UseProxy = result == NULL ? "" : result;
    }
-   
+
    // Determine what host and port to use based on the proxy settings
-   string Host;   
-   if (Proxy.empty() == true || Proxy.Host.empty() == true)
-   {
-   }
-   else
+   if (UseProxy.empty() == false) 
    {
-      if (Proxy.Port != 0)
+      Proxy = UseProxy;
+      if (Proxy.Port != 1)
         curl_easy_setopt(curl, CURLOPT_PROXYPORT, Proxy.Port);
       curl_easy_setopt(curl, CURLOPT_PROXY, Proxy.Host.c_str());
    }
-}
-
-
+}                                                                      /*}}}*/
 // HttpsMethod::Fetch - Fetch an item                                  /*{{{*/
 // ---------------------------------------------------------------------
 /* This adds an item to the pipeline. We keep the pipeline at a fixed
@@ -191,12 +178,15 @@ bool HttpsMethod::Fetch(FetchItem *Itm)
    curl_easy_setopt(curl, CURLOPT_SSLVERSION, final_version);
 
    // cache-control
-   if(_config->FindB("Acquire::http::No-Cache",false) == false)
+   if(_config->FindB("Acquire::https::No-Cache",
+       _config->FindB("Acquire::http::No-Cache",false)) == false)
    {
       // cache enabled
-      if (_config->FindB("Acquire::http::No-Store",false) == true)
+      if (_config->FindB("Acquire::https::No-Store",
+               _config->FindB("Acquire::http::No-Store",false)) == true)
         headers = curl_slist_append(headers,"Cache-Control: no-store");
-      ioprintf(ss, "Cache-Control: max-age=%u", _config->FindI("Acquire::http::Max-Age",0));
+      ioprintf(ss, "Cache-Control: max-age=%u", _config->FindI("Acquire::https::Max-Age",
+               _config->FindI("Acquire::http::Max-Age",0)));
       headers = curl_slist_append(headers, ss.str().c_str());
    } else {
       // cache disabled by user
@@ -206,22 +196,28 @@ bool HttpsMethod::Fetch(FetchItem *Itm)
    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
 
    // speed limit
-   int dlLimit = _config->FindI("Acquire::http::Dl-Limit",0)*1024;
+   int dlLimit = _config->FindI("Acquire::https::Dl-Limit",
+               _config->FindI("Acquire::http::Dl-Limit",0))*1024;
    if (dlLimit > 0)
       curl_easy_setopt(curl, CURLOPT_MAX_RECV_SPEED_LARGE, dlLimit);
 
    // set header
-   curl_easy_setopt(curl, CURLOPT_USERAGENT,"Debian APT-CURL/1.0 ("VERSION")");
+   curl_easy_setopt(curl, CURLOPT_USERAGENT,
+       _config->Find("Acquire::https::User-Agent",
+               _config->Find("Acquire::http::User-Agent",
+                       "Debian APT-CURL/1.0 ("VERSION")").c_str()).c_str());
 
    // set timeout
-   int timeout = _config->FindI("Acquire::http::Timeout",120);
+   int timeout = _config->FindI("Acquire::https::Timeout",
+               _config->FindI("Acquire::http::Timeout",120));
    curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, timeout);
    //set really low lowspeed timeout (see #497983)
    curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, DL_MIN_SPEED);
    curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME, timeout);
 
    // set redirect options and default to 10 redirects
-   bool AllowRedirect = _config->FindI("Acquire::https::AllowRedirect", true);
+   bool AllowRedirect = _config->FindB("Acquire::https::AllowRedirect",
+       _config->FindB("Acquire::http::AllowRedirect",true));
    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, AllowRedirect);
    curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 10);
 
index 27d95bdde0a0051ae568a07616921d40748b7711..262c78cabdfa99a2425767199ae6ff7ff7fbc00f 100644 (file)
+// Includes                                                                    /*{{{*/
 #include <apt-pkg/fileutl.h>
+#include <apt-pkg/mmap.h>
 #include <apt-pkg/error.h>
 #include <apt-pkg/acquire-method.h>
 #include <apt-pkg/strutl.h>
 #include <apt-pkg/hashes.h>
 
 #include <sys/stat.h>
+#include <sys/uio.h>
 #include <unistd.h>
 #include <utime.h>
 #include <stdio.h>
 #include <errno.h>
 #include <apti18n.h>
-
-/* this method implements a patch functionality similar to "patch --ed" that is
- * used by the "tiffany" incremental packages download stuff. it differs from 
- * "ed" insofar that it is way more restricted (and therefore secure). in the
- * moment only the "c", "a" and "d" commands of ed are implemented (diff 
- * doesn't output any other). additionally the records must be reverse sorted 
- * by line number and may not overlap (diff *seems* to produce this kind of 
- * output). 
+                                                                               /*}}}*/
+/** \brief RredMethod - ed-style incremential patch method                     {{{
+ *
+ *  This method implements a patch functionality similar to "patch --ed" that is
+ *  used by the "tiffany" incremental packages download stuff. It differs from
+ *  "ed" insofar that it is way more restricted (and therefore secure).
+ *  The currently supported ed commands are "<em>c</em>hange", "<em>a</em>dd" and
+ *  "<em>d</em>elete" (diff doesn't output any other).
+ *  Additionally the records must be reverse sorted by line number and
+ *  may not overlap (diff *seems* to produce this kind of output).
  * */
+class RredMethod : public pkgAcqMethod {
+       bool Debug;
+       // the size of this doesn't really matter (except for performance)
+       const static int BUF_SIZE = 1024;
+       // the supported ed commands
+       enum Mode {MODE_CHANGED='c', MODE_DELETED='d', MODE_ADDED='a'};
+       // return values
+       enum State {ED_OK, ED_ORDERING, ED_PARSER, ED_FAILURE, MMAP_FAILED};
 
-const char *Prog;
+       State applyFile(FILE *ed_cmds, FILE *in_file, FILE *out_file,
+                    unsigned long &line, char *buffer, Hashes *hash) const;
+       void ignoreLineInFile(FILE *fin, char *buffer) const;
+       void copyLinesFromFileToFile(FILE *fin, FILE *fout, unsigned int lines,
+                                   Hashes *hash, char *buffer) const;
 
-class RredMethod : public pkgAcqMethod
-{
-   bool Debug;
-   // the size of this doesn't really matter (except for performance)    
-   const static int BUF_SIZE = 1024;
-   // the ed commands
-   enum Mode {MODE_CHANGED, MODE_DELETED, MODE_ADDED};
-   // return values
-   enum State {ED_OK, ED_ORDERING, ED_PARSER, ED_FAILURE};
-   // this applies a single hunk, it uses a tail recursion to 
-   // reverse the hunks in the file
-   int ed_rec(FILE *ed_cmds, FILE *in_file, FILE *out_file, int line, 
-      char *buffer, unsigned int bufsize, Hashes *hash);
-   // apply a patch file
-   int ed_file(FILE *ed_cmds, FILE *in_file, FILE *out_file, Hashes *hash);
-   // the methods main method
-   virtual bool Fetch(FetchItem *Itm);
-   
-   public:
-   
-   RredMethod() : pkgAcqMethod("1.1",SingleInstance | SendConfig) {};
+       State patchFile(FileFd &Patch, FileFd &From, FileFd &out_file, Hashes *hash) const;
+       State patchMMap(FileFd &Patch, FileFd &From, FileFd &out_file, Hashes *hash) const;
+
+protected:
+       // the methods main method
+       virtual bool Fetch(FetchItem *Itm);
+
+public:
+       RredMethod() : pkgAcqMethod("1.1",SingleInstance | SendConfig) {};
 };
+                                                                               /*}}}*/
+/** \brief applyFile - in reverse order with a tail recursion                  {{{
+ *
+ *  As it is expected that the commands are in reversed order in the patch file
+ *  we check in the first half if the command is valid, but doesn't execute it
+ *  and move a step deeper. After reaching the end of the file we apply the
+ *  patches in the correct order: last found command first.
+ *
+ *  \param ed_cmds patch file to apply
+ *  \param in_file base file we want to patch
+ *  \param out_file file to write the patched result to
+ *  \param line of command operation
+ *  \param buffer internal used read/write buffer
+ *  \param hash the created file for correctness
+ *  \return the success State of the ed command executor
+ */
+RredMethod::State RredMethod::applyFile(FILE *ed_cmds, FILE *in_file, FILE *out_file,
+                       unsigned long &line, char *buffer, Hashes *hash) const {
+       // get the current command and parse it
+       if (fgets(buffer, BUF_SIZE, ed_cmds) == NULL) {
+               if (Debug == true)
+                       std::clog << "rred: encounter end of file - we can start patching now." << std::endl;
+               line = 0;
+               return ED_OK;
+       }
 
-int RredMethod::ed_rec(FILE *ed_cmds, FILE *in_file, FILE *out_file, int line, 
-      char *buffer, unsigned int bufsize, Hashes *hash) {
-   int pos;
-   int startline;
-   int stopline;
-   int mode;
-   int written;
-   char *idx;
-
-   /* get the current command and parse it*/
-   if (fgets(buffer, bufsize, ed_cmds) == NULL) {
-      return line;
-   }
-   startline = strtol(buffer, &idx, 10);
-   if (startline < line) {
-      return ED_ORDERING;
-   }
-   if (*idx == ',') {
-      idx++;
-      stopline = strtol(idx, &idx, 10);
-   }
-   else {
-      stopline = startline;
-   }
-   if (*idx == 'c') {
-      mode = MODE_CHANGED;
-          if (Debug == true) {
-                  std::clog << "changing from line " << startline 
-                            << " to " << stopline << std::endl;
-          }
-   }
-   else if (*idx == 'a') {
-      mode = MODE_ADDED;
-          if (Debug == true) {
-                  std::clog << "adding after line " << startline << std::endl;
-          }
-   }
-   else if (*idx == 'd') {
-      mode = MODE_DELETED;
-          if (Debug == true) {
-                  std::clog << "deleting from line " << startline 
-                            <<  " to " << stopline << std::endl;
-          }
-   }
-   else {
-      return ED_PARSER;
-   }
-   /* get the current position */
-   pos = ftell(ed_cmds);
-   /* if this is add or change then go to the next full stop */
-   if ((mode == MODE_CHANGED) || (mode == MODE_ADDED)) {
-      do {
-         fgets(buffer, bufsize, ed_cmds);
-         while ((strlen(buffer) == (bufsize - 1)) 
-               && (buffer[bufsize - 2] != '\n')) {
-            fgets(buffer, bufsize, ed_cmds);
-            buffer[0] = ' ';
-         }
-      } while (strncmp(buffer, ".", 1) != 0);
-   }
-   /* do the recursive call */
-   line = ed_rec(ed_cmds, in_file, out_file, line, buffer, bufsize, 
-         hash);
-   /* pass on errors */
-   if (line < 0) {
-      return line;
-   }
-   /* apply our hunk */
-   fseek(ed_cmds, pos, SEEK_SET); 
-   /* first wind to the current position */
-   if (mode != MODE_ADDED) {
-      startline -= 1;
-   }
-   while (line < startline) {
-      fgets(buffer, bufsize, in_file);
-      written = fwrite(buffer, 1, strlen(buffer), out_file);
-      hash->Add((unsigned char*)buffer, written);
-      while ((strlen(buffer) == (bufsize - 1)) 
-            && (buffer[bufsize - 2] != '\n')) {
-         fgets(buffer, bufsize, in_file);
-         written = fwrite(buffer, 1, strlen(buffer), out_file);
-         hash->Add((unsigned char*)buffer, written);
-      }
-      line++;
-   }
-   /* include from ed script */
-   if ((mode == MODE_ADDED) || (mode == MODE_CHANGED)) {
-      do {
-         fgets(buffer, bufsize, ed_cmds);
-         if (strncmp(buffer, ".", 1) != 0) {
-            written = fwrite(buffer, 1, strlen(buffer), out_file);
-            hash->Add((unsigned char*)buffer, written);
-            while ((strlen(buffer) == (bufsize - 1)) 
-                  && (buffer[bufsize - 2] != '\n')) {
-               fgets(buffer, bufsize, ed_cmds);
-               written = fwrite(buffer, 1, strlen(buffer), out_file);
-               hash->Add((unsigned char*)buffer, written);
-            }
-         }
-         else {
-            break;
-         }
-      } while (1);
-   }
-   /* ignore the corresponding number of lines from input */
-   if ((mode == MODE_DELETED) || (mode == MODE_CHANGED)) {
-      while (line < stopline) {
-         fgets(buffer, bufsize, in_file);
-         while ((strlen(buffer) == (bufsize - 1)) 
-               && (buffer[bufsize - 2] != '\n')) {
-            fgets(buffer, bufsize, in_file);
-         }
-         line++;
-      }
-   }
-   return line;
-}
+       // parse in the effected linenumbers
+       char* idx;
+       errno=0;
+       unsigned long const startline = strtol(buffer, &idx, 10);
+       if (errno == ERANGE || errno == EINVAL) {
+               _error->Errno("rred", "startline is an invalid number");
+               return ED_PARSER;
+       }
+       if (startline > line) {
+               _error->Error("rred: The start line (%lu) of the next command is higher than the last line (%lu). This is not allowed.", startline, line);
+               return ED_ORDERING;
+       }
+       unsigned long stopline;
+       if (*idx == ',') {
+               idx++;
+               errno=0;
+               stopline = strtol(idx, &idx, 10);
+               if (errno == ERANGE || errno == EINVAL) {
+                       _error->Errno("rred", "stopline is an invalid number");
+                       return ED_PARSER;
+               }
+       }
+       else {
+               stopline = startline;
+       }
+       line = startline;
+
+       // which command to execute on this line(s)?
+       switch (*idx) {
+               case MODE_CHANGED:
+                       if (Debug == true)
+                               std::clog << "Change from line " << startline << " to " << stopline << std::endl;
+                       break;
+               case MODE_ADDED:
+                       if (Debug == true)
+                               std::clog << "Insert after line " << startline << std::endl;
+                       break;
+               case MODE_DELETED:
+                       if (Debug == true)
+                               std::clog << "Delete from line " << startline << " to " << stopline << std::endl;
+                       break;
+               default:
+                       _error->Error("rred: Unknown ed command '%c'. Abort.", *idx);
+                       return ED_PARSER;
+       }
+       unsigned char mode = *idx;
+
+       // save the current position
+       unsigned const long pos = ftell(ed_cmds);
+
+       // if this is add or change then go to the next full stop
+       unsigned int data_length = 0;
+       if (mode == MODE_CHANGED || mode == MODE_ADDED) {
+               do {
+                       ignoreLineInFile(ed_cmds, buffer);
+                       data_length++;
+               }
+               while (strncmp(buffer, ".", 1) != 0);
+               data_length--; // the dot should not be copied
+       }
+
+       // do the recursive call - the last command is the one we need to execute at first
+       const State child = applyFile(ed_cmds, in_file, out_file, line, buffer, hash);
+       if (child != ED_OK) {
+               return child;
+       }
+
+       // change and delete are working on "line" - add is done after "line"
+       if (mode != MODE_ADDED)
+               line++;
+
+       // first wind to the current position and copy over all unchanged lines
+       if (line < startline) {
+               copyLinesFromFileToFile(in_file, out_file, (startline - line), hash, buffer);
+               line = startline;
+       }
 
-int RredMethod::ed_file(FILE *ed_cmds, FILE *in_file, FILE *out_file, 
-      Hashes *hash) {
+       if (mode != MODE_ADDED)
+               line--;
+
+       // include data from ed script
+       if (mode == MODE_CHANGED || mode == MODE_ADDED) {
+               fseek(ed_cmds, pos, SEEK_SET);
+               copyLinesFromFileToFile(ed_cmds, out_file, data_length, hash, buffer);
+       }
+
+       // ignore the corresponding number of lines from input
+       if (mode == MODE_CHANGED || mode == MODE_DELETED) {
+               while (line < stopline) {
+                       ignoreLineInFile(in_file, buffer);
+                       line++;
+               }
+       }
+       return ED_OK;
+}
+                                                                               /*}}}*/
+void RredMethod::copyLinesFromFileToFile(FILE *fin, FILE *fout, unsigned int lines,/*{{{*/
+                                       Hashes *hash, char *buffer) const {
+       while (0 < lines--) {
+               do {
+                       fgets(buffer, BUF_SIZE, fin);
+                       size_t const written = fwrite(buffer, 1, strlen(buffer), fout);
+                       hash->Add((unsigned char*)buffer, written);
+               } while (strlen(buffer) == (BUF_SIZE - 1) &&
+                      buffer[BUF_SIZE - 2] != '\n');
+       }
+}
+                                                                               /*}}}*/
+void RredMethod::ignoreLineInFile(FILE *fin, char *buffer) const {             /*{{{*/
+       fgets(buffer, BUF_SIZE, fin);
+       while (strlen(buffer) == (BUF_SIZE - 1) &&
+              buffer[BUF_SIZE - 2] != '\n') {
+               fgets(buffer, BUF_SIZE, fin);
+               buffer[0] = ' ';
+       }
+}
+                                                                               /*}}}*/
+RredMethod::State RredMethod::patchFile(FileFd &Patch, FileFd &From,           /*{{{*/
+                                       FileFd &out_file, Hashes *hash) const {
    char buffer[BUF_SIZE];
-   int result;
-   int written;
-   
+   FILE* fFrom = fdopen(From.Fd(), "r");
+   FILE* fPatch = fdopen(Patch.Fd(), "r");
+   FILE* fTo = fdopen(out_file.Fd(), "w");
+
    /* we do a tail recursion to read the commands in the right order */
-   result = ed_rec(ed_cmds, in_file, out_file, 0, buffer, BUF_SIZE, 
-         hash);
+   unsigned long line = -1; // assign highest possible value
+   State const result = applyFile(fPatch, fFrom, fTo, line, buffer, hash);
    
    /* read the rest from infile */
-   if (result >= 0) {
-      while (fgets(buffer, BUF_SIZE, in_file) != NULL) {
-         written = fwrite(buffer, 1, strlen(buffer), out_file);
+   if (result == ED_OK) {
+      while (fgets(buffer, BUF_SIZE, fFrom) != NULL) {
+         size_t const written = fwrite(buffer, 1, strlen(buffer), fTo);
          hash->Add((unsigned char*)buffer, written);
       }
+      fflush(fTo);
    }
-   else {
-      return ED_FAILURE;
-   }
-   return ED_OK;
+   return result;
 }
+                                                                               /*}}}*/
+struct EdCommand {                                                             /*{{{*/
+  size_t data_start;
+  size_t data_end;
+  size_t data_lines;
+  size_t first_line;
+  size_t last_line;
+  char type;
+};
+#define IOV_COUNT 1024 /* Don't really want IOV_MAX since it can be arbitrarily large */
+                                                                               /*}}}*/
+RredMethod::State RredMethod::patchMMap(FileFd &Patch, FileFd &From,           /*{{{*/
+                                       FileFd &out_file, Hashes *hash) const {
+#ifdef _POSIX_MAPPED_FILES
+       MMap ed_cmds(Patch, MMap::ReadOnly);
+       MMap in_file(From, MMap::ReadOnly);
+
+       if (ed_cmds.Size() == 0 || in_file.Size() == 0)
+               return MMAP_FAILED;
+
+       EdCommand* commands = 0;
+       size_t command_count = 0;
+       size_t command_alloc = 0;
+
+       const char* begin = (char*) ed_cmds.Data();
+       const char* end = begin;
+       const char* ed_end = (char*) ed_cmds.Data() + ed_cmds.Size();
+
+       const char* input = (char*) in_file.Data();
+       const char* input_end = (char*) in_file.Data() + in_file.Size();
+
+       size_t i;
+
+       /* 1. Parse entire script.  It is executed in reverse order, so we cather it
+        *    in the `commands' buffer first
+        */
+
+       for(;;) {
+               EdCommand cmd;
+               cmd.data_start = 0;
+               cmd.data_end = 0;
+
+               while(begin != ed_end && *begin == '\n')
+                       ++begin;
+               while(end != ed_end && *end != '\n')
+                       ++end;
+               if(end == ed_end && begin == end)
+                       break;
+
+               /* Determine command range */
+               const char* tmp = begin;
+
+               for(;;) {
+                       /* atoll is safe despite lacking NUL-termination; we know there's an
+                        * alphabetic character at end[-1]
+                        */
+                       if(tmp == end) {
+                               cmd.first_line = atol(begin);
+                               cmd.last_line = cmd.first_line;
+                               break;
+                       }
+                       if(*tmp == ',') {
+                               cmd.first_line = atol(begin);
+                               cmd.last_line = atol(tmp + 1);
+                               break;
+                       }
+                       ++tmp;
+               }
+
+               // which command to execute on this line(s)?
+               switch (end[-1]) {
+                       case MODE_CHANGED:
+                               if (Debug == true)
+                                       std::clog << "Change from line " << cmd.first_line << " to " << cmd.last_line << std::endl;
+                               break;
+                       case MODE_ADDED:
+                               if (Debug == true)
+                                       std::clog << "Insert after line " << cmd.first_line << std::endl;
+                               break;
+                       case MODE_DELETED:
+                               if (Debug == true)
+                                       std::clog << "Delete from line " << cmd.first_line << " to " << cmd.last_line << std::endl;
+                               break;
+                       default:
+                               _error->Error("rred: Unknown ed command '%c'. Abort.", end[-1]);
+                               free(commands);
+                               return ED_PARSER;
+               }
+               cmd.type = end[-1];
+
+               /* Determine the size of the inserted text, so we don't have to scan this
+                * text again later.
+                */
+               begin = end + 1;
+               end = begin;
+               cmd.data_lines = 0;
+
+               if(cmd.type == MODE_ADDED || cmd.type == MODE_CHANGED) {
+                       cmd.data_start = begin - (char*) ed_cmds.Data();
+                       while(end != ed_end) {
+                               if(*end == '\n') {
+                                       if(end[-1] == '.' && end[-2] == '\n')
+                                               break;
+                                       ++cmd.data_lines;
+                               }
+                               ++end;
+                       }
+                       cmd.data_end = end - (char*) ed_cmds.Data() - 1;
+                       begin = end + 1;
+                       end = begin;
+               }
+               if(command_count == command_alloc) {
+                       command_alloc = (command_alloc + 64) * 3 / 2;
+                       commands = (EdCommand*) realloc(commands, command_alloc * sizeof(EdCommand));
+               }
+               commands[command_count++] = cmd;
+       }
+
+       struct iovec* iov = new struct iovec[IOV_COUNT];
+       size_t iov_size = 0;
+
+       size_t amount, remaining;
+       size_t line = 1;
+       EdCommand* cmd;
+
+       /* 2. Execute script.  We gather writes in a `struct iov' array, and flush
+        *    using writev to minimize the number of system calls.  Data is read
+        *    directly from the memory mappings of the input file and the script.
+        */
+
+       for(i = command_count; i-- > 0; ) {
+               cmd = &commands[i];
+               if(cmd->type == MODE_ADDED)
+                       amount = cmd->first_line + 1;
+               else
+                       amount = cmd->first_line;
+
+               if(line < amount) {
+                       begin = input;
+                       while(line != amount) {
+                               input = (const char*) memchr(input, '\n', input_end - input);
+                               if(!input)
+                                       break;
+                               ++line;
+                               ++input;
+                       }
 
+                       iov[iov_size].iov_base = (void*) begin;
+                       iov[iov_size].iov_len = input - begin;
+                       hash->Add((const unsigned char*) begin, input - begin);
 
-bool RredMethod::Fetch(FetchItem *Itm)
+                       if(++iov_size == IOV_COUNT) {
+                               writev(out_file.Fd(), iov, IOV_COUNT);
+                               iov_size = 0;
+                       }
+               }
+
+               if(cmd->type == MODE_DELETED || cmd->type == MODE_CHANGED) {
+                       remaining = (cmd->last_line - cmd->first_line) + 1;
+                       line += remaining;
+                       while(remaining) {
+                               input = (const char*) memchr(input, '\n', input_end - input);
+                               if(!input)
+                                       break;
+                               --remaining;
+                               ++input;
+                       }
+               }
+
+               if(cmd->type == MODE_CHANGED || cmd->type == MODE_ADDED) {
+                       if(cmd->data_end != cmd->data_start) {
+                               iov[iov_size].iov_base = (void*) ((char*)ed_cmds.Data() + cmd->data_start);
+                               iov[iov_size].iov_len = cmd->data_end - cmd->data_start;
+                               hash->Add((const unsigned char*) ((char*)ed_cmds.Data() + cmd->data_start),
+                               iov[iov_size].iov_len);
+
+                               if(++iov_size == IOV_COUNT) {
+                                       writev(out_file.Fd(), iov, IOV_COUNT);
+                                       iov_size = 0;
+                               }
+                       }
+               }
+       }
+
+       if(input != input_end) {
+               iov[iov_size].iov_base = (void*) input;
+               iov[iov_size].iov_len = input_end - input;
+               hash->Add((const unsigned char*) input, input_end - input);
+               ++iov_size;
+       }
+
+       if(iov_size) {
+               writev(out_file.Fd(), iov, iov_size);
+               iov_size = 0;
+       }
+
+       for(i = 0; i < iov_size; i += IOV_COUNT) {
+               if(iov_size - i < IOV_COUNT)
+                       writev(out_file.Fd(), iov + i, iov_size - i);
+               else
+                       writev(out_file.Fd(), iov + i, IOV_COUNT);
+       }
+
+       delete [] iov;
+       free(commands);
+
+       return ED_OK;
+#else
+       return MMAP_FAILED;
+#endif
+}
+                                                                               /*}}}*/
+bool RredMethod::Fetch(FetchItem *Itm)                                         /*{{{*/
 {
-   Debug = _config->FindB("Debug::pkgAcquire::RRed",false);
+   Debug = _config->FindB("Debug::pkgAcquire::RRed", false);
    URI Get = Itm->Uri;
    string Path = Get.Host + Get.Path; // To account for relative paths
-   // Path contains the filename to patch
+
    FetchResult Res;
    Res.Filename = Itm->DestFile;
-   URIStart(Res);
-   // Res.Filename the destination filename
+   if (Itm->Uri.empty() == true) {
+      Path = Itm->DestFile;
+      Itm->DestFile.append(".result");
+   } else
+      URIStart(Res);
 
    if (Debug == true) 
       std::clog << "Patching " << Path << " with " << Path 
@@ -211,19 +452,27 @@ bool RredMethod::Fetch(FetchItem *Itm)
       return false;
    
    Hashes Hash;
-   FILE* fFrom = fdopen(From.Fd(), "r");
-   FILE* fPatch = fdopen(Patch.Fd(), "r");
-   FILE* fTo = fdopen(To.Fd(), "w");
    // now do the actual patching
-   if (ed_file(fPatch, fFrom, fTo, &Hash) != ED_OK) {
-     _error->Errno("rred", _("Could not patch file"));  
-      return false;
+   State const result = patchMMap(Patch, From, To, &Hash);
+   if (result == MMAP_FAILED) {
+      // retry with patchFile
+      lseek(Patch.Fd(), 0, SEEK_SET);
+      lseek(From.Fd(), 0, SEEK_SET);
+      To.Open(Itm->DestFile,FileFd::WriteEmpty);
+      if (_error->PendingError() == true)
+         return false;
+      if (patchFile(Patch, From, To, &Hash) != ED_OK) {
+        return _error->WarningE("rred", _("Could not patch %s with mmap and with file operation usage - the patch seems to be corrupt."), Path.c_str());
+      } else if (Debug == true) {
+        std::clog << "rred: finished file patching of " << Path  << " after mmap failed." << std::endl;
+      }
+   } else if (result != ED_OK) {
+      return _error->Errno("rred", _("Could not patch %s with mmap (but no mmap specific fail) - the patch seems to be corrupt."), Path.c_str());
+   } else if (Debug == true) {
+      std::clog << "rred: finished mmap patching of " << Path << std::endl;
    }
 
    // write out the result
-   fflush(fFrom);
-   fflush(fPatch);
-   fflush(fTo);
    From.Close();
    Patch.Close();
    To.Close();
@@ -250,13 +499,44 @@ bool RredMethod::Fetch(FetchItem *Itm)
 
    return true;
 }
-
-int main(int argc, char *argv[])
-{
-   RredMethod Mth;
-
-   Prog = strrchr(argv[0],'/');
-   Prog++;
-   
-   return Mth.Run();
+                                                                               /*}}}*/
+/** \brief Wrapper class for testing rred */                                   /*{{{*/
+class TestRredMethod : public RredMethod {
+public:
+       /** \brief Run rred in debug test mode
+        *
+        *  This method can be used to run the rred method outside
+        *  of the "normal" acquire environment for easier testing.
+        *
+        *  \param base basename of all files involved in this rred test
+        */
+       bool Run(char const *base) {
+               _config->CndSet("Debug::pkgAcquire::RRed", "true");
+               FetchItem *test = new FetchItem;
+               test->DestFile = base;
+               return Fetch(test);
+       }
+};
+                                                                               /*}}}*/
+/** \brief Starter for the rred method (or its test method)                    {{{
+ *
+ *  Used without parameters is the normal behavior for methods for
+ *  the APT acquire system. While this works great for the acquire system
+ *  it is very hard to test the method and therefore the method also
+ *  accepts one parameter which will switch it directly to debug test mode:
+ *  The test mode expects that if "Testfile" is given as parameter
+ *  the file "Testfile" should be ed-style patched with "Testfile.ed"
+ *  and will write the result to "Testfile.result".
+ */
+int main(int argc, char *argv[]) {
+       if (argc <= 1) {
+               RredMethod Mth;
+               return Mth.Run();
+       } else {
+               TestRredMethod Mth;
+               bool result = Mth.Run(argv[1]);
+               _error->DumpErrors();
+               return result;
+       }
 }
+                                                                               /*}}}*/