]> git.saurik.com Git - apt.git/blame - apt-pkg/indexcopy.cc
* apt-pkg/indexcopy.cc:
[apt.git] / apt-pkg / indexcopy.cc
CommitLineData
143abaeb
AL
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
90f057fd 3// $Id: indexcopy.cc,v 1.10 2002/03/26 07:38:58 jgg Exp $
143abaeb
AL
4/* ######################################################################
5
6 Index Copying - Aid for copying and verifying the index files
7
8 This class helps apt-cache reconstruct a damaged index files.
9
10 ##################################################################### */
11 /*}}}*/
12// Include Files /*{{{*/
13#include "indexcopy.h"
14
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>
a75c6a6e
MZ
21#include <apt-pkg/indexrecords.h>
22#include <apt-pkg/md5.h>
23#include <apt-pkg/cdrom.h>
24#include <apti18n.h>
143abaeb 25
90f057fd 26#include <iostream>
a75c6a6e 27#include <sstream>
143abaeb
AL
28#include <unistd.h>
29#include <sys/stat.h>
cf440fac
DK
30#include <sys/types.h>
31#include <fcntl.h>
143abaeb 32#include <stdio.h>
143abaeb
AL
33 /*}}}*/
34
076d01b0
AL
35using namespace std;
36
22f8568d
MV
37
38
143abaeb
AL
39// IndexCopy::CopyPackages - Copy the package files from the CD /*{{{*/
40// ---------------------------------------------------------------------
41/* */
a75c6a6e
MZ
42bool IndexCopy::CopyPackages(string CDROM,string Name,vector<string> &List,
43 pkgCdromStatus *log)
143abaeb 44{
a75c6a6e 45 OpProgress *Progress = NULL;
143abaeb
AL
46 if (List.size() == 0)
47 return true;
48
a75c6a6e
MZ
49 if(log)
50 Progress = log->GetOpProgress();
143abaeb
AL
51
52 bool NoStat = _config->FindB("APT::CDROM::Fast",false);
53 bool Debug = _config->FindB("Debug::aptcdrom",false);
54
55 // Prepare the progress indicator
56 unsigned long TotalSize = 0;
57 for (vector<string>::iterator I = List.begin(); I != List.end(); I++)
58 {
59 struct stat Buf;
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;
65 }
66
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++)
72 {
73 string OrigPath = string(*I,CDROM.length());
74 unsigned long FileSize = 0;
75
76 // Open the package file
77 FileFd Pkg;
78 if (FileExists(*I + GetFileName()) == true)
79 {
80 Pkg.Open(*I + GetFileName(),FileFd::ReadOnly);
81 FileSize = Pkg.Size();
82 }
83 else
84 {
85 FileFd From(*I + GetFileName() + ".gz",FileFd::ReadOnly);
86 if (_error->PendingError() == true)
87 return false;
88 FileSize = From.Size();
89
90 // Get a temp file
91 FILE *tmp = tmpfile();
92 if (tmp == 0)
93 return _error->Errno("tmpfile","Unable to create a tmp file");
94 Pkg.Fd(dup(fileno(tmp)));
95 fclose(tmp);
96
97 // Fork gzip
3826564e 98 pid_t Process = fork();
143abaeb
AL
99 if (Process < 0)
100 return _error->Errno("fork","Couldn't fork gzip");
101
102 // The child
103 if (Process == 0)
104 {
105 dup2(From.Fd(),STDIN_FILENO);
106 dup2(Pkg.Fd(),STDOUT_FILENO);
107 SetCloseExec(STDIN_FILENO,false);
108 SetCloseExec(STDOUT_FILENO,false);
109
110 const char *Args[3];
076d01b0
AL
111 string Tmp = _config->Find("Dir::bin::gzip","gzip");
112 Args[0] = Tmp.c_str();
143abaeb
AL
113 Args[1] = "-d";
114 Args[2] = 0;
115 execvp(Args[0],(char **)Args);
116 exit(100);
117 }
118
119 // Wait for gzip to finish
1ae93c94 120 if (ExecWait(Process,_config->Find("Dir::bin::gzip","gzip").c_str(),false) == false)
143abaeb 121 return _error->Error("gzip failed, perhaps the disk is full.");
1ae93c94 122
143abaeb
AL
123 Pkg.Seek(0);
124 }
b2e465d6 125 pkgTagFile Parser(&Pkg);
143abaeb
AL
126 if (_error->PendingError() == true)
127 return false;
128
129 // Open the output file
130 char S[400];
20ebd488
AL
131 snprintf(S,sizeof(S),"cdrom:[%s]/%s%s",Name.c_str(),
132 (*I).c_str() + CDROM.length(),GetFileName());
143abaeb
AL
133 string TargetF = _config->FindDir("Dir::State::lists") + "partial/";
134 TargetF += URItoFileName(S);
135 if (_config->FindB("APT::CDROM::NoAct",false) == true)
136 TargetF = "/dev/null";
22041bd2 137 FileFd Target(TargetF,FileFd::WriteAtomic);
b2e465d6 138 FILE *TargetFl = fdopen(dup(Target.Fd()),"w");
143abaeb
AL
139 if (_error->PendingError() == true)
140 return false;
b2e465d6
AL
141 if (TargetFl == 0)
142 return _error->Errno("fdopen","Failed to reopen fd");
143abaeb
AL
143
144 // Setup the progress meter
a75c6a6e
MZ
145 if(Progress)
146 Progress->OverallProgress(CurrentSize,TotalSize,FileSize,
147 string("Reading ") + Type() + " Indexes");
143abaeb
AL
148
149 // Parse
a75c6a6e
MZ
150 if(Progress)
151 Progress->SubProgress(Pkg.Size());
143abaeb
AL
152 pkgTagSection Section;
153 this->Section = &Section;
154 string Prefix;
155 unsigned long Hits = 0;
156 unsigned long Chop = 0;
157 while (Parser.Step(Section) == true)
158 {
a75c6a6e
MZ
159 if(Progress)
160 Progress->Progress(Parser.Offset());
143abaeb
AL
161 string File;
162 unsigned long Size;
163 if (GetFile(File,Size) == false)
b2e465d6
AL
164 {
165 fclose(TargetFl);
143abaeb 166 return false;
b2e465d6 167 }
143abaeb
AL
168
169 if (Chop != 0)
170 File = OrigPath + ChopDirs(File,Chop);
171
172 // See if the file exists
173 bool Mangled = false;
174 if (NoStat == false || Hits < 10)
175 {
176 // Attempt to fix broken structure
177 if (Hits == 0)
178 {
179 if (ReconstructPrefix(Prefix,OrigPath,CDROM,File) == false &&
180 ReconstructChop(Chop,*I,File) == false)
181 {
182 if (Debug == true)
183 clog << "Missed: " << File << endl;
184 NotFound++;
185 continue;
186 }
187 if (Chop != 0)
188 File = OrigPath + ChopDirs(File,Chop);
189 }
190
191 // Get the size
192 struct stat Buf;
193 if (stat(string(CDROM + Prefix + File).c_str(),&Buf) != 0 ||
194 Buf.st_size == 0)
195 {
196 // Attempt to fix busted symlink support for one instance
197 string OrigFile = File;
198 string::size_type Start = File.find("binary-");
199 string::size_type End = File.find("/",Start+3);
200 if (Start != string::npos && End != string::npos)
201 {
202 File.replace(Start,End-Start,"binary-all");
203 Mangled = true;
204 }
205
206 if (Mangled == false ||
207 stat(string(CDROM + Prefix + File).c_str(),&Buf) != 0)
208 {
209 if (Debug == true)
210 clog << "Missed(2): " << OrigFile << endl;
211 NotFound++;
212 continue;
213 }
214 }
215
216 // Size match
217 if ((unsigned)Buf.st_size != Size)
218 {
219 if (Debug == true)
220 clog << "Wrong Size: " << File << endl;
221 WrongSize++;
222 continue;
223 }
224 }
225
226 Packages++;
227 Hits++;
228
b2e465d6 229 if (RewriteEntry(TargetFl,File) == false)
143abaeb 230 {
b2e465d6
AL
231 fclose(TargetFl);
232 return false;
143abaeb 233 }
143abaeb 234 }
b2e465d6 235 fclose(TargetFl);
143abaeb
AL
236
237 if (Debug == true)
238 cout << " Processed by using Prefix '" << Prefix << "' and chop " << Chop << endl;
239
240 if (_config->FindB("APT::CDROM::NoAct",false) == false)
241 {
242 // Move out of the partial directory
243 Target.Close();
244 string FinalF = _config->FindDir("Dir::State::lists");
245 FinalF += URItoFileName(S);
246 if (rename(TargetF.c_str(),FinalF.c_str()) != 0)
247 return _error->Errno("rename","Failed to rename");
143abaeb 248 }
a75c6a6e 249
143abaeb
AL
250 /* Mangle the source to be in the proper notation with
251 prefix dist [component] */
252 *I = string(*I,Prefix.length());
253 ConvertToSourceList(CDROM,*I);
254 *I = Prefix + ' ' + *I;
255
256 CurrentSize += FileSize;
257 }
a75c6a6e
MZ
258 if(Progress)
259 Progress->Done();
143abaeb
AL
260
261 // Some stats
a75c6a6e
MZ
262 if(log) {
263 stringstream msg;
264 if(NotFound == 0 && WrongSize == 0)
265 ioprintf(msg, _("Wrote %i records.\n"), Packages);
266 else if (NotFound != 0 && WrongSize == 0)
267 ioprintf(msg, _("Wrote %i records with %i missing files.\n"),
268 Packages, NotFound);
269 else if (NotFound == 0 && WrongSize != 0)
db0db9fe 270 ioprintf(msg, _("Wrote %i records with %i mismatched files\n"),
a75c6a6e
MZ
271 Packages, WrongSize);
272 if (NotFound != 0 && WrongSize != 0)
db0db9fe 273 ioprintf(msg, _("Wrote %i records with %i missing files and %i mismatched files\n"), Packages, NotFound, WrongSize);
a75c6a6e 274 }
143abaeb
AL
275
276 if (Packages == 0)
dd27443e
AL
277 _error->Warning("No valid records were found.");
278
143abaeb 279 if (NotFound + WrongSize > 10)
46e39c8e 280 _error->Warning("A lot of entries were discarded, something may be wrong.\n");
a75c6a6e 281
143abaeb
AL
282
283 return true;
284}
285 /*}}}*/
286// IndexCopy::ChopDirs - Chop off the leading directory components /*{{{*/
287// ---------------------------------------------------------------------
288/* */
289string IndexCopy::ChopDirs(string Path,unsigned int Depth)
290{
291 string::size_type I = 0;
292 do
293 {
294 I = Path.find('/',I+1);
295 Depth--;
296 }
297 while (I != string::npos && Depth != 0);
298
299 if (I == string::npos)
300 return string();
301
302 return string(Path,I+1);
303}
304 /*}}}*/
305// IndexCopy::ReconstructPrefix - Fix strange prefixing /*{{{*/
306// ---------------------------------------------------------------------
307/* This prepends dir components from the path to the package files to
308 the path to the deb until it is found */
309bool IndexCopy::ReconstructPrefix(string &Prefix,string OrigPath,string CD,
310 string File)
311{
312 bool Debug = _config->FindB("Debug::aptcdrom",false);
313 unsigned int Depth = 1;
314 string MyPrefix = Prefix;
315 while (1)
316 {
317 struct stat Buf;
318 if (stat(string(CD + MyPrefix + File).c_str(),&Buf) != 0)
319 {
320 if (Debug == true)
321 cout << "Failed, " << CD + MyPrefix + File << endl;
322 if (GrabFirst(OrigPath,MyPrefix,Depth++) == true)
323 continue;
324
325 return false;
326 }
327 else
328 {
329 Prefix = MyPrefix;
330 return true;
331 }
332 }
333 return false;
334}
335 /*}}}*/
336// IndexCopy::ReconstructChop - Fixes bad source paths /*{{{*/
337// ---------------------------------------------------------------------
338/* This removes path components from the filename and prepends the location
339 of the package files until a file is found */
340bool IndexCopy::ReconstructChop(unsigned long &Chop,string Dir,string File)
341{
342 // Attempt to reconstruct the filename
343 unsigned long Depth = 0;
344 while (1)
345 {
346 struct stat Buf;
347 if (stat(string(Dir + File).c_str(),&Buf) != 0)
348 {
349 File = ChopDirs(File,1);
350 Depth++;
351 if (File.empty() == false)
352 continue;
353 return false;
354 }
355 else
356 {
357 Chop = Depth;
358 return true;
359 }
360 }
361 return false;
362}
363 /*}}}*/
364// IndexCopy::ConvertToSourceList - Convert a Path to a sourcelist /*{{{*/
365// ---------------------------------------------------------------------
366/* We look for things in dists/ notation and convert them to
367 <dist> <component> form otherwise it is left alone. This also strips
0f770a0c
AL
368 the CD path.
369
370 This implements a regex sort of like:
371 (.*)/dists/([^/]*)/(.*)/binary-*
372 ^ ^ ^- Component
373 | |-------- Distribution
374 |------------------- Path
375
376 It was deciced to use only a single word for dist (rather than say
377 unstable/non-us) to increase the chance that each CD gets a single
378 line in sources.list.
379 */
143abaeb
AL
380void IndexCopy::ConvertToSourceList(string CD,string &Path)
381{
382 char S[300];
20ebd488 383 snprintf(S,sizeof(S),"binary-%s",_config->Find("Apt::Architecture").c_str());
143abaeb
AL
384
385 // Strip the cdrom base path
386 Path = string(Path,CD.length());
387 if (Path.empty() == true)
388 Path = "/";
389
390 // Too short to be a dists/ type
391 if (Path.length() < strlen("dists/"))
392 return;
393
394 // Not a dists type.
076d01b0 395 if (stringcmp(Path.c_str(),Path.c_str()+strlen("dists/"),"dists/") != 0)
143abaeb 396 return;
7834cb57 397
143abaeb
AL
398 // Isolate the dist
399 string::size_type Slash = strlen("dists/");
400 string::size_type Slash2 = Path.find('/',Slash + 1);
401 if (Slash2 == string::npos || Slash2 + 2 >= Path.length())
402 return;
403 string Dist = string(Path,Slash,Slash2 - Slash);
404
405 // Isolate the component
0f770a0c
AL
406 Slash = Slash2;
407 for (unsigned I = 0; I != 10; I++)
408 {
409 Slash = Path.find('/',Slash+1);
410 if (Slash == string::npos || Slash + 2 >= Path.length())
411 return;
412 string Comp = string(Path,Slash2+1,Slash - Slash2-1);
413
414 // Verify the trailing binary- bit
415 string::size_type BinSlash = Path.find('/',Slash + 1);
416 if (Slash == string::npos)
417 return;
418 string Binary = string(Path,Slash+1,BinSlash - Slash-1);
419
420 if (Binary != S && Binary != "source")
421 continue;
422
423 Path = Dist + ' ' + Comp;
143abaeb 424 return;
0f770a0c 425 }
143abaeb
AL
426}
427 /*}}}*/
428// IndexCopy::GrabFirst - Return the first Depth path components /*{{{*/
429// ---------------------------------------------------------------------
430/* */
431bool IndexCopy::GrabFirst(string Path,string &To,unsigned int Depth)
432{
433 string::size_type I = 0;
434 do
435 {
436 I = Path.find('/',I+1);
437 Depth--;
438 }
439 while (I != string::npos && Depth != 0);
440
441 if (I == string::npos)
442 return false;
443
444 To = string(Path,0,I+1);
445 return true;
446}
447 /*}}}*/
143abaeb
AL
448// PackageCopy::GetFile - Get the file information from the section /*{{{*/
449// ---------------------------------------------------------------------
450/* */
451bool PackageCopy::GetFile(string &File,unsigned long &Size)
452{
453 File = Section->FindS("Filename");
454 Size = Section->FindI("Size");
455 if (File.empty() || Size == 0)
456 return _error->Error("Cannot find filename or size tag");
457 return true;
458}
459 /*}}}*/
460// PackageCopy::RewriteEntry - Rewrite the entry with a new filename /*{{{*/
461// ---------------------------------------------------------------------
462/* */
b2e465d6 463bool PackageCopy::RewriteEntry(FILE *Target,string File)
143abaeb 464{
b2e465d6
AL
465 TFRewriteData Changes[] = {{"Filename",File.c_str()},
466 {}};
467
468 if (TFRewrite(Target,*Section,TFRewritePackageOrder,Changes) == false)
469 return false;
470 fputc('\n',Target);
471 return true;
143abaeb
AL
472}
473 /*}}}*/
474// SourceCopy::GetFile - Get the file information from the section /*{{{*/
475// ---------------------------------------------------------------------
476/* */
477bool SourceCopy::GetFile(string &File,unsigned long &Size)
478{
479 string Files = Section->FindS("Files");
480 if (Files.empty() == true)
481 return false;
482
483 // Stash the / terminated directory prefix
484 string Base = Section->FindS("Directory");
485 if (Base.empty() == false && Base[Base.length()-1] != '/')
486 Base += '/';
487
b2e465d6 488 // Read the first file triplet
143abaeb
AL
489 const char *C = Files.c_str();
490 string sSize;
491 string MD5Hash;
492
493 // Parse each of the elements
494 if (ParseQuoteWord(C,MD5Hash) == false ||
495 ParseQuoteWord(C,sSize) == false ||
496 ParseQuoteWord(C,File) == false)
497 return _error->Error("Error parsing file record");
498
499 // Parse the size and append the directory
500 Size = atoi(sSize.c_str());
501 File = Base + File;
502 return true;
503}
504 /*}}}*/
505// SourceCopy::RewriteEntry - Rewrite the entry with a new filename /*{{{*/
506// ---------------------------------------------------------------------
507/* */
b2e465d6 508bool SourceCopy::RewriteEntry(FILE *Target,string File)
143abaeb 509{
b2e465d6
AL
510 string Dir(File,0,File.rfind('/'));
511 TFRewriteData Changes[] = {{"Directory",Dir.c_str()},
512 {}};
513
514 if (TFRewrite(Target,*Section,TFRewriteSourceOrder,Changes) == false)
515 return false;
516 fputc('\n',Target);
517 return true;
143abaeb
AL
518}
519 /*}}}*/
22f8568d
MV
520// SigVerify::Verify - Verify a files md5sum against its metaindex /*{{{*/
521// ---------------------------------------------------------------------
522/* */
a75c6a6e
MZ
523bool SigVerify::Verify(string prefix, string file, indexRecords *MetaIndex)
524{
525 const indexRecords::checkSum *Record = MetaIndex->Lookup(file);
526
8d357c52
MV
527 // we skip non-existing files in the verifcation to support a cdrom
528 // with no Packages file (just a Package.gz), see LP: #255545
529 // (non-existing files are not considered a error)
530 if(!FileExists(prefix+file))
531 {
a1e42d1f 532 _error->Warning(_("Skipping nonexistent file %s"), string(prefix+file).c_str());
8d357c52
MV
533 return true;
534 }
535
a75c6a6e
MZ
536 if (!Record)
537 {
a1e42d1f 538 _error->Warning(_("Can't find authentication record for: %s"), file.c_str());
a75c6a6e
MZ
539 return false;
540 }
541
495e5cb2 542 if (!Record->Hash.VerifyFile(prefix+file))
a75c6a6e 543 {
a1e42d1f 544 _error->Warning(_("Hash mismatch for: %s"),file.c_str());
a75c6a6e
MZ
545 return false;
546 }
547
548 if(_config->FindB("Debug::aptcdrom",false))
549 {
550 cout << "File: " << prefix+file << endl;
495e5cb2 551 cout << "Expected Hash " << Record->Hash.toStr() << endl;
a75c6a6e
MZ
552 }
553
554 return true;
555}
92fcbfc1
DK
556 /*}}}*/
557bool SigVerify::CopyMetaIndex(string CDROM, string CDName, /*{{{*/
a75c6a6e
MZ
558 string prefix, string file)
559{
560 char S[400];
561 snprintf(S,sizeof(S),"cdrom:[%s]/%s%s",CDName.c_str(),
562 (prefix).c_str() + CDROM.length(),file.c_str());
563 string TargetF = _config->FindDir("Dir::State::lists");
564 TargetF += URItoFileName(S);
565
566 FileFd Target;
567 FileFd Rel;
22041bd2 568 Target.Open(TargetF,FileFd::WriteAtomic);
a75c6a6e
MZ
569 Rel.Open(prefix + file,FileFd::ReadOnly);
570 if (_error->PendingError() == true)
571 return false;
572 if (CopyFile(Rel,Target) == false)
573 return false;
574
575 return true;
576}
92fcbfc1
DK
577 /*}}}*/
578bool SigVerify::CopyAndVerify(string CDROM,string Name,vector<string> &SigList, /*{{{*/
a75c6a6e
MZ
579 vector<string> PkgList,vector<string> SrcList)
580{
581 if (SigList.size() == 0)
582 return true;
583
584 bool Debug = _config->FindB("Debug::aptcdrom",false);
585
586 // Read all Release files
587 for (vector<string>::iterator I = SigList.begin(); I != SigList.end(); I++)
588 {
589 if(Debug)
590 cout << "Signature verify for: " << *I << endl;
591
592 indexRecords *MetaIndex = new indexRecords;
593 string prefix = *I;
594
a319c4ee
DK
595 string const releasegpg = *I+"Release.gpg";
596 string const release = *I+"Release";
597
a75c6a6e 598 // a Release.gpg without a Release should never happen
a319c4ee 599 if(FileExists(release) == false)
cfb3d242
DK
600 {
601 delete MetaIndex;
a75c6a6e 602 continue;
cfb3d242 603 }
a75c6a6e 604
a75c6a6e
MZ
605 pid_t pid = ExecFork();
606 if(pid < 0) {
607 _error->Error("Fork failed");
608 return false;
609 }
cf440fac
DK
610 if(pid == 0)
611 RunGPGV(release, releasegpg);
612
a75c6a6e
MZ
613 if(!ExecWait(pid, "gpgv")) {
614 _error->Warning("Signature verification failed for: %s",
a319c4ee 615 releasegpg.c_str());
a75c6a6e
MZ
616 // something went wrong, don't copy the Release.gpg
617 // FIXME: delete any existing gpg file?
618 continue;
619 }
620
621 // Open the Release file and add it to the MetaIndex
a319c4ee 622 if(!MetaIndex->Load(release))
a75c6a6e 623 {
9b5d79ec 624 _error->Error("%s",MetaIndex->ErrorText.c_str());
a75c6a6e
MZ
625 return false;
626 }
627
628 // go over the Indexfiles and see if they verify
629 // if so, remove them from our copy of the lists
630 vector<string> keys = MetaIndex->MetaKeys();
631 for (vector<string>::iterator I = keys.begin(); I != keys.end(); I++)
632 {
633 if(!Verify(prefix,*I, MetaIndex)) {
634 // something went wrong, don't copy the Release.gpg
635 // FIXME: delete any existing gpg file?
7efdcd3a 636 _error->Discard();
a75c6a6e
MZ
637 continue;
638 }
639 }
640
641 // we need a fresh one for the Release.gpg
642 delete MetaIndex;
643
644 // everything was fine, copy the Release and Release.gpg file
645 CopyMetaIndex(CDROM, Name, prefix, "Release");
646 CopyMetaIndex(CDROM, Name, prefix, "Release.gpg");
647 }
648
649 return true;
650}
92fcbfc1 651 /*}}}*/
cf440fac 652// SigVerify::RunGPGV - returns the command needed for verify /*{{{*/
a319c4ee
DK
653// ---------------------------------------------------------------------
654/* Generating the commandline for calling gpgv is somehow complicated as
655 we need to add multiple keyrings and user supplied options. Also, as
656 the cdrom code currently can not use the gpgv method we have two places
657 these need to be done - so the place for this method is wrong but better
658 than code duplication… */
cf440fac
DK
659bool SigVerify::RunGPGV(std::string const &File, std::string const &FileGPG,
660 int const &statusfd, int fd[2])
a319c4ee
DK
661{
662 string const gpgvpath = _config->Find("Dir::Bin::gpg", "/usr/bin/gpgv");
663 // FIXME: remove support for deprecated APT::GPGV setting
4368851d
DK
664 string const trustedFile = _config->FindFile("Dir::Etc::Trusted");
665 string const trustedPath = _config->FindDir("Dir::Etc::TrustedParts");
a319c4ee 666
cf440fac
DK
667 bool const Debug = _config->FindB("Debug::Acquire::gpgv", false);
668
669 if (Debug == true)
a319c4ee
DK
670 {
671 std::clog << "gpgv path: " << gpgvpath << std::endl;
672 std::clog << "Keyring file: " << trustedFile << std::endl;
673 std::clog << "Keyring path: " << trustedPath << std::endl;
674 }
675
5b777e8f
MV
676 std::vector<string> keyrings;
677 if (DirectoryExists(trustedPath))
678 {
679 keyrings = GetListOfFilesInDir(trustedPath, "gpg", false, true);
680 if (FileExists(trustedFile) == true)
681 keyrings.push_back(trustedFile);
682 }
a319c4ee
DK
683
684 std::vector<const char *> Args;
685 Args.reserve(30);
686
687 if (keyrings.empty() == true)
cf440fac 688 return false;
a319c4ee
DK
689
690 Args.push_back(gpgvpath.c_str());
691 Args.push_back("--ignore-time-conflict");
692
cf440fac
DK
693 if (statusfd != -1)
694 {
695 Args.push_back("--status-fd");
696 char fd[10];
697 snprintf(fd, sizeof(fd), "%i", statusfd);
698 Args.push_back(fd);
699 }
700
a319c4ee
DK
701 for (vector<string>::const_iterator K = keyrings.begin();
702 K != keyrings.end(); ++K)
703 {
704 Args.push_back("--keyring");
705 Args.push_back(K->c_str());
706 }
707
708 Configuration::Item const *Opts;
709 Opts = _config->Tree("Acquire::gpgv::Options");
710 if (Opts != 0)
711 {
712 Opts = Opts->Child;
713 for (; Opts != 0; Opts = Opts->Next)
714 {
715 if (Opts->Value.empty() == true)
716 continue;
717 Args.push_back(Opts->Value.c_str());
718 }
719 }
720
cf440fac
DK
721 Args.push_back(FileGPG.c_str());
722 Args.push_back(File.c_str());
723 Args.push_back(NULL);
724
725 if (Debug == true)
726 {
727 std::clog << "Preparing to exec: " << gpgvpath;
728 for (std::vector<const char *>::const_iterator a = Args.begin(); *a != NULL; ++a)
729 std::clog << " " << *a;
730 std::clog << std::endl;
731 }
732
733 if (statusfd != -1)
734 {
735 int const nullfd = open("/dev/null", O_RDONLY);
736 close(fd[0]);
737 // Redirect output to /dev/null; we read from the status fd
738 dup2(nullfd, STDOUT_FILENO);
739 dup2(nullfd, STDERR_FILENO);
740 // Redirect the pipe to the status fd (3)
741 dup2(fd[1], statusfd);
742
743 putenv((char *)"LANG=");
744 putenv((char *)"LC_ALL=");
745 putenv((char *)"LC_MESSAGES=");
746 }
747
748 execvp(gpgvpath.c_str(), (char **) &Args[0]);
749 return true;
a319c4ee
DK
750}
751 /*}}}*/
92fcbfc1
DK
752bool TranslationsCopy::CopyTranslations(string CDROM,string Name, /*{{{*/
753 vector<string> &List, pkgCdromStatus *log)
22f8568d
MV
754{
755 OpProgress *Progress = NULL;
756 if (List.size() == 0)
757 return true;
758
759 if(log)
760 Progress = log->GetOpProgress();
761
762 bool Debug = _config->FindB("Debug::aptcdrom",false);
763
764 // Prepare the progress indicator
765 unsigned long TotalSize = 0;
766 for (vector<string>::iterator I = List.begin(); I != List.end(); I++)
767 {
768 struct stat Buf;
769 if (stat(string(*I).c_str(),&Buf) != 0 &&
770 stat(string(*I + ".gz").c_str(),&Buf) != 0)
771 return _error->Errno("stat","Stat failed for %s",
772 string(*I).c_str());
773 TotalSize += Buf.st_size;
774 }
775
776 unsigned long CurrentSize = 0;
777 unsigned int NotFound = 0;
778 unsigned int WrongSize = 0;
779 unsigned int Packages = 0;
780 for (vector<string>::iterator I = List.begin(); I != List.end(); I++)
781 {
782 string OrigPath = string(*I,CDROM.length());
783 unsigned long FileSize = 0;
784
785 // Open the package file
786 FileFd Pkg;
787 if (FileExists(*I) == true)
788 {
789 Pkg.Open(*I,FileFd::ReadOnly);
790 FileSize = Pkg.Size();
791 }
792 else
793 {
794 FileFd From(*I + ".gz",FileFd::ReadOnly);
795 if (_error->PendingError() == true)
796 return false;
797 FileSize = From.Size();
798
799 // Get a temp file
800 FILE *tmp = tmpfile();
801 if (tmp == 0)
802 return _error->Errno("tmpfile","Unable to create a tmp file");
803 Pkg.Fd(dup(fileno(tmp)));
804 fclose(tmp);
805
806 // Fork gzip
807 pid_t Process = fork();
808 if (Process < 0)
809 return _error->Errno("fork","Couldn't fork gzip");
810
811 // The child
812 if (Process == 0)
813 {
814 dup2(From.Fd(),STDIN_FILENO);
815 dup2(Pkg.Fd(),STDOUT_FILENO);
816 SetCloseExec(STDIN_FILENO,false);
817 SetCloseExec(STDOUT_FILENO,false);
818
819 const char *Args[3];
820 string Tmp = _config->Find("Dir::bin::gzip","gzip");
821 Args[0] = Tmp.c_str();
822 Args[1] = "-d";
823 Args[2] = 0;
824 execvp(Args[0],(char **)Args);
825 exit(100);
826 }
827
828 // Wait for gzip to finish
829 if (ExecWait(Process,_config->Find("Dir::bin::gzip","gzip").c_str(),false) == false)
830 return _error->Error("gzip failed, perhaps the disk is full.");
831
832 Pkg.Seek(0);
833 }
834 pkgTagFile Parser(&Pkg);
835 if (_error->PendingError() == true)
836 return false;
837
838 // Open the output file
839 char S[400];
840 snprintf(S,sizeof(S),"cdrom:[%s]/%s",Name.c_str(),
841 (*I).c_str() + CDROM.length());
842 string TargetF = _config->FindDir("Dir::State::lists") + "partial/";
843 TargetF += URItoFileName(S);
844 if (_config->FindB("APT::CDROM::NoAct",false) == true)
845 TargetF = "/dev/null";
22041bd2 846 FileFd Target(TargetF,FileFd::WriteAtomic);
22f8568d
MV
847 FILE *TargetFl = fdopen(dup(Target.Fd()),"w");
848 if (_error->PendingError() == true)
849 return false;
850 if (TargetFl == 0)
851 return _error->Errno("fdopen","Failed to reopen fd");
852
853 // Setup the progress meter
854 if(Progress)
855 Progress->OverallProgress(CurrentSize,TotalSize,FileSize,
856 string("Reading Translation Indexes"));
857
858 // Parse
859 if(Progress)
860 Progress->SubProgress(Pkg.Size());
861 pkgTagSection Section;
862 this->Section = &Section;
863 string Prefix;
864 unsigned long Hits = 0;
865 unsigned long Chop = 0;
866 while (Parser.Step(Section) == true)
867 {
868 if(Progress)
869 Progress->Progress(Parser.Offset());
870
871 const char *Start;
872 const char *Stop;
873 Section.GetSection(Start,Stop);
874 fwrite(Start,Stop-Start, 1, TargetFl);
875 fputc('\n',TargetFl);
876
877 Packages++;
878 Hits++;
879 }
880 fclose(TargetFl);
881
882 if (Debug == true)
883 cout << " Processed by using Prefix '" << Prefix << "' and chop " << Chop << endl;
884
885 if (_config->FindB("APT::CDROM::NoAct",false) == false)
886 {
887 // Move out of the partial directory
888 Target.Close();
889 string FinalF = _config->FindDir("Dir::State::lists");
890 FinalF += URItoFileName(S);
891 if (rename(TargetF.c_str(),FinalF.c_str()) != 0)
892 return _error->Errno("rename","Failed to rename");
893 }
894
895
896 CurrentSize += FileSize;
897 }
898 if(Progress)
899 Progress->Done();
900
901 // Some stats
902 if(log) {
903 stringstream msg;
904 if(NotFound == 0 && WrongSize == 0)
905 ioprintf(msg, _("Wrote %i records.\n"), Packages);
906 else if (NotFound != 0 && WrongSize == 0)
907 ioprintf(msg, _("Wrote %i records with %i missing files.\n"),
908 Packages, NotFound);
909 else if (NotFound == 0 && WrongSize != 0)
910 ioprintf(msg, _("Wrote %i records with %i mismatched files\n"),
911 Packages, WrongSize);
912 if (NotFound != 0 && WrongSize != 0)
913 ioprintf(msg, _("Wrote %i records with %i missing files and %i mismatched files\n"), Packages, NotFound, WrongSize);
914 }
915
916 if (Packages == 0)
917 _error->Warning("No valid records were found.");
918
919 if (NotFound + WrongSize > 10)
46e39c8e 920 _error->Warning("A lot of entries were discarded, something may be wrong.\n");
22f8568d
MV
921
922
923 return true;
924}
92fcbfc1 925 /*}}}*/