]>
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");