]> git.saurik.com Git - apt.git/blobdiff - ftparchive/writer.cc
merge with debian/experimental
[apt.git] / ftparchive / writer.cc
index 95b73a84da4ae9da348e99d96e02adfa62e13c98..27e53faf81f90a6b3a318f94aa5cdcda6d4a0951 100644 (file)
    ##################################################################### */
                                                                        /*}}}*/
 // Include Files                                                       /*{{{*/
-#include "writer.h"
-    
-#include <apti18n.h>
+#include <config.h>
+
 #include <apt-pkg/strutl.h>
 #include <apt-pkg/error.h>
 #include <apt-pkg/configuration.h>
+#include <apt-pkg/aptconfiguration.h>
 #include <apt-pkg/md5.h>
-#include <apt-pkg/sha1.h>
-#include <apt-pkg/sha256.h>
+#include <apt-pkg/hashes.h>
 #include <apt-pkg/deblistparser.h>
 
 #include <sys/types.h>
 #include <ftw.h>
 #include <fnmatch.h>
 #include <iostream>
+#include <sstream>
 #include <memory>
-    
+
+#include "writer.h"
 #include "cachedb.h"
 #include "apt-ftparchive.h"
 #include "multicompress.h"
+
+#include <apti18n.h>
                                                                        /*}}}*/
 using namespace std;
 FTWScanner *FTWScanner::Owner;
@@ -54,10 +57,15 @@ inline void SetTFRewriteData(struct TFRewriteData &tfrd,
 // FTWScanner::FTWScanner - Constructor                                        /*{{{*/
 // ---------------------------------------------------------------------
 /* */
-FTWScanner::FTWScanner()
+FTWScanner::FTWScanner(string const &Arch): Arch(Arch)
 {
    ErrorPrinted = false;
    NoLinkAct = !_config->FindB("APT::FTPArchive::DeLinkAct",true);
+
+   DoMD5 = _config->FindB("APT::FTPArchive::MD5",true);
+   DoSHA1 = _config->FindB("APT::FTPArchive::SHA1",true);
+   DoSHA256 = _config->FindB("APT::FTPArchive::SHA256",true);
+   DoSHA512 = _config->FindB("APT::FTPArchive::SHA512",true);
 }
                                                                        /*}}}*/
 // FTWScanner::Scanner - FTW Scanner                                   /*{{{*/
@@ -85,7 +93,7 @@ int FTWScanner::ScannerFTW(const char *File,const struct stat *sb,int Flag)
 // FTWScanner::ScannerFile - File Scanner                              /*{{{*/
 // ---------------------------------------------------------------------
 /* */
-int FTWScanner::ScannerFile(const char *File, bool ReadLink)
+int FTWScanner::ScannerFile(const char *File, bool const &ReadLink)
 {
    const char *LastComponent = strrchr(File, '/');
    char *RealPath = NULL;
@@ -95,7 +103,7 @@ int FTWScanner::ScannerFile(const char *File, bool ReadLink)
    else
       LastComponent++;
 
-   vector<string>::iterator I;
+   vector<string>::const_iterator I;
    for(I = Owner->Patterns.begin(); I != Owner->Patterns.end(); ++I)
    {
       if (fnmatch((*I).c_str(), LastComponent, 0) == 0)
@@ -128,7 +136,7 @@ int FTWScanner::ScannerFile(const char *File, bool ReadLink)
       {
         Owner->NewLine(1);
         
-        bool Type = _error->PopMessage(Err);
+        bool const Type = _error->PopMessage(Err);
         if (Type == true)
            cerr << _("E: ") << Err << endl;
         else
@@ -149,7 +157,7 @@ int FTWScanner::ScannerFile(const char *File, bool ReadLink)
 // FTWScanner::RecursiveScan - Just scan a directory tree              /*{{{*/
 // ---------------------------------------------------------------------
 /* */
-bool FTWScanner::RecursiveScan(string Dir)
+bool FTWScanner::RecursiveScan(string const &Dir)
 {
    char *RealPath = NULL;
    /* If noprefix is set then jam the scan root in, so we don't generate
@@ -164,7 +172,7 @@ bool FTWScanner::RecursiveScan(string Dir)
    
    // Do recursive directory searching
    Owner = this;
-   int Res = ftw(Dir.c_str(),ScannerFTW,30);
+   int const Res = ftw(Dir.c_str(),ScannerFTW,30);
    
    // Error treewalking?
    if (Res != 0)
@@ -181,7 +189,7 @@ bool FTWScanner::RecursiveScan(string Dir)
 // ---------------------------------------------------------------------
 /* This is an alternative to using FTW to locate files, it reads the list
    of files from another file. */
-bool FTWScanner::LoadFileList(string Dir,string File)
+bool FTWScanner::LoadFileList(string const &Dir, string const &File)
 {
    char *RealPath = NULL;
    /* If noprefix is set then jam the scan root in, so we don't generate
@@ -240,8 +248,8 @@ bool FTWScanner::LoadFileList(string Dir,string File)
 // ---------------------------------------------------------------------
 /* */
 bool FTWScanner::Delink(string &FileName,const char *OriginalPath,
-                       unsigned long &DeLinkBytes,
-                       off_t FileSize)
+                       unsigned long long &DeLinkBytes,
+                       unsigned long long const &FileSize)
 {
    // See if this isn't an internaly prefix'd file name.
    if (InternalPrefix.empty() == false &&
@@ -298,26 +306,27 @@ bool FTWScanner::Delink(string &FileName,const char *OriginalPath,
 // PackagesWriter::PackagesWriter - Constructor                                /*{{{*/
 // ---------------------------------------------------------------------
 /* */
-PackagesWriter::PackagesWriter(string DB,string Overrides,string ExtOverrides,
-                              string aArch) :
-   Db(DB),Stats(Db.Stats), Arch(aArch)
+PackagesWriter::PackagesWriter(string const &DB,string const &Overrides,string const &ExtOverrides,
+                              string const &Arch) :
+   FTWScanner(Arch), Db(DB), Stats(Db.Stats), TransWriter(NULL)
 {
    Output = stdout;
-   SetExts(".deb .udeb .foo .bar .baz");
-   AddPattern("*.deb");
+   SetExts(".deb .udeb");
    DeLinkLimit = 0;
-   
+
    // Process the command line options
-   DoMD5 = _config->FindB("APT::FTPArchive::MD5",true);
-   DoSHA1 = _config->FindB("APT::FTPArchive::SHA1",true);
-   DoSHA256 = _config->FindB("APT::FTPArchive::SHA256",true);
+   DoMD5 = _config->FindB("APT::FTPArchive::Packages::MD5",DoMD5);
+   DoSHA1 = _config->FindB("APT::FTPArchive::Packages::SHA1",DoSHA1);
+   DoSHA256 = _config->FindB("APT::FTPArchive::Packages::SHA256",DoSHA256);
+   DoSHA256 = _config->FindB("APT::FTPArchive::Packages::SHA512",true);
+   DoAlwaysStat = _config->FindB("APT::FTPArchive::AlwaysStat", false);
    DoContents = _config->FindB("APT::FTPArchive::Contents",true);
    NoOverride = _config->FindB("APT::FTPArchive::NoOverrideMsg",false);
    LongDescription = _config->FindB("APT::FTPArchive::LongDescription",true);
 
    if (Db.Loaded() == false)
       DoContents = false;
-      
+
    // Read the override file
    if (Overrides.empty() == false && Over.ReadOverride(Overrides) == false)
       return;
@@ -333,23 +342,22 @@ PackagesWriter::PackagesWriter(string DB,string Overrides,string ExtOverrides,
 // FTWScanner::SetExts - Set extensions to support                      /*{{{*/
 // ---------------------------------------------------------------------
 /* */
-bool FTWScanner::SetExts(string Vals)
+bool FTWScanner::SetExts(string const &Vals)
 {
    ClearPatterns();
    string::size_type Start = 0;
    while (Start <= Vals.length()-1)
    {
-      string::size_type Space = Vals.find(' ',Start);
-      string::size_type Length;
-      if (Space == string::npos)
+      string::size_type const Space = Vals.find(' ',Start);
+      string::size_type const Length = ((Space == string::npos) ? Vals.length() : Space) - Start;
+      if ( Arch.empty() == false )
       {
-         Length = Vals.length()-Start;
+        AddPattern(string("*_") + Arch + Vals.substr(Start, Length));
+        AddPattern(string("*_all") + Vals.substr(Start, Length));
       }
       else
-      {
-         Length = Space-Start;
-      }
-      AddPattern(string("*") + Vals.substr(Start, Length));
+        AddPattern(string("*") + Vals.substr(Start, Length));
+
       Start += Length + 1;
    }
 
@@ -365,13 +373,13 @@ bool FTWScanner::SetExts(string Vals)
 bool PackagesWriter::DoPackage(string FileName)
 {      
    // Pull all the data we need form the DB
-   if (Db.GetFileInfo(FileName, true, DoContents, true, DoMD5, DoSHA1, DoSHA256
+   if (Db.GetFileInfo(FileName, true, DoContents, true, DoMD5, DoSHA1, DoSHA256, DoSHA512, DoAlwaysStat)
                  == false)
    {
       return false;
    }
 
-   off_t FileSize = Db.GetFileSize();
+   unsigned long long FileSize = Db.GetFileSize();
    if (Delink(FileName,OriginalPath,Stats.DeLinkBytes,FileSize) == false)
       return false;
    
@@ -407,7 +415,7 @@ bool PackagesWriter::DoPackage(string FileName)
    }
 
    char Size[40];
-   sprintf(Size,"%lu", (unsigned long) FileSize);
+   sprintf(Size,"%llu", (unsigned long long) FileSize);
    
    // Strip the DirStrip prefix from the FileName and add the PathPrefix
    string NewFileName;
@@ -435,9 +443,14 @@ bool PackagesWriter::DoPackage(string FileName)
 
    unsigned int End = 0;
    SetTFRewriteData(Changes[End++], "Size", Size);
-   SetTFRewriteData(Changes[End++], "MD5sum", Db.MD5Res.c_str());
-   SetTFRewriteData(Changes[End++], "SHA1", Db.SHA1Res.c_str());
-   SetTFRewriteData(Changes[End++], "SHA256", Db.SHA256Res.c_str());
+   if (DoMD5 == true)
+      SetTFRewriteData(Changes[End++], "MD5sum", Db.MD5Res.c_str());
+   if (DoSHA1 == true)
+      SetTFRewriteData(Changes[End++], "SHA1", Db.SHA1Res.c_str());
+   if (DoSHA256 == true)
+      SetTFRewriteData(Changes[End++], "SHA256", Db.SHA256Res.c_str());
+   if (DoSHA512 == true)
+      SetTFRewriteData(Changes[End++], "SHA512", Db.SHA512Res.c_str());
    SetTFRewriteData(Changes[End++], "Filename", NewFileName.c_str());
    SetTFRewriteData(Changes[End++], "Priority", OverItem->Priority.c_str());
    SetTFRewriteData(Changes[End++], "Status", 0);
@@ -449,6 +462,8 @@ bool PackagesWriter::DoPackage(string FileName)
       descmd5.Add(desc.c_str());
       DescriptionMd5 = descmd5.Result().Value();
       SetTFRewriteData(Changes[End++], "Description-md5", DescriptionMd5.c_str());
+      if (TransWriter != NULL)
+        TransWriter->DoPackage(Package, desc, DescriptionMd5);
    }
 
    // Rewrite the maintainer field if necessary
@@ -480,8 +495,8 @@ bool PackagesWriter::DoPackage(string FileName)
       SetTFRewriteData(Changes[End++], "Suggests", OptionalStr.c_str());
    }
 
-   for (map<string,string>::iterator I = OverItem->FieldOverride.begin(); 
-        I != OverItem->FieldOverride.end(); I++) 
+   for (map<string,string>::const_iterator I = OverItem->FieldOverride.begin(); 
+        I != OverItem->FieldOverride.end(); ++I)
       SetTFRewriteData(Changes[End++],I->first.c_str(),I->second.c_str());
 
    SetTFRewriteData(Changes[End++], 0, 0);
@@ -495,11 +510,60 @@ bool PackagesWriter::DoPackage(string FileName)
 }
                                                                        /*}}}*/
 
+// TranslationWriter::TranslationWriter - Constructor                  /*{{{*/
+// ---------------------------------------------------------------------
+/* Create a Translation-Master file for this Packages file */
+TranslationWriter::TranslationWriter(string const &File, string const &TransCompress,
+                                       mode_t const &Permissions) : Output(NULL),
+                                                       RefCounter(0)
+{
+   if (File.empty() == true)
+      return;
+
+   Comp = new MultiCompress(File, TransCompress, Permissions);
+   Output = Comp->Input;
+}
+                                                                       /*}}}*/
+// TranslationWriter::DoPackage - Process a single package             /*{{{*/
+// ---------------------------------------------------------------------
+/* Create a Translation-Master file for this Packages file */
+bool TranslationWriter::DoPackage(string const &Pkg, string const &Desc,
+                                 string const &MD5)
+{
+   if (Output == NULL)
+      return true;
+
+   // Different archs can include different versions and therefore
+   // different descriptions - so we need to check for both name and md5.
+   string const Record = Pkg + ":" + MD5;
+
+   if (Included.find(Record) != Included.end())
+      return true;
+
+   fprintf(Output, "Package: %s\nDescription-md5: %s\nDescription-en: %s\n",
+          Pkg.c_str(), MD5.c_str(), Desc.c_str());
+
+   Included.insert(Record);
+   return true;
+}
+                                                                       /*}}}*/
+// TranslationWriter::~TranslationWriter - Destructor                  /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+TranslationWriter::~TranslationWriter()
+{
+   if (Comp == NULL)
+      return;
+
+   delete Comp;
+}
+                                                                       /*}}}*/
+
 // SourcesWriter::SourcesWriter - Constructor                          /*{{{*/
 // ---------------------------------------------------------------------
 /* */
-SourcesWriter::SourcesWriter(string BOverrides,string SOverrides,
-                            string ExtOverrides)
+SourcesWriter::SourcesWriter(string const &BOverrides,string const &SOverrides,
+                            string const &ExtOverrides)
 {
    Output = stdout;
    AddPattern("*.dsc");
@@ -508,6 +572,9 @@ SourcesWriter::SourcesWriter(string BOverrides,string SOverrides,
    BufSize = 0;
    
    // Process the command line options
+   DoMD5 = _config->FindB("APT::FTPArchive::Sources::MD5",DoMD5);
+   DoSHA1 = _config->FindB("APT::FTPArchive::Sources::SHA1",DoSHA1);
+   DoSHA256 = _config->FindB("APT::FTPArchive::Sources::SHA256",DoSHA256);
    NoOverride = _config->FindB("APT::FTPArchive::NoOverrideMsg",false);
 
    // Read the override file
@@ -545,7 +612,7 @@ bool SourcesWriter::DoPackage(string FileName)
    if (St.st_size > 128*1024)
       return _error->Error("DSC file '%s' is too large!",FileName.c_str());
          
-   if (BufSize < (unsigned)St.st_size+1)
+   if (BufSize < (unsigned long long)St.st_size+1)
    {
       BufSize = St.st_size+1;
       Buffer = (char *)realloc(Buffer,St.st_size+1);
@@ -557,13 +624,20 @@ bool SourcesWriter::DoPackage(string FileName)
    // Hash the file
    char *Start = Buffer;
    char *BlkEnd = Buffer + St.st_size;
-   MD5Summation MD5;
-   MD5.Add((unsigned char *)Start,BlkEnd - Start);
 
+   MD5Summation MD5;
    SHA1Summation SHA1;
    SHA256Summation SHA256;
-   SHA1.Add((unsigned char *)Start,BlkEnd - Start);
-   SHA256.Add((unsigned char *)Start,BlkEnd - Start);
+   SHA256Summation SHA512;
+
+   if (DoMD5 == true)
+      MD5.Add((unsigned char *)Start,BlkEnd - Start);
+   if (DoSHA1 == true)
+      SHA1.Add((unsigned char *)Start,BlkEnd - Start);
+   if (DoSHA256 == true)
+      SHA256.Add((unsigned char *)Start,BlkEnd - Start);
+   if (DoSHA512 == true)
+      SHA512.Add((unsigned char *)Start,BlkEnd - Start);
 
    // Add an extra \n to the end, just in case
    *BlkEnd++ = '\n';
@@ -656,23 +730,29 @@ bool SourcesWriter::DoPackage(string FileName)
    
    // Add the dsc to the files hash list
    string const strippedName = flNotDir(FileName);
-   char Files[1000];
-   snprintf(Files,sizeof(Files),"\n %s %lu %s\n %s",
-           string(MD5.Result()).c_str(),St.st_size,
-           strippedName.c_str(),
-           Tags.FindS("Files").c_str());
-
-   char ChecksumsSha1[1000];
-   snprintf(ChecksumsSha1,sizeof(ChecksumsSha1),"\n %s %lu %s\n %s",
-           string(SHA1.Result()).c_str(),St.st_size,
-           strippedName.c_str(),
-           Tags.FindS("Checksums-Sha1").c_str());
-
-   char ChecksumsSha256[1000];
-   snprintf(ChecksumsSha256,sizeof(ChecksumsSha256),"\n %s %lu %s\n %s",
-           string(SHA256.Result()).c_str(),St.st_size,
-           strippedName.c_str(),
-           Tags.FindS("Checksums-Sha256").c_str());
+   std::ostringstream ostreamFiles;
+   if (DoMD5 == true && Tags.Exists("Files"))
+      ostreamFiles << "\n " << string(MD5.Result()) << " " << St.st_size << " "
+                  << strippedName << "\n " << Tags.FindS("Files");
+   string const Files = ostreamFiles.str();
+
+   std::ostringstream ostreamSha1;
+   if (DoSHA1 == true && Tags.Exists("Checksums-Sha1"))
+      ostreamSha1 << "\n " << string(SHA1.Result()) << " " << St.st_size << " "
+                  << strippedName << "\n " << Tags.FindS("Checksums-Sha1");
+   string const ChecksumsSha1 = ostreamSha1.str();
+
+   std::ostringstream ostreamSha256;
+   if (DoSHA256 == true && Tags.Exists("Checksums-Sha256"))
+      ostreamSha256 << "\n " << string(SHA256.Result()) << " " << St.st_size << " "
+                  << strippedName << "\n " << Tags.FindS("Checksums-Sha256");
+   string const ChecksumsSha256 = ostreamSha256.str();
+
+   std::ostringstream ostreamSha512;
+   if (Tags.Exists("Checksums-Sha512"))
+      ostreamSha512 << "\n " << string(SHA512.Result()) << " " << St.st_size << " "
+                  << strippedName << "\n " << Tags.FindS("Checksums-Sha512");
+   string const ChecksumsSha512 = ostreamSha512.str();
 
    // Strip the DirStrip prefix from the FileName and add the PathPrefix
    string NewFileName;
@@ -690,7 +770,7 @@ bool SourcesWriter::DoPackage(string FileName)
 
    // Perform the delinking operation over all of the files
    string ParseJnk;
-   const char *C = Files;
+   const char *C = Files.c_str();
    char *RealPath = NULL;
    for (;isspace(*C); C++);
    while (*C != 0)
@@ -723,9 +803,14 @@ bool SourcesWriter::DoPackage(string FileName)
 
    unsigned int End = 0;
    SetTFRewriteData(Changes[End++],"Source",Package.c_str(),"Package");
-   SetTFRewriteData(Changes[End++],"Files",Files);
-   SetTFRewriteData(Changes[End++],"Checksums-Sha1",ChecksumsSha1);
-   SetTFRewriteData(Changes[End++],"Checksums-Sha256",ChecksumsSha256);
+   if (Files.empty() == false)
+      SetTFRewriteData(Changes[End++],"Files",Files.c_str());
+   if (ChecksumsSha1.empty() == false)
+      SetTFRewriteData(Changes[End++],"Checksums-Sha1",ChecksumsSha1.c_str());
+   if (ChecksumsSha256.empty() == false)
+      SetTFRewriteData(Changes[End++],"Checksums-Sha256",ChecksumsSha256.c_str());
+   if (ChecksumsSha512.empty() == false)
+      SetTFRewriteData(Changes[End++],"Checksums-Sha512",ChecksumsSha512.c_str());
    if (Directory != "./")
       SetTFRewriteData(Changes[End++],"Directory",Directory.c_str());
    SetTFRewriteData(Changes[End++],"Priority",BestPrio.c_str());
@@ -746,8 +831,8 @@ bool SourcesWriter::DoPackage(string FileName)
    if (NewMaint.empty() == false)
       SetTFRewriteData(Changes[End++], "Maintainer", NewMaint.c_str());
    
-   for (map<string,string>::iterator I = SOverItem->FieldOverride.begin(); 
-        I != SOverItem->FieldOverride.end(); I++) 
+   for (map<string,string>::const_iterator I = SOverItem->FieldOverride.begin(); 
+        I != SOverItem->FieldOverride.end(); ++I)
       SetTFRewriteData(Changes[End++],I->first.c_str(),I->second.c_str());
 
    SetTFRewriteData(Changes[End++], 0, 0);
@@ -766,11 +851,11 @@ bool SourcesWriter::DoPackage(string FileName)
 // ContentsWriter::ContentsWriter - Constructor                                /*{{{*/
 // ---------------------------------------------------------------------
 /* */
-ContentsWriter::ContentsWriter(string DB) : 
-                   Db(DB), Stats(Db.Stats)
+ContentsWriter::ContentsWriter(string const &DB, string const &Arch) :
+                   FTWScanner(Arch), Db(DB), Stats(Db.Stats)
 
 {
-   AddPattern("*.deb");
+   SetExts(".deb");
    Output = stdout;
 }
                                                                        /*}}}*/
@@ -778,9 +863,9 @@ ContentsWriter::ContentsWriter(string DB) :
 // ---------------------------------------------------------------------
 /* If Package is the empty string the control record will be parsed to
    determine what the package name is. */
-bool ContentsWriter::DoPackage(string FileName,string Package)
+bool ContentsWriter::DoPackage(string FileName, string Package)
 {
-   if (!Db.GetFileInfo(FileName, Package.empty(), true, false, false, false, false))
+   if (!Db.GetFileInfo(FileName, Package.empty(), true, false, false, false, false, false))
    {
       return false;
    }
@@ -799,7 +884,7 @@ bool ContentsWriter::DoPackage(string FileName,string Package)
 // ContentsWriter::ReadFromPkgs - Read from a packages file            /*{{{*/
 // ---------------------------------------------------------------------
 /* */
-bool ContentsWriter::ReadFromPkgs(string PkgFile,string PkgCompress)
+bool ContentsWriter::ReadFromPkgs(string const &PkgFile,string const &PkgCompress)
 {
    MultiCompress Pkgs(PkgFile,PkgCompress,0,false);
    if (_error->PendingError() == true)
@@ -854,21 +939,31 @@ bool ContentsWriter::ReadFromPkgs(string PkgFile,string PkgCompress)
 // ReleaseWriter::ReleaseWriter - Constructor                          /*{{{*/
 // ---------------------------------------------------------------------
 /* */
-ReleaseWriter::ReleaseWriter(string DB)
+ReleaseWriter::ReleaseWriter(string const &DB)
 {
-   AddPattern("Packages");
-   AddPattern("Packages.gz");
-   AddPattern("Packages.bz2");
-   AddPattern("Packages.lzma");
-   AddPattern("Sources");
-   AddPattern("Sources.gz");
-   AddPattern("Sources.bz2");
-   AddPattern("Sources.lzma");
-   AddPattern("Release");
-   AddPattern("md5sum.txt");
+   if (_config->FindB("APT::FTPArchive::Release::Default-Patterns", true) == true)
+   {
+      AddPattern("Packages");
+      AddPattern("Packages.gz");
+      AddPattern("Packages.bz2");
+      AddPattern("Packages.lzma");
+      AddPattern("Packages.xz");
+      AddPattern("Sources");
+      AddPattern("Sources.gz");
+      AddPattern("Sources.bz2");
+      AddPattern("Sources.lzma");
+      AddPattern("Sources.xz");
+      AddPattern("Release");
+      AddPattern("Index");
+      AddPattern("md5sum.txt");
+   }
+   AddPatterns(_config->FindVector("APT::FTPArchive::Release::Patterns"));
 
    Output = stdout;
-   time_t now = time(NULL);
+   time_t const now = time(NULL);
+
+   setlocale(LC_TIME, "C");
+
    char datestr[128];
    if (strftime(datestr, sizeof(datestr), "%a, %d %b %Y %H:%M:%S UTC",
                 gmtime(&now)) == 0)
@@ -876,6 +971,17 @@ ReleaseWriter::ReleaseWriter(string DB)
       datestr[0] = '\0';
    }
 
+   time_t const validuntil = now + _config->FindI("APT::FTPArchive::Release::ValidTime", 0);
+   char validstr[128];
+   if (now == validuntil ||
+       strftime(validstr, sizeof(validstr), "%a, %d %b %Y %H:%M:%S UTC",
+                gmtime(&validuntil)) == 0)
+   {
+      validstr[0] = '\0';
+   }
+
+   setlocale(LC_TIME, "");
+
    map<string,string> Fields;
    Fields["Origin"] = "";
    Fields["Label"] = "";
@@ -883,6 +989,7 @@ ReleaseWriter::ReleaseWriter(string DB)
    Fields["Version"] = "";
    Fields["Codename"] = "";
    Fields["Date"] = datestr;
+   Fields["Valid-Until"] = validstr;
    Fields["Architectures"] = "";
    Fields["Components"] = "";
    Fields["Description"] = "";
@@ -898,6 +1005,10 @@ ReleaseWriter::ReleaseWriter(string DB)
 
       fprintf(Output, "%s: %s\n", (*I).first.c_str(), Value.c_str());
    }
+
+   DoMD5 = _config->FindB("APT::FTPArchive::Release::MD5",DoMD5);
+   DoSHA1 = _config->FindB("APT::FTPArchive::Release::SHA1",DoSHA1);
+   DoSHA256 = _config->FindB("APT::FTPArchive::Release::SHA256",DoSHA256);
 }
                                                                        /*}}}*/
 // ReleaseWriter::DoPackage - Process a single package                 /*{{{*/
@@ -930,22 +1041,18 @@ bool ReleaseWriter::DoPackage(string FileName)
 
    CheckSums[NewFileName].size = fd.Size();
 
-   MD5Summation MD5;
-   MD5.AddFD(fd.Fd(), fd.Size());
-   CheckSums[NewFileName].MD5 = MD5.Result();
-
-   fd.Seek(0);
-   SHA1Summation SHA1;
-   SHA1.AddFD(fd.Fd(), fd.Size());
-   CheckSums[NewFileName].SHA1 = SHA1.Result();
-
-   fd.Seek(0);
-   SHA256Summation SHA256;
-   SHA256.AddFD(fd.Fd(), fd.Size());
-   CheckSums[NewFileName].SHA256 = SHA256.Result();
-
+   Hashes hs;
+   hs.AddFD(fd.Fd(), 0, DoMD5, DoSHA1, DoSHA256, DoSHA512);
+   if (DoMD5 == true)
+      CheckSums[NewFileName].MD5 = hs.MD5.Result();
+   if (DoSHA1 == true)
+      CheckSums[NewFileName].SHA1 = hs.SHA1.Result();
+   if (DoSHA256 == true)
+      CheckSums[NewFileName].SHA256 = hs.SHA256.Result();
+   if (DoSHA512 == true)
+      CheckSums[NewFileName].SHA512 = hs.SHA512.Result();
    fd.Close();
-   
+
    return true;
 }
 
@@ -954,37 +1061,52 @@ bool ReleaseWriter::DoPackage(string FileName)
 // ---------------------------------------------------------------------
 void ReleaseWriter::Finish()
 {
-   fprintf(Output, "MD5Sum:\n");
-   for(map<string,struct CheckSum>::iterator I = CheckSums.begin();
-       I != CheckSums.end();
-       ++I)
+   if (DoMD5 == true)
    {
-      fprintf(Output, " %s %16ld %s\n",
-              (*I).second.MD5.c_str(),
-              (*I).second.size,
-              (*I).first.c_str());
+      fprintf(Output, "MD5Sum:\n");
+      for(map<string,struct CheckSum>::const_iterator I = CheckSums.begin();
+         I != CheckSums.end(); ++I)
+      {
+        fprintf(Output, " %s %16llu %s\n",
+                (*I).second.MD5.c_str(),
+                (*I).second.size,
+                (*I).first.c_str());
+      }
    }
-
-   fprintf(Output, "SHA1:\n");
-   for(map<string,struct CheckSum>::iterator I = CheckSums.begin();
-       I != CheckSums.end();
-       ++I)
+   if (DoSHA1 == true)
    {
-      fprintf(Output, " %s %16ld %s\n",
-              (*I).second.SHA1.c_str(),
-              (*I).second.size,
-              (*I).first.c_str());
+      fprintf(Output, "SHA1:\n");
+      for(map<string,struct CheckSum>::const_iterator I = CheckSums.begin();
+         I != CheckSums.end(); ++I)
+      {
+        fprintf(Output, " %s %16llu %s\n",
+                (*I).second.SHA1.c_str(),
+                (*I).second.size,
+                (*I).first.c_str());
+      }
+   }
+   if (DoSHA256 == true)
+   {
+      fprintf(Output, "SHA256:\n");
+      for(map<string,struct CheckSum>::const_iterator I = CheckSums.begin();
+         I != CheckSums.end(); ++I)
+      {
+        fprintf(Output, " %s %16llu %s\n",
+                (*I).second.SHA256.c_str(),
+                (*I).second.size,
+                (*I).first.c_str());
+      }
    }
 
-   fprintf(Output, "SHA256:\n");
-   for(map<string,struct CheckSum>::iterator I = CheckSums.begin();
+   fprintf(Output, "SHA512:\n");
+   for(map<string,struct CheckSum>::const_iterator I = CheckSums.begin();
        I != CheckSums.end();
        ++I)
    {
-      fprintf(Output, " %s %16ld %s\n",
-              (*I).second.SHA256.c_str(),
+      fprintf(Output, " %s %16llu %s\n",
+              (*I).second.SHA512.c_str(),
               (*I).second.size,
               (*I).first.c_str());
    }
-}
 
+}