]>
git.saurik.com Git - apt.git/blob - apt-pkg/indexcopy.cc
dcba78dce6390b7edfb33fe0975853023b30bc1b
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>
33 #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
;
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
58 unsigned long TotalSize
= 0;
59 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
62 if (stat(string(*I
+ GetFileName()).c_str(),&Buf
) != 0 &&
63 stat(string(*I
+ GetFileName() + ".gz").c_str(),&Buf
) != 0)
64 return _error
->Errno("stat","Stat failed for %s",
65 string(*I
+ GetFileName()).c_str());
66 TotalSize
+= Buf
.st_size
;
69 unsigned long CurrentSize
= 0;
70 unsigned int NotFound
= 0;
71 unsigned int WrongSize
= 0;
72 unsigned int Packages
= 0;
73 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
75 string OrigPath
= string(*I
,CDROM
.length());
76 unsigned long FileSize
= 0;
78 // Open the package file
80 if (RealFileExists(*I
+ GetFileName()) == true)
82 Pkg
.Open(*I
+ GetFileName(),FileFd::ReadOnly
);
83 FileSize
= Pkg
.Size();
87 FileFd
From(*I
+ GetFileName() + ".gz",FileFd::ReadOnly
);
88 if (_error
->PendingError() == true)
90 FileSize
= From
.Size();
93 FILE *tmp
= tmpfile();
95 return _error
->Errno("tmpfile","Unable to create a tmp file");
96 Pkg
.Fd(dup(fileno(tmp
)));
100 pid_t Process
= fork();
102 return _error
->Errno("fork","Couldn't fork gzip");
107 dup2(From
.Fd(),STDIN_FILENO
);
108 dup2(Pkg
.Fd(),STDOUT_FILENO
);
109 SetCloseExec(STDIN_FILENO
,false);
110 SetCloseExec(STDOUT_FILENO
,false);
113 string Tmp
= _config
->Find("Dir::bin::gzip","gzip");
114 Args
[0] = Tmp
.c_str();
117 execvp(Args
[0],(char **)Args
);
121 // Wait for gzip to finish
122 if (ExecWait(Process
,_config
->Find("Dir::bin::gzip","gzip").c_str(),false) == false)
123 return _error
->Error("gzip failed, perhaps the disk is full.");
127 pkgTagFile
Parser(&Pkg
);
128 if (_error
->PendingError() == true)
131 // Open the output file
133 snprintf(S
,sizeof(S
),"cdrom:[%s]/%s%s",Name
.c_str(),
134 (*I
).c_str() + CDROM
.length(),GetFileName());
135 string TargetF
= _config
->FindDir("Dir::State::lists") + "partial/";
136 TargetF
+= URItoFileName(S
);
138 if (_config
->FindB("APT::CDROM::NoAct",false) == true)
140 TargetF
= "/dev/null";
141 Target
.Open(TargetF
,FileFd::WriteExists
);
143 Target
.Open(TargetF
,FileFd::WriteAtomic
);
145 FILE *TargetFl
= fdopen(dup(Target
.Fd()),"w");
146 if (_error
->PendingError() == true)
149 return _error
->Errno("fdopen","Failed to reopen fd");
151 // Setup the progress meter
153 Progress
->OverallProgress(CurrentSize
,TotalSize
,FileSize
,
154 string("Reading ") + Type() + " Indexes");
158 Progress
->SubProgress(Pkg
.Size());
159 pkgTagSection Section
;
160 this->Section
= &Section
;
162 unsigned long Hits
= 0;
163 unsigned long Chop
= 0;
164 while (Parser
.Step(Section
) == true)
167 Progress
->Progress(Parser
.Offset());
170 if (GetFile(File
,Size
) == false)
177 File
= OrigPath
+ ChopDirs(File
,Chop
);
179 // See if the file exists
180 bool Mangled
= false;
181 if (NoStat
== false || Hits
< 10)
183 // Attempt to fix broken structure
186 if (ReconstructPrefix(Prefix
,OrigPath
,CDROM
,File
) == false &&
187 ReconstructChop(Chop
,*I
,File
) == false)
190 clog
<< "Missed: " << File
<< endl
;
195 File
= OrigPath
+ ChopDirs(File
,Chop
);
200 if (stat(string(CDROM
+ Prefix
+ File
).c_str(),&Buf
) != 0 ||
203 // Attempt to fix busted symlink support for one instance
204 string OrigFile
= File
;
205 string::size_type Start
= File
.find("binary-");
206 string::size_type End
= File
.find("/",Start
+3);
207 if (Start
!= string::npos
&& End
!= string::npos
)
209 File
.replace(Start
,End
-Start
,"binary-all");
213 if (Mangled
== false ||
214 stat(string(CDROM
+ Prefix
+ File
).c_str(),&Buf
) != 0)
217 clog
<< "Missed(2): " << OrigFile
<< endl
;
224 if ((unsigned)Buf
.st_size
!= Size
)
227 clog
<< "Wrong Size: " << File
<< endl
;
236 if (RewriteEntry(TargetFl
,File
) == false)
245 cout
<< " Processed by using Prefix '" << Prefix
<< "' and chop " << Chop
<< endl
;
247 if (_config
->FindB("APT::CDROM::NoAct",false) == false)
249 // Move out of the partial directory
251 string FinalF
= _config
->FindDir("Dir::State::lists");
252 FinalF
+= URItoFileName(S
);
253 if (rename(TargetF
.c_str(),FinalF
.c_str()) != 0)
254 return _error
->Errno("rename","Failed to rename");
257 /* Mangle the source to be in the proper notation with
258 prefix dist [component] */
259 *I
= string(*I
,Prefix
.length());
260 ConvertToSourceList(CDROM
,*I
);
261 *I
= Prefix
+ ' ' + *I
;
263 CurrentSize
+= FileSize
;
271 if(NotFound
== 0 && WrongSize
== 0)
272 ioprintf(msg
, _("Wrote %i records.\n"), Packages
);
273 else if (NotFound
!= 0 && WrongSize
== 0)
274 ioprintf(msg
, _("Wrote %i records with %i missing files.\n"),
276 else if (NotFound
== 0 && WrongSize
!= 0)
277 ioprintf(msg
, _("Wrote %i records with %i mismatched files\n"),
278 Packages
, WrongSize
);
279 if (NotFound
!= 0 && WrongSize
!= 0)
280 ioprintf(msg
, _("Wrote %i records with %i missing files and %i mismatched files\n"), Packages
, NotFound
, WrongSize
);
284 _error
->Warning("No valid records were found.");
286 if (NotFound
+ WrongSize
> 10)
287 _error
->Warning("A lot of entries were discarded, something may be wrong.\n");
293 // IndexCopy::ChopDirs - Chop off the leading directory components /*{{{*/
294 // ---------------------------------------------------------------------
296 string
IndexCopy::ChopDirs(string Path
,unsigned int Depth
)
298 string::size_type I
= 0;
301 I
= Path
.find('/',I
+1);
304 while (I
!= string::npos
&& Depth
!= 0);
306 if (I
== string::npos
)
309 return string(Path
,I
+1);
312 // IndexCopy::ReconstructPrefix - Fix strange prefixing /*{{{*/
313 // ---------------------------------------------------------------------
314 /* This prepends dir components from the path to the package files to
315 the path to the deb until it is found */
316 bool IndexCopy::ReconstructPrefix(string
&Prefix
,string OrigPath
,string CD
,
319 bool Debug
= _config
->FindB("Debug::aptcdrom",false);
320 unsigned int Depth
= 1;
321 string MyPrefix
= Prefix
;
325 if (stat(string(CD
+ MyPrefix
+ File
).c_str(),&Buf
) != 0)
328 cout
<< "Failed, " << CD
+ MyPrefix
+ File
<< endl
;
329 if (GrabFirst(OrigPath
,MyPrefix
,Depth
++) == true)
343 // IndexCopy::ReconstructChop - Fixes bad source paths /*{{{*/
344 // ---------------------------------------------------------------------
345 /* This removes path components from the filename and prepends the location
346 of the package files until a file is found */
347 bool IndexCopy::ReconstructChop(unsigned long &Chop
,string Dir
,string File
)
349 // Attempt to reconstruct the filename
350 unsigned long Depth
= 0;
354 if (stat(string(Dir
+ File
).c_str(),&Buf
) != 0)
356 File
= ChopDirs(File
,1);
358 if (File
.empty() == false)
371 // IndexCopy::ConvertToSourceList - Convert a Path to a sourcelist /*{{{*/
372 // ---------------------------------------------------------------------
373 /* We look for things in dists/ notation and convert them to
374 <dist> <component> form otherwise it is left alone. This also strips
377 This implements a regex sort of like:
378 (.*)/dists/([^/]*)/(.*)/binary-*
380 | |-------- Distribution
381 |------------------- Path
383 It was deciced to use only a single word for dist (rather than say
384 unstable/non-us) to increase the chance that each CD gets a single
385 line in sources.list.
387 void IndexCopy::ConvertToSourceList(string CD
,string
&Path
)
390 snprintf(S
,sizeof(S
),"binary-%s",_config
->Find("Apt::Architecture").c_str());
392 // Strip the cdrom base path
393 Path
= string(Path
,CD
.length());
394 if (Path
.empty() == true)
397 // Too short to be a dists/ type
398 if (Path
.length() < strlen("dists/"))
402 if (stringcmp(Path
.c_str(),Path
.c_str()+strlen("dists/"),"dists/") != 0)
406 string::size_type Slash
= strlen("dists/");
407 string::size_type Slash2
= Path
.find('/',Slash
+ 1);
408 if (Slash2
== string::npos
|| Slash2
+ 2 >= Path
.length())
410 string Dist
= string(Path
,Slash
,Slash2
- Slash
);
412 // Isolate the component
414 for (unsigned I
= 0; I
!= 10; I
++)
416 Slash
= Path
.find('/',Slash
+1);
417 if (Slash
== string::npos
|| Slash
+ 2 >= Path
.length())
419 string Comp
= string(Path
,Slash2
+1,Slash
- Slash2
-1);
421 // Verify the trailing binary- bit
422 string::size_type BinSlash
= Path
.find('/',Slash
+ 1);
423 if (Slash
== string::npos
)
425 string Binary
= string(Path
,Slash
+1,BinSlash
- Slash
-1);
427 if (Binary
!= S
&& Binary
!= "source")
430 Path
= Dist
+ ' ' + Comp
;
435 // IndexCopy::GrabFirst - Return the first Depth path components /*{{{*/
436 // ---------------------------------------------------------------------
438 bool IndexCopy::GrabFirst(string Path
,string
&To
,unsigned int Depth
)
440 string::size_type I
= 0;
443 I
= Path
.find('/',I
+1);
446 while (I
!= string::npos
&& Depth
!= 0);
448 if (I
== string::npos
)
451 To
= string(Path
,0,I
+1);
455 // PackageCopy::GetFile - Get the file information from the section /*{{{*/
456 // ---------------------------------------------------------------------
458 bool PackageCopy::GetFile(string
&File
,unsigned long &Size
)
460 File
= Section
->FindS("Filename");
461 Size
= Section
->FindI("Size");
462 if (File
.empty() || Size
== 0)
463 return _error
->Error("Cannot find filename or size tag");
467 // PackageCopy::RewriteEntry - Rewrite the entry with a new filename /*{{{*/
468 // ---------------------------------------------------------------------
470 bool PackageCopy::RewriteEntry(FILE *Target
,string File
)
472 TFRewriteData Changes
[] = {{"Filename",File
.c_str()},
475 if (TFRewrite(Target
,*Section
,TFRewritePackageOrder
,Changes
) == false)
481 // SourceCopy::GetFile - Get the file information from the section /*{{{*/
482 // ---------------------------------------------------------------------
484 bool SourceCopy::GetFile(string
&File
,unsigned long &Size
)
486 string Files
= Section
->FindS("Files");
487 if (Files
.empty() == true)
490 // Stash the / terminated directory prefix
491 string Base
= Section
->FindS("Directory");
492 if (Base
.empty() == false && Base
[Base
.length()-1] != '/')
495 // Read the first file triplet
496 const char *C
= Files
.c_str();
500 // Parse each of the elements
501 if (ParseQuoteWord(C
,MD5Hash
) == false ||
502 ParseQuoteWord(C
,sSize
) == false ||
503 ParseQuoteWord(C
,File
) == false)
504 return _error
->Error("Error parsing file record");
506 // Parse the size and append the directory
507 Size
= atoi(sSize
.c_str());
512 // SourceCopy::RewriteEntry - Rewrite the entry with a new filename /*{{{*/
513 // ---------------------------------------------------------------------
515 bool SourceCopy::RewriteEntry(FILE *Target
,string File
)
517 string
Dir(File
,0,File
.rfind('/'));
518 TFRewriteData Changes
[] = {{"Directory",Dir
.c_str()},
521 if (TFRewrite(Target
,*Section
,TFRewriteSourceOrder
,Changes
) == false)
527 // SigVerify::Verify - Verify a files md5sum against its metaindex /*{{{*/
528 // ---------------------------------------------------------------------
530 bool SigVerify::Verify(string prefix
, string file
, indexRecords
*MetaIndex
)
532 const indexRecords::checkSum
*Record
= MetaIndex
->Lookup(file
);
534 // we skip non-existing files in the verifcation to support a cdrom
535 // with no Packages file (just a Package.gz), see LP: #255545
536 // (non-existing files are not considered a error)
537 if(!RealFileExists(prefix
+file
))
539 _error
->Warning(_("Skipping nonexistent file %s"), string(prefix
+file
).c_str());
545 _error
->Warning(_("Can't find authentication record for: %s"), file
.c_str());
549 if (!Record
->Hash
.VerifyFile(prefix
+file
))
551 _error
->Warning(_("Hash mismatch for: %s"),file
.c_str());
555 if(_config
->FindB("Debug::aptcdrom",false))
557 cout
<< "File: " << prefix
+file
<< endl
;
558 cout
<< "Expected Hash " << Record
->Hash
.toStr() << endl
;
564 bool SigVerify::CopyMetaIndex(string CDROM
, string CDName
, /*{{{*/
565 string prefix
, string file
)
568 snprintf(S
,sizeof(S
),"cdrom:[%s]/%s%s",CDName
.c_str(),
569 (prefix
).c_str() + CDROM
.length(),file
.c_str());
570 string TargetF
= _config
->FindDir("Dir::State::lists");
571 TargetF
+= URItoFileName(S
);
575 Target
.Open(TargetF
,FileFd::WriteAtomic
);
576 Rel
.Open(prefix
+ file
,FileFd::ReadOnly
);
577 if (_error
->PendingError() == true)
579 if (CopyFile(Rel
,Target
) == false)
585 bool SigVerify::CopyAndVerify(string CDROM
,string Name
,vector
<string
> &SigList
, /*{{{*/
586 vector
<string
> PkgList
,vector
<string
> SrcList
)
588 if (SigList
.size() == 0)
591 bool Debug
= _config
->FindB("Debug::aptcdrom",false);
593 // Read all Release files
594 for (vector
<string
>::iterator I
= SigList
.begin(); I
!= SigList
.end(); I
++)
597 cout
<< "Signature verify for: " << *I
<< endl
;
599 indexRecords
*MetaIndex
= new indexRecords
;
602 string
const releasegpg
= *I
+"Release.gpg";
603 string
const release
= *I
+"Release";
605 // a Release.gpg without a Release should never happen
606 if(RealFileExists(release
) == false)
612 pid_t pid
= ExecFork();
614 _error
->Error("Fork failed");
618 RunGPGV(release
, releasegpg
);
620 if(!ExecWait(pid
, "gpgv")) {
621 _error
->Warning("Signature verification failed for: %s",
623 // something went wrong, don't copy the Release.gpg
624 // FIXME: delete any existing gpg file?
628 // Open the Release file and add it to the MetaIndex
629 if(!MetaIndex
->Load(release
))
631 _error
->Error("%s",MetaIndex
->ErrorText
.c_str());
635 // go over the Indexfiles and see if they verify
636 // if so, remove them from our copy of the lists
637 vector
<string
> keys
= MetaIndex
->MetaKeys();
638 for (vector
<string
>::iterator I
= keys
.begin(); I
!= keys
.end(); I
++)
640 if(!Verify(prefix
,*I
, MetaIndex
)) {
641 // something went wrong, don't copy the Release.gpg
642 // FIXME: delete any existing gpg file?
648 // we need a fresh one for the Release.gpg
651 // everything was fine, copy the Release and Release.gpg file
652 CopyMetaIndex(CDROM
, Name
, prefix
, "Release");
653 CopyMetaIndex(CDROM
, Name
, prefix
, "Release.gpg");
659 // SigVerify::RunGPGV - returns the command needed for verify /*{{{*/
660 // ---------------------------------------------------------------------
661 /* Generating the commandline for calling gpgv is somehow complicated as
662 we need to add multiple keyrings and user supplied options. Also, as
663 the cdrom code currently can not use the gpgv method we have two places
664 these need to be done - so the place for this method is wrong but better
665 than code duplication… */
666 bool SigVerify::RunGPGV(std::string
const &File
, std::string
const &FileGPG
,
667 int const &statusfd
, int fd
[2])
671 #define SIGMSG "-----BEGIN PGP SIGNED MESSAGE-----\n"
672 char buffer
[sizeof(SIGMSG
)];
673 FILE* gpg
= fopen(File
.c_str(), "r");
675 return _error
->Errno("RunGPGV", _("Could not open file %s"), File
.c_str());
676 char const * const test
= fgets(buffer
, sizeof(buffer
), gpg
);
678 if (test
== NULL
|| strcmp(buffer
, SIGMSG
) != 0)
679 return _error
->Error(_("File %s doesn't start with a clearsigned message"), File
.c_str());
684 string
const gpgvpath
= _config
->Find("Dir::Bin::gpg", "/usr/bin/gpgv");
685 // FIXME: remove support for deprecated APT::GPGV setting
686 string
const trustedFile
= _config
->Find("APT::GPGV::TrustedKeyring", _config
->FindFile("Dir::Etc::Trusted"));
687 string
const trustedPath
= _config
->FindDir("Dir::Etc::TrustedParts");
689 bool const Debug
= _config
->FindB("Debug::Acquire::gpgv", false);
693 std::clog
<< "gpgv path: " << gpgvpath
<< std::endl
;
694 std::clog
<< "Keyring file: " << trustedFile
<< std::endl
;
695 std::clog
<< "Keyring path: " << trustedPath
<< std::endl
;
698 std::vector
<string
> keyrings
;
699 if (DirectoryExists(trustedPath
))
700 keyrings
= GetListOfFilesInDir(trustedPath
, "gpg", false, true);
701 if (RealFileExists(trustedFile
) == true)
702 keyrings
.push_back(trustedFile
);
704 std::vector
<const char *> Args
;
707 if (keyrings
.empty() == true)
709 // TRANSLATOR: %s is the trusted keyring parts directory
710 return _error
->Error(_("No keyring installed in %s."),
711 _config
->FindDir("Dir::Etc::TrustedParts").c_str());
714 Args
.push_back(gpgvpath
.c_str());
715 Args
.push_back("--ignore-time-conflict");
719 Args
.push_back("--status-fd");
721 snprintf(fd
, sizeof(fd
), "%i", statusfd
);
725 for (vector
<string
>::const_iterator K
= keyrings
.begin();
726 K
!= keyrings
.end(); ++K
)
728 Args
.push_back("--keyring");
729 Args
.push_back(K
->c_str());
732 Configuration::Item
const *Opts
;
733 Opts
= _config
->Tree("Acquire::gpgv::Options");
737 for (; Opts
!= 0; Opts
= Opts
->Next
)
739 if (Opts
->Value
.empty() == true)
741 Args
.push_back(Opts
->Value
.c_str());
745 Args
.push_back(FileGPG
.c_str());
747 Args
.push_back(File
.c_str());
748 Args
.push_back(NULL
);
752 std::clog
<< "Preparing to exec: " << gpgvpath
;
753 for (std::vector
<const char *>::const_iterator a
= Args
.begin(); *a
!= NULL
; ++a
)
754 std::clog
<< " " << *a
;
755 std::clog
<< std::endl
;
760 int const nullfd
= open("/dev/null", O_RDONLY
);
762 // Redirect output to /dev/null; we read from the status fd
763 dup2(nullfd
, STDOUT_FILENO
);
764 dup2(nullfd
, STDERR_FILENO
);
765 // Redirect the pipe to the status fd (3)
766 dup2(fd
[1], statusfd
);
768 putenv((char *)"LANG=");
769 putenv((char *)"LC_ALL=");
770 putenv((char *)"LC_MESSAGES=");
773 execvp(gpgvpath
.c_str(), (char **) &Args
[0]);
777 bool TranslationsCopy::CopyTranslations(string CDROM
,string Name
, /*{{{*/
778 vector
<string
> &List
, pkgCdromStatus
*log
)
780 OpProgress
*Progress
= NULL
;
781 if (List
.size() == 0)
785 Progress
= log
->GetOpProgress();
787 bool Debug
= _config
->FindB("Debug::aptcdrom",false);
789 // Prepare the progress indicator
790 unsigned long TotalSize
= 0;
791 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
794 if (stat(string(*I
).c_str(),&Buf
) != 0 &&
795 stat(string(*I
+ ".gz").c_str(),&Buf
) != 0)
796 return _error
->Errno("stat","Stat failed for %s",
798 TotalSize
+= Buf
.st_size
;
801 unsigned long CurrentSize
= 0;
802 unsigned int NotFound
= 0;
803 unsigned int WrongSize
= 0;
804 unsigned int Packages
= 0;
805 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
807 string OrigPath
= string(*I
,CDROM
.length());
808 unsigned long FileSize
= 0;
810 // Open the package file
812 if (RealFileExists(*I
) == true)
814 Pkg
.Open(*I
,FileFd::ReadOnly
);
815 FileSize
= Pkg
.Size();
819 FileFd
From(*I
+ ".gz",FileFd::ReadOnly
);
820 if (_error
->PendingError() == true)
822 FileSize
= From
.Size();
825 FILE *tmp
= tmpfile();
827 return _error
->Errno("tmpfile","Unable to create a tmp file");
828 Pkg
.Fd(dup(fileno(tmp
)));
832 pid_t Process
= fork();
834 return _error
->Errno("fork","Couldn't fork gzip");
839 dup2(From
.Fd(),STDIN_FILENO
);
840 dup2(Pkg
.Fd(),STDOUT_FILENO
);
841 SetCloseExec(STDIN_FILENO
,false);
842 SetCloseExec(STDOUT_FILENO
,false);
845 string Tmp
= _config
->Find("Dir::bin::gzip","gzip");
846 Args
[0] = Tmp
.c_str();
849 execvp(Args
[0],(char **)Args
);
853 // Wait for gzip to finish
854 if (ExecWait(Process
,_config
->Find("Dir::bin::gzip","gzip").c_str(),false) == false)
855 return _error
->Error("gzip failed, perhaps the disk is full.");
859 pkgTagFile
Parser(&Pkg
);
860 if (_error
->PendingError() == true)
863 // Open the output file
865 snprintf(S
,sizeof(S
),"cdrom:[%s]/%s",Name
.c_str(),
866 (*I
).c_str() + CDROM
.length());
867 string TargetF
= _config
->FindDir("Dir::State::lists") + "partial/";
868 TargetF
+= URItoFileName(S
);
869 if (_config
->FindB("APT::CDROM::NoAct",false) == true)
870 TargetF
= "/dev/null";
871 FileFd
Target(TargetF
,FileFd::WriteAtomic
);
872 FILE *TargetFl
= fdopen(dup(Target
.Fd()),"w");
873 if (_error
->PendingError() == true)
876 return _error
->Errno("fdopen","Failed to reopen fd");
878 // Setup the progress meter
880 Progress
->OverallProgress(CurrentSize
,TotalSize
,FileSize
,
881 string("Reading Translation Indexes"));
885 Progress
->SubProgress(Pkg
.Size());
886 pkgTagSection Section
;
887 this->Section
= &Section
;
889 unsigned long Hits
= 0;
890 unsigned long Chop
= 0;
891 while (Parser
.Step(Section
) == true)
894 Progress
->Progress(Parser
.Offset());
898 Section
.GetSection(Start
,Stop
);
899 fwrite(Start
,Stop
-Start
, 1, TargetFl
);
900 fputc('\n',TargetFl
);
908 cout
<< " Processed by using Prefix '" << Prefix
<< "' and chop " << Chop
<< endl
;
910 if (_config
->FindB("APT::CDROM::NoAct",false) == false)
912 // Move out of the partial directory
914 string FinalF
= _config
->FindDir("Dir::State::lists");
915 FinalF
+= URItoFileName(S
);
916 if (rename(TargetF
.c_str(),FinalF
.c_str()) != 0)
917 return _error
->Errno("rename","Failed to rename");
921 CurrentSize
+= FileSize
;
929 if(NotFound
== 0 && WrongSize
== 0)
930 ioprintf(msg
, _("Wrote %i records.\n"), Packages
);
931 else if (NotFound
!= 0 && WrongSize
== 0)
932 ioprintf(msg
, _("Wrote %i records with %i missing files.\n"),
934 else if (NotFound
== 0 && WrongSize
!= 0)
935 ioprintf(msg
, _("Wrote %i records with %i mismatched files\n"),
936 Packages
, WrongSize
);
937 if (NotFound
!= 0 && WrongSize
!= 0)
938 ioprintf(msg
, _("Wrote %i records with %i missing files and %i mismatched files\n"), Packages
, NotFound
, WrongSize
);
942 _error
->Warning("No valid records were found.");
944 if (NotFound
+ WrongSize
> 10)
945 _error
->Warning("A lot of entries were discarded, something may be wrong.\n");