]> git.saurik.com Git - apt.git/blobdiff - apt-inst/contrib/extracttar.cc
Merge branch 'debian/sid' into debian/experimental
[apt.git] / apt-inst / contrib / extracttar.cc
index 95869fe4a3dac20024305e0551df7c756d943700..2c86d0d01053c143d6dd76ac3683b94d659edd86 100644 (file)
@@ -1,12 +1,12 @@
 // -*- mode: cpp; mode: fold -*-
 // Description                                                         /*{{{*/
 // -*- mode: cpp; mode: fold -*-
 // Description                                                         /*{{{*/
-// $Id: extracttar.cc,v 1.4 2001/09/30 04:06:59 jgg Exp $
+// $Id: extracttar.cc,v 1.8.2.1 2004/01/16 18:58:50 mdz Exp $
 /* ######################################################################
 
    Extract a Tar - Tar Extractor
 
    Some performance measurements showed that zlib performed quite poorly
 /* ######################################################################
 
    Extract a Tar - Tar Extractor
 
    Some performance measurements showed that zlib performed quite poorly
-   in comparision to a forked gzip process. This tar extractor makes use
+   in comparison to a forked gzip process. This tar extractor makes use
    of the fact that dup'd file descriptors have the same seek pointer
    and that gzip will not read past the end of a compressed stream, 
    even if there is more data. We use the dup property to track extraction
    of the fact that dup'd file descriptors have the same seek pointer
    and that gzip will not read past the end of a compressed stream, 
    even if there is more data. We use the dup property to track extraction
    ##################################################################### */
                                                                        /*}}}*/
 // Include Files                                                       /*{{{*/
    ##################################################################### */
                                                                        /*}}}*/
 // Include Files                                                       /*{{{*/
-#ifdef __GNUG__
-#pragma implementation "apt-pkg/extracttar.h"
-#endif
-#include <apt-pkg/extracttar.h>
+#include<config.h>
 
 
+#include <apt-pkg/dirstream.h>
+#include <apt-pkg/extracttar.h>
 #include <apt-pkg/error.h>
 #include <apt-pkg/strutl.h>
 #include <apt-pkg/configuration.h>
 #include <apt-pkg/error.h>
 #include <apt-pkg/strutl.h>
 #include <apt-pkg/configuration.h>
-#include <system.h>
+#include <apt-pkg/fileutl.h>
 
 
-#include <stdlib.h>
+#include <string.h>
+#include <algorithm>
+#include <string>
 #include <unistd.h>
 #include <signal.h>
 #include <fcntl.h>
 #include <unistd.h>
 #include <signal.h>
 #include <fcntl.h>
-#include <iostream.h>
+#include <iostream>
+
+#include <apti18n.h>
                                                                        /*}}}*/
                                                                        /*}}}*/
+
+using namespace std;
     
 // The on disk header for a tar file.
 struct ExtractTar::TarHeader
     
 // The on disk header for a tar file.
 struct ExtractTar::TarHeader
@@ -55,12 +60,10 @@ struct ExtractTar::TarHeader
 // ExtractTar::ExtractTar - Constructor                                        /*{{{*/
 // ---------------------------------------------------------------------
 /* */
 // ExtractTar::ExtractTar - Constructor                                        /*{{{*/
 // ---------------------------------------------------------------------
 /* */
-ExtractTar::ExtractTar(FileFd &Fd,unsigned long Max) : File(Fd), 
-                         MaxInSize(Max)
-
+ExtractTar::ExtractTar(FileFd &Fd,unsigned long long Max,string DecompressionProgram)
+       : File(Fd), MaxInSize(Max), DecompressProg(DecompressionProgram)
 {
    GZPid = -1;
 {
    GZPid = -1;
-   InFd = -1;
    Eof = false;
 }
                                                                        /*}}}*/
    Eof = false;
 }
                                                                        /*}}}*/
@@ -90,7 +93,8 @@ bool ExtractTar::Done(bool Force)
    
    // Make sure we clean it up!
    kill(GZPid,SIGINT);
    
    // Make sure we clean it up!
    kill(GZPid,SIGINT);
-   if (ExecWait(GZPid,_config->Find("dir::bin::gzip","/bin/gzip").c_str(),
+   string confvar = string("dir::bin::") + DecompressProg;
+   if (ExecWait(GZPid,_config->Find(confvar.c_str(),DecompressProg.c_str()).c_str(),
                Force) == false)
    {
       GZPid = -1;
                Force) == false)
    {
       GZPid = -1;
@@ -108,10 +112,16 @@ bool ExtractTar::Done(bool Force)
    gzip will efficiently ignore the extra bits. */
 bool ExtractTar::StartGzip()
 {
    gzip will efficiently ignore the extra bits. */
 bool ExtractTar::StartGzip()
 {
+   if (DecompressProg.empty())
+   {
+      InFd.OpenDescriptor(File.Fd(), FileFd::ReadOnly, FileFd::None, false);
+      return true;
+   }
+
    int Pipes[2];
    if (pipe(Pipes) != 0)
    int Pipes[2];
    if (pipe(Pipes) != 0)
-      return _error->Errno("pipe","Failed to create pipes");
-   
+      return _error->Errno("pipe",_("Failed to create pipes"));
+
    // Fork off the process
    GZPid = ExecFork();
 
    // Fork off the process
    GZPid = ExecFork();
 
@@ -127,20 +137,22 @@ bool ExtractTar::StartGzip()
       dup2(Fd,STDERR_FILENO);
       close(Fd);
       SetCloseExec(STDOUT_FILENO,false);
       dup2(Fd,STDERR_FILENO);
       close(Fd);
       SetCloseExec(STDOUT_FILENO,false);
-      SetCloseExec(STDIN_FILENO,false);      
+      SetCloseExec(STDIN_FILENO,false);
       SetCloseExec(STDERR_FILENO,false);
       SetCloseExec(STDERR_FILENO,false);
-      
+
       const char *Args[3];
       const char *Args[3];
-      Args[0] = _config->Find("dir::bin::gzip","/bin/gzip").c_str();
+      string confvar = string("dir::bin::") + DecompressProg;
+      string argv0 = _config->Find(confvar.c_str(),DecompressProg.c_str());
+      Args[0] = argv0.c_str();
       Args[1] = "-d";
       Args[2] = 0;
       Args[1] = "-d";
       Args[2] = 0;
-      execv(Args[0],(char **)Args);
-      cerr << "Failed to exec gzip " << Args[0] << endl;
+      execvp(Args[0],(char **)Args);
+      cerr << _("Failed to exec gzip ") << Args[0] << endl;
       _exit(100);
    }
 
    // Fix up our FDs
       _exit(100);
    }
 
    // Fix up our FDs
-   InFd.Fd(Pipes[0]);
+   InFd.OpenDescriptor(Pipes[0], FileFd::ReadOnly, FileFd::None, true);
    close(Pipes[1]);
    return true;
 }
    close(Pipes[1]);
    return true;
 }
@@ -156,8 +168,8 @@ bool ExtractTar::Go(pkgDirStream &Stream)
       return false;
    
    // Loop over all blocks
       return false;
    
    // Loop over all blocks
-   string LastLongLink;
-   string LastLongName;
+   string LastLongLink, ItemLink;
+   string LastLongName, ItemName;
    while (1)
    {
       bool BadRecord = false;      
    while (1)
    {
       bool BadRecord = false;      
@@ -172,7 +184,7 @@ bool ExtractTar::Go(pkgDirStream &Stream)
       TarHeader *Tar = (TarHeader *)Block;
       unsigned long CheckSum;
       if (StrToNum(Tar->Checksum,CheckSum,sizeof(Tar->Checksum),8) == false)
       TarHeader *Tar = (TarHeader *)Block;
       unsigned long CheckSum;
       if (StrToNum(Tar->Checksum,CheckSum,sizeof(Tar->Checksum),8) == false)
-        return _error->Error("Corrupted archive");
+        return _error->Error(_("Corrupted archive"));
       
       /* Compute the checksum field. The actual checksum is blanked out
          with spaces so it is not included in the computation */
       
       /* Compute the checksum field. The actual checksum is blanked out
          with spaces so it is not included in the computation */
@@ -187,37 +199,39 @@ bool ExtractTar::Go(pkgDirStream &Stream)
         return Done(true);
       
       if (NewSum != CheckSum)
         return Done(true);
       
       if (NewSum != CheckSum)
-        return _error->Error("Tar Checksum failed, archive corrupted");
+        return _error->Error(_("Tar checksum failed, archive corrupted"));
    
       // Decode all of the fields
       pkgDirStream::Item Itm;
       if (StrToNum(Tar->Mode,Itm.Mode,sizeof(Tar->Mode),8) == false ||
    
       // Decode all of the fields
       pkgDirStream::Item Itm;
       if (StrToNum(Tar->Mode,Itm.Mode,sizeof(Tar->Mode),8) == false ||
-         StrToNum(Tar->UserID,Itm.UID,sizeof(Tar->UserID),8) == false ||
-         StrToNum(Tar->GroupID,Itm.GID,sizeof(Tar->GroupID),8) == false ||
-         StrToNum(Tar->Size,Itm.Size,sizeof(Tar->Size),8) == false ||
-         StrToNum(Tar->MTime,Itm.MTime,sizeof(Tar->MTime),8) == false ||
+          (Base256ToNum(Tar->UserID,Itm.UID,8) == false &&
+            StrToNum(Tar->UserID,Itm.UID,sizeof(Tar->UserID),8) == false) ||
+          (Base256ToNum(Tar->GroupID,Itm.GID,8) == false &&
+            StrToNum(Tar->GroupID,Itm.GID,sizeof(Tar->GroupID),8) == false) ||
+          (Base256ToNum(Tar->Size,Itm.Size,12) == false &&
+            StrToNum(Tar->Size,Itm.Size,sizeof(Tar->Size),8) == false) ||
+          (Base256ToNum(Tar->MTime,Itm.MTime,12) == false &&
+            StrToNum(Tar->MTime,Itm.MTime,sizeof(Tar->MTime),8) == false) ||
          StrToNum(Tar->Major,Itm.Major,sizeof(Tar->Major),8) == false ||
          StrToNum(Tar->Minor,Itm.Minor,sizeof(Tar->Minor),8) == false)
          StrToNum(Tar->Major,Itm.Major,sizeof(Tar->Major),8) == false ||
          StrToNum(Tar->Minor,Itm.Minor,sizeof(Tar->Minor),8) == false)
-        return _error->Error("Corrupted archive");
-      
-      // Grab the filename
+        return _error->Error(_("Corrupted archive"));
+
+      // Grab the filename and link target: use last long name if one was
+      // set, otherwise use the header value as-is, but remember that it may
+      // fill the entire 100-byte block and needs to be zero-terminated.
+      // See Debian Bug #689582.
       if (LastLongName.empty() == false)
         Itm.Name = (char *)LastLongName.c_str();
       else
       if (LastLongName.empty() == false)
         Itm.Name = (char *)LastLongName.c_str();
       else
-      {
-        Tar->Name[sizeof(Tar->Name)] = 0;
-        Itm.Name = Tar->Name;
-      }      
+        Itm.Name = (char *)ItemName.assign(Tar->Name, sizeof(Tar->Name)).c_str();
       if (Itm.Name[0] == '.' && Itm.Name[1] == '/' && Itm.Name[2] != 0)
         Itm.Name += 2;
       if (Itm.Name[0] == '.' && Itm.Name[1] == '/' && Itm.Name[2] != 0)
         Itm.Name += 2;
-      
-      // Grab the link target
-      Tar->Name[sizeof(Tar->LinkName)] = 0;
-      Itm.LinkTarget = Tar->LinkName;
 
       if (LastLongLink.empty() == false)
         Itm.LinkTarget = (char *)LastLongLink.c_str();
 
       if (LastLongLink.empty() == false)
         Itm.LinkTarget = (char *)LastLongLink.c_str();
-      
+      else
+        Itm.LinkTarget = (char *)ItemLink.assign(Tar->LinkName, sizeof(Tar->LinkName)).c_str();
+
       // Convert the type over
       switch (Tar->LinkFlag)
       {
       // Convert the type over
       switch (Tar->LinkFlag)
       {
@@ -252,7 +266,7 @@ bool ExtractTar::Go(pkgDirStream &Stream)
 
         case GNU_LongLink:
         {
 
         case GNU_LongLink:
         {
-           unsigned long Length = Itm.Size;
+           unsigned long long Length = Itm.Size;
            unsigned char Block[512];
            while (Length > 0)
            {
            unsigned char Block[512];
            while (Length > 0)
            {
@@ -271,7 +285,7 @@ bool ExtractTar::Go(pkgDirStream &Stream)
         
         case GNU_LongName:
         {
         
         case GNU_LongName:
         {
-           unsigned long Length = Itm.Size;
+           unsigned long long Length = Itm.Size;
            unsigned char Block[512];
            while (Length > 0)
            {
            unsigned char Block[512];
            while (Length > 0)
            {
@@ -290,7 +304,7 @@ bool ExtractTar::Go(pkgDirStream &Stream)
         
         default:
         BadRecord = true;
         
         default:
         BadRecord = true;
-        _error->Warning("Unkown TAR header type %u, member %s",(unsigned)Tar->LinkFlag,Tar->Name);
+        _error->Warning(_("Unknown TAR header type %u, member %s"),(unsigned)Tar->LinkFlag,Tar->Name);
         break;
       }
       
         break;
       }
       
@@ -300,11 +314,11 @@ bool ExtractTar::Go(pkgDirStream &Stream)
            return false;
       
       // Copy the file over the FD
            return false;
       
       // Copy the file over the FD
-      unsigned long Size = Itm.Size;
+      unsigned long long Size = Itm.Size;
       while (Size != 0)
       {
         unsigned char Junk[32*1024];
       while (Size != 0)
       {
         unsigned char Junk[32*1024];
-        unsigned long Read = MIN(Size,sizeof(Junk));
+        unsigned long Read = min(Size, (unsigned long long)sizeof(Junk));
         if (InFd.Read(Junk,((Read+511)/512)*512) == false)
            return false;
         
         if (InFd.Read(Junk,((Read+511)/512)*512) == false)
            return false;
         
@@ -329,7 +343,7 @@ bool ExtractTar::Go(pkgDirStream &Stream)
       }
       
       // And finish up
       }
       
       // And finish up
-      if (Itm.Size != 0 && BadRecord == false)
+      if (BadRecord == false)
         if (Stream.FinishedFile(Itm,Fd) == false)
            return false;
       
         if (Stream.FinishedFile(Itm,Fd) == false)
            return false;