]> git.saurik.com Git - apt.git/blobdiff - ftparchive/writer.cc
* Merged from the mvo branch
[apt.git] / ftparchive / writer.cc
index 3b1cb69f55b0110bd3d612417732430c54e38faa..4e6c9a77ddab6d2049d83ab1334b773de3e4742c 100644 (file)
@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // Description                                                         /*{{{*/
-// $Id: writer.cc,v 1.9 2003/12/26 20:50:01 mdz Exp $
+// $Id: writer.cc,v 1.14 2004/03/24 01:40:43 mdz Exp $
 /* ######################################################################
 
    Writer 
    ##################################################################### */
                                                                        /*}}}*/
 // Include Files                                                       /*{{{*/
-#ifdef __GNUG__
-#pragma implementation "writer.h"
-#endif
-
 #include "writer.h"
     
 #include <apti18n.h>
@@ -23,6 +19,7 @@
 #include <apt-pkg/configuration.h>
 #include <apt-pkg/md5.h>
 #include <apt-pkg/sha1.h>
+#include <apt-pkg/sha256.h>
 #include <apt-pkg/deblistparser.h>
 
 #include <sys/types.h>
 #include <ftw.h>
 #include <fnmatch.h>
 #include <iostream>
+#include <memory>
     
 #include "cachedb.h"
 #include "apt-ftparchive.h"
 #include "multicompress.h"
                                                                        /*}}}*/
-
 using namespace std;
 FTWScanner *FTWScanner::Owner;
 
@@ -71,7 +68,7 @@ FTWScanner::FTWScanner()
 // ---------------------------------------------------------------------
 /* This is the FTW scanner, it processes each directory element in the 
    directory tree. */
-int FTWScanner::Scanner(const char *File,const struct stat *sb,int Flag)
+int FTWScanner::ScannerFTW(const char *File,const struct stat *sb,int Flag)
 {
    if (Flag == FTW_DNR)
    {
@@ -86,6 +83,14 @@ int FTWScanner::Scanner(const char *File,const struct stat *sb,int Flag)
    if (Flag != FTW_F)
       return 0;
 
+   return ScannerFile(File, true);
+}
+                                                                       /*}}}*/
+// FTWScanner::ScannerFile - File Scanner                              /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+int FTWScanner::ScannerFile(const char *File, bool ReadLink)
+{
    const char *LastComponent = strrchr(File, '/');
    if (LastComponent == NULL)
       LastComponent = File;
@@ -106,7 +111,8 @@ int FTWScanner::Scanner(const char *File,const struct stat *sb,int Flag)
       given are not links themselves. */
    char Jnk[2];
    Owner->OriginalPath = File;
-   if (Owner->RealPath != 0 && readlink(File,Jnk,sizeof(Jnk)) != -1 &&
+   if (ReadLink && Owner->RealPath != 0 &&
+       readlink(File,Jnk,sizeof(Jnk)) != -1 &&
        realpath(File,Owner->RealPath) != 0)
       Owner->DoPackage(Owner->RealPath);
    else
@@ -155,7 +161,7 @@ bool FTWScanner::RecursiveScan(string Dir)
    
    // Do recursive directory searching
    Owner = this;
-   int Res = ftw(Dir.c_str(),Scanner,30);
+   int Res = ftw(Dir.c_str(),ScannerFTW,30);
    
    // Error treewalking?
    if (Res != 0)
@@ -210,12 +216,14 @@ bool FTWScanner::LoadFileList(string Dir,string File)
         FileName = Line;
       }
       
+#if 0
       struct stat St;
       int Flag = FTW_F;
       if (stat(FileName,&St) != 0)
         Flag = FTW_NS;
+#endif
 
-      if (Scanner(FileName,&St,Flag) != 0)
+      if (ScannerFile(FileName, false) != 0)
         break;
    }
   
@@ -228,7 +236,7 @@ bool FTWScanner::LoadFileList(string Dir,string File)
 /* */
 bool FTWScanner::Delink(string &FileName,const char *OriginalPath,
                        unsigned long &DeLinkBytes,
-                       struct stat &St)
+                       off_t FileSize)
 {
    // See if this isn't an internaly prefix'd file name.
    if (InternalPrefix.empty() == false &&
@@ -244,7 +252,7 @@ bool FTWScanner::Delink(string &FileName,const char *OriginalPath,
         
         NewLine(1);
         ioprintf(c1out, _(" DeLink %s [%s]\n"), (OriginalPath + InternalPrefix.length()),
-                   SizeToStr(St.st_size).c_str());
+                   SizeToStr(FileSize).c_str());
         c1out << flush;
         
         if (NoLinkAct == false)
@@ -270,7 +278,7 @@ bool FTWScanner::Delink(string &FileName,const char *OriginalPath,
            }       
         }
         
-        DeLinkBytes += St.st_size;
+        DeLinkBytes += FileSize;
         if (DeLinkBytes/1024 >= DeLinkLimit)
            ioprintf(c1out, _(" DeLink limit of %sB hit.\n"), SizeToStr(DeLinkBytes).c_str());      
       }
@@ -285,17 +293,22 @@ bool FTWScanner::Delink(string &FileName,const char *OriginalPath,
 // PackagesWriter::PackagesWriter - Constructor                                /*{{{*/
 // ---------------------------------------------------------------------
 /* */
-PackagesWriter::PackagesWriter(string DB,string Overrides,string ExtOverrides) :
-                   Db(DB),Stats(Db.Stats)
+PackagesWriter::PackagesWriter(string DB,string Overrides,string ExtOverrides,
+                              string aArch) :
+   Db(DB),Stats(Db.Stats), Arch(aArch)
 {
    Output = stdout;
+   SetExts(".deb .udeb .foo .bar .baz");
    AddPattern("*.deb");
    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);
    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;
@@ -319,15 +332,20 @@ bool FTWScanner::SetExts(string Vals)
 {
    ClearPatterns();
    string::size_type Start = 0;
-   for(string::size_type space = Vals.find(' ');
-       space != string::npos;
-       space = Vals.find(' ', space))
+   while (Start <= Vals.length()-1)
    {
-      if (space > 0)
+      string::size_type Space = Vals.find(' ',Start);
+      string::size_type Length;
+      if (Space == string::npos)
+      {
+         Length = Vals.length()-Start;
+      }
+      else
       {
-         AddPattern(string("*") + string(Start, space-1));
-         Start = space + 1;
+         Length = Space-Start;
       }
+      AddPattern(string("*") + Vals.substr(Start, Length));
+      Start += Length + 1;
    }
 
    return true;
@@ -337,42 +355,40 @@ bool FTWScanner::SetExts(string Vals)
 // PackagesWriter::DoPackage - Process a single package                        /*{{{*/
 // ---------------------------------------------------------------------
 /* This method takes a package and gets its control information and 
-   MD5 then writes out a control record with the proper fields rewritten
-   and the path/size/hash appended. */
+   MD5, SHA1 and SHA256 then writes out a control record with the proper fields 
+   rewritten and the path/size/hash appended. */
 bool PackagesWriter::DoPackage(string FileName)
 {      
-   // Open the archive
-   FileFd F(FileName,FileFd::ReadOnly);
-   if (_error->PendingError() == true)
-      return false;
-   
-   // Stat the file for later
-   struct stat St;
-   if (fstat(F.Fd(),&St) != 0)
-      return _error->Errno("fstat",_("Failed to stat %s"),FileName.c_str());
-
    // Pull all the data we need form the DB
-   string MD5Res;
-   if (Db.SetFile(FileName,St,&F) == false ||
-       Db.LoadControl() == false ||
-       (DoContents == true && Db.LoadContents(true) == false) ||
-       (DoMD5 == true && Db.GetMD5(MD5Res,false) == false))
+   if (Db.GetFileInfo(FileName, true, DoContents, true, DoMD5, DoSHA1, DoSHA256) 
+                 == false)
+   {
       return false;
+   }
 
-   if (Delink(FileName,OriginalPath,Stats.DeLinkBytes,St) == false)
+   off_t FileSize = Db.GetFileSize();
+   if (Delink(FileName,OriginalPath,Stats.DeLinkBytes,FileSize) == false)
       return false;
    
    // Lookup the overide information
    pkgTagSection &Tags = Db.Control.Section;
    string Package = Tags.FindS("Package");
-   Override::Item Tmp;
-   Override::Item *OverItem = Over.GetItem(Package);
+   string Architecture;
+   // if we generate a Packages file for a given arch, we use it to
+   // look for overrides. if we run in "simple" mode without the 
+   // "Architecures" variable in the config we use the architecure value
+   // from the deb file
+   if(Arch != "")
+      Architecture = Arch;
+   else
+      Architecture = Tags.FindS("Architecture");
+   auto_ptr<Override::Item> OverItem(Over.GetItem(Package,Architecture));
    
    if (Package.empty() == true)
       return _error->Error(_("Archive had no package field"));
-   
+
    // If we need to do any rewriting of the header do it now..
-   if (OverItem == 0)
+   if (OverItem.get() == 0)
    {
       if (NoOverride == false)
       {
@@ -380,13 +396,13 @@ bool PackagesWriter::DoPackage(string FileName)
         ioprintf(c1out, _("  %s has no override entry\n"), Package.c_str());
       }
       
-      OverItem = &Tmp;
-      Tmp.FieldOverride["Section"] = Tags.FindS("Section");
-      Tmp.Priority = Tags.FindS("Priority");
+      OverItem = auto_ptr<Override::Item>(new Override::Item);
+      OverItem->FieldOverride["Section"] = Tags.FindS("Section");
+      OverItem->Priority = Tags.FindS("Priority");
    }
 
    char Size[40];
-   sprintf(Size,"%lu",St.st_size);
+   sprintf(Size,"%lu", (unsigned long) FileSize);
    
    // Strip the DirStrip prefix from the FileName and add the PathPrefix
    string NewFileName;
@@ -399,19 +415,37 @@ bool PackagesWriter::DoPackage(string FileName)
       NewFileName = FileName;
    if (PathPrefix.empty() == false)
       NewFileName = flCombine(PathPrefix,NewFileName);
-          
+
+   /* Configuration says we don't want to include the long Description
+      in the package file - instead we want to ship a separated file */
+   string desc;
+   if (LongDescription == false) {
+      desc = Tags.FindS("Description").append("\n");
+      OverItem->FieldOverride["Description"] = desc.substr(0, desc.find('\n')).c_str();
+   }
+
    // This lists all the changes to the fields we are going to make.
    // (7 hardcoded + maintainer + suggests + end marker)
-   TFRewriteData Changes[6+2+OverItem->FieldOverride.size()+1];
+   TFRewriteData Changes[6+2+OverItem->FieldOverride.size()+1+1];
 
    unsigned int End = 0;
    SetTFRewriteData(Changes[End++], "Size", Size);
-   SetTFRewriteData(Changes[End++], "MD5sum", MD5Res.c_str());
+   SetTFRewriteData(Changes[End++], "MD5sum", Db.MD5Res.c_str());
+   SetTFRewriteData(Changes[End++], "SHA1", Db.SHA1Res.c_str());
+   SetTFRewriteData(Changes[End++], "SHA256", Db.SHA256Res.c_str());
    SetTFRewriteData(Changes[End++], "Filename", NewFileName.c_str());
    SetTFRewriteData(Changes[End++], "Priority", OverItem->Priority.c_str());
    SetTFRewriteData(Changes[End++], "Status", 0);
    SetTFRewriteData(Changes[End++], "Optional", 0);
 
+   string DescriptionMd5;
+   if (LongDescription == false) {
+      MD5Summation descmd5;
+      descmd5.Add(desc.c_str());
+      DescriptionMd5 = descmd5.Result().Value();
+      SetTFRewriteData(Changes[End++], "Description-md5", DescriptionMd5.c_str());
+   }
+
    // Rewrite the maintainer field if necessary
    bool MaintFailed;
    string NewMaint = OverItem->SwapMaint(Tags.FindS("Maintainer"),MaintFailed);
@@ -429,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. */
@@ -477,6 +511,10 @@ SourcesWriter::SourcesWriter(string BOverrides,string SOverrides,
    else
       NoOverride = true;
 
+   // WTF?? The logic above: if we can't read binary overrides, don't even try
+   // reading source overrides. if we can read binary overrides, then say there
+   // are no overrides. THIS MAKES NO SENSE! -- ajt@d.o, 2006/02/28
+
    if (ExtOverrides.empty() == false)
       SOver.ReadExtraOverride(ExtOverrides);
    
@@ -549,10 +587,10 @@ bool SourcesWriter::DoPackage(string FileName)
       
    // Lookup the overide information, finding first the best priority.
    string BestPrio;
-   char Buffer[1000];
    string Bins = Tags.FindS("Binary");
-   Override::Item *OverItem = 0;
-   if (Bins.empty() == false && Bins.length() < sizeof(Buffer))
+   char Buffer[Bins.length() + 1];
+   auto_ptr<Override::Item> OverItem(0);
+   if (Bins.empty() == false)
    {
       strcpy(Buffer,Bins.c_str());
       
@@ -564,11 +602,9 @@ bool SourcesWriter::DoPackage(string FileName)
       unsigned char BestPrioV = pkgCache::State::Extra;
       for (unsigned I = 0; BinList[I] != 0; I++)
       {
-        Override::Item *Itm = BOver.GetItem(BinList[I]);
-        if (Itm == 0)
+        auto_ptr<Override::Item> Itm(BOver.GetItem(BinList[I]));
+        if (Itm.get() == 0)
            continue;
-        if (OverItem == 0)
-           OverItem = Itm;
 
         unsigned char NewPrioV = debListParser::GetPrio(Itm->Priority);
         if (NewPrioV < BestPrioV || BestPrio.empty() == true)
@@ -576,12 +612,14 @@ bool SourcesWriter::DoPackage(string FileName)
            BestPrioV = NewPrioV;
            BestPrio = Itm->Priority;
         }       
+
+        if (OverItem.get() == 0)
+           OverItem = Itm;
       }
    }
    
    // If we need to do any rewriting of the header do it now..
-   Override::Item Tmp;   
-   if (OverItem == 0)
+   if (OverItem.get() == 0)
    {
       if (NoOverride == false)
       {
@@ -589,15 +627,21 @@ bool SourcesWriter::DoPackage(string FileName)
         ioprintf(c1out, _("  %s has no override entry\n"), Tags.FindS("Source").c_str());
       }
       
-      OverItem = &Tmp;
+      OverItem = auto_ptr<Override::Item>(new Override::Item);
    }
    
-   Override::Item *SOverItem = SOver.GetItem(Tags.FindS("Source"));
-   if (SOverItem == 0)
+   auto_ptr<Override::Item> SOverItem(SOver.GetItem(Tags.FindS("Source")));
+   // const auto_ptr<Override::Item> autoSOverItem(SOverItem);
+   if (SOverItem.get() == 0)
    {
-      SOverItem = BOver.GetItem(Tags.FindS("Source"));
-      if (SOverItem == 0)
-        SOverItem = OverItem;
+      ioprintf(c1out, _("  %s has no source override entry\n"), Tags.FindS("Source").c_str());
+      SOverItem = auto_ptr<Override::Item>(BOver.GetItem(Tags.FindS("Source")));
+      if (SOverItem.get() == 0)
+      {
+        ioprintf(c1out, _("  %s has no binary override entry either\n"), Tags.FindS("Source").c_str());
+        SOverItem = auto_ptr<Override::Item>(new Override::Item);
+        *SOverItem = *OverItem;
+      }
    }
    
    // Add the dsc to the files hash list
@@ -639,7 +683,7 @@ bool SourcesWriter::DoPackage(string FileName)
          realpath(OriginalPath.c_str(),RealPath) != 0)
       {
         string RP = RealPath;
-        if (Delink(RP,OriginalPath.c_str(),Stats.DeLinkBytes,St) == false)
+        if (Delink(RP,OriginalPath.c_str(),Stats.DeLinkBytes,St.st_size) == false)
            return false;
       }
    }
@@ -709,26 +753,14 @@ ContentsWriter::ContentsWriter(string DB) :
    determine what the package name is. */
 bool ContentsWriter::DoPackage(string FileName,string Package)
 {
-   // Open the archive
-   FileFd F(FileName,FileFd::ReadOnly);
-   if (_error->PendingError() == true)
-      return false;
-   
-   // Stat the file for later
-   struct stat St;
-   if (fstat(F.Fd(),&St) != 0)
-      return _error->Errno("fstat","Failed too stat %s",FileName.c_str());
-
-   // Ready the DB
-   if (Db.SetFile(FileName,St,&F) == false || 
-       Db.LoadContents(false) == false)
+   if (!Db.GetFileInfo(FileName, Package.empty(), true, false, false, false, false))
+   {
       return false;
+   }
 
    // Parse the package name
    if (Package.empty() == true)
    {
-      if (Db.LoadControl() == false)
-        return false;
       Package = Db.Control.Section.FindS("Package");
    }
 
@@ -748,7 +780,7 @@ bool ContentsWriter::ReadFromPkgs(string PkgFile,string PkgCompress)
    
    // Open the package file
    int CompFd = -1;
-   int Proc = -1;
+   pid_t Proc = -1;
    if (Pkgs.OpenOld(CompFd,Proc) == false)
       return false;
    
@@ -799,6 +831,15 @@ ReleaseWriter::ReleaseWriter(string 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");
+
    Output = stdout;
    time_t now = time(NULL);
    char datestr[128];
@@ -842,9 +883,14 @@ bool ReleaseWriter::DoPackage(string FileName)
        FileName.length() > DirStrip.length() &&
        stringcmp(FileName.begin(),FileName.begin() + DirStrip.length(),
                 DirStrip.begin(),DirStrip.end()) == 0)
+   {
       NewFileName = string(FileName.begin() + DirStrip.length(),FileName.end());
+      while (NewFileName[0] == '/')
+         NewFileName = string(NewFileName.begin() + 1,NewFileName.end());
+   }
    else 
       NewFileName = FileName;
+
    if (PathPrefix.empty() == false)
       NewFileName = flCombine(PathPrefix,NewFileName);
 
@@ -855,16 +901,21 @@ bool ReleaseWriter::DoPackage(string FileName)
       return false;
    }
 
-   CheckSums[FileName].size = fd.Size();
+   CheckSums[NewFileName].size = fd.Size();
 
    MD5Summation MD5;
    MD5.AddFD(fd.Fd(), fd.Size());
-   CheckSums[FileName].MD5 = MD5.Result();
+   CheckSums[NewFileName].MD5 = MD5.Result();
 
    fd.Seek(0);
    SHA1Summation SHA1;
    SHA1.AddFD(fd.Fd(), fd.Size());
-   CheckSums[FileName].SHA1 = SHA1.Result();
+   CheckSums[NewFileName].SHA1 = SHA1.Result();
+
+   fd.Seek(0);
+   SHA256Summation SHA256;
+   SHA256.AddFD(fd.Fd(), fd.Size());
+   CheckSums[NewFileName].SHA256 = SHA256.Result();
 
    fd.Close();
    
@@ -897,5 +948,16 @@ void ReleaseWriter::Finish()
               (*I).second.size,
               (*I).first.c_str());
    }
+
+   fprintf(Output, "SHA256:\n");
+   for(map<string,struct CheckSum>::iterator I = CheckSums.begin();
+       I != CheckSums.end();
+       ++I)
+   {
+      fprintf(Output, " %s %16ld %s\n",
+              (*I).second.SHA256.c_str(),
+              (*I).second.size,
+              (*I).first.c_str());
+   }
 }