]> git.saurik.com Git - apt.git/blobdiff - ftparchive/writer.cc
* Have "apt-ftparchive release" strip the leading path ...
[apt.git] / ftparchive / writer.cc
index a4877d635d3e5f4f0e1addbaab5961bf7091e083..e495a4c455230d072894a979d9ff82a40a6536bf 100644 (file)
@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // Description                                                         /*{{{*/
-// $Id: writer.cc,v 1.4 2001/06/26 02:50:27 jgg Exp $
+// $Id: writer.cc,v 1.11 2004/01/02 21:48:13 mdz Exp $
 /* ######################################################################
 
    Writer 
 
 #include "writer.h"
     
+#include <apti18n.h>
 #include <apt-pkg/strutl.h>
 #include <apt-pkg/error.h>
 #include <apt-pkg/configuration.h>
 #include <apt-pkg/md5.h>
+#include <apt-pkg/sha1.h>
 #include <apt-pkg/deblistparser.h>
 
 #include <sys/types.h>
 #include <unistd.h>
+#include <ctime>
 #include <ftw.h>
+#include <fnmatch.h>
 #include <iostream>
     
 #include "cachedb.h"
@@ -57,8 +61,6 @@ FTWScanner::FTWScanner()
 {
    ErrorPrinted = false;
    NoLinkAct = !_config->FindB("APT::FTPArchive::DeLinkAct",true);
-   TmpExt = 0;
-   Ext[0] = 0;
    RealPath = 0;
    long PMax = pathconf(".",_PC_PATH_MAX);
    if (PMax > 0)
@@ -74,26 +76,29 @@ int FTWScanner::Scanner(const char *File,const struct stat *sb,int Flag)
    if (Flag == FTW_DNR)
    {
       Owner->NewLine(1);
-      c1out << "W: Unable to read directory " << File << endl;
+      ioprintf(c1out, _("W: Unable to read directory %s\n"), File);
    }   
    if (Flag == FTW_NS)
    {
       Owner->NewLine(1);
-      c1out << "W: Unable to stat " << File << endl;
+      ioprintf(c1out, _("W: Unable to stat %s\n"), File);
    }   
    if (Flag != FTW_F)
       return 0;
 
-   // See if it is a .deb
-   if (strlen(File) < 4)
-      return 0;
-   
-   unsigned CurExt = 0;
-   for (; Owner->Ext[CurExt] != 0; CurExt++)
-      if (strcmp(File+strlen(File)-strlen(Owner->Ext[CurExt]),
-                Owner->Ext[CurExt]) == 0)
-        break;
-   if (Owner->Ext[CurExt] == 0)
+   const char *LastComponent = strrchr(File, '/');
+   if (LastComponent == NULL)
+      LastComponent = File;
+   else
+      LastComponent++;
+
+   vector<string>::iterator I;
+   for(I = Owner->Patterns.begin(); I != Owner->Patterns.end(); ++I)
+   {
+      if (fnmatch((*I).c_str(), LastComponent, 0) == 0)
+         break;
+   }
+   if (I == Owner->Patterns.end())
       return 0;
 
    /* Process it. If the file is a link then resolve it into an absolute
@@ -118,16 +123,16 @@ int FTWScanner::Scanner(const char *File,const struct stat *sb,int Flag)
         
         bool Type = _error->PopMessage(Err);
         if (Type == true)
-           c1out << "E: " << Err << endl;
+           cerr << _("E: ") << Err << endl;
         else
-           c1out << "W: " << Err << endl;
+           cerr << _("W: ") << Err << endl;
         
         if (Err.find(File) != string::npos)
            SeenPath = true;
       }      
       
       if (SeenPath == false)
-        cerr << "E: Errors apply to file '" << File << "'" << endl;
+        cerr << _("E: Errors apply to file ") << "'" << File << "'" << endl;
       return 0;
    }
    
@@ -144,7 +149,7 @@ bool FTWScanner::RecursiveScan(string Dir)
    if (InternalPrefix.empty() == true)
    {
       if (realpath(Dir.c_str(),RealPath) == 0)
-        return _error->Errno("realpath","Failed to resolve %s",Dir.c_str());
+        return _error->Errno("realpath",_("Failed to resolve %s"),Dir.c_str());
       InternalPrefix = RealPath;      
    }
    
@@ -156,7 +161,7 @@ bool FTWScanner::RecursiveScan(string Dir)
    if (Res != 0)
    {
       if (_error->PendingError() == false)
-        _error->Errno("ftw","Tree walking failed");
+        _error->Errno("ftw",_("Tree walking failed"));
       return false;
    }
    
@@ -174,14 +179,14 @@ bool FTWScanner::LoadFileList(string Dir,string File)
    if (InternalPrefix.empty() == true)
    {
       if (realpath(Dir.c_str(),RealPath) == 0)
-        return _error->Errno("realpath","Failed to resolve %s",Dir.c_str());
+        return _error->Errno("realpath",_("Failed to resolve %s"),Dir.c_str());
       InternalPrefix = RealPath;      
    }
    
    Owner = this;
    FILE *List = fopen(File.c_str(),"r");
    if (List == 0)
-      return _error->Errno("fopen","Failed to open %s",File.c_str());
+      return _error->Errno("fopen",_("Failed to open %s"),File.c_str());
    
    /* We are a tad tricky here.. We prefix the buffer with the directory
       name, that way if we need a full path with just use line.. Sneaky and
@@ -238,25 +243,26 @@ bool FTWScanner::Delink(string &FileName,const char *OriginalPath,
            cout << endl;
         
         NewLine(1);
-        c1out << " DeLink " << (OriginalPath + InternalPrefix.length())
-           << " [" << SizeToStr(St.st_size) << "B]" << endl << flush;
+        ioprintf(c1out, _(" DeLink %s [%s]\n"), (OriginalPath + InternalPrefix.length()),
+                   SizeToStr(St.st_size).c_str());
+        c1out << flush;
         
         if (NoLinkAct == false)
         {
            char OldLink[400];
            if (readlink(OriginalPath,OldLink,sizeof(OldLink)) == -1)
-              _error->Errno("readlink","Failed to readlink %s",OriginalPath);
+              _error->Errno("readlink",_("Failed to readlink %s"),OriginalPath);
            else
            {
               if (unlink(OriginalPath) != 0)
-                 _error->Errno("unlink","Failed to unlink %s",OriginalPath);
+                 _error->Errno("unlink",_("Failed to unlink %s"),OriginalPath);
               else
               {
                  if (link(FileName.c_str(),OriginalPath) != 0)
                  {
                     // Panic! Restore the symlink
                     symlink(OldLink,OriginalPath);
-                    return _error->Errno("link","*** Failed to link %s to %s",
+                    return _error->Errno("link",_("*** Failed to link %s to %s"),
                                          FileName.c_str(),
                                          OriginalPath);
                  }            
@@ -266,7 +272,7 @@ bool FTWScanner::Delink(string &FileName,const char *OriginalPath,
         
         DeLinkBytes += St.st_size;
         if (DeLinkBytes/1024 >= DeLinkLimit)
-           c1out << " DeLink limit of " << SizeToStr(DeLinkBytes) << "B hit." << endl;      
+           ioprintf(c1out, _(" DeLink limit of %sB hit.\n"), SizeToStr(DeLinkBytes).c_str());      
       }
       
       FileName = OriginalPath;
@@ -275,17 +281,6 @@ bool FTWScanner::Delink(string &FileName,const char *OriginalPath,
    return true;
 }
                                                                        /*}}}*/
-// FTWScanner::SetExts - Set extensions to support                     /*{{{*/
-// ---------------------------------------------------------------------
-/* */
-bool FTWScanner::SetExts(string Vals)
-{
-   delete [] TmpExt;
-   TmpExt = new char[Vals.length()+1];
-   strcpy(TmpExt,Vals.c_str());
-   return TokSplitString(' ',TmpExt,(char **)Ext,sizeof(Ext)/sizeof(Ext[0]));
-}
-                                                                       /*}}}*/
 
 // PackagesWriter::PackagesWriter - Constructor                                /*{{{*/
 // ---------------------------------------------------------------------
@@ -294,8 +289,7 @@ PackagesWriter::PackagesWriter(string DB,string Overrides,string ExtOverrides) :
                    Db(DB),Stats(Db.Stats)
 {
    Output = stdout;
-   Ext[0] = ".deb";
-   Ext[1] = 0;
+   AddPattern("*.deb");
    DeLinkLimit = 0;
    
    // Process the command line options
@@ -317,6 +311,28 @@ PackagesWriter::PackagesWriter(string DB,string Overrides,string ExtOverrides) :
 
    _error->DumpErrors();
 }
+                                                                        /*}}}*/
+// FTWScanner::SetExts - Set extensions to support                      /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+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))
+   {
+      if (space > 0)
+      {
+         AddPattern(string("*") + string(Start, space-1));
+         Start = space + 1;
+      }
+   }
+
+   return true;
+}
+
                                                                        /*}}}*/
 // PackagesWriter::DoPackage - Process a single package                        /*{{{*/
 // ---------------------------------------------------------------------
@@ -333,7 +349,7 @@ bool PackagesWriter::DoPackage(string FileName)
    // 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());
+      return _error->Errno("fstat",_("Failed to stat %s"),FileName.c_str());
 
    // Pull all the data we need form the DB
    string MD5Res;
@@ -353,7 +369,7 @@ bool PackagesWriter::DoPackage(string FileName)
    Override::Item *OverItem = Over.GetItem(Package);
    
    if (Package.empty() == true)
-      return _error->Error("Archive had no package field");
+      return _error->Error(_("Archive had no package field"));
    
    // If we need to do any rewriting of the header do it now..
    if (OverItem == 0)
@@ -361,7 +377,7 @@ bool PackagesWriter::DoPackage(string FileName)
       if (NoOverride == false)
       {
         NewLine(1);
-        c1out << "  " << Package << " has no override entry" << endl;
+        ioprintf(c1out, _("  %s has no override entry\n"), Package.c_str());
       }
       
       OverItem = &Tmp;
@@ -404,9 +420,8 @@ bool PackagesWriter::DoPackage(string FileName)
       if (NoOverride == false)
       {
         NewLine(1);
-        c1out << "  " << Package << " maintainer is " <<
-              Tags.FindS("Maintainer") << " not " <<
-              OverItem->OldMaint << endl;
+        ioprintf(c1out, _("  %s maintainer is %s not %s\n"),
+              Package.c_str(), Tags.FindS("Maintainer").c_str(), OverItem->OldMaint.c_str());
       }      
    }
    
@@ -448,8 +463,7 @@ SourcesWriter::SourcesWriter(string BOverrides,string SOverrides,
                             string ExtOverrides)
 {
    Output = stdout;
-   Ext[0] = ".dsc";
-   Ext[1] = 0;
+   AddPattern("*.dsc");
    DeLinkLimit = 0;
    Buffer = 0;
    BufSize = 0;
@@ -572,7 +586,7 @@ bool SourcesWriter::DoPackage(string FileName)
       if (NoOverride == false)
       {
         NewLine(1);     
-        c1out << "  " << Tags.FindS("Source") << " has no override entry" << endl;
+        ioprintf(c1out, _("  %s has no override entry\n"), Tags.FindS("Source").c_str());
       }
       
       OverItem = &Tmp;
@@ -603,10 +617,10 @@ bool SourcesWriter::DoPackage(string FileName)
       NewFileName = OriginalPath;
    if (PathPrefix.empty() == false)
       NewFileName = flCombine(PathPrefix,NewFileName);
-    
+
    string Directory = flNotFile(OriginalPath);
    string Package = Tags.FindS("Source");
-   
+
    // Perform the delinking operation over all of the files
    string ParseJnk;
    const char *C = Files;
@@ -633,7 +647,7 @@ bool SourcesWriter::DoPackage(string FileName)
    Directory = flNotFile(NewFileName);
    if (Directory.length() > 2)
       Directory.erase(Directory.end()-1);
-      
+
    // This lists all the changes to the fields we are going to make.
    // (5 hardcoded + maintainer + end marker)
    TFRewriteData Changes[5+1+SOverItem->FieldOverride.size()+1];
@@ -641,7 +655,8 @@ 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++],"Directory",Directory.c_str());
+   if (Directory != "./")
+      SetTFRewriteData(Changes[End++],"Directory",Directory.c_str());
    SetTFRewriteData(Changes[End++],"Priority",BestPrio.c_str());
    SetTFRewriteData(Changes[End++],"Status",0);
 
@@ -653,9 +668,8 @@ bool SourcesWriter::DoPackage(string FileName)
       if (NoOverride == false)
       {
         NewLine(1);     
-        c1out << "  " << Package << " maintainer is " <<
-              Tags.FindS("Maintainer") << " not " <<
-              OverItem->OldMaint << endl;
+        ioprintf(c1out, _("  %s maintainer is %s not %s\n"), Package.c_str(),
+              Tags.FindS("Maintainer").c_str(), OverItem->OldMaint.c_str());
       }      
    }
    if (NewMaint.empty() == false)
@@ -685,8 +699,7 @@ ContentsWriter::ContentsWriter(string DB) :
                    Db(DB), Stats(Db.Stats)
 
 {
-   Ext[0] = ".deb";
-   Ext[1] = 0;
+   AddPattern("*.deb");
    Output = stdout;
 }
                                                                        /*}}}*/
@@ -776,4 +789,125 @@ bool ContentsWriter::ReadFromPkgs(string PkgFile,string PkgCompress)
    
    return true;
 }
+
                                                                        /*}}}*/
+
+// ReleaseWriter::ReleaseWriter - Constructor                          /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+ReleaseWriter::ReleaseWriter(string DB)
+{
+   AddPattern("Packages");
+   AddPattern("Packages.gz");
+   AddPattern("Packages.bz2");
+   AddPattern("Sources");
+   AddPattern("Sources.gz");
+   AddPattern("Sources.bz2");
+   AddPattern("Release");
+   AddPattern("md5sum.txt");
+
+   Output = stdout;
+   time_t now = time(NULL);
+   char datestr[128];
+   if (strftime(datestr, sizeof(datestr), "%a, %d %b %Y %H:%M:%S UTC",
+                gmtime(&now)) == 0)
+   {
+      datestr[0] = '\0';
+   }
+
+   map<string,string> Fields;
+   Fields["Origin"] = "";
+   Fields["Label"] = "";
+   Fields["Suite"] = "";
+   Fields["Version"] = "";
+   Fields["Codename"] = "";
+   Fields["Date"] = datestr;
+   Fields["Architectures"] = "";
+   Fields["Components"] = "";
+   Fields["Description"] = "";
+
+   for(map<string,string>::const_iterator I = Fields.begin();
+       I != Fields.end();
+       ++I)
+   {
+      string Config = string("APT::FTPArchive::Release::") + (*I).first;
+      string Value = _config->Find(Config, (*I).second.c_str());
+      if (Value == "")
+         continue;
+
+      fprintf(Output, "%s: %s\n", (*I).first.c_str(), Value.c_str());
+   }
+}
+                                                                       /*}}}*/
+// ReleaseWriter::DoPackage - Process a single package                 /*{{{*/
+// ---------------------------------------------------------------------
+bool ReleaseWriter::DoPackage(string FileName)
+{
+   // Strip the DirStrip prefix from the FileName and add the PathPrefix
+   string NewFileName;
+   if (DirStrip.empty() == false &&
+       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(FileName.begin() + 1,FileName.end());
+   }
+   else 
+      NewFileName = FileName;
+
+   if (PathPrefix.empty() == false)
+      NewFileName = flCombine(PathPrefix,NewFileName);
+
+   FileFd fd(FileName, FileFd::ReadOnly);
+
+   if (!fd.IsOpen())
+   {
+      return false;
+   }
+
+   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.Close();
+   
+   return true;
+}
+
+                                                                       /*}}}*/
+// ReleaseWriter::Finish - Output the checksums                                /*{{{*/
+// ---------------------------------------------------------------------
+void ReleaseWriter::Finish()
+{
+   fprintf(Output, "MD5Sum:\n");
+   for(map<string,struct CheckSum>::iterator I = CheckSums.begin();
+       I != CheckSums.end();
+       ++I)
+   {
+      fprintf(Output, " %s %16ld %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)
+   {
+      fprintf(Output, " %s %16ld %s\n",
+              (*I).second.SHA1.c_str(),
+              (*I).second.size,
+              (*I).first.c_str());
+   }
+}
+