]>
git.saurik.com Git - apt.git/blob - apt-pkg/indexcopy.cc
   1 // -*- mode: cpp; mode: fold -*- 
   3 // $Id: indexcopy.cc,v 1.10 2002/03/26 07:38:58 jgg Exp $ 
   4 /* ###################################################################### 
   6    Index Copying - Aid for copying and verifying the index files 
   8    This class helps apt-cache reconstruct a damaged index files.  
  10    ##################################################################### */ 
  12 // Include Files                                                        /*{{{*/ 
  13 #include "indexcopy.h" 
  15 #include <apt-pkg/error.h> 
  16 #include <apt-pkg/progress.h> 
  17 #include <apt-pkg/strutl.h> 
  18 #include <apt-pkg/fileutl.h> 
  19 #include <apt-pkg/configuration.h> 
  20 #include <apt-pkg/tagfile.h> 
  21 #include <apt-pkg/indexrecords.h> 
  22 #include <apt-pkg/md5.h> 
  23 #include <apt-pkg/cdrom.h> 
  30 #include <sys/types.h> 
  39 // IndexCopy::CopyPackages - Copy the package files from the CD         /*{{{*/ 
  40 // --------------------------------------------------------------------- 
  42 bool IndexCopy::CopyPackages(string CDROM
,string Name
,vector
<string
> &List
, 
  45    OpProgress 
*Progress 
= NULL
; 
  50       Progress 
= log
->GetOpProgress(); 
  52    bool NoStat 
= _config
->FindB("APT::CDROM::Fast",false); 
  53    bool Debug 
= _config
->FindB("Debug::aptcdrom",false); 
  55    // Prepare the progress indicator 
  56    unsigned long TotalSize 
= 0; 
  57    for (vector
<string
>::iterator I 
= List
.begin(); I 
!= List
.end(); I
++) 
  60       if (stat(string(*I 
+ GetFileName()).c_str(),&Buf
) != 0 && 
  61           stat(string(*I 
+ GetFileName() + ".gz").c_str(),&Buf
) != 0) 
  62          return _error
->Errno("stat","Stat failed for %s", 
  63                               string(*I 
+ GetFileName()).c_str()); 
  64       TotalSize 
+= Buf
.st_size
; 
  67    unsigned long CurrentSize 
= 0; 
  68    unsigned int NotFound 
= 0; 
  69    unsigned int WrongSize 
= 0; 
  70    unsigned int Packages 
= 0; 
  71    for (vector
<string
>::iterator I 
= List
.begin(); I 
!= List
.end(); I
++) 
  73       string OrigPath 
= string(*I
,CDROM
.length()); 
  74       unsigned long FileSize 
= 0; 
  76       // Open the package file 
  78       if (RealFileExists(*I 
+ GetFileName()) == true) 
  80          Pkg
.Open(*I 
+ GetFileName(),FileFd::ReadOnly
); 
  81          FileSize 
= Pkg
.Size(); 
  85          FileFd 
From(*I 
+ GetFileName() + ".gz",FileFd::ReadOnly
); 
  86          if (_error
->PendingError() == true) 
  88          FileSize 
= From
.Size(); 
  91          FILE *tmp 
= tmpfile(); 
  93             return _error
->Errno("tmpfile","Unable to create a tmp file"); 
  94          Pkg
.Fd(dup(fileno(tmp
))); 
  98          pid_t Process 
= fork(); 
 100             return _error
->Errno("fork","Couldn't fork gzip"); 
 105             dup2(From
.Fd(),STDIN_FILENO
); 
 106             dup2(Pkg
.Fd(),STDOUT_FILENO
); 
 107             SetCloseExec(STDIN_FILENO
,false); 
 108             SetCloseExec(STDOUT_FILENO
,false); 
 111             string Tmp 
=  _config
->Find("Dir::bin::gzip","gzip"); 
 112             Args
[0] = Tmp
.c_str(); 
 115             execvp(Args
[0],(char **)Args
); 
 119          // Wait for gzip to finish 
 120          if (ExecWait(Process
,_config
->Find("Dir::bin::gzip","gzip").c_str(),false) == false) 
 121             return _error
->Error("gzip failed, perhaps the disk is full."); 
 125       pkgTagFile 
Parser(&Pkg
); 
 126       if (_error
->PendingError() == true) 
 129       // Open the output file 
 131       snprintf(S
,sizeof(S
),"cdrom:[%s]/%s%s",Name
.c_str(), 
 132                (*I
).c_str() + CDROM
.length(),GetFileName()); 
 133       string TargetF 
= _config
->FindDir("Dir::State::lists") + "partial/"; 
 134       TargetF 
+= URItoFileName(S
); 
 136       if (_config
->FindB("APT::CDROM::NoAct",false) == true) 
 138          TargetF 
= "/dev/null"; 
 139          Target
.Open(TargetF
,FileFd::WriteExists
); 
 141          Target
.Open(TargetF
,FileFd::WriteAtomic
); 
 143       FILE *TargetFl 
= fdopen(dup(Target
.Fd()),"w"); 
 144       if (_error
->PendingError() == true) 
 147          return _error
->Errno("fdopen","Failed to reopen fd"); 
 149       // Setup the progress meter 
 151          Progress
->OverallProgress(CurrentSize
,TotalSize
,FileSize
, 
 152                                    string("Reading ") + Type() + " Indexes"); 
 156          Progress
->SubProgress(Pkg
.Size()); 
 157       pkgTagSection Section
; 
 158       this->Section 
= &Section
; 
 160       unsigned long Hits 
= 0; 
 161       unsigned long Chop 
= 0; 
 162       while (Parser
.Step(Section
) == true) 
 165             Progress
->Progress(Parser
.Offset()); 
 168          if (GetFile(File
,Size
) == false) 
 175             File 
= OrigPath 
+ ChopDirs(File
,Chop
); 
 177          // See if the file exists 
 178          bool Mangled 
= false; 
 179          if (NoStat 
== false || Hits 
< 10) 
 181             // Attempt to fix broken structure 
 184                if (ReconstructPrefix(Prefix
,OrigPath
,CDROM
,File
) == false && 
 185                    ReconstructChop(Chop
,*I
,File
) == false) 
 188                      clog 
<< "Missed: " << File 
<< endl
; 
 193                   File 
= OrigPath 
+ ChopDirs(File
,Chop
); 
 198             if (stat(string(CDROM 
+ Prefix 
+ File
).c_str(),&Buf
) != 0 ||  
 201                // Attempt to fix busted symlink support for one instance 
 202                string OrigFile 
= File
; 
 203                string::size_type Start 
= File
.find("binary-"); 
 204                string::size_type End 
= File
.find("/",Start
+3); 
 205                if (Start 
!= string::npos 
&& End 
!= string::npos
) 
 207                   File
.replace(Start
,End
-Start
,"binary-all"); 
 211                if (Mangled 
== false || 
 212                    stat(string(CDROM 
+ Prefix 
+ File
).c_str(),&Buf
) != 0) 
 215                      clog 
<< "Missed(2): " << OrigFile 
<< endl
; 
 222             if ((unsigned)Buf
.st_size 
!= Size
) 
 225                   clog 
<< "Wrong Size: " << File 
<< endl
; 
 234          if (RewriteEntry(TargetFl
,File
) == false) 
 243          cout 
<< " Processed by using Prefix '" << Prefix 
<< "' and chop " << Chop 
<< endl
; 
 245       if (_config
->FindB("APT::CDROM::NoAct",false) == false) 
 247          // Move out of the partial directory 
 249          string FinalF 
= _config
->FindDir("Dir::State::lists"); 
 250          FinalF 
+= URItoFileName(S
); 
 251          if (rename(TargetF
.c_str(),FinalF
.c_str()) != 0) 
 252             return _error
->Errno("rename","Failed to rename"); 
 255       /* Mangle the source to be in the proper notation with 
 256          prefix dist [component] */  
 257       *I 
= string(*I
,Prefix
.length()); 
 258       ConvertToSourceList(CDROM
,*I
); 
 259       *I 
= Prefix 
+ ' ' + *I
; 
 261       CurrentSize 
+= FileSize
; 
 269       if(NotFound 
== 0 && WrongSize 
== 0) 
 270          ioprintf(msg
, _("Wrote %i records.\n"), Packages
); 
 271       else if (NotFound 
!= 0 && WrongSize 
== 0) 
 272          ioprintf(msg
, _("Wrote %i records with %i missing files.\n"),  
 274       else if (NotFound 
== 0 && WrongSize 
!= 0) 
 275          ioprintf(msg
, _("Wrote %i records with %i mismatched files\n"),  
 276                   Packages
, WrongSize
); 
 277       if (NotFound 
!= 0 && WrongSize 
!= 0) 
 278          ioprintf(msg
, _("Wrote %i records with %i missing files and %i mismatched files\n"), Packages
, NotFound
, WrongSize
); 
 282       _error
->Warning("No valid records were found."); 
 284    if (NotFound 
+ WrongSize 
> 10) 
 285       _error
->Warning("A lot of entries were discarded, something may be wrong.\n"); 
 291 // IndexCopy::ChopDirs - Chop off the leading directory components      /*{{{*/ 
 292 // --------------------------------------------------------------------- 
 294 string 
IndexCopy::ChopDirs(string Path
,unsigned int Depth
) 
 296    string::size_type I 
= 0; 
 299       I 
= Path
.find('/',I
+1); 
 302    while (I 
!= string::npos 
&& Depth 
!= 0); 
 304    if (I 
== string::npos
) 
 307    return string(Path
,I
+1); 
 310 // IndexCopy::ReconstructPrefix - Fix strange prefixing                 /*{{{*/ 
 311 // --------------------------------------------------------------------- 
 312 /* This prepends dir components from the path to the package files to 
 313    the path to the deb until it is found */ 
 314 bool IndexCopy::ReconstructPrefix(string 
&Prefix
,string OrigPath
,string CD
, 
 317    bool Debug 
= _config
->FindB("Debug::aptcdrom",false); 
 318    unsigned int Depth 
= 1; 
 319    string MyPrefix 
= Prefix
; 
 323       if (stat(string(CD 
+ MyPrefix 
+ File
).c_str(),&Buf
) != 0) 
 326             cout 
<< "Failed, " << CD 
+ MyPrefix 
+ File 
<< endl
; 
 327          if (GrabFirst(OrigPath
,MyPrefix
,Depth
++) == true) 
 341 // IndexCopy::ReconstructChop - Fixes bad source paths                  /*{{{*/ 
 342 // --------------------------------------------------------------------- 
 343 /* This removes path components from the filename and prepends the location 
 344    of the package files until a file is found */ 
 345 bool IndexCopy::ReconstructChop(unsigned long &Chop
,string Dir
,string File
) 
 347    // Attempt to reconstruct the filename 
 348    unsigned long Depth 
= 0; 
 352       if (stat(string(Dir 
+ File
).c_str(),&Buf
) != 0) 
 354          File 
= ChopDirs(File
,1); 
 356          if (File
.empty() == false) 
 369 // IndexCopy::ConvertToSourceList - Convert a Path to a sourcelist      /*{{{*/ 
 370 // --------------------------------------------------------------------- 
 371 /* We look for things in dists/ notation and convert them to  
 372    <dist> <component> form otherwise it is left alone. This also strips 
 375    This implements a regex sort of like:  
 376     (.*)/dists/([^/]*)/(.*)/binary-*  
 378      |          |-------- Distribution 
 379      |------------------- Path 
 381    It was deciced to use only a single word for dist (rather than say 
 382    unstable/non-us) to increase the chance that each CD gets a single 
 383    line in sources.list. 
 385 void IndexCopy::ConvertToSourceList(string CD
,string 
&Path
) 
 388    snprintf(S
,sizeof(S
),"binary-%s",_config
->Find("Apt::Architecture").c_str()); 
 390    // Strip the cdrom base path 
 391    Path 
= string(Path
,CD
.length()); 
 392    if (Path
.empty() == true) 
 395    // Too short to be a dists/ type 
 396    if (Path
.length() < strlen("dists/")) 
 400    if (stringcmp(Path
.c_str(),Path
.c_str()+strlen("dists/"),"dists/") != 0) 
 404    string::size_type Slash 
= strlen("dists/"); 
 405    string::size_type Slash2 
= Path
.find('/',Slash 
+ 1); 
 406    if (Slash2 
== string::npos 
|| Slash2 
+ 2 >= Path
.length()) 
 408    string Dist 
= string(Path
,Slash
,Slash2 
- Slash
); 
 410    // Isolate the component 
 412    for (unsigned I 
= 0; I 
!= 10; I
++) 
 414       Slash 
= Path
.find('/',Slash
+1); 
 415       if (Slash 
== string::npos 
|| Slash 
+ 2 >= Path
.length()) 
 417       string Comp 
= string(Path
,Slash2
+1,Slash 
- Slash2
-1); 
 419       // Verify the trailing binary- bit 
 420       string::size_type BinSlash 
= Path
.find('/',Slash 
+ 1); 
 421       if (Slash 
== string::npos
) 
 423       string Binary 
= string(Path
,Slash
+1,BinSlash 
- Slash
-1); 
 425       if (Binary 
!= S 
&& Binary 
!= "source") 
 428       Path 
= Dist 
+ ' ' + Comp
; 
 433 // IndexCopy::GrabFirst - Return the first Depth path components        /*{{{*/ 
 434 // --------------------------------------------------------------------- 
 436 bool IndexCopy::GrabFirst(string Path
,string 
&To
,unsigned int Depth
) 
 438    string::size_type I 
= 0; 
 441       I 
= Path
.find('/',I
+1); 
 444    while (I 
!= string::npos 
&& Depth 
!= 0); 
 446    if (I 
== string::npos
) 
 449    To 
= string(Path
,0,I
+1); 
 453 // PackageCopy::GetFile - Get the file information from the section     /*{{{*/ 
 454 // --------------------------------------------------------------------- 
 456 bool PackageCopy::GetFile(string 
&File
,unsigned long &Size
) 
 458    File 
= Section
->FindS("Filename"); 
 459    Size 
= Section
->FindI("Size"); 
 460    if (File
.empty() || Size 
== 0) 
 461       return _error
->Error("Cannot find filename or size tag"); 
 465 // PackageCopy::RewriteEntry - Rewrite the entry with a new filename    /*{{{*/ 
 466 // --------------------------------------------------------------------- 
 468 bool PackageCopy::RewriteEntry(FILE *Target
,string File
) 
 470    TFRewriteData Changes
[] = {{"Filename",File
.c_str()}, 
 473    if (TFRewrite(Target
,*Section
,TFRewritePackageOrder
,Changes
) == false) 
 479 // SourceCopy::GetFile - Get the file information from the section      /*{{{*/ 
 480 // --------------------------------------------------------------------- 
 482 bool SourceCopy::GetFile(string 
&File
,unsigned long &Size
) 
 484    string Files 
= Section
->FindS("Files"); 
 485    if (Files
.empty() == true) 
 488    // Stash the / terminated directory prefix 
 489    string Base 
= Section
->FindS("Directory"); 
 490    if (Base
.empty() == false && Base
[Base
.length()-1] != '/') 
 493    // Read the first file triplet 
 494    const char *C 
= Files
.c_str(); 
 498    // Parse each of the elements 
 499    if (ParseQuoteWord(C
,MD5Hash
) == false || 
 500        ParseQuoteWord(C
,sSize
) == false || 
 501        ParseQuoteWord(C
,File
) == false) 
 502       return _error
->Error("Error parsing file record"); 
 504    // Parse the size and append the directory 
 505    Size 
= atoi(sSize
.c_str()); 
 510 // SourceCopy::RewriteEntry - Rewrite the entry with a new filename     /*{{{*/ 
 511 // --------------------------------------------------------------------- 
 513 bool SourceCopy::RewriteEntry(FILE *Target
,string File
) 
 515    string 
Dir(File
,0,File
.rfind('/')); 
 516    TFRewriteData Changes
[] = {{"Directory",Dir
.c_str()}, 
 519    if (TFRewrite(Target
,*Section
,TFRewriteSourceOrder
,Changes
) == false) 
 525 // SigVerify::Verify - Verify a files md5sum against its metaindex      /*{{{*/ 
 526 // --------------------------------------------------------------------- 
 528 bool SigVerify::Verify(string prefix
, string file
, indexRecords 
*MetaIndex
) 
 530    const indexRecords::checkSum 
*Record 
= MetaIndex
->Lookup(file
); 
 532    // we skip non-existing files in the verifcation to support a cdrom 
 533    // with no Packages file (just a Package.gz), see LP: #255545 
 534    // (non-existing files are not considered a error) 
 535    if(!RealFileExists(prefix
+file
)) 
 537       _error
->Warning(_("Skipping nonexistent file %s"), string(prefix
+file
).c_str()); 
 543       _error
->Warning(_("Can't find authentication record for: %s"), file
.c_str()); 
 547    if (!Record
->Hash
.VerifyFile(prefix
+file
)) 
 549       _error
->Warning(_("Hash mismatch for: %s"),file
.c_str()); 
 553    if(_config
->FindB("Debug::aptcdrom",false))  
 555       cout 
<< "File: " << prefix
+file 
<< endl
; 
 556       cout 
<< "Expected Hash " << Record
->Hash
.toStr() << endl
; 
 562 bool SigVerify::CopyMetaIndex(string CDROM
, string CDName
,              /*{{{*/ 
 563                               string prefix
, string file
) 
 566       snprintf(S
,sizeof(S
),"cdrom:[%s]/%s%s",CDName
.c_str(), 
 567                (prefix
).c_str() + CDROM
.length(),file
.c_str()); 
 568       string TargetF 
= _config
->FindDir("Dir::State::lists"); 
 569       TargetF 
+= URItoFileName(S
); 
 573       Target
.Open(TargetF
,FileFd::WriteAtomic
); 
 574       Rel
.Open(prefix 
+ file
,FileFd::ReadOnly
); 
 575       if (_error
->PendingError() == true) 
 577       if (CopyFile(Rel
,Target
) == false) 
 583 bool SigVerify::CopyAndVerify(string CDROM
,string Name
,vector
<string
> &SigList
, /*{{{*/ 
 584                               vector
<string
> PkgList
,vector
<string
> SrcList
) 
 586    if (SigList
.size() == 0) 
 589    bool Debug 
= _config
->FindB("Debug::aptcdrom",false); 
 591    // Read all Release files 
 592    for (vector
<string
>::iterator I 
= SigList
.begin(); I 
!= SigList
.end(); I
++) 
 595          cout 
<< "Signature verify for: " << *I 
<< endl
; 
 597       indexRecords 
*MetaIndex 
= new indexRecords
; 
 600       string 
const releasegpg 
= *I
+"Release.gpg"; 
 601       string 
const release 
= *I
+"Release"; 
 603       // a Release.gpg without a Release should never happen 
 604       if(RealFileExists(release
) == false) 
 610       pid_t pid 
= ExecFork(); 
 612          _error
->Error("Fork failed"); 
 616          RunGPGV(release
, releasegpg
); 
 618       if(!ExecWait(pid
, "gpgv")) { 
 619          _error
->Warning("Signature verification failed for: %s", 
 621          // something went wrong, don't copy the Release.gpg 
 622          // FIXME: delete any existing gpg file? 
 626       // Open the Release file and add it to the MetaIndex 
 627       if(!MetaIndex
->Load(release
)) 
 629          _error
->Error("%s",MetaIndex
->ErrorText
.c_str()); 
 633       // go over the Indexfiles and see if they verify 
 634       // if so, remove them from our copy of the lists 
 635       vector
<string
> keys 
= MetaIndex
->MetaKeys(); 
 636       for (vector
<string
>::iterator I 
= keys
.begin(); I 
!= keys
.end(); I
++) 
 638          if(!Verify(prefix
,*I
, MetaIndex
)) { 
 639             // something went wrong, don't copy the Release.gpg 
 640             // FIXME: delete any existing gpg file? 
 646       // we need a fresh one for the Release.gpg 
 649       // everything was fine, copy the Release and Release.gpg file 
 650       CopyMetaIndex(CDROM
, Name
, prefix
, "Release"); 
 651       CopyMetaIndex(CDROM
, Name
, prefix
, "Release.gpg"); 
 657 // SigVerify::RunGPGV - returns the command needed for verify           /*{{{*/ 
 658 // --------------------------------------------------------------------- 
 659 /* Generating the commandline for calling gpgv is somehow complicated as 
 660    we need to add multiple keyrings and user supplied options. Also, as 
 661    the cdrom code currently can not use the gpgv method we have two places 
 662    these need to be done - so the place for this method is wrong but better 
 663    than code duplication… */ 
 664 bool SigVerify::RunGPGV(std::string 
const &File
, std::string 
const &FileGPG
, 
 665                         int const &statusfd
, int fd
[2]) 
 669       #define SIGMSG "-----BEGIN PGP SIGNED MESSAGE-----\n" 
 670       char buffer
[sizeof(SIGMSG
)]; 
 671       FILE* gpg 
= fopen(File
.c_str(), "r"); 
 673          return _error
->Errno("RunGPGV", _("Could not open file %s"), File
.c_str()); 
 674       char const * const test 
= fgets(buffer
, sizeof(buffer
), gpg
); 
 676       if (test 
== NULL 
|| strcmp(buffer
, SIGMSG
) != 0) 
 677          return _error
->Error(_("File %s doesn't start with a clearsigned message"), File
.c_str()); 
 682    string 
const gpgvpath 
= _config
->Find("Dir::Bin::gpg", "/usr/bin/gpgv"); 
 683    // FIXME: remove support for deprecated APT::GPGV setting 
 684    string 
const trustedFile 
= _config
->Find("APT::GPGV::TrustedKeyring", _config
->FindFile("Dir::Etc::Trusted")); 
 685    string 
const trustedPath 
= _config
->FindDir("Dir::Etc::TrustedParts"); 
 687    bool const Debug 
= _config
->FindB("Debug::Acquire::gpgv", false); 
 691       std::clog 
<< "gpgv path: " << gpgvpath 
<< std::endl
; 
 692       std::clog 
<< "Keyring file: " << trustedFile 
<< std::endl
; 
 693       std::clog 
<< "Keyring path: " << trustedPath 
<< std::endl
; 
 696    std::vector
<string
> keyrings
; 
 697    if (DirectoryExists(trustedPath
)) 
 698      keyrings 
= GetListOfFilesInDir(trustedPath
, "gpg", false, true); 
 699    if (RealFileExists(trustedFile
) == true) 
 700      keyrings
.push_back(trustedFile
); 
 702    std::vector
<const char *> Args
; 
 705    if (keyrings
.empty() == true) 
 707       // TRANSLATOR: %s is the trusted keyring parts directory 
 708       return _error
->Error(_("No keyring installed in %s."), 
 709                            _config
->FindDir("Dir::Etc::TrustedParts").c_str()); 
 712    Args
.push_back(gpgvpath
.c_str()); 
 713    Args
.push_back("--ignore-time-conflict"); 
 717       Args
.push_back("--status-fd"); 
 719       snprintf(fd
, sizeof(fd
), "%i", statusfd
); 
 723    for (vector
<string
>::const_iterator K 
= keyrings
.begin(); 
 724         K 
!= keyrings
.end(); ++K
) 
 726       Args
.push_back("--keyring"); 
 727       Args
.push_back(K
->c_str()); 
 730    Configuration::Item 
const *Opts
; 
 731    Opts 
= _config
->Tree("Acquire::gpgv::Options"); 
 735       for (; Opts 
!= 0; Opts 
= Opts
->Next
) 
 737          if (Opts
->Value
.empty() == true) 
 739          Args
.push_back(Opts
->Value
.c_str()); 
 743    Args
.push_back(FileGPG
.c_str()); 
 745       Args
.push_back(File
.c_str()); 
 746    Args
.push_back(NULL
); 
 750       std::clog 
<< "Preparing to exec: " << gpgvpath
; 
 751       for (std::vector
<const char *>::const_iterator a 
= Args
.begin(); *a 
!= NULL
; ++a
) 
 752          std::clog 
<< " " << *a
; 
 753       std::clog 
<< std::endl
; 
 758       int const nullfd 
= open("/dev/null", O_RDONLY
); 
 760       // Redirect output to /dev/null; we read from the status fd 
 761       dup2(nullfd
, STDOUT_FILENO
); 
 762       dup2(nullfd
, STDERR_FILENO
); 
 763       // Redirect the pipe to the status fd (3) 
 764       dup2(fd
[1], statusfd
); 
 766       putenv((char *)"LANG="); 
 767       putenv((char *)"LC_ALL="); 
 768       putenv((char *)"LC_MESSAGES="); 
 771    execvp(gpgvpath
.c_str(), (char **) &Args
[0]); 
 775 bool TranslationsCopy::CopyTranslations(string CDROM
,string Name
,       /*{{{*/ 
 776                                 vector
<string
> &List
, pkgCdromStatus 
*log
) 
 778    OpProgress 
*Progress 
= NULL
; 
 779    if (List
.size() == 0) 
 783       Progress 
= log
->GetOpProgress(); 
 785    bool Debug 
= _config
->FindB("Debug::aptcdrom",false); 
 787    // Prepare the progress indicator 
 788    unsigned long TotalSize 
= 0; 
 789    for (vector
<string
>::iterator I 
= List
.begin(); I 
!= List
.end(); I
++) 
 792       if (stat(string(*I
).c_str(),&Buf
) != 0 && 
 793           stat(string(*I 
+ ".gz").c_str(),&Buf
) != 0) 
 794          return _error
->Errno("stat","Stat failed for %s", 
 796       TotalSize 
+= Buf
.st_size
; 
 799    unsigned long CurrentSize 
= 0; 
 800    unsigned int NotFound 
= 0; 
 801    unsigned int WrongSize 
= 0; 
 802    unsigned int Packages 
= 0; 
 803    for (vector
<string
>::iterator I 
= List
.begin(); I 
!= List
.end(); I
++) 
 805       string OrigPath 
= string(*I
,CDROM
.length()); 
 806       unsigned long FileSize 
= 0; 
 808       // Open the package file 
 810       if (RealFileExists(*I
) == true) 
 812          Pkg
.Open(*I
,FileFd::ReadOnly
); 
 813          FileSize 
= Pkg
.Size(); 
 817          FileFd 
From(*I 
+ ".gz",FileFd::ReadOnly
); 
 818          if (_error
->PendingError() == true) 
 820          FileSize 
= From
.Size(); 
 823          FILE *tmp 
= tmpfile(); 
 825             return _error
->Errno("tmpfile","Unable to create a tmp file"); 
 826          Pkg
.Fd(dup(fileno(tmp
))); 
 830          pid_t Process 
= fork(); 
 832             return _error
->Errno("fork","Couldn't fork gzip"); 
 837             dup2(From
.Fd(),STDIN_FILENO
); 
 838             dup2(Pkg
.Fd(),STDOUT_FILENO
); 
 839             SetCloseExec(STDIN_FILENO
,false); 
 840             SetCloseExec(STDOUT_FILENO
,false); 
 843             string Tmp 
=  _config
->Find("Dir::bin::gzip","gzip"); 
 844             Args
[0] = Tmp
.c_str(); 
 847             execvp(Args
[0],(char **)Args
); 
 851          // Wait for gzip to finish 
 852          if (ExecWait(Process
,_config
->Find("Dir::bin::gzip","gzip").c_str(),false) == false) 
 853             return _error
->Error("gzip failed, perhaps the disk is full."); 
 857       pkgTagFile 
Parser(&Pkg
); 
 858       if (_error
->PendingError() == true) 
 861       // Open the output file 
 863       snprintf(S
,sizeof(S
),"cdrom:[%s]/%s",Name
.c_str(), 
 864                (*I
).c_str() + CDROM
.length()); 
 865       string TargetF 
= _config
->FindDir("Dir::State::lists") + "partial/"; 
 866       TargetF 
+= URItoFileName(S
); 
 867       if (_config
->FindB("APT::CDROM::NoAct",false) == true) 
 868          TargetF 
= "/dev/null"; 
 869       FileFd 
Target(TargetF
,FileFd::WriteAtomic
); 
 870       FILE *TargetFl 
= fdopen(dup(Target
.Fd()),"w"); 
 871       if (_error
->PendingError() == true) 
 874          return _error
->Errno("fdopen","Failed to reopen fd"); 
 876       // Setup the progress meter 
 878          Progress
->OverallProgress(CurrentSize
,TotalSize
,FileSize
, 
 879                                    string("Reading Translation Indexes")); 
 883          Progress
->SubProgress(Pkg
.Size()); 
 884       pkgTagSection Section
; 
 885       this->Section 
= &Section
; 
 887       unsigned long Hits 
= 0; 
 888       unsigned long Chop 
= 0; 
 889       while (Parser
.Step(Section
) == true) 
 892             Progress
->Progress(Parser
.Offset()); 
 896          Section
.GetSection(Start
,Stop
); 
 897          fwrite(Start
,Stop
-Start
, 1, TargetFl
); 
 898          fputc('\n',TargetFl
); 
 906          cout 
<< " Processed by using Prefix '" << Prefix 
<< "' and chop " << Chop 
<< endl
; 
 908       if (_config
->FindB("APT::CDROM::NoAct",false) == false) 
 910          // Move out of the partial directory 
 912          string FinalF 
= _config
->FindDir("Dir::State::lists"); 
 913          FinalF 
+= URItoFileName(S
); 
 914          if (rename(TargetF
.c_str(),FinalF
.c_str()) != 0) 
 915             return _error
->Errno("rename","Failed to rename"); 
 919       CurrentSize 
+= FileSize
; 
 927       if(NotFound 
== 0 && WrongSize 
== 0) 
 928          ioprintf(msg
, _("Wrote %i records.\n"), Packages
); 
 929       else if (NotFound 
!= 0 && WrongSize 
== 0) 
 930          ioprintf(msg
, _("Wrote %i records with %i missing files.\n"),  
 932       else if (NotFound 
== 0 && WrongSize 
!= 0) 
 933          ioprintf(msg
, _("Wrote %i records with %i mismatched files\n"),  
 934                   Packages
, WrongSize
); 
 935       if (NotFound 
!= 0 && WrongSize 
!= 0) 
 936          ioprintf(msg
, _("Wrote %i records with %i missing files and %i mismatched files\n"), Packages
, NotFound
, WrongSize
); 
 940       _error
->Warning("No valid records were found."); 
 942    if (NotFound 
+ WrongSize 
> 10) 
 943       _error
->Warning("A lot of entries were discarded, something may be wrong.\n");