瀏覽代碼

cdrom and source support
Author: jgg
Date: 1999-07-12 02:59:36 GMT
cdrom and source support

Arch Librarian 22 年之前
父節點
當前提交
143abaebde
共有 4 個文件被更改,包括 630 次插入397 次删除
  1. 29 396
      cmdline/apt-cdrom.cc
  2. 535 0
      cmdline/indexcopy.cc
  3. 65 0
      cmdline/indexcopy.h
  4. 1 1
      cmdline/makefile

+ 29 - 396
cmdline/apt-cdrom.cc

@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
 // Description								/*{{{*/
-// $Id: apt-cdrom.cc,v 1.27 1999/07/11 22:42:32 jgg Exp $
+// $Id: apt-cdrom.cc,v 1.28 1999/07/12 02:59:36 jgg Exp $
 /* ######################################################################
 /* ######################################################################
    
    
    APT CDROM - Tool for handling APT's CDROM database.
    APT CDROM - Tool for handling APT's CDROM database.
@@ -16,11 +16,12 @@
 #include <apt-pkg/init.h>
 #include <apt-pkg/init.h>
 #include <apt-pkg/fileutl.h>
 #include <apt-pkg/fileutl.h>
 #include <apt-pkg/progress.h>
 #include <apt-pkg/progress.h>
-#include <apt-pkg/tagfile.h>
 #include <apt-pkg/cdromutl.h>
 #include <apt-pkg/cdromutl.h>
 #include <apt-pkg/strutl.h>
 #include <apt-pkg/strutl.h>
 #include <config.h>
 #include <config.h>
 
 
+#include "indexcopy.h"
+
 #include <iostream>
 #include <iostream>
 #include <fstream>
 #include <fstream>
 #include <vector>
 #include <vector>
@@ -47,7 +48,7 @@ bool FindPackages(string CD,vector<string> &List,vector<string> &SList,
 
 
    if (CD[CD.length()-1] != '/')
    if (CD[CD.length()-1] != '/')
       CD += '/';   
       CD += '/';   
-   
+
    if (chdir(CD.c_str()) != 0)
    if (chdir(CD.c_str()) != 0)
       return _error->Errno("chdir","Unable to change to %s",CD.c_str());
       return _error->Errno("chdir","Unable to change to %s",CD.c_str());
 
 
@@ -70,7 +71,7 @@ bool FindPackages(string CD,vector<string> &List,vector<string> &SList,
       if (_config->FindB("APT::CDROM::Thorough",false) == false)
       if (_config->FindB("APT::CDROM::Thorough",false) == false)
 	 return true;
 	 return true;
    }
    }
-   if (stat("Sources",&Buf) == 0) 
+   if (stat("Sources.gz",&Buf) == 0 || stat("Sources",&Buf) == 0)
    {
    {
       SList.push_back(CD);
       SList.push_back(CD);
       
       
@@ -185,6 +186,8 @@ int Score(string Path)
       Res += 2;
       Res += 2;
    if (Path.find("/non-US/") != string::npos)
    if (Path.find("/non-US/") != string::npos)
       Res += 2;
       Res += 2;
+   if (Path.find("/source/") != string::npos)
+      Res += 1;
    return Res;
    return Res;
 }
 }
 									/*}}}*/
 									/*}}}*/
@@ -198,7 +201,8 @@ bool DropRepeats(vector<string> &List,const char *Name)
    for (unsigned int I = 0; I != List.size(); I++)
    for (unsigned int I = 0; I != List.size(); I++)
    {
    {
       struct stat Buf;
       struct stat Buf;
-      if (stat((List[I] + Name).c_str(),&Buf) != 0)
+      if (stat((List[I] + Name).c_str(),&Buf) != 0 &&
+	  stat((List[I] + Name + ".gz").c_str(),&Buf) != 0)
 	 _error->Errno("stat","Failed to stat %s%s",List[I].c_str(),
 	 _error->Errno("stat","Failed to stat %s%s",List[I].c_str(),
 		       Name);
 		       Name);
       Inodes[I] = Buf.st_ino;
       Inodes[I] = Buf.st_ino;
@@ -241,389 +245,6 @@ bool DropRepeats(vector<string> &List,const char *Name)
    return true;
    return true;
 }
 }
 									/*}}}*/
 									/*}}}*/
-// ConvertToSourceList - Convert a Path to a sourcelist entry		/*{{{*/
-// ---------------------------------------------------------------------
-/* We look for things in dists/ notation and convert them to 
-   <dist> <component> form otherwise it is left alone. This also strips
-   the CD path. */
-void ConvertToSourceList(string CD,string &Path)
-{
-   char S[300];
-   sprintf(S,"binary-%s",_config->Find("Apt::Architecture").c_str());
-   
-   // Strip the cdrom base path
-   Path = string(Path,CD.length());
-   if (Path.empty() == true)
-      Path = "/";
-   
-   // Too short to be a dists/ type
-   if (Path.length() < strlen("dists/"))
-      return;
-   
-   // Not a dists type.
-   if (stringcmp(Path.begin(),Path.begin()+strlen("dists/"),"dists/") != 0)
-      return;
-
-   // Isolate the dist
-   string::size_type Slash = strlen("dists/");
-   string::size_type Slash2 = Path.find('/',Slash + 1);
-   if (Slash2 == string::npos || Slash2 + 2 >= Path.length())
-      return;
-   string Dist = string(Path,Slash,Slash2 - Slash);
-   
-   // Isolate the component
-   Slash = Path.find('/',Slash2+1);
-   if (Slash == string::npos || Slash + 2 >= Path.length())
-      return;
-   string Comp = string(Path,Slash2+1,Slash - Slash2-1);
-   
-   // Verify the trailing binar - bit
-   Slash2 = Path.find('/',Slash + 1);
-   if (Slash == string::npos)
-      return;
-   string Binary = string(Path,Slash+1,Slash2 - Slash-1);
-   
-   if (Binary != S)
-      return;
-   
-   Path = Dist + ' ' + Comp;
-}
-									/*}}}*/
-// GrabFirst - Return the first Depth path components			/*{{{*/
-// ---------------------------------------------------------------------
-/* */
-bool GrabFirst(string Path,string &To,unsigned int Depth)
-{
-   string::size_type I = 0;
-   do
-   {
-      I = Path.find('/',I+1);
-      Depth--;
-   }
-   while (I != string::npos && Depth != 0);
-   
-   if (I == string::npos)
-      return false;
-
-   To = string(Path,0,I+1);
-   return true;
-}
-									/*}}}*/
-// ChopDirs - Chop off the leading directory components			/*{{{*/
-// ---------------------------------------------------------------------
-/* */
-string ChopDirs(string Path,unsigned int Depth)
-{
-   string::size_type I = 0;
-   do
-   {
-      I = Path.find('/',I+1);
-      Depth--;
-   }
-   while (I != string::npos && Depth != 0);
-   
-   if (I == string::npos)
-      return string();
-   
-   return string(Path,I+1);
-}
-									/*}}}*/
-// ReconstructPrefix - Fix strange prefixing				/*{{{*/
-// ---------------------------------------------------------------------
-/* This prepends dir components from the path to the package files to
-   the path to the deb until it is found */
-bool ReconstructPrefix(string &Prefix,string OrigPath,string CD,
-		       string File)
-{
-   bool Debug = _config->FindB("Debug::aptcdrom",false);
-   unsigned int Depth = 1;
-   string MyPrefix = Prefix;
-   while (1)
-   {
-      struct stat Buf;
-      if (stat(string(CD + MyPrefix + File).c_str(),&Buf) != 0)
-      {
-	 if (Debug == true)
-	    cout << "Failed, " << CD + MyPrefix + File << endl;
-	 if (GrabFirst(OrigPath,MyPrefix,Depth++) == true)
-	    continue;
-	 
-	 return false;
-      }
-      else
-      {
-	 Prefix = MyPrefix;
-	 return true;
-      }      
-   }
-   return false;
-}
-									/*}}}*/
-// ReconstructChop - Fixes bad source paths				/*{{{*/
-// ---------------------------------------------------------------------
-/* This removes path components from the filename and prepends the location
-   of the package files until a file is found */
-bool ReconstructChop(unsigned long &Chop,string Dir,string File)
-{
-   // Attempt to reconstruct the filename
-   unsigned long Depth = 0;
-   while (1)
-   {
-      struct stat Buf;
-      if (stat(string(Dir + File).c_str(),&Buf) != 0)
-      {
-	 File = ChopDirs(File,1);
-	 Depth++;
-	 if (File.empty() == false)
-	    continue;
-	 return false;
-      }
-      else
-      {
-	 Chop = Depth;
-	 return true;
-      }
-   }
-   return false;
-}
-									/*}}}*/
-
-// CopyPackages - Copy the package files from the CD			/*{{{*/
-// ---------------------------------------------------------------------
-/* */
-bool CopyPackages(string CDROM,string Name,vector<string> &List)
-{
-   OpTextProgress Progress;
-   
-   bool NoStat = _config->FindB("APT::CDROM::Fast",false);
-   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++)
-   {
-      struct stat Buf;
-      if (stat(string(*I + "Packages").c_str(),&Buf) != 0)
-	 return _error->Errno("stat","Stat failed for %s",
-			      string(*I + "Packages").c_str());
-      TotalSize += Buf.st_size;
-   }	
-
-   unsigned long 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++)
-   {      
-      string OrigPath = string(*I,CDROM.length());
-      
-      // Open the package file
-      FileFd Pkg(*I + "Packages",FileFd::ReadOnly);
-      pkgTagFile Parser(Pkg);
-      if (_error->PendingError() == true)
-	 return false;
-      
-      // Open the output file
-      char S[400];
-      sprintf(S,"cdrom:%s/%sPackages",Name.c_str(),(*I).c_str() + CDROM.length());
-      string TargetF = _config->FindDir("Dir::State::lists") + "partial/";
-      TargetF += URItoFileName(S);
-      if (_config->FindB("APT::CDROM::NoAct",false) == true)
-	 TargetF = "/dev/null";
-      FileFd Target(TargetF,FileFd::WriteEmpty);      
-      if (_error->PendingError() == true)
-	 return false;
-      
-      // Setup the progress meter
-      Progress.OverallProgress(CurrentSize,TotalSize,Pkg.Size(),
-			       "Reading Package Lists");
-
-      // Parse
-      Progress.SubProgress(Pkg.Size());
-      pkgTagSection Section;
-      string Prefix;
-      unsigned long Hits = 0;
-      unsigned long Chop = 0;
-      while (Parser.Step(Section) == true)
-      {
-	 Progress.Progress(Parser.Offset());
-	 
-	 string File = Section.FindS("Filename");
-	 unsigned long Size = Section.FindI("Size");
-	 if (File.empty() || Size == 0)
-	    return _error->Error("Cannot find filename or size tag");
-	 
-	 if (Chop != 0)
-	    File = OrigPath + ChopDirs(File,Chop);
-	 
-	 // See if the file exists
-	 bool Mangled = false;
-	 if (NoStat == false || Hits < 10)
-	 {
-	    // Attempt to fix broken structure
-	    if (Hits == 0)
-	    {
-	       if (ReconstructPrefix(Prefix,OrigPath,CDROM,File) == false &&
-		   ReconstructChop(Chop,*I,File) == false)
-	       {
-		  if (Debug == true)
-		     clog << "Missed: " << File << endl;
-		  NotFound++;
-		  continue;
-	       }
-	       if (Chop != 0)
-		  File = OrigPath + ChopDirs(File,Chop);
-	    }
-	    
-	    // Get the size
-	    struct stat Buf;
-	    if (stat(string(CDROM + Prefix + File).c_str(),&Buf) != 0 || 
-		Buf.st_size == 0)
-	    {
-	       // Attempt to fix busted symlink support for one instance
-	       string OrigFile = File;
-	       string::size_type Start = File.find("binary-");
-	       string::size_type End = File.find("/",Start+3);
-	       if (Start != string::npos && End != string::npos)
-	       {
-		  File.replace(Start,End-Start,"binary-all");
-		  Mangled = true;
-	       }
-	       
-	       if (Mangled == false ||
-		   stat(string(CDROM + Prefix + File).c_str(),&Buf) != 0)
-	       {
-		  if (Debug == true)
-		     clog << "Missed(2): " << OrigFile << endl;
-		  NotFound++;
-		  continue;
-	       }	       
-	    }	    
-	    			    	    
-	    // Size match
-	    if ((unsigned)Buf.st_size != Size)
-	    {
-	       if (Debug == true)
-		  clog << "Wrong Size: " << File << endl;
-	       WrongSize++;
-	       continue;
-	    }
-	 }
-	 
-	 Packages++;
-	 Hits++;
-	 
-	 // Copy it to the target package file
-	 const char *Start;
-	 const char *Stop;
-	 if (Chop != 0 || Mangled == true)
-	 {
-	    // Mangle the output filename
-	    const char *Filename;
-	    Section.Find("Filename",Filename,Stop);
-	    
-	    /* We need to rewrite the filename field so we emit
-	       all fields except the filename file and rewrite that one */
-	    for (unsigned int I = 0; I != Section.Count(); I++)
-	    {
-	       Section.Get(Start,Stop,I);
-	       if (Start <= Filename && Stop > Filename)
-	       {
-		  char S[500];
-		  sprintf(S,"Filename: %s\n",File.c_str());
-		  if (I + 1 == Section.Count())
-		     strcat(S,"\n");
-		  if (Target.Write(S,strlen(S)) == false)
-		     return false;
-	       }
-	       else
-	       {
-		  if (Target.Write(Start,Stop-Start) == false)
-		     return false;
-		  if (Stop[-1] != '\n')
-		     if (Target.Write("\n",1) == false)
-			return false;
-	       }	       
-	    }
-	    if (Target.Write("\n",1) == false)
-	       return false;
-	 }
-	 else
-	 {
-	    Section.GetSection(Start,Stop);
-	    if (Target.Write(Start,Stop-Start) == false)
-	       return false;
-	 }	 
-      }
-
-      if (Debug == true)
-	 cout << " Processed by using Prefix '" << Prefix << "' and chop " << Chop << endl;
-	 
-      if (_config->FindB("APT::CDROM::NoAct",false) == false)
-      {
-	 // Move out of the partial directory
-	 Target.Close();
-	 string FinalF = _config->FindDir("Dir::State::lists");
-	 FinalF += URItoFileName(S);
-	 if (rename(TargetF.c_str(),FinalF.c_str()) != 0)
-	    return _error->Errno("rename","Failed to rename");
-
-	 // Copy the release file
-	 sprintf(S,"cdrom:%s/%sRelease",Name.c_str(),(*I).c_str() + CDROM.length());
-	 string TargetF = _config->FindDir("Dir::State::lists") + "partial/";
-	 TargetF += URItoFileName(S);
-	 if (FileExists(*I + "Release") == true)
-	 {
-	    FileFd Target(TargetF,FileFd::WriteEmpty);
-	    FileFd Rel(*I + "Release",FileFd::ReadOnly);
-	    if (_error->PendingError() == true)
-	       return false;
-	    
-	    if (CopyFile(Rel,Target) == false)
-	       return false;
-	 }
-	 else
-	 {
-	    // Empty release file
-	    FileFd Target(TargetF,FileFd::WriteEmpty);	    
-	 }	 
-
-	 // Rename the release file
-	 FinalF = _config->FindDir("Dir::State::lists");
-	 FinalF += URItoFileName(S);
-	 if (rename(TargetF.c_str(),FinalF.c_str()) != 0)
-	    return _error->Errno("rename","Failed to rename");
-      }
-      
-      /* Mangle the source to be in the proper notation with
-       	 prefix dist [component] */ 
-      *I = string(*I,Prefix.length());
-      ConvertToSourceList(CDROM,*I);
-      *I = Prefix + ' ' + *I;
-      
-      CurrentSize += Pkg.Size();
-   }   
-   Progress.Done();
-   
-   // Some stats
-   cout << "Wrote " << Packages << " package records" ;
-   if (NotFound != 0)
-      cout << " with " << NotFound << " missing files";
-   if (NotFound != 0 && WrongSize != 0)
-      cout << " and"; 
-   if (WrongSize != 0)
-      cout << " with " << WrongSize << " mismatched files";
-   cout << '.' << endl;
-   
-   if (Packages == 0)
-      return _error->Error("No valid package records were found.");
-   
-   if (NotFound + WrongSize > 10)
-      cout << "Alot of package entries were discarded, perhaps this CD is funny?" << endl;
-
-   return true;
-}
-									/*}}}*/
 
 
 // ReduceSourceList - Takes the path list and reduces it		/*{{{*/
 // ReduceSourceList - Takes the path list and reduces it		/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
@@ -724,8 +345,11 @@ bool WriteDatabase(Configuration &Cnf)
    appends the new CDROM entires just after the first block of comments.
    appends the new CDROM entires just after the first block of comments.
    This places them first in the file. It also removes any old entries
    This places them first in the file. It also removes any old entries
    that were the same. */
    that were the same. */
-bool WriteSourceList(string Name,vector<string> &List)
+bool WriteSourceList(string Name,vector<string> &List,bool Source)
 {
 {
+   if (List.size() == 0)
+      return true;
+
    string File = _config->FindFile("Dir::Etc::sourcelist");
    string File = _config->FindFile("Dir::Etc::sourcelist");
 
 
    // Open the stream for reading
    // Open the stream for reading
@@ -742,6 +366,12 @@ bool WriteSourceList(string Name,vector<string> &List)
 
 
    // Create a short uri without the path
    // Create a short uri without the path
    string ShortURI = "cdrom:" + Name + "/";   
    string ShortURI = "cdrom:" + Name + "/";   
+
+   const char *Type;
+   if (Source == true)
+      Type = "deb-src";
+   else
+      Type = "deb";
    
    
    char Buffer[300];
    char Buffer[300];
    int CurLine = 0;
    int CurLine = 0;
@@ -767,18 +397,17 @@ bool WriteSourceList(string Name,vector<string> &List)
 	    string::size_type Space = (*I).find(' ');
 	    string::size_type Space = (*I).find(' ');
 	    if (Space == string::npos)
 	    if (Space == string::npos)
 	       return _error->Error("Internal error");
 	       return _error->Error("Internal error");
-	    
-	    Out << "deb \"cdrom:" << Name << "/" << string(*I,0,Space) << 
+	    Out << Type << " \"cdrom:" << Name << "/" << string(*I,0,Space) << 
 	       "\" " << string(*I,Space+1) << endl;
 	       "\" " << string(*I,Space+1) << endl;
 	 }
 	 }
       }
       }
       First = false;
       First = false;
       
       
       // Grok it
       // Grok it
-      string Type;
+      string cType;
       string URI;
       string URI;
       char *C = Buffer;
       char *C = Buffer;
-      if (ParseQuoteWord(C,Type) == false ||
+      if (ParseQuoteWord(C,cType) == false ||
 	  ParseQuoteWord(C,URI) == false)
 	  ParseQuoteWord(C,URI) == false)
       {
       {
 	 Out << Buffer << endl;
 	 Out << Buffer << endl;
@@ -786,7 +415,7 @@ bool WriteSourceList(string Name,vector<string> &List)
       }
       }
 
 
       // Emit lines like this one
       // Emit lines like this one
-      if (Type != "deb" || string(URI,0,ShortURI.length()) != ShortURI)
+      if (cType != Type || string(URI,0,ShortURI.length()) != ShortURI)
       {
       {
 	 Out << Buffer << endl;
 	 Out << Buffer << endl;
 	 continue;
 	 continue;
@@ -973,7 +602,10 @@ bool DoAdd(CommandLine &)
    cout << "This Disc is called '" << Name << "'" << endl;
    cout << "This Disc is called '" << Name << "'" << endl;
    
    
    // Copy the package files to the state directory
    // Copy the package files to the state directory
-   if (CopyPackages(CDROM,Name,List) == false)
+   PackageCopy Copy;
+   SourceCopy SrcCopy;
+   if (Copy.CopyPackages(CDROM,Name,List) == false ||
+       SrcCopy.CopyPackages(CDROM,Name,sList) == false)
       return false;
       return false;
    
    
    ReduceSourcelist(CDROM,List);
    ReduceSourcelist(CDROM,List);
@@ -986,7 +618,8 @@ bool DoAdd(CommandLine &)
 	 return false;
 	 return false;
       
       
       cout << "Writing new source list" << endl;
       cout << "Writing new source list" << endl;
-      if (WriteSourceList(Name,List) == false)
+      if (WriteSourceList(Name,List,false) == false ||
+	  WriteSourceList(Name,sList,true) == false)
 	 return false;
 	 return false;
    }
    }
 
 

+ 535 - 0
cmdline/indexcopy.cc

@@ -0,0 +1,535 @@
+// -*- mode: cpp; mode: fold -*-
+// Description								/*{{{*/
+// $Id: indexcopy.cc,v 1.1 1999/07/12 02:59:36 jgg Exp $
+/* ######################################################################
+
+   Index Copying - Aid for copying and verifying the index files
+   
+   This class helps apt-cache reconstruct a damaged index files. 
+   
+   ##################################################################### */
+									/*}}}*/
+// Include Files							/*{{{*/
+#include "indexcopy.h"
+
+#include <apt-pkg/error.h>
+#include <apt-pkg/progress.h>
+#include <apt-pkg/strutl.h>
+#include <apt-pkg/fileutl.h>
+#include <apt-pkg/configuration.h>
+#include <apt-pkg/tagfile.h>
+
+#include <iostream.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <wait.h>
+									/*}}}*/
+
+// IndexCopy::CopyPackages - Copy the package files from the CD		/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool IndexCopy::CopyPackages(string CDROM,string Name,vector<string> &List)
+{
+   if (List.size() == 0)
+      return true;
+   
+   OpTextProgress Progress;
+   
+   bool NoStat = _config->FindB("APT::CDROM::Fast",false);
+   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++)
+   {
+      struct stat Buf;
+      if (stat(string(*I + GetFileName()).c_str(),&Buf) != 0 &&
+	  stat(string(*I + GetFileName() + ".gz").c_str(),&Buf) != 0)
+	 return _error->Errno("stat","Stat failed for %s",
+			      string(*I + GetFileName()).c_str());
+      TotalSize += Buf.st_size;
+   }	
+
+   unsigned long 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++)
+   {      
+      string OrigPath = string(*I,CDROM.length());
+      unsigned long FileSize = 0;
+      
+      // Open the package file
+      FileFd Pkg;
+      if (FileExists(*I + GetFileName()) == true)
+      {
+	 Pkg.Open(*I + GetFileName(),FileFd::ReadOnly);
+	 FileSize = Pkg.Size();
+      }      
+      else
+      {
+	 FileFd From(*I + GetFileName() + ".gz",FileFd::ReadOnly);
+	 if (_error->PendingError() == true)
+	    return false;
+	 FileSize = From.Size();
+	 
+	 // Get a temp file
+	 FILE *tmp = tmpfile();
+	 if (tmp == 0)
+	    return _error->Errno("tmpfile","Unable to create a tmp file");
+	 Pkg.Fd(dup(fileno(tmp)));
+	 fclose(tmp);
+	 
+	 // Fork gzip
+	 int Process = fork();
+	 if (Process < 0)
+	    return _error->Errno("fork","Couldn't fork gzip");
+	 
+	 // The child
+	 if (Process == 0)
+	 {	    
+	    dup2(From.Fd(),STDIN_FILENO);
+	    dup2(Pkg.Fd(),STDOUT_FILENO);
+	    SetCloseExec(STDIN_FILENO,false);
+	    SetCloseExec(STDOUT_FILENO,false);
+	    
+	    const char *Args[3];
+	    Args[0] = _config->Find("Dir::bin::gzip","gzip").c_str();
+	    Args[1] = "-d";
+	    Args[2] = 0;
+	    execvp(Args[0],(char **)Args);
+	    exit(100);
+	 }
+	 
+	 // Wait for gzip to finish
+	 int Status;
+	 if (waitpid(Process,&Status,0) != Process)
+	    return _error->Errno("wait","Waiting for gzip failed");
+	 if (WIFEXITED(Status) == 0 || WEXITSTATUS(Status) != 0)
+	    return _error->Error("gzip failed, perhaps the disk is full.");
+	 Pkg.Seek(0);
+      }
+      pkgTagFile Parser(Pkg);
+      if (_error->PendingError() == true)
+	 return false;
+      
+      // Open the output file
+      char S[400];
+      sprintf(S,"cdrom:%s/%s%s",Name.c_str(),(*I).c_str() + CDROM.length(),
+	      GetFileName());
+      string TargetF = _config->FindDir("Dir::State::lists") + "partial/";
+      TargetF += URItoFileName(S);
+      if (_config->FindB("APT::CDROM::NoAct",false) == true)
+	 TargetF = "/dev/null";
+      FileFd Target(TargetF,FileFd::WriteEmpty);      
+      if (_error->PendingError() == true)
+	 return false;
+      
+      // Setup the progress meter
+      Progress.OverallProgress(CurrentSize,TotalSize,FileSize,
+			       string("Reading ") + Type() + " Indexes");
+
+      // Parse
+      Progress.SubProgress(Pkg.Size());
+      pkgTagSection Section;
+      this->Section = &Section;
+      string Prefix;
+      unsigned long Hits = 0;
+      unsigned long Chop = 0;
+      while (Parser.Step(Section) == true)
+      {
+	 Progress.Progress(Parser.Offset());
+	 string File;
+	 unsigned long Size;
+	 if (GetFile(File,Size) == false)
+	    return false;
+	 
+	 if (Chop != 0)
+	    File = OrigPath + ChopDirs(File,Chop);
+	 
+	 // See if the file exists
+	 bool Mangled = false;
+	 if (NoStat == false || Hits < 10)
+	 {
+	    // Attempt to fix broken structure
+	    if (Hits == 0)
+	    {
+	       if (ReconstructPrefix(Prefix,OrigPath,CDROM,File) == false &&
+		   ReconstructChop(Chop,*I,File) == false)
+	       {
+		  if (Debug == true)
+		     clog << "Missed: " << File << endl;
+		  NotFound++;
+		  continue;
+	       }
+	       if (Chop != 0)
+		  File = OrigPath + ChopDirs(File,Chop);
+	    }
+	    
+	    // Get the size
+	    struct stat Buf;
+	    if (stat(string(CDROM + Prefix + File).c_str(),&Buf) != 0 || 
+		Buf.st_size == 0)
+	    {
+	       // Attempt to fix busted symlink support for one instance
+	       string OrigFile = File;
+	       string::size_type Start = File.find("binary-");
+	       string::size_type End = File.find("/",Start+3);
+	       if (Start != string::npos && End != string::npos)
+	       {
+		  File.replace(Start,End-Start,"binary-all");
+		  Mangled = true;
+	       }
+	       
+	       if (Mangled == false ||
+		   stat(string(CDROM + Prefix + File).c_str(),&Buf) != 0)
+	       {
+		  if (Debug == true)
+		     clog << "Missed(2): " << OrigFile << endl;
+		  NotFound++;
+		  continue;
+	       }	       
+	    }	    
+	    			    	    
+	    // Size match
+	    if ((unsigned)Buf.st_size != Size)
+	    {
+	       if (Debug == true)
+		  clog << "Wrong Size: " << File << endl;
+	       WrongSize++;
+	       continue;
+	    }
+	 }
+	 
+	 Packages++;
+	 Hits++;
+	 
+	 // Copy it to the target package file
+	 if (Chop != 0 || Mangled == true)
+	 {
+	    if (RewriteEntry(Target,File) == false)
+	       continue;
+	 }
+	 else
+	 {
+	    const char *Start;
+	    const char *Stop;
+	    Section.GetSection(Start,Stop);
+	    if (Target.Write(Start,Stop-Start) == false)
+	       return false;
+	 }	 
+      }
+
+      if (Debug == true)
+	 cout << " Processed by using Prefix '" << Prefix << "' and chop " << Chop << endl;
+	 
+      if (_config->FindB("APT::CDROM::NoAct",false) == false)
+      {
+	 // Move out of the partial directory
+	 Target.Close();
+	 string FinalF = _config->FindDir("Dir::State::lists");
+	 FinalF += URItoFileName(S);
+	 if (rename(TargetF.c_str(),FinalF.c_str()) != 0)
+	    return _error->Errno("rename","Failed to rename");
+
+	 // Copy the release file
+	 sprintf(S,"cdrom:%s/%sRelease",Name.c_str(),(*I).c_str() + CDROM.length());
+	 string TargetF = _config->FindDir("Dir::State::lists") + "partial/";
+	 TargetF += URItoFileName(S);
+	 if (FileExists(*I + "Release") == true)
+	 {
+	    FileFd Target(TargetF,FileFd::WriteEmpty);
+	    FileFd Rel(*I + "Release",FileFd::ReadOnly);
+	    if (_error->PendingError() == true)
+	       return false;
+	    
+	    if (CopyFile(Rel,Target) == false)
+	       return false;
+	 }
+	 else
+	 {
+	    // Empty release file
+	    FileFd Target(TargetF,FileFd::WriteEmpty);	    
+	 }	 
+
+	 // Rename the release file
+	 FinalF = _config->FindDir("Dir::State::lists");
+	 FinalF += URItoFileName(S);
+	 if (rename(TargetF.c_str(),FinalF.c_str()) != 0)
+	    return _error->Errno("rename","Failed to rename");
+      }
+      
+      /* Mangle the source to be in the proper notation with
+       	 prefix dist [component] */ 
+      *I = string(*I,Prefix.length());
+      ConvertToSourceList(CDROM,*I);
+      *I = Prefix + ' ' + *I;
+      
+      CurrentSize += FileSize;
+   }   
+   Progress.Done();
+   
+   // Some stats
+   cout << "Wrote " << Packages << " records" ;
+   if (NotFound != 0)
+      cout << " with " << NotFound << " missing files";
+   if (NotFound != 0 && WrongSize != 0)
+      cout << " and"; 
+   if (WrongSize != 0)
+      cout << " with " << WrongSize << " mismatched files";
+   cout << '.' << endl;
+   
+   if (Packages == 0)
+      return _error->Error("No valid records were found.");
+   
+   if (NotFound + WrongSize > 10)
+      cout << "Alot of entries were discarded, something may be wrong." << endl;
+
+   return true;
+}
+									/*}}}*/
+// IndexCopy::ChopDirs - Chop off the leading directory components	/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+string IndexCopy::ChopDirs(string Path,unsigned int Depth)
+{
+   string::size_type I = 0;
+   do
+   {
+      I = Path.find('/',I+1);
+      Depth--;
+   }
+   while (I != string::npos && Depth != 0);
+   
+   if (I == string::npos)
+      return string();
+   
+   return string(Path,I+1);
+}
+									/*}}}*/
+// IndexCopy::ReconstructPrefix - Fix strange prefixing			/*{{{*/
+// ---------------------------------------------------------------------
+/* This prepends dir components from the path to the package files to
+   the path to the deb until it is found */
+bool IndexCopy::ReconstructPrefix(string &Prefix,string OrigPath,string CD,
+				  string File)
+{
+   bool Debug = _config->FindB("Debug::aptcdrom",false);
+   unsigned int Depth = 1;
+   string MyPrefix = Prefix;
+   while (1)
+   {
+      struct stat Buf;
+      if (stat(string(CD + MyPrefix + File).c_str(),&Buf) != 0)
+      {
+	 if (Debug == true)
+	    cout << "Failed, " << CD + MyPrefix + File << endl;
+	 if (GrabFirst(OrigPath,MyPrefix,Depth++) == true)
+	    continue;
+	 
+	 return false;
+      }
+      else
+      {
+	 Prefix = MyPrefix;
+	 return true;
+      }      
+   }
+   return false;
+}
+									/*}}}*/
+// IndexCopy::ReconstructChop - Fixes bad source paths			/*{{{*/
+// ---------------------------------------------------------------------
+/* This removes path components from the filename and prepends the location
+   of the package files until a file is found */
+bool IndexCopy::ReconstructChop(unsigned long &Chop,string Dir,string File)
+{
+   // Attempt to reconstruct the filename
+   unsigned long Depth = 0;
+   while (1)
+   {
+      struct stat Buf;
+      if (stat(string(Dir + File).c_str(),&Buf) != 0)
+      {
+	 File = ChopDirs(File,1);
+	 Depth++;
+	 if (File.empty() == false)
+	    continue;
+	 return false;
+      }
+      else
+      {
+	 Chop = Depth;
+	 return true;
+      }
+   }
+   return false;
+}
+									/*}}}*/
+// IndexCopy::ConvertToSourceList - Convert a Path to a sourcelist 	/*{{{*/
+// ---------------------------------------------------------------------
+/* We look for things in dists/ notation and convert them to 
+   <dist> <component> form otherwise it is left alone. This also strips
+   the CD path. */
+void IndexCopy::ConvertToSourceList(string CD,string &Path)
+{
+   char S[300];
+   sprintf(S,"binary-%s",_config->Find("Apt::Architecture").c_str());
+   
+   // Strip the cdrom base path
+   Path = string(Path,CD.length());
+   if (Path.empty() == true)
+      Path = "/";
+   
+   // Too short to be a dists/ type
+   if (Path.length() < strlen("dists/"))
+      return;
+   
+   // Not a dists type.
+   if (stringcmp(Path.begin(),Path.begin()+strlen("dists/"),"dists/") != 0)
+      return;
+
+   // Isolate the dist
+   string::size_type Slash = strlen("dists/");
+   string::size_type Slash2 = Path.find('/',Slash + 1);
+   if (Slash2 == string::npos || Slash2 + 2 >= Path.length())
+      return;
+   string Dist = string(Path,Slash,Slash2 - Slash);
+   
+   // Isolate the component
+   Slash = Path.find('/',Slash2+1);
+   if (Slash == string::npos || Slash + 2 >= Path.length())
+      return;
+   string Comp = string(Path,Slash2+1,Slash - Slash2-1);
+   
+   // Verify the trailing binar - bit
+   Slash2 = Path.find('/',Slash + 1);
+   if (Slash == string::npos)
+      return;
+   string Binary = string(Path,Slash+1,Slash2 - Slash-1);
+   
+   if (Binary != S && Binary != "source")
+      return;
+   
+   Path = Dist + ' ' + Comp;
+}
+									/*}}}*/
+// IndexCopy::GrabFirst - Return the first Depth path components	/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool IndexCopy::GrabFirst(string Path,string &To,unsigned int Depth)
+{
+   string::size_type I = 0;
+   do
+   {
+      I = Path.find('/',I+1);
+      Depth--;
+   }
+   while (I != string::npos && Depth != 0);
+   
+   if (I == string::npos)
+      return false;
+
+   To = string(Path,0,I+1);
+   return true;
+}
+									/*}}}*/
+// IndexCopy::CopyWithReplace - Copy a section and replace text		/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool IndexCopy::CopyWithReplace(FileFd &Target,const char *Tag,string New)
+{
+   // Mangle the output filename
+   const char *Start;
+   const char *Stop;
+   const char *Filename;
+   Section->Find(Tag,Filename,Stop);
+   
+   /* We need to rewrite the filename field so we emit
+      all fields except the filename file and rewrite that one */
+   for (unsigned int I = 0; I != Section->Count(); I++)
+   {
+      Section->Get(Start,Stop,I);
+      if (Start <= Filename && Stop > Filename)
+      {
+	 char S[500];
+	 sprintf(S,"%s: %s\n",Tag,New.c_str());
+	 if (I + 1 == Section->Count())
+	    strcat(S,"\n");
+	 if (Target.Write(S,strlen(S)) == false)
+	    return false;
+      }
+      else
+      {
+	 if (Target.Write(Start,Stop-Start) == false)
+	    return false;
+	 if (Stop[-1] != '\n')
+	    if (Target.Write("\n",1) == false)
+	       return false;
+      }	       
+   }
+   if (Target.Write("\n",1) == false)
+      return false;
+}
+									/*}}}*/
+// PackageCopy::GetFile - Get the file information from the section	/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool PackageCopy::GetFile(string &File,unsigned long &Size)
+{
+   File = Section->FindS("Filename");
+   Size = Section->FindI("Size");
+   if (File.empty() || Size == 0)
+      return _error->Error("Cannot find filename or size tag");
+   return true;
+}
+									/*}}}*/
+// PackageCopy::RewriteEntry - Rewrite the entry with a new filename	/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool PackageCopy::RewriteEntry(FileFd &Target,string File)
+{
+   return CopyWithReplace(Target,"Filename",File);
+}
+									/*}}}*/
+// SourceCopy::GetFile - Get the file information from the section	/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool SourceCopy::GetFile(string &File,unsigned long &Size)
+{
+   string Files = Section->FindS("Files");
+   if (Files.empty() == true)
+      return false;
+
+   // Stash the / terminated directory prefix
+   string Base = Section->FindS("Directory");
+   if (Base.empty() == false && Base[Base.length()-1] != '/')
+      Base += '/';
+   
+   // Iterate over the entire list grabbing each triplet
+   const char *C = Files.c_str();
+   string sSize;
+   string MD5Hash;
+   
+   // Parse each of the elements
+   if (ParseQuoteWord(C,MD5Hash) == false ||
+       ParseQuoteWord(C,sSize) == false ||
+       ParseQuoteWord(C,File) == false)
+      return _error->Error("Error parsing file record");
+   
+   // Parse the size and append the directory
+   Size = atoi(sSize.c_str());
+   File = Base + File;
+   return true;
+}
+									/*}}}*/
+// SourceCopy::RewriteEntry - Rewrite the entry with a new filename	/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool SourceCopy::RewriteEntry(FileFd &Target,string File)
+{
+   return CopyWithReplace(Target,"Directory",
+			  string(File,0,File.rfind('/')));
+}
+									/*}}}*/

+ 65 - 0
cmdline/indexcopy.h

@@ -0,0 +1,65 @@
+// -*- mode: cpp; mode: fold -*-
+// Description								/*{{{*/
+// $Id: indexcopy.h,v 1.1 1999/07/12 02:59:36 jgg Exp $
+/* ######################################################################
+
+   Index Copying - Aid for copying and verifying the index files
+   
+   ##################################################################### */
+									/*}}}*/
+#ifndef INDEXCOPY_H
+#define INDEXCOPY_H
+
+#include <vector>
+#include <string>
+
+class pkgTagSection;
+class FileFd;
+
+class IndexCopy
+{
+   protected:
+   
+   pkgTagSection *Section;
+   
+   string ChopDirs(string Path,unsigned int Depth);
+   bool ReconstructPrefix(string &Prefix,string OrigPath,string CD,
+			  string File);
+   bool ReconstructChop(unsigned long &Chop,string Dir,string File);
+   void ConvertToSourceList(string CD,string &Path);
+   bool GrabFirst(string Path,string &To,unsigned int Depth);
+   bool CopyWithReplace(FileFd &Target,const char *Tag,string New);
+   virtual bool GetFile(string &Filename,unsigned long &Size) = 0;
+   virtual bool RewriteEntry(FileFd &Target,string File) = 0;
+   virtual const char *GetFileName() = 0;
+   virtual const char *Type() = 0;
+   public:
+
+   bool CopyPackages(string CDROM,string Name,vector<string> &List);
+};
+
+class PackageCopy : public IndexCopy
+{
+   protected:
+   
+   virtual bool GetFile(string &Filename,unsigned long &Size);
+   virtual bool RewriteEntry(FileFd &Target,string File);
+   virtual const char *GetFileName() {return "Packages";};
+   virtual const char *Type() {return "Package";};
+   
+   public:
+};
+
+class SourceCopy : public IndexCopy
+{
+   protected:
+   
+   virtual bool GetFile(string &Filename,unsigned long &Size);
+   virtual bool RewriteEntry(FileFd &Target,string File);
+   virtual const char *GetFileName() {return "Sources";};
+   virtual const char *Type() {return "Source";};
+   
+   public:
+};
+
+#endif

+ 1 - 1
cmdline/makefile

@@ -30,5 +30,5 @@ include $(PROGRAM_H)
 PROGRAM=apt-cdrom
 PROGRAM=apt-cdrom
 SLIBS = -lapt-pkg
 SLIBS = -lapt-pkg
 LIB_MAKES = apt-pkg/makefile
 LIB_MAKES = apt-pkg/makefile
-SOURCE = apt-cdrom.cc
+SOURCE = apt-cdrom.cc indexcopy.cc
 include $(PROGRAM_H)
 include $(PROGRAM_H)