]>
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/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>
29 #include <sys/types.h>
34 #include "indexcopy.h"
40 // DecompressFile - wrapper for decompressing gzip/bzip2/xz compressed files /*{{{*/
41 // ---------------------------------------------------------------------
43 bool DecompressFile(string Filename
, int *fd
, off_t
*FileSize
)
46 string CompressProgFind
;
51 if (stat((Filename
+ ".gz").c_str(), &Buf
) == 0)
53 CompressProg
= "gzip";
54 CompressProgFind
= "Dir::bin::gzip";
55 From
.Open(Filename
+ ".gz",FileFd::ReadOnly
);
57 else if (stat((Filename
+ ".bz2").c_str(), &Buf
) == 0)
59 CompressProg
= "bzip2";
60 CompressProgFind
= "Dir::bin::bzip2";
61 From
.Open(Filename
+ ".bz2",FileFd::ReadOnly
);
63 else if (stat((Filename
+ ".xz").c_str(), &Buf
) == 0)
66 CompressProgFind
= "Dir::bin::xz";
67 From
.Open(Filename
+ ".xz",FileFd::ReadOnly
);
71 return _error
->Errno("decompressor", "Unable to parse file");
74 if (_error
->PendingError() == true)
77 *FileSize
= Buf
.st_size
;
80 FILE *tmp
= tmpfile();
82 return _error
->Errno("tmpfile","Unable to create a tmp file");
83 *fd
= dup(fileno(tmp
));
87 pid_t Process
= fork();
89 return _error
->Errno("fork","Couldn't fork to run decompressor");
94 dup2(From
.Fd(),STDIN_FILENO
);
95 dup2(*fd
,STDOUT_FILENO
);
96 SetCloseExec(STDIN_FILENO
,false);
97 SetCloseExec(STDOUT_FILENO
,false);
100 string Tmp
= _config
->Find(CompressProgFind
, CompressProg
);
101 Args
[0] = Tmp
.c_str();
104 if(execvp(Args
[0],(char **)Args
))
105 return(_error
->Errno("decompressor","decompress failed"));
106 /* Should never get here */
110 // Wait for decompress to finish
111 if (ExecWait(Process
,CompressProg
.c_str(),false) == false)
117 // IndexCopy::CopyPackages - Copy the package files from the CD /*{{{*/
118 // ---------------------------------------------------------------------
120 bool IndexCopy::CopyPackages(string CDROM
,string Name
,vector
<string
> &List
,
123 OpProgress
*Progress
= NULL
;
124 if (List
.empty() == true)
128 Progress
= log
->GetOpProgress();
130 bool NoStat
= _config
->FindB("APT::CDROM::Fast",false);
131 bool Debug
= _config
->FindB("Debug::aptcdrom",false);
133 // Prepare the progress indicator
135 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); ++I
)
138 if (stat(string(*I
+ GetFileName()).c_str(),&Buf
) != 0 &&
139 stat(string(*I
+ GetFileName() + ".gz").c_str(),&Buf
) != 0 &&
140 stat(string(*I
+ GetFileName() + ".xz").c_str(),&Buf
) != 0 &&
141 stat(string(*I
+ GetFileName() + ".bz2").c_str(),&Buf
) != 0)
142 return _error
->Errno("stat","Stat failed for %s",
143 string(*I
+ GetFileName()).c_str());
144 TotalSize
+= Buf
.st_size
;
147 off_t CurrentSize
= 0;
148 unsigned int NotFound
= 0;
149 unsigned int WrongSize
= 0;
150 unsigned int Packages
= 0;
151 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); ++I
)
153 string OrigPath
= string(*I
,CDROM
.length());
156 // Open the package file
158 if (RealFileExists(*I
+ GetFileName()) == true)
160 Pkg
.Open(*I
+ GetFileName(),FileFd::ReadOnly
);
161 FileSize
= Pkg
.Size();
166 if (!DecompressFile(string(*I
+ GetFileName()), &fd
, &FileSize
))
167 return _error
->Errno("decompress","Decompress failed for %s",
168 string(*I
+ GetFileName()).c_str());
173 pkgTagFile
Parser(&Pkg
);
174 if (_error
->PendingError() == true)
177 // Open the output file
179 snprintf(S
,sizeof(S
),"cdrom:[%s]/%s%s",Name
.c_str(),
180 (*I
).c_str() + CDROM
.length(),GetFileName());
181 string TargetF
= _config
->FindDir("Dir::State::lists") + "partial/";
182 TargetF
+= URItoFileName(S
);
184 if (_config
->FindB("APT::CDROM::NoAct",false) == true)
186 TargetF
= "/dev/null";
187 Target
.Open(TargetF
,FileFd::WriteExists
);
189 Target
.Open(TargetF
,FileFd::WriteAtomic
);
191 FILE *TargetFl
= fdopen(dup(Target
.Fd()),"w");
192 if (_error
->PendingError() == true)
195 return _error
->Errno("fdopen","Failed to reopen fd");
197 // Setup the progress meter
199 Progress
->OverallProgress(CurrentSize
,TotalSize
,FileSize
,
200 string("Reading ") + Type() + " Indexes");
204 Progress
->SubProgress(Pkg
.Size());
205 pkgTagSection Section
;
206 this->Section
= &Section
;
208 unsigned long Hits
= 0;
209 unsigned long Chop
= 0;
210 while (Parser
.Step(Section
) == true)
213 Progress
->Progress(Parser
.Offset());
215 unsigned long long Size
;
216 if (GetFile(File
,Size
) == false)
223 File
= OrigPath
+ ChopDirs(File
,Chop
);
225 // See if the file exists
226 bool Mangled
= false;
227 if (NoStat
== false || Hits
< 10)
229 // Attempt to fix broken structure
232 if (ReconstructPrefix(Prefix
,OrigPath
,CDROM
,File
) == false &&
233 ReconstructChop(Chop
,*I
,File
) == false)
236 clog
<< "Missed: " << File
<< endl
;
241 File
= OrigPath
+ ChopDirs(File
,Chop
);
246 if (stat(string(CDROM
+ Prefix
+ File
).c_str(),&Buf
) != 0 ||
249 // Attempt to fix busted symlink support for one instance
250 string OrigFile
= File
;
251 string::size_type Start
= File
.find("binary-");
252 string::size_type End
= File
.find("/",Start
+3);
253 if (Start
!= string::npos
&& End
!= string::npos
)
255 File
.replace(Start
,End
-Start
,"binary-all");
259 if (Mangled
== false ||
260 stat(string(CDROM
+ Prefix
+ File
).c_str(),&Buf
) != 0)
263 clog
<< "Missed(2): " << OrigFile
<< endl
;
270 if ((unsigned long long)Buf
.st_size
!= Size
)
273 clog
<< "Wrong Size: " << File
<< endl
;
282 if (RewriteEntry(TargetFl
,File
) == false)
291 cout
<< " Processed by using Prefix '" << Prefix
<< "' and chop " << Chop
<< endl
;
293 if (_config
->FindB("APT::CDROM::NoAct",false) == false)
295 // Move out of the partial directory
297 string FinalF
= _config
->FindDir("Dir::State::lists");
298 FinalF
+= URItoFileName(S
);
299 if (rename(TargetF
.c_str(),FinalF
.c_str()) != 0)
300 return _error
->Errno("rename","Failed to rename");
303 /* Mangle the source to be in the proper notation with
304 prefix dist [component] */
305 *I
= string(*I
,Prefix
.length());
306 ConvertToSourceList(CDROM
,*I
);
307 *I
= Prefix
+ ' ' + *I
;
309 CurrentSize
+= FileSize
;
317 if(NotFound
== 0 && WrongSize
== 0)
318 ioprintf(msg
, _("Wrote %i records.\n"), Packages
);
319 else if (NotFound
!= 0 && WrongSize
== 0)
320 ioprintf(msg
, _("Wrote %i records with %i missing files.\n"),
322 else if (NotFound
== 0 && WrongSize
!= 0)
323 ioprintf(msg
, _("Wrote %i records with %i mismatched files\n"),
324 Packages
, WrongSize
);
325 if (NotFound
!= 0 && WrongSize
!= 0)
326 ioprintf(msg
, _("Wrote %i records with %i missing files and %i mismatched files\n"), Packages
, NotFound
, WrongSize
);
330 _error
->Warning("No valid records were found.");
332 if (NotFound
+ WrongSize
> 10)
333 _error
->Warning("A lot of entries were discarded, something may be wrong.\n");
339 // IndexCopy::ChopDirs - Chop off the leading directory components /*{{{*/
340 // ---------------------------------------------------------------------
342 string
IndexCopy::ChopDirs(string Path
,unsigned int Depth
)
344 string::size_type I
= 0;
347 I
= Path
.find('/',I
+1);
350 while (I
!= string::npos
&& Depth
!= 0);
352 if (I
== string::npos
)
355 return string(Path
,I
+1);
358 // IndexCopy::ReconstructPrefix - Fix strange prefixing /*{{{*/
359 // ---------------------------------------------------------------------
360 /* This prepends dir components from the path to the package files to
361 the path to the deb until it is found */
362 bool IndexCopy::ReconstructPrefix(string
&Prefix
,string OrigPath
,string CD
,
365 bool Debug
= _config
->FindB("Debug::aptcdrom",false);
366 unsigned int Depth
= 1;
367 string MyPrefix
= Prefix
;
371 if (stat(string(CD
+ MyPrefix
+ File
).c_str(),&Buf
) != 0)
374 cout
<< "Failed, " << CD
+ MyPrefix
+ File
<< endl
;
375 if (GrabFirst(OrigPath
,MyPrefix
,Depth
++) == true)
389 // IndexCopy::ReconstructChop - Fixes bad source paths /*{{{*/
390 // ---------------------------------------------------------------------
391 /* This removes path components from the filename and prepends the location
392 of the package files until a file is found */
393 bool IndexCopy::ReconstructChop(unsigned long &Chop
,string Dir
,string File
)
395 // Attempt to reconstruct the filename
396 unsigned long Depth
= 0;
400 if (stat(string(Dir
+ File
).c_str(),&Buf
) != 0)
402 File
= ChopDirs(File
,1);
404 if (File
.empty() == false)
417 // IndexCopy::ConvertToSourceList - Convert a Path to a sourcelist /*{{{*/
418 // ---------------------------------------------------------------------
419 /* We look for things in dists/ notation and convert them to
420 <dist> <component> form otherwise it is left alone. This also strips
423 This implements a regex sort of like:
424 (.*)/dists/([^/]*)/(.*)/binary-*
426 | |-------- Distribution
427 |------------------- Path
429 It was deciced to use only a single word for dist (rather than say
430 unstable/non-us) to increase the chance that each CD gets a single
431 line in sources.list.
433 void IndexCopy::ConvertToSourceList(string CD
,string
&Path
)
436 snprintf(S
,sizeof(S
),"binary-%s",_config
->Find("Apt::Architecture").c_str());
438 // Strip the cdrom base path
439 Path
= string(Path
,CD
.length());
440 if (Path
.empty() == true)
443 // Too short to be a dists/ type
444 if (Path
.length() < strlen("dists/"))
448 if (stringcmp(Path
.c_str(),Path
.c_str()+strlen("dists/"),"dists/") != 0)
452 string::size_type Slash
= strlen("dists/");
453 string::size_type Slash2
= Path
.find('/',Slash
+ 1);
454 if (Slash2
== string::npos
|| Slash2
+ 2 >= Path
.length())
456 string Dist
= string(Path
,Slash
,Slash2
- Slash
);
458 // Isolate the component
460 for (unsigned I
= 0; I
!= 10; I
++)
462 Slash
= Path
.find('/',Slash
+1);
463 if (Slash
== string::npos
|| Slash
+ 2 >= Path
.length())
465 string Comp
= string(Path
,Slash2
+1,Slash
- Slash2
-1);
467 // Verify the trailing binary- bit
468 string::size_type BinSlash
= Path
.find('/',Slash
+ 1);
469 if (Slash
== string::npos
)
471 string Binary
= string(Path
,Slash
+1,BinSlash
- Slash
-1);
473 if (Binary
!= S
&& Binary
!= "source")
476 Path
= Dist
+ ' ' + Comp
;
481 // IndexCopy::GrabFirst - Return the first Depth path components /*{{{*/
482 // ---------------------------------------------------------------------
484 bool IndexCopy::GrabFirst(string Path
,string
&To
,unsigned int Depth
)
486 string::size_type I
= 0;
489 I
= Path
.find('/',I
+1);
492 while (I
!= string::npos
&& Depth
!= 0);
494 if (I
== string::npos
)
497 To
= string(Path
,0,I
+1);
501 // PackageCopy::GetFile - Get the file information from the section /*{{{*/
502 // ---------------------------------------------------------------------
504 bool PackageCopy::GetFile(string
&File
,unsigned long long &Size
)
506 File
= Section
->FindS("Filename");
507 Size
= Section
->FindI("Size");
508 if (File
.empty() || Size
== 0)
509 return _error
->Error("Cannot find filename or size tag");
513 // PackageCopy::RewriteEntry - Rewrite the entry with a new filename /*{{{*/
514 // ---------------------------------------------------------------------
516 bool PackageCopy::RewriteEntry(FILE *Target
,string File
)
518 TFRewriteData Changes
[] = {{"Filename",File
.c_str()},
521 if (TFRewrite(Target
,*Section
,TFRewritePackageOrder
,Changes
) == false)
527 // SourceCopy::GetFile - Get the file information from the section /*{{{*/
528 // ---------------------------------------------------------------------
530 bool SourceCopy::GetFile(string
&File
,unsigned long long &Size
)
532 string Files
= Section
->FindS("Files");
533 if (Files
.empty() == true)
536 // Stash the / terminated directory prefix
537 string Base
= Section
->FindS("Directory");
538 if (Base
.empty() == false && Base
[Base
.length()-1] != '/')
541 // Read the first file triplet
542 const char *C
= Files
.c_str();
546 // Parse each of the elements
547 if (ParseQuoteWord(C
,MD5Hash
) == false ||
548 ParseQuoteWord(C
,sSize
) == false ||
549 ParseQuoteWord(C
,File
) == false)
550 return _error
->Error("Error parsing file record");
552 // Parse the size and append the directory
553 Size
= strtoull(sSize
.c_str(), NULL
, 10);
558 // SourceCopy::RewriteEntry - Rewrite the entry with a new filename /*{{{*/
559 // ---------------------------------------------------------------------
561 bool SourceCopy::RewriteEntry(FILE *Target
,string File
)
563 string
Dir(File
,0,File
.rfind('/'));
564 TFRewriteData Changes
[] = {{"Directory",Dir
.c_str()},
567 if (TFRewrite(Target
,*Section
,TFRewriteSourceOrder
,Changes
) == false)
573 // SigVerify::Verify - Verify a files md5sum against its metaindex /*{{{*/
574 // ---------------------------------------------------------------------
576 bool SigVerify::Verify(string prefix
, string file
, indexRecords
*MetaIndex
)
578 const indexRecords::checkSum
*Record
= MetaIndex
->Lookup(file
);
580 // we skip non-existing files in the verifcation to support a cdrom
581 // with no Packages file (just a Package.gz), see LP: #255545
582 // (non-existing files are not considered a error)
583 if(!RealFileExists(prefix
+file
))
585 _error
->Warning(_("Skipping nonexistent file %s"), string(prefix
+file
).c_str());
591 _error
->Warning(_("Can't find authentication record for: %s"), file
.c_str());
595 if (!Record
->Hash
.VerifyFile(prefix
+file
))
597 _error
->Warning(_("Hash mismatch for: %s"),file
.c_str());
601 if(_config
->FindB("Debug::aptcdrom",false))
603 cout
<< "File: " << prefix
+file
<< endl
;
604 cout
<< "Expected Hash " << Record
->Hash
.toStr() << endl
;
610 bool SigVerify::CopyMetaIndex(string CDROM
, string CDName
, /*{{{*/
611 string prefix
, string file
)
614 snprintf(S
,sizeof(S
),"cdrom:[%s]/%s%s",CDName
.c_str(),
615 (prefix
).c_str() + CDROM
.length(),file
.c_str());
616 string TargetF
= _config
->FindDir("Dir::State::lists");
617 TargetF
+= URItoFileName(S
);
621 Target
.Open(TargetF
,FileFd::WriteAtomic
);
622 Rel
.Open(prefix
+ file
,FileFd::ReadOnly
);
623 if (_error
->PendingError() == true)
625 if (CopyFile(Rel
,Target
) == false)
631 bool SigVerify::CopyAndVerify(string CDROM
,string Name
,vector
<string
> &SigList
, /*{{{*/
632 vector
<string
> PkgList
,vector
<string
> SrcList
)
634 if (SigList
.empty() == true)
637 bool Debug
= _config
->FindB("Debug::aptcdrom",false);
639 // Read all Release files
640 for (vector
<string
>::iterator I
= SigList
.begin(); I
!= SigList
.end(); ++I
)
643 cout
<< "Signature verify for: " << *I
<< endl
;
645 indexRecords
*MetaIndex
= new indexRecords
;
648 string
const releasegpg
= *I
+"Release.gpg";
649 string
const release
= *I
+"Release";
651 // a Release.gpg without a Release should never happen
652 if(RealFileExists(release
) == false)
658 pid_t pid
= ExecFork();
660 _error
->Error("Fork failed");
664 RunGPGV(release
, releasegpg
);
666 if(!ExecWait(pid
, "gpgv")) {
667 _error
->Warning("Signature verification failed for: %s",
669 // something went wrong, don't copy the Release.gpg
670 // FIXME: delete any existing gpg file?
674 // Open the Release file and add it to the MetaIndex
675 if(!MetaIndex
->Load(release
))
677 _error
->Error("%s",MetaIndex
->ErrorText
.c_str());
681 // go over the Indexfiles and see if they verify
682 // if so, remove them from our copy of the lists
683 vector
<string
> keys
= MetaIndex
->MetaKeys();
684 for (vector
<string
>::iterator I
= keys
.begin(); I
!= keys
.end(); ++I
)
686 if(!Verify(prefix
,*I
, MetaIndex
)) {
687 // something went wrong, don't copy the Release.gpg
688 // FIXME: delete any existing gpg file?
694 // we need a fresh one for the Release.gpg
697 // everything was fine, copy the Release and Release.gpg file
698 CopyMetaIndex(CDROM
, Name
, prefix
, "Release");
699 CopyMetaIndex(CDROM
, Name
, prefix
, "Release.gpg");
705 // SigVerify::RunGPGV - returns the command needed for verify /*{{{*/
706 // ---------------------------------------------------------------------
707 /* Generating the commandline for calling gpgv is somehow complicated as
708 we need to add multiple keyrings and user supplied options. Also, as
709 the cdrom code currently can not use the gpgv method we have two places
710 these need to be done - so the place for this method is wrong but better
711 than code duplication… */
712 bool SigVerify::RunGPGV(std::string
const &File
, std::string
const &FileGPG
,
713 int const &statusfd
, int fd
[2])
717 #define SIGMSG "-----BEGIN PGP SIGNED MESSAGE-----\n"
718 char buffer
[sizeof(SIGMSG
)];
719 FILE* gpg
= fopen(File
.c_str(), "r");
721 return _error
->Errno("RunGPGV", _("Could not open file %s"), File
.c_str());
722 char const * const test
= fgets(buffer
, sizeof(buffer
), gpg
);
724 if (test
== NULL
|| strcmp(buffer
, SIGMSG
) != 0)
725 return _error
->Error(_("File %s doesn't start with a clearsigned message"), File
.c_str());
730 string
const gpgvpath
= _config
->Find("Dir::Bin::gpg", "/usr/bin/gpgv");
731 // FIXME: remove support for deprecated APT::GPGV setting
732 string
const trustedFile
= _config
->Find("APT::GPGV::TrustedKeyring", _config
->FindFile("Dir::Etc::Trusted"));
733 string
const trustedPath
= _config
->FindDir("Dir::Etc::TrustedParts");
735 bool const Debug
= _config
->FindB("Debug::Acquire::gpgv", false);
739 std::clog
<< "gpgv path: " << gpgvpath
<< std::endl
;
740 std::clog
<< "Keyring file: " << trustedFile
<< std::endl
;
741 std::clog
<< "Keyring path: " << trustedPath
<< std::endl
;
744 std::vector
<string
> keyrings
;
745 if (DirectoryExists(trustedPath
))
746 keyrings
= GetListOfFilesInDir(trustedPath
, "gpg", false, true);
747 if (RealFileExists(trustedFile
) == true)
748 keyrings
.push_back(trustedFile
);
750 std::vector
<const char *> Args
;
753 if (keyrings
.empty() == true)
755 // TRANSLATOR: %s is the trusted keyring parts directory
756 return _error
->Error(_("No keyring installed in %s."),
757 _config
->FindDir("Dir::Etc::TrustedParts").c_str());
760 Args
.push_back(gpgvpath
.c_str());
761 Args
.push_back("--ignore-time-conflict");
765 Args
.push_back("--status-fd");
767 snprintf(fd
, sizeof(fd
), "%i", statusfd
);
771 for (vector
<string
>::const_iterator K
= keyrings
.begin();
772 K
!= keyrings
.end(); ++K
)
774 Args
.push_back("--keyring");
775 Args
.push_back(K
->c_str());
778 Configuration::Item
const *Opts
;
779 Opts
= _config
->Tree("Acquire::gpgv::Options");
783 for (; Opts
!= 0; Opts
= Opts
->Next
)
785 if (Opts
->Value
.empty() == true)
787 Args
.push_back(Opts
->Value
.c_str());
791 Args
.push_back(FileGPG
.c_str());
793 Args
.push_back(File
.c_str());
794 Args
.push_back(NULL
);
798 std::clog
<< "Preparing to exec: " << gpgvpath
;
799 for (std::vector
<const char *>::const_iterator a
= Args
.begin(); *a
!= NULL
; ++a
)
800 std::clog
<< " " << *a
;
801 std::clog
<< std::endl
;
806 int const nullfd
= open("/dev/null", O_RDONLY
);
808 // Redirect output to /dev/null; we read from the status fd
809 dup2(nullfd
, STDOUT_FILENO
);
810 dup2(nullfd
, STDERR_FILENO
);
811 // Redirect the pipe to the status fd (3)
812 dup2(fd
[1], statusfd
);
814 putenv((char *)"LANG=");
815 putenv((char *)"LC_ALL=");
816 putenv((char *)"LC_MESSAGES=");
819 execvp(gpgvpath
.c_str(), (char **) &Args
[0]);
823 bool TranslationsCopy::CopyTranslations(string CDROM
,string Name
, /*{{{*/
824 vector
<string
> &List
, pkgCdromStatus
*log
)
826 OpProgress
*Progress
= NULL
;
827 if (List
.empty() == true)
831 Progress
= log
->GetOpProgress();
833 bool Debug
= _config
->FindB("Debug::aptcdrom",false);
835 // Prepare the progress indicator
837 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); ++I
)
841 if (stat(string(*I
).c_str(),&Buf
) != 0 &&
842 stat(string(*I
+ ".gz").c_str(),&Buf
) != 0 &&
843 stat(string(*I
+ ".bz2").c_str(),&Buf
) != 0 &&
844 stat(string(*I
+ ".xz").c_str(),&Buf
) != 0)
845 return _error
->Errno("stat","Stat failed for %s",
847 TotalSize
+= Buf
.st_size
;
850 off_t CurrentSize
= 0;
851 unsigned int NotFound
= 0;
852 unsigned int WrongSize
= 0;
853 unsigned int Packages
= 0;
854 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); ++I
)
856 string OrigPath
= string(*I
,CDROM
.length());
859 // Open the package file
861 if (RealFileExists(*I
) == true)
863 Pkg
.Open(*I
,FileFd::ReadOnly
);
864 FileSize
= Pkg
.Size();
869 if (!DecompressFile(*I
, &fd
, &FileSize
))
870 return _error
->Errno("decompress","Decompress failed for %s", (*I
).c_str());
874 pkgTagFile
Parser(&Pkg
);
875 if (_error
->PendingError() == true)
878 // Open the output file
880 snprintf(S
,sizeof(S
),"cdrom:[%s]/%s",Name
.c_str(),
881 (*I
).c_str() + CDROM
.length());
882 string TargetF
= _config
->FindDir("Dir::State::lists") + "partial/";
883 TargetF
+= URItoFileName(S
);
884 if (_config
->FindB("APT::CDROM::NoAct",false) == true)
885 TargetF
= "/dev/null";
886 FileFd
Target(TargetF
,FileFd::WriteAtomic
);
887 FILE *TargetFl
= fdopen(dup(Target
.Fd()),"w");
888 if (_error
->PendingError() == true)
891 return _error
->Errno("fdopen","Failed to reopen fd");
893 // Setup the progress meter
895 Progress
->OverallProgress(CurrentSize
,TotalSize
,FileSize
,
896 string("Reading Translation Indexes"));
900 Progress
->SubProgress(Pkg
.Size());
901 pkgTagSection Section
;
902 this->Section
= &Section
;
904 unsigned long Hits
= 0;
905 while (Parser
.Step(Section
) == true)
908 Progress
->Progress(Parser
.Offset());
912 Section
.GetSection(Start
,Stop
);
913 fwrite(Start
,Stop
-Start
, 1, TargetFl
);
914 fputc('\n',TargetFl
);
922 cout
<< " Processed by using Prefix '" << Prefix
<< "' and chop " << endl
;
924 if (_config
->FindB("APT::CDROM::NoAct",false) == false)
926 // Move out of the partial directory
928 string FinalF
= _config
->FindDir("Dir::State::lists");
929 FinalF
+= URItoFileName(S
);
930 if (rename(TargetF
.c_str(),FinalF
.c_str()) != 0)
931 return _error
->Errno("rename","Failed to rename");
935 CurrentSize
+= FileSize
;
943 if(NotFound
== 0 && WrongSize
== 0)
944 ioprintf(msg
, _("Wrote %i records.\n"), Packages
);
945 else if (NotFound
!= 0 && WrongSize
== 0)
946 ioprintf(msg
, _("Wrote %i records with %i missing files.\n"),
948 else if (NotFound
== 0 && WrongSize
!= 0)
949 ioprintf(msg
, _("Wrote %i records with %i mismatched files\n"),
950 Packages
, WrongSize
);
951 if (NotFound
!= 0 && WrongSize
!= 0)
952 ioprintf(msg
, _("Wrote %i records with %i missing files and %i mismatched files\n"), Packages
, NotFound
, WrongSize
);
956 _error
->Warning("No valid records were found.");
958 if (NotFound
+ WrongSize
> 10)
959 _error
->Warning("A lot of entries were discarded, something may be wrong.\n");