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