]> git.saurik.com Git - apt.git/blobdiff - apt-pkg/indexcopy.cc
- provide a {Package,Version}List similar to {Package,Version}Set
[apt.git] / apt-pkg / indexcopy.cc
index 53eb111722fc9f9c383f4eddcef12ffb34ea4958..4df018ef45512c26244a16bbf175db24be81ffa6 100644 (file)
@@ -10,7 +10,7 @@
    ##################################################################### */
                                                                        /*}}}*/
 // Include Files                                                       /*{{{*/
-#include "indexcopy.h"
+#include<config.h>
 
 #include <apt-pkg/error.h>
 #include <apt-pkg/progress.h>
 #include <apt-pkg/indexrecords.h>
 #include <apt-pkg/md5.h>
 #include <apt-pkg/cdrom.h>
-#include <apti18n.h>
 
 #include <iostream>
 #include <sstream>
 #include <unistd.h>
 #include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
 #include <stdio.h>
+#include <stdlib.h>
+
+#include "indexcopy.h"
+#include <apti18n.h>
                                                                        /*}}}*/
 
 using namespace std;
@@ -41,7 +46,7 @@ bool IndexCopy::CopyPackages(string CDROM,string Name,vector<string> &List,
                             pkgCdromStatus *log)
 {
    OpProgress *Progress = NULL;
-   if (List.size() == 0)
+   if (List.empty() == true)
       return true;
    
    if(log) 
@@ -51,8 +56,8 @@ bool IndexCopy::CopyPackages(string CDROM,string Name,vector<string> &List,
    bool Debug = _config->FindB("Debug::aptcdrom",false);
    
    // Prepare the progress indicator
-   unsigned long TotalSize = 0;
-   for (vector<string>::iterator I = List.begin(); I != List.end(); I++)
+   off_t TotalSize = 0;
+   for (vector<string>::iterator I = List.begin(); I != List.end(); ++I)
    {
       struct stat Buf;
       if (stat(string(*I + GetFileName()).c_str(),&Buf) != 0 &&
@@ -62,18 +67,18 @@ bool IndexCopy::CopyPackages(string CDROM,string Name,vector<string> &List,
       TotalSize += Buf.st_size;
    }   
 
-   unsigned long CurrentSize = 0;
+   off_t CurrentSize = 0;
    unsigned int NotFound = 0;
    unsigned int WrongSize = 0;
    unsigned int Packages = 0;
-   for (vector<string>::iterator I = List.begin(); I != List.end(); I++)
+   for (vector<string>::iterator I = List.begin(); I != List.end(); ++I)
    {      
       string OrigPath = string(*I,CDROM.length());
-      unsigned long FileSize = 0;
+      off_t FileSize = 0;
       
       // Open the package file
       FileFd Pkg;
-      if (FileExists(*I + GetFileName()) == true)
+      if (RealFileExists(*I + GetFileName()) == true)
       {
         Pkg.Open(*I + GetFileName(),FileFd::ReadOnly);
         FileSize = Pkg.Size();
@@ -130,9 +135,14 @@ bool IndexCopy::CopyPackages(string CDROM,string Name,vector<string> &List,
               (*I).c_str() + CDROM.length(),GetFileName());
       string TargetF = _config->FindDir("Dir::State::lists") + "partial/";
       TargetF += URItoFileName(S);
+      FileFd Target;
       if (_config->FindB("APT::CDROM::NoAct",false) == true)
+      {
         TargetF = "/dev/null";
-      FileFd Target(TargetF,FileFd::WriteEmpty);
+         Target.Open(TargetF,FileFd::WriteExists);
+      } else {
+         Target.Open(TargetF,FileFd::WriteAtomic);
+      }
       FILE *TargetFl = fdopen(dup(Target.Fd()),"w");
       if (_error->PendingError() == true)
         return false;
@@ -157,7 +167,7 @@ bool IndexCopy::CopyPackages(string CDROM,string Name,vector<string> &List,
         if(Progress)
            Progress->Progress(Parser.Offset());
         string File;
-        unsigned long Size;
+        unsigned long long Size;
         if (GetFile(File,Size) == false)
         {
            fclose(TargetFl);
@@ -212,7 +222,7 @@ bool IndexCopy::CopyPackages(string CDROM,string Name,vector<string> &List,
            }       
                                            
            // Size match
-           if ((unsigned)Buf.st_size != Size)
+           if ((unsigned long long)Buf.st_size != Size)
            {
               if (Debug == true)
                  clog << "Wrong Size: " << File << endl;
@@ -446,7 +456,7 @@ bool IndexCopy::GrabFirst(string Path,string &To,unsigned int Depth)
 // PackageCopy::GetFile - Get the file information from the section    /*{{{*/
 // ---------------------------------------------------------------------
 /* */
-bool PackageCopy::GetFile(string &File,unsigned long &Size)
+bool PackageCopy::GetFile(string &File,unsigned long long &Size)
 {
    File = Section->FindS("Filename");
    Size = Section->FindI("Size");
@@ -472,7 +482,7 @@ bool PackageCopy::RewriteEntry(FILE *Target,string File)
 // SourceCopy::GetFile - Get the file information from the section     /*{{{*/
 // ---------------------------------------------------------------------
 /* */
-bool SourceCopy::GetFile(string &File,unsigned long &Size)
+bool SourceCopy::GetFile(string &File,unsigned long long &Size)
 {
    string Files = Section->FindS("Files");
    if (Files.empty() == true)
@@ -495,7 +505,7 @@ bool SourceCopy::GetFile(string &File,unsigned long &Size)
       return _error->Error("Error parsing file record");
    
    // Parse the size and append the directory
-   Size = atoi(sSize.c_str());
+   Size = strtoull(sSize.c_str(), NULL, 10);
    File = Base + File;
    return true;
 }
@@ -525,7 +535,7 @@ bool SigVerify::Verify(string prefix, string file, indexRecords *MetaIndex)
    // we skip non-existing files in the verifcation to support a cdrom
    // with no Packages file (just a Package.gz), see LP: #255545
    // (non-existing files are not considered a error)
-   if(!FileExists(prefix+file))
+   if(!RealFileExists(prefix+file))
    {
       _error->Warning(_("Skipping nonexistent file %s"), string(prefix+file).c_str());
       return true;
@@ -563,7 +573,7 @@ bool SigVerify::CopyMetaIndex(string CDROM, string CDName,          /*{{{*/
 
       FileFd Target;
       FileFd Rel;
-      Target.Open(TargetF,FileFd::WriteEmpty);
+      Target.Open(TargetF,FileFd::WriteAtomic);
       Rel.Open(prefix + file,FileFd::ReadOnly);
       if (_error->PendingError() == true)
         return false;
@@ -576,13 +586,13 @@ bool SigVerify::CopyMetaIndex(string CDROM, string CDName,                /*{{{*/
 bool SigVerify::CopyAndVerify(string CDROM,string Name,vector<string> &SigList,        /*{{{*/
                              vector<string> PkgList,vector<string> SrcList)
 {
-   if (SigList.size() == 0)
+   if (SigList.empty() == true)
       return true;
 
    bool Debug = _config->FindB("Debug::aptcdrom",false);
 
    // Read all Release files
-   for (vector<string>::iterator I = SigList.begin(); I != SigList.end(); I++)
+   for (vector<string>::iterator I = SigList.begin(); I != SigList.end(); ++I)
    { 
       if(Debug)
         cout << "Signature verify for: " << *I << endl;
@@ -590,66 +600,34 @@ bool SigVerify::CopyAndVerify(string CDROM,string Name,vector<string> &SigList,
       indexRecords *MetaIndex = new indexRecords;
       string prefix = *I; 
 
+      string const releasegpg = *I+"Release.gpg";
+      string const release = *I+"Release";
+
       // a Release.gpg without a Release should never happen
-      if(!FileExists(*I+"Release"))
+      if(RealFileExists(release) == false)
       {
         delete MetaIndex;
         continue;
       }
 
-
-      // verify the gpg signature of "Release"
-      // gpg --verify "*I+Release.gpg", "*I+Release"
-      const char *Args[400];
-      unsigned int i = 0;
-
-      string gpgvpath = _config->Find("Dir::Bin::gpg", "/usr/bin/gpgv");
-      string pubringpath = _config->Find("Apt::GPGV::TrustedKeyring", "/etc/apt/trusted.gpg");
-      string releasegpg = *I+"Release.gpg";
-      string release = *I+"Release";
-
-      Args[i++] = gpgvpath.c_str();
-      Args[i++] = "--keyring";
-      Args[i++] = pubringpath.c_str();
-      Configuration::Item const *Opts;
-      Opts = _config->Tree("Acquire::gpgv::Options");
-      if (Opts != 0)
-      {
-         Opts = Opts->Child;
-        for (; Opts != 0; Opts = Opts->Next)
-         {
-            if (Opts->Value.empty() == true)
-               continue;
-            Args[i++] = Opts->Value.c_str();
-           if(i >= 390) { 
-              _error->Error("Argument list from Acquire::gpgv::Options too long. Exiting.");
-              return false;
-           }
-         }
-      }
-      
-      Args[i++] = releasegpg.c_str();
-      Args[i++] = release.c_str();
-      Args[i++] = NULL;
-      
       pid_t pid = ExecFork();
       if(pid < 0) {
         _error->Error("Fork failed");
         return false;
       }
-      if(pid == 0) {
-        execvp(gpgvpath.c_str(), (char**)Args);
-      }
+      if(pid == 0)
+        RunGPGV(release, releasegpg);
+
       if(!ExecWait(pid, "gpgv")) {
         _error->Warning("Signature verification failed for: %s",
-                        string(*I+"Release.gpg").c_str());
+                        releasegpg.c_str());
         // something went wrong, don't copy the Release.gpg
         // FIXME: delete any existing gpg file?
         continue;
       }
 
       // Open the Release file and add it to the MetaIndex
-      if(!MetaIndex->Load(*I+"Release"))
+      if(!MetaIndex->Load(release))
       {
         _error->Error("%s",MetaIndex->ErrorText.c_str());
         return false;
@@ -658,7 +636,7 @@ bool SigVerify::CopyAndVerify(string CDROM,string Name,vector<string> &SigList,
       // go over the Indexfiles and see if they verify
       // if so, remove them from our copy of the lists
       vector<string> keys = MetaIndex->MetaKeys();
-      for (vector<string>::iterator I = keys.begin(); I != keys.end(); I++)
+      for (vector<string>::iterator I = keys.begin(); I != keys.end(); ++I)
       { 
         if(!Verify(prefix,*I, MetaIndex)) {
            // something went wrong, don't copy the Release.gpg
@@ -676,6 +654,124 @@ bool SigVerify::CopyAndVerify(string CDROM,string Name,vector<string> &SigList,
       CopyMetaIndex(CDROM, Name, prefix, "Release.gpg");
    }   
 
+   return true;
+}
+                                                                       /*}}}*/
+// SigVerify::RunGPGV - returns the command needed for verify          /*{{{*/
+// ---------------------------------------------------------------------
+/* Generating the commandline for calling gpgv is somehow complicated as
+   we need to add multiple keyrings and user supplied options. Also, as
+   the cdrom code currently can not use the gpgv method we have two places
+   these need to be done - so the place for this method is wrong but better
+   than code duplication… */
+bool SigVerify::RunGPGV(std::string const &File, std::string const &FileGPG,
+                       int const &statusfd, int fd[2])
+{
+   if (File == FileGPG)
+   {
+      #define SIGMSG "-----BEGIN PGP SIGNED MESSAGE-----\n"
+      char buffer[sizeof(SIGMSG)];
+      FILE* gpg = fopen(File.c_str(), "r");
+      if (gpg == NULL)
+        return _error->Errno("RunGPGV", _("Could not open file %s"), File.c_str());
+      char const * const test = fgets(buffer, sizeof(buffer), gpg);
+      fclose(gpg);
+      if (test == NULL || strcmp(buffer, SIGMSG) != 0)
+        return _error->Error(_("File %s doesn't start with a clearsigned message"), File.c_str());
+      #undef SIGMSG
+   }
+
+
+   string const gpgvpath = _config->Find("Dir::Bin::gpg", "/usr/bin/gpgv");
+   // FIXME: remove support for deprecated APT::GPGV setting
+   string const trustedFile = _config->Find("APT::GPGV::TrustedKeyring", _config->FindFile("Dir::Etc::Trusted"));
+   string const trustedPath = _config->FindDir("Dir::Etc::TrustedParts");
+
+   bool const Debug = _config->FindB("Debug::Acquire::gpgv", false);
+
+   if (Debug == true)
+   {
+      std::clog << "gpgv path: " << gpgvpath << std::endl;
+      std::clog << "Keyring file: " << trustedFile << std::endl;
+      std::clog << "Keyring path: " << trustedPath << std::endl;
+   }
+
+   std::vector<string> keyrings;
+   if (DirectoryExists(trustedPath))
+     keyrings = GetListOfFilesInDir(trustedPath, "gpg", false, true);
+   if (RealFileExists(trustedFile) == true)
+     keyrings.push_back(trustedFile);
+
+   std::vector<const char *> Args;
+   Args.reserve(30);
+
+   if (keyrings.empty() == true)
+   {
+      // TRANSLATOR: %s is the trusted keyring parts directory
+      return _error->Error(_("No keyring installed in %s."),
+                          _config->FindDir("Dir::Etc::TrustedParts").c_str());
+   }
+
+   Args.push_back(gpgvpath.c_str());
+   Args.push_back("--ignore-time-conflict");
+
+   if (statusfd != -1)
+   {
+      Args.push_back("--status-fd");
+      char fd[10];
+      snprintf(fd, sizeof(fd), "%i", statusfd);
+      Args.push_back(fd);
+   }
+
+   for (vector<string>::const_iterator K = keyrings.begin();
+       K != keyrings.end(); ++K)
+   {
+      Args.push_back("--keyring");
+      Args.push_back(K->c_str());
+   }
+
+   Configuration::Item const *Opts;
+   Opts = _config->Tree("Acquire::gpgv::Options");
+   if (Opts != 0)
+   {
+      Opts = Opts->Child;
+      for (; Opts != 0; Opts = Opts->Next)
+      {
+        if (Opts->Value.empty() == true)
+           continue;
+        Args.push_back(Opts->Value.c_str());
+      }
+   }
+
+   Args.push_back(FileGPG.c_str());
+   if (FileGPG != File)
+      Args.push_back(File.c_str());
+   Args.push_back(NULL);
+
+   if (Debug == true)
+   {
+      std::clog << "Preparing to exec: " << gpgvpath;
+      for (std::vector<const char *>::const_iterator a = Args.begin(); *a != NULL; ++a)
+        std::clog << " " << *a;
+      std::clog << std::endl;
+   }
+
+   if (statusfd != -1)
+   {
+      int const nullfd = open("/dev/null", O_RDONLY);
+      close(fd[0]);
+      // Redirect output to /dev/null; we read from the status fd
+      dup2(nullfd, STDOUT_FILENO);
+      dup2(nullfd, STDERR_FILENO);
+      // Redirect the pipe to the status fd (3)
+      dup2(fd[1], statusfd);
+
+      putenv((char *)"LANG=");
+      putenv((char *)"LC_ALL=");
+      putenv((char *)"LC_MESSAGES=");
+   }
+
+   execvp(gpgvpath.c_str(), (char **) &Args[0]);
    return true;
 }
                                                                        /*}}}*/
@@ -683,7 +779,7 @@ bool TranslationsCopy::CopyTranslations(string CDROM,string Name,   /*{{{*/
                                vector<string> &List, pkgCdromStatus *log)
 {
    OpProgress *Progress = NULL;
-   if (List.size() == 0)
+   if (List.empty() == true)
       return true;
    
    if(log) 
@@ -692,8 +788,8 @@ bool TranslationsCopy::CopyTranslations(string CDROM,string Name,   /*{{{*/
    bool Debug = _config->FindB("Debug::aptcdrom",false);
    
    // Prepare the progress indicator
-   unsigned long TotalSize = 0;
-   for (vector<string>::iterator I = List.begin(); I != List.end(); I++)
+   off_t TotalSize = 0;
+   for (vector<string>::iterator I = List.begin(); I != List.end(); ++I)
    {
       struct stat Buf;
       if (stat(string(*I).c_str(),&Buf) != 0 &&
@@ -703,18 +799,18 @@ bool TranslationsCopy::CopyTranslations(string CDROM,string Name, /*{{{*/
       TotalSize += Buf.st_size;
    }   
 
-   unsigned long CurrentSize = 0;
+   off_t CurrentSize = 0;
    unsigned int NotFound = 0;
    unsigned int WrongSize = 0;
    unsigned int Packages = 0;
-   for (vector<string>::iterator I = List.begin(); I != List.end(); I++)
+   for (vector<string>::iterator I = List.begin(); I != List.end(); ++I)
    {      
       string OrigPath = string(*I,CDROM.length());
-      unsigned long FileSize = 0;
+      off_t FileSize = 0;
       
       // Open the package file
       FileFd Pkg;
-      if (FileExists(*I) == true)
+      if (RealFileExists(*I) == true)
       {
         Pkg.Open(*I,FileFd::ReadOnly);
         FileSize = Pkg.Size();
@@ -773,7 +869,7 @@ bool TranslationsCopy::CopyTranslations(string CDROM,string Name,   /*{{{*/
       TargetF += URItoFileName(S);
       if (_config->FindB("APT::CDROM::NoAct",false) == true)
         TargetF = "/dev/null";
-      FileFd Target(TargetF,FileFd::WriteEmpty);
+      FileFd Target(TargetF,FileFd::WriteAtomic);
       FILE *TargetFl = fdopen(dup(Target.Fd()),"w");
       if (_error->PendingError() == true)
         return false;
@@ -792,7 +888,6 @@ bool TranslationsCopy::CopyTranslations(string CDROM,string Name,   /*{{{*/
       this->Section = &Section;
       string Prefix;
       unsigned long Hits = 0;
-      unsigned long Chop = 0;
       while (Parser.Step(Section) == true)
       {
         if(Progress)
@@ -810,7 +905,7 @@ bool TranslationsCopy::CopyTranslations(string CDROM,string Name,   /*{{{*/
       fclose(TargetFl);
 
       if (Debug == true)
-        cout << " Processed by using Prefix '" << Prefix << "' and chop " << Chop << endl;
+        cout << " Processed by using Prefix '" << Prefix << "' and chop " << endl;
         
       if (_config->FindB("APT::CDROM::NoAct",false) == false)
       {