]>
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                                                        /*{{{*/ 
  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/aptconfiguration.h> 
  20 #include <apt-pkg/configuration.h> 
  21 #include <apt-pkg/tagfile.h> 
  22 #include <apt-pkg/indexrecords.h> 
  23 #include <apt-pkg/md5.h> 
  24 #include <apt-pkg/cdrom.h> 
  30 #include <sys/types.h> 
  35 #include "indexcopy.h" 
  41 // IndexCopy::CopyPackages - Copy the package files from the CD         /*{{{*/ 
  42 // --------------------------------------------------------------------- 
  44 bool IndexCopy::CopyPackages(string CDROM
,string Name
,vector
<string
> &List
, 
  47    OpProgress 
*Progress 
= NULL
; 
  48    if (List
.empty() == true) 
  52       Progress 
= log
->GetOpProgress(); 
  54    bool NoStat 
= _config
->FindB("APT::CDROM::Fast",false); 
  55    bool Debug 
= _config
->FindB("Debug::aptcdrom",false); 
  57    // Prepare the progress indicator 
  59    std::vector
<APT::Configuration::Compressor
> const compressor 
= APT::Configuration::getCompressors(); 
  60    for (vector
<string
>::iterator I 
= List
.begin(); I 
!= List
.end(); ++I
) 
  64       std::string file 
= std::string(*I
).append(GetFileName()); 
  65       for (std::vector
<APT::Configuration::Compressor
>::const_iterator c 
= compressor
.begin(); 
  66            c 
!= compressor
.end(); ++c
) 
  68          if (stat(std::string(file 
+ c
->Extension
).c_str(), &Buf
) != 0) 
  75          return _error
->Errno("stat", "Stat failed for %s", file
.c_str()); 
  76       TotalSize 
+= Buf
.st_size
; 
  79    off_t CurrentSize 
= 0; 
  80    unsigned int NotFound 
= 0; 
  81    unsigned int WrongSize 
= 0; 
  82    unsigned int Packages 
= 0; 
  83    for (vector
<string
>::iterator I 
= List
.begin(); I 
!= List
.end(); ++I
) 
  85       string OrigPath 
= string(*I
,CDROM
.length()); 
  87       // Open the package file 
  88       FileFd 
Pkg(*I 
+ GetFileName(), FileFd::ReadOnly
, FileFd::Auto
); 
  89       off_t 
const FileSize 
= Pkg
.Size(); 
  91       pkgTagFile 
Parser(&Pkg
); 
  92       if (_error
->PendingError() == true) 
  95       // Open the output file 
  97       snprintf(S
,sizeof(S
),"cdrom:[%s]/%s%s",Name
.c_str(), 
  98                (*I
).c_str() + CDROM
.length(),GetFileName()); 
  99       string TargetF 
= _config
->FindDir("Dir::State::lists") + "partial/"; 
 100       TargetF 
+= URItoFileName(S
); 
 102       if (_config
->FindB("APT::CDROM::NoAct",false) == true) 
 104          TargetF 
= "/dev/null"; 
 105          Target
.Open(TargetF
,FileFd::WriteExists
); 
 107          Target
.Open(TargetF
,FileFd::WriteAtomic
); 
 109       FILE *TargetFl 
= fdopen(dup(Target
.Fd()),"w"); 
 110       if (_error
->PendingError() == true) 
 113          return _error
->Errno("fdopen","Failed to reopen fd"); 
 115       // Setup the progress meter 
 117          Progress
->OverallProgress(CurrentSize
,TotalSize
,FileSize
, 
 118                                    string("Reading ") + Type() + " Indexes"); 
 122          Progress
->SubProgress(Pkg
.Size()); 
 123       pkgTagSection Section
; 
 124       this->Section 
= &Section
; 
 126       unsigned long Hits 
= 0; 
 127       unsigned long Chop 
= 0; 
 128       while (Parser
.Step(Section
) == true) 
 131             Progress
->Progress(Parser
.Offset()); 
 133          unsigned long long Size
; 
 134          if (GetFile(File
,Size
) == false) 
 141             File 
= OrigPath 
+ ChopDirs(File
,Chop
); 
 143          // See if the file exists 
 144          if (NoStat 
== false || Hits 
< 10) 
 146             // Attempt to fix broken structure 
 149                if (ReconstructPrefix(Prefix
,OrigPath
,CDROM
,File
) == false && 
 150                    ReconstructChop(Chop
,*I
,File
) == false) 
 153                      clog 
<< "Missed: " << File 
<< endl
; 
 158                   File 
= OrigPath 
+ ChopDirs(File
,Chop
); 
 163             if (stat(string(CDROM 
+ Prefix 
+ File
).c_str(),&Buf
) != 0 ||  
 166                bool Mangled 
= false; 
 167                // Attempt to fix busted symlink support for one instance 
 168                string OrigFile 
= File
; 
 169                string::size_type Start 
= File
.find("binary-"); 
 170                string::size_type End 
= File
.find("/",Start
+3); 
 171                if (Start 
!= string::npos 
&& End 
!= string::npos
) 
 173                   File
.replace(Start
,End
-Start
,"binary-all"); 
 177                if (Mangled 
== false || 
 178                    stat(string(CDROM 
+ Prefix 
+ File
).c_str(),&Buf
) != 0) 
 181                      clog 
<< "Missed(2): " << OrigFile 
<< endl
; 
 188             if ((unsigned long long)Buf
.st_size 
!= Size
) 
 191                   clog 
<< "Wrong Size: " << File 
<< endl
; 
 200          if (RewriteEntry(TargetFl
,File
) == false) 
 209          cout 
<< " Processed by using Prefix '" << Prefix 
<< "' and chop " << Chop 
<< endl
; 
 211       if (_config
->FindB("APT::CDROM::NoAct",false) == false) 
 213          // Move out of the partial directory 
 215          string FinalF 
= _config
->FindDir("Dir::State::lists"); 
 216          FinalF 
+= URItoFileName(S
); 
 217          if (rename(TargetF
.c_str(),FinalF
.c_str()) != 0) 
 218             return _error
->Errno("rename","Failed to rename"); 
 221       /* Mangle the source to be in the proper notation with 
 222          prefix dist [component] */  
 223       *I 
= string(*I
,Prefix
.length()); 
 224       ConvertToSourceList(CDROM
,*I
); 
 225       *I 
= Prefix 
+ ' ' + *I
; 
 227       CurrentSize 
+= FileSize
; 
 235       if(NotFound 
== 0 && WrongSize 
== 0) 
 236          ioprintf(msg
, _("Wrote %i records.\n"), Packages
); 
 237       else if (NotFound 
!= 0 && WrongSize 
== 0) 
 238          ioprintf(msg
, _("Wrote %i records with %i missing files.\n"),  
 240       else if (NotFound 
== 0 && WrongSize 
!= 0) 
 241          ioprintf(msg
, _("Wrote %i records with %i mismatched files\n"),  
 242                   Packages
, WrongSize
); 
 243       if (NotFound 
!= 0 && WrongSize 
!= 0) 
 244          ioprintf(msg
, _("Wrote %i records with %i missing files and %i mismatched files\n"), Packages
, NotFound
, WrongSize
); 
 248       _error
->Warning("No valid records were found."); 
 250    if (NotFound 
+ WrongSize 
> 10) 
 251       _error
->Warning("A lot of entries were discarded, something may be wrong.\n"); 
 257 // IndexCopy::ChopDirs - Chop off the leading directory components      /*{{{*/ 
 258 // --------------------------------------------------------------------- 
 260 string 
IndexCopy::ChopDirs(string Path
,unsigned int Depth
) 
 262    string::size_type I 
= 0; 
 265       I 
= Path
.find('/',I
+1); 
 268    while (I 
!= string::npos 
&& Depth 
!= 0); 
 270    if (I 
== string::npos
) 
 273    return string(Path
,I
+1); 
 276 // IndexCopy::ReconstructPrefix - Fix strange prefixing                 /*{{{*/ 
 277 // --------------------------------------------------------------------- 
 278 /* This prepends dir components from the path to the package files to 
 279    the path to the deb until it is found */ 
 280 bool IndexCopy::ReconstructPrefix(string 
&Prefix
,string OrigPath
,string CD
, 
 283    bool Debug 
= _config
->FindB("Debug::aptcdrom",false); 
 284    unsigned int Depth 
= 1; 
 285    string MyPrefix 
= Prefix
; 
 289       if (stat(string(CD 
+ MyPrefix 
+ File
).c_str(),&Buf
) != 0) 
 292             cout 
<< "Failed, " << CD 
+ MyPrefix 
+ File 
<< endl
; 
 293          if (GrabFirst(OrigPath
,MyPrefix
,Depth
++) == true) 
 307 // IndexCopy::ReconstructChop - Fixes bad source paths                  /*{{{*/ 
 308 // --------------------------------------------------------------------- 
 309 /* This removes path components from the filename and prepends the location 
 310    of the package files until a file is found */ 
 311 bool IndexCopy::ReconstructChop(unsigned long &Chop
,string Dir
,string File
) 
 313    // Attempt to reconstruct the filename 
 314    unsigned long Depth 
= 0; 
 318       if (stat(string(Dir 
+ File
).c_str(),&Buf
) != 0) 
 320          File 
= ChopDirs(File
,1); 
 322          if (File
.empty() == false) 
 335 // IndexCopy::ConvertToSourceList - Convert a Path to a sourcelist      /*{{{*/ 
 336 // --------------------------------------------------------------------- 
 337 /* We look for things in dists/ notation and convert them to  
 338    <dist> <component> form otherwise it is left alone. This also strips 
 341    This implements a regex sort of like:  
 342     (.*)/dists/([^/]*)/(.*)/binary-*  
 344      |          |-------- Distribution 
 345      |------------------- Path 
 347    It was deciced to use only a single word for dist (rather than say 
 348    unstable/non-us) to increase the chance that each CD gets a single 
 349    line in sources.list. 
 351 void IndexCopy::ConvertToSourceList(string CD
,string 
&Path
) 
 353    // Strip the cdrom base path 
 354    Path 
= string(Path
,CD
.length()); 
 355    if (Path
.empty() == true) 
 358    // Too short to be a dists/ type 
 359    if (Path
.length() < strlen("dists/")) 
 363    if (stringcmp(Path
.c_str(),Path
.c_str()+strlen("dists/"),"dists/") != 0) 
 367    string::size_type Slash 
= strlen("dists/"); 
 368    string::size_type Slash2 
= Path
.find('/',Slash 
+ 1); 
 369    if (Slash2 
== string::npos 
|| Slash2 
+ 2 >= Path
.length()) 
 371    string Dist 
= string(Path
,Slash
,Slash2 
- Slash
); 
 373    // Isolate the component 
 375    for (unsigned I 
= 0; I 
!= 10; I
++) 
 377       Slash 
= Path
.find('/',Slash
+1); 
 378       if (Slash 
== string::npos 
|| Slash 
+ 2 >= Path
.length()) 
 380       string Comp 
= string(Path
,Slash2
+1,Slash 
- Slash2
-1); 
 382       // Verify the trailing binary- bit 
 383       string::size_type BinSlash 
= Path
.find('/',Slash 
+ 1); 
 384       if (Slash 
== string::npos
) 
 386       string Binary 
= string(Path
,Slash
+1,BinSlash 
- Slash
-1); 
 388       if (strncmp(Binary
.c_str(), "binary-", strlen("binary-")) == 0) 
 390          Binary
.erase(0, strlen("binary-")); 
 391          if (APT::Configuration::checkArchitecture(Binary
) == false) 
 394       else if (Binary 
!= "source") 
 397       Path 
= Dist 
+ ' ' + Comp
; 
 402 // IndexCopy::GrabFirst - Return the first Depth path components        /*{{{*/ 
 403 // --------------------------------------------------------------------- 
 405 bool IndexCopy::GrabFirst(string Path
,string 
&To
,unsigned int Depth
) 
 407    string::size_type I 
= 0; 
 410       I 
= Path
.find('/',I
+1); 
 413    while (I 
!= string::npos 
&& Depth 
!= 0); 
 415    if (I 
== string::npos
) 
 418    To 
= string(Path
,0,I
+1); 
 422 // PackageCopy::GetFile - Get the file information from the section     /*{{{*/ 
 423 // --------------------------------------------------------------------- 
 425 bool PackageCopy::GetFile(string 
&File
,unsigned long long &Size
) 
 427    File 
= Section
->FindS("Filename"); 
 428    Size 
= Section
->FindI("Size"); 
 429    if (File
.empty() || Size 
== 0) 
 430       return _error
->Error("Cannot find filename or size tag"); 
 434 // PackageCopy::RewriteEntry - Rewrite the entry with a new filename    /*{{{*/ 
 435 // --------------------------------------------------------------------- 
 437 bool PackageCopy::RewriteEntry(FILE *Target
,string File
) 
 439    TFRewriteData Changes
[] = {{"Filename",File
.c_str()}, 
 442    if (TFRewrite(Target
,*Section
,TFRewritePackageOrder
,Changes
) == false) 
 448 // SourceCopy::GetFile - Get the file information from the section      /*{{{*/ 
 449 // --------------------------------------------------------------------- 
 451 bool SourceCopy::GetFile(string 
&File
,unsigned long long &Size
) 
 453    string Files 
= Section
->FindS("Files"); 
 454    if (Files
.empty() == true) 
 457    // Stash the / terminated directory prefix 
 458    string Base 
= Section
->FindS("Directory"); 
 459    if (Base
.empty() == false && Base
[Base
.length()-1] != '/') 
 462    // Read the first file triplet 
 463    const char *C 
= Files
.c_str(); 
 467    // Parse each of the elements 
 468    if (ParseQuoteWord(C
,MD5Hash
) == false || 
 469        ParseQuoteWord(C
,sSize
) == false || 
 470        ParseQuoteWord(C
,File
) == false) 
 471       return _error
->Error("Error parsing file record"); 
 473    // Parse the size and append the directory 
 474    Size 
= strtoull(sSize
.c_str(), NULL
, 10); 
 479 // SourceCopy::RewriteEntry - Rewrite the entry with a new filename     /*{{{*/ 
 480 // --------------------------------------------------------------------- 
 482 bool SourceCopy::RewriteEntry(FILE *Target
,string File
) 
 484    string 
Dir(File
,0,File
.rfind('/')); 
 485    TFRewriteData Changes
[] = {{"Directory",Dir
.c_str()}, 
 488    if (TFRewrite(Target
,*Section
,TFRewriteSourceOrder
,Changes
) == false) 
 494 // SigVerify::Verify - Verify a files md5sum against its metaindex      /*{{{*/ 
 495 // --------------------------------------------------------------------- 
 497 bool SigVerify::Verify(string prefix
, string file
, indexRecords 
*MetaIndex
) 
 499    const indexRecords::checkSum 
*Record 
= MetaIndex
->Lookup(file
); 
 500    bool const Debug 
= _config
->FindB("Debug::aptcdrom",false); 
 502    // we skip non-existing files in the verifcation of the Release file 
 503    // as non-existing files do not harm, but a warning scares people and 
 504    // makes it hard to strip unneeded files from an ISO like uncompressed 
 505    // indexes as it is done on the mirrors (see also LP: #255545 ) 
 506    if(!RealFileExists(prefix
+file
)) 
 509          cout 
<< "Skipping nonexistent in " << prefix 
<< " file " << file 
<< std::endl
; 
 515       _error
->Warning(_("Can't find authentication record for: %s"), file
.c_str()); 
 519    if (!Record
->Hash
.VerifyFile(prefix
+file
)) 
 521       _error
->Warning(_("Hash mismatch for: %s"),file
.c_str()); 
 527       cout 
<< "File: " << prefix
+file 
<< endl
; 
 528       cout 
<< "Expected Hash " << Record
->Hash
.toStr() << endl
; 
 534 bool SigVerify::CopyMetaIndex(string CDROM
, string CDName
,              /*{{{*/ 
 535                               string prefix
, string file
) 
 538       snprintf(S
,sizeof(S
),"cdrom:[%s]/%s%s",CDName
.c_str(), 
 539                (prefix
).c_str() + CDROM
.length(),file
.c_str()); 
 540       string TargetF 
= _config
->FindDir("Dir::State::lists"); 
 541       TargetF 
+= URItoFileName(S
); 
 545       Target
.Open(TargetF
,FileFd::WriteAtomic
); 
 546       Rel
.Open(prefix 
+ file
,FileFd::ReadOnly
); 
 547       if (_error
->PendingError() == true) 
 549       if (CopyFile(Rel
,Target
) == false) 
 555 bool SigVerify::CopyAndVerify(string CDROM
,string Name
,vector
<string
> &SigList
, /*{{{*/ 
 556                               vector
<string
> PkgList
,vector
<string
> SrcList
) 
 558    if (SigList
.empty() == true) 
 561    bool Debug 
= _config
->FindB("Debug::aptcdrom",false); 
 563    // Read all Release files 
 564    for (vector
<string
>::iterator I 
= SigList
.begin(); I 
!= SigList
.end(); ++I
) 
 567          cout 
<< "Signature verify for: " << *I 
<< endl
; 
 569       indexRecords 
*MetaIndex 
= new indexRecords
; 
 572       string 
const releasegpg 
= *I
+"Release.gpg"; 
 573       string 
const release 
= *I
+"Release"; 
 574       string 
const inrelease 
= *I
+"InRelease"; 
 575       bool useInRelease 
= true; 
 577       // a Release.gpg without a Release should never happen 
 578       if (RealFileExists(inrelease
) == true) 
 580       else if(RealFileExists(release
) == false || RealFileExists(releasegpg
) == false) 
 586          useInRelease 
= false; 
 588       pid_t pid 
= ExecFork(); 
 590          _error
->Error("Fork failed"); 
 595          if (useInRelease 
== true) 
 596             RunGPGV(inrelease
, inrelease
); 
 598             RunGPGV(release
, releasegpg
); 
 601       if(!ExecWait(pid
, "gpgv")) { 
 602          _error
->Warning("Signature verification failed for: %s", 
 603                          (useInRelease 
? inrelease
.c_str() : releasegpg
.c_str())); 
 604          // something went wrong, don't copy the Release.gpg 
 605          // FIXME: delete any existing gpg file? 
 609       // Open the Release file and add it to the MetaIndex 
 610       if(!MetaIndex
->Load(release
)) 
 612          _error
->Error("%s",MetaIndex
->ErrorText
.c_str()); 
 616       // go over the Indexfiles and see if they verify 
 617       // if so, remove them from our copy of the lists 
 618       vector
<string
> keys 
= MetaIndex
->MetaKeys(); 
 619       for (vector
<string
>::iterator I 
= keys
.begin(); I 
!= keys
.end(); ++I
) 
 621          if(!Verify(prefix
,*I
, MetaIndex
)) { 
 622             // something went wrong, don't copy the Release.gpg 
 623             // FIXME: delete any existing gpg file? 
 629       // we need a fresh one for the Release.gpg 
 632       // everything was fine, copy the Release and Release.gpg file 
 633       if (useInRelease 
== true) 
 634          CopyMetaIndex(CDROM
, Name
, prefix
, "InRelease"); 
 637          CopyMetaIndex(CDROM
, Name
, prefix
, "Release"); 
 638          CopyMetaIndex(CDROM
, Name
, prefix
, "Release.gpg"); 
 645 // SigVerify::RunGPGV - returns the command needed for verify           /*{{{*/ 
 646 // --------------------------------------------------------------------- 
 647 /* Generating the commandline for calling gpgv is somehow complicated as 
 648    we need to add multiple keyrings and user supplied options. Also, as 
 649    the cdrom code currently can not use the gpgv method we have two places 
 650    these need to be done - so the place for this method is wrong but better 
 651    than code duplication… */ 
 652 bool SigVerify::RunGPGV(std::string 
const &File
, std::string 
const &FileGPG
, 
 653                         int const &statusfd
, int fd
[2]) 
 657       #define SIGMSG "-----BEGIN PGP SIGNED MESSAGE-----\n" 
 658       char buffer
[sizeof(SIGMSG
)]; 
 659       FILE* gpg 
= fopen(File
.c_str(), "r"); 
 661          return _error
->Errno("RunGPGV", _("Could not open file %s"), File
.c_str()); 
 662       char const * const test 
= fgets(buffer
, sizeof(buffer
), gpg
); 
 664       if (test 
== NULL 
|| strcmp(buffer
, SIGMSG
) != 0) 
 665          return _error
->Error(_("File %s doesn't start with a clearsigned message"), File
.c_str()); 
 670    string 
const gpgvpath 
= _config
->Find("Dir::Bin::gpg", "/usr/bin/gpgv"); 
 671    // FIXME: remove support for deprecated APT::GPGV setting 
 672    string 
const trustedFile 
= _config
->Find("APT::GPGV::TrustedKeyring", _config
->FindFile("Dir::Etc::Trusted")); 
 673    string 
const trustedPath 
= _config
->FindDir("Dir::Etc::TrustedParts"); 
 675    bool const Debug 
= _config
->FindB("Debug::Acquire::gpgv", false); 
 679       std::clog 
<< "gpgv path: " << gpgvpath 
<< std::endl
; 
 680       std::clog 
<< "Keyring file: " << trustedFile 
<< std::endl
; 
 681       std::clog 
<< "Keyring path: " << trustedPath 
<< std::endl
; 
 684    std::vector
<string
> keyrings
; 
 685    if (DirectoryExists(trustedPath
)) 
 686      keyrings 
= GetListOfFilesInDir(trustedPath
, "gpg", false, true); 
 687    if (RealFileExists(trustedFile
) == true) 
 688      keyrings
.push_back(trustedFile
); 
 690    std::vector
<const char *> Args
; 
 693    if (keyrings
.empty() == true) 
 695       // TRANSLATOR: %s is the trusted keyring parts directory 
 696       return _error
->Error(_("No keyring installed in %s."), 
 697                            _config
->FindDir("Dir::Etc::TrustedParts").c_str()); 
 700    Args
.push_back(gpgvpath
.c_str()); 
 701    Args
.push_back("--ignore-time-conflict"); 
 705       Args
.push_back("--status-fd"); 
 707       snprintf(fd
, sizeof(fd
), "%i", statusfd
); 
 711    for (vector
<string
>::const_iterator K 
= keyrings
.begin(); 
 712         K 
!= keyrings
.end(); ++K
) 
 714       Args
.push_back("--keyring"); 
 715       Args
.push_back(K
->c_str()); 
 718    Configuration::Item 
const *Opts
; 
 719    Opts 
= _config
->Tree("Acquire::gpgv::Options"); 
 723       for (; Opts 
!= 0; Opts 
= Opts
->Next
) 
 725          if (Opts
->Value
.empty() == true) 
 727          Args
.push_back(Opts
->Value
.c_str()); 
 731    Args
.push_back(FileGPG
.c_str()); 
 733       Args
.push_back(File
.c_str()); 
 734    Args
.push_back(NULL
); 
 738       std::clog 
<< "Preparing to exec: " << gpgvpath
; 
 739       for (std::vector
<const char *>::const_iterator a 
= Args
.begin(); *a 
!= NULL
; ++a
) 
 740          std::clog 
<< " " << *a
; 
 741       std::clog 
<< std::endl
; 
 746       int const nullfd 
= open("/dev/null", O_RDONLY
); 
 748       // Redirect output to /dev/null; we read from the status fd 
 749       dup2(nullfd
, STDOUT_FILENO
); 
 750       dup2(nullfd
, STDERR_FILENO
); 
 751       // Redirect the pipe to the status fd (3) 
 752       dup2(fd
[1], statusfd
); 
 754       putenv((char *)"LANG="); 
 755       putenv((char *)"LC_ALL="); 
 756       putenv((char *)"LC_MESSAGES="); 
 759    execvp(gpgvpath
.c_str(), (char **) &Args
[0]); 
 763 bool TranslationsCopy::CopyTranslations(string CDROM
,string Name
,       /*{{{*/ 
 764                                 vector
<string
> &List
, pkgCdromStatus 
*log
) 
 766    OpProgress 
*Progress 
= NULL
; 
 767    if (List
.empty() == true) 
 771       Progress 
= log
->GetOpProgress(); 
 773    bool Debug 
= _config
->FindB("Debug::aptcdrom",false); 
 775    // Prepare the progress indicator 
 777    std::vector
<APT::Configuration::Compressor
> const compressor 
= APT::Configuration::getCompressors(); 
 778    for (vector
<string
>::iterator I 
= List
.begin(); I 
!= List
.end(); ++I
) 
 782       std::string file 
= *I
; 
 783       for (std::vector
<APT::Configuration::Compressor
>::const_iterator c 
= compressor
.begin(); 
 784            c 
!= compressor
.end(); ++c
) 
 786          if (stat(std::string(file 
+ c
->Extension
).c_str(), &Buf
) != 0) 
 793          return _error
->Errno("stat", "Stat failed for %s", file
.c_str()); 
 794       TotalSize 
+= Buf
.st_size
; 
 797    off_t CurrentSize 
= 0; 
 798    unsigned int NotFound 
= 0; 
 799    unsigned int WrongSize 
= 0; 
 800    unsigned int Packages 
= 0; 
 801    for (vector
<string
>::iterator I 
= List
.begin(); I 
!= List
.end(); ++I
) 
 803       // Open the package file 
 804       FileFd 
Pkg(*I
, FileFd::ReadOnly
, FileFd::Auto
); 
 805       off_t 
const FileSize 
= Pkg
.Size(); 
 807       pkgTagFile 
Parser(&Pkg
); 
 808       if (_error
->PendingError() == true) 
 811       // Open the output file 
 813       snprintf(S
,sizeof(S
),"cdrom:[%s]/%s",Name
.c_str(), 
 814                (*I
).c_str() + CDROM
.length()); 
 815       string TargetF 
= _config
->FindDir("Dir::State::lists") + "partial/"; 
 816       TargetF 
+= URItoFileName(S
); 
 818       if (_config
->FindB("APT::CDROM::NoAct",false) == true) 
 820          TargetF 
= "/dev/null"; 
 821          Target
.Open(TargetF
,FileFd::WriteExists
); 
 823          Target
.Open(TargetF
,FileFd::WriteAtomic
); 
 825       FILE *TargetFl 
= fdopen(dup(Target
.Fd()),"w"); 
 826       if (_error
->PendingError() == true) 
 829          return _error
->Errno("fdopen","Failed to reopen fd"); 
 831       // Setup the progress meter 
 833          Progress
->OverallProgress(CurrentSize
,TotalSize
,FileSize
, 
 834                                    string("Reading Translation Indexes")); 
 838          Progress
->SubProgress(Pkg
.Size()); 
 839       pkgTagSection Section
; 
 840       this->Section 
= &Section
; 
 842       unsigned long Hits 
= 0; 
 843       while (Parser
.Step(Section
) == true) 
 846             Progress
->Progress(Parser
.Offset()); 
 850          Section
.GetSection(Start
,Stop
); 
 851          fwrite(Start
,Stop
-Start
, 1, TargetFl
); 
 852          fputc('\n',TargetFl
); 
 860          cout 
<< " Processed by using Prefix '" << Prefix 
<< "' and chop " << endl
; 
 862       if (_config
->FindB("APT::CDROM::NoAct",false) == false) 
 864          // Move out of the partial directory 
 866          string FinalF 
= _config
->FindDir("Dir::State::lists"); 
 867          FinalF 
+= URItoFileName(S
); 
 868          if (rename(TargetF
.c_str(),FinalF
.c_str()) != 0) 
 869             return _error
->Errno("rename","Failed to rename"); 
 873       CurrentSize 
+= FileSize
; 
 881       if(NotFound 
== 0 && WrongSize 
== 0) 
 882          ioprintf(msg
, _("Wrote %i records.\n"), Packages
); 
 883       else if (NotFound 
!= 0 && WrongSize 
== 0) 
 884          ioprintf(msg
, _("Wrote %i records with %i missing files.\n"),  
 886       else if (NotFound 
== 0 && WrongSize 
!= 0) 
 887          ioprintf(msg
, _("Wrote %i records with %i mismatched files\n"),  
 888                   Packages
, WrongSize
); 
 889       if (NotFound 
!= 0 && WrongSize 
!= 0) 
 890          ioprintf(msg
, _("Wrote %i records with %i missing files and %i mismatched files\n"), Packages
, NotFound
, WrongSize
); 
 894       _error
->Warning("No valid records were found."); 
 896    if (NotFound 
+ WrongSize 
> 10) 
 897       _error
->Warning("A lot of entries were discarded, something may be wrong.\n");