]> git.saurik.com Git - apt.git/blame - apt-pkg/acquire-item.cc
* commited the latest mirror failure detection code
[apt.git] / apt-pkg / acquire-item.cc
CommitLineData
0118833a
AL
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
b3d44315 3// $Id: acquire-item.cc,v 1.46.2.9 2004/01/16 18:51:11 mdz Exp $
0118833a
AL
4/* ######################################################################
5
6 Acquire Item - Item to acquire
7
8 Each item can download to exactly one file at a time. This means you
9 cannot create an item that fetches two uri's to two files at the same
10 time. The pkgAcqIndex class creates a second class upon instantiation
11 to fetch the other index files because of this.
b185acc2 12
0118833a
AL
13 ##################################################################### */
14 /*}}}*/
15// Include Files /*{{{*/
16#ifdef __GNUG__
17#pragma implementation "apt-pkg/acquire-item.h"
18#endif
19#include <apt-pkg/acquire-item.h>
20#include <apt-pkg/configuration.h>
b2e465d6 21#include <apt-pkg/sourcelist.h>
b3d44315 22#include <apt-pkg/vendorlist.h>
03e39e59 23#include <apt-pkg/error.h>
cdcc6d34 24#include <apt-pkg/strutl.h>
36375005 25#include <apt-pkg/fileutl.h>
b3d44315 26#include <apt-pkg/md5.h>
0a8a80e5 27
b2e465d6
AL
28#include <apti18n.h>
29
0a8a80e5
AL
30#include <sys/stat.h>
31#include <unistd.h>
c88edf1d 32#include <errno.h>
5819a761 33#include <string>
c88edf1d 34#include <stdio.h>
0118833a
AL
35 /*}}}*/
36
b3d44315 37using namespace std;
5819a761 38
0118833a
AL
39// Acquire::Item::Item - Constructor /*{{{*/
40// ---------------------------------------------------------------------
41/* */
8267fe24 42pkgAcquire::Item::Item(pkgAcquire *Owner) : Owner(Owner), FileSize(0),
6b1ff003
AL
43 PartialSize(0), Mode(0), ID(0), Complete(false),
44 Local(false), QueueCounter(0)
0118833a
AL
45{
46 Owner->Add(this);
c88edf1d 47 Status = StatIdle;
0118833a
AL
48}
49 /*}}}*/
50// Acquire::Item::~Item - Destructor /*{{{*/
51// ---------------------------------------------------------------------
52/* */
53pkgAcquire::Item::~Item()
54{
55 Owner->Remove(this);
56}
57 /*}}}*/
c88edf1d
AL
58// Acquire::Item::Failed - Item failed to download /*{{{*/
59// ---------------------------------------------------------------------
93bf083d
AL
60/* We return to an idle state if there are still other queues that could
61 fetch this object */
7d8afa39 62void pkgAcquire::Item::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
c88edf1d 63{
93bf083d 64 Status = StatIdle;
db890fdb 65 ErrorText = LookupTag(Message,"Message");
c88edf1d 66 if (QueueCounter <= 1)
93bf083d 67 {
a72ace20 68 /* This indicates that the file is not available right now but might
7d8afa39 69 be sometime later. If we do a retry cycle then this should be
17caf1b1 70 retried [CDROMs] */
7d8afa39
AL
71 if (Cnf->LocalOnly == true &&
72 StringToBool(LookupTag(Message,"Transient-Failure"),false) == true)
a72ace20
AL
73 {
74 Status = StatIdle;
681d76d0 75 Dequeue();
a72ace20
AL
76 return;
77 }
78
93bf083d 79 Status = StatError;
681d76d0 80 Dequeue();
93bf083d 81 }
36280399
MV
82
83 // report mirror failure back to LP if we actually use a mirror
84 if(!UsedMirror.empty())
85 ReportMirrorFailure(ErrorText);
c88edf1d
AL
86}
87 /*}}}*/
8267fe24
AL
88// Acquire::Item::Start - Item has begun to download /*{{{*/
89// ---------------------------------------------------------------------
17caf1b1
AL
90/* Stash status and the file size. Note that setting Complete means
91 sub-phases of the acquire process such as decompresion are operating */
727f18af 92void pkgAcquire::Item::Start(string /*Message*/,unsigned long Size)
8267fe24
AL
93{
94 Status = StatFetching;
95 if (FileSize == 0 && Complete == false)
96 FileSize = Size;
97}
98 /*}}}*/
c88edf1d
AL
99// Acquire::Item::Done - Item downloaded OK /*{{{*/
100// ---------------------------------------------------------------------
101/* */
459681d3
AL
102void pkgAcquire::Item::Done(string Message,unsigned long Size,string,
103 pkgAcquire::MethodConfig *Cnf)
c88edf1d 104{
b98f2859
AL
105 // We just downloaded something..
106 string FileName = LookupTag(Message,"Filename");
36280399 107 UsedMirror = LookupTag(Message,"UsedMirror");
b98f2859
AL
108 if (Complete == false && FileName == DestFile)
109 {
110 if (Owner->Log != 0)
111 Owner->Log->Fetched(Size,atoi(LookupTag(Message,"Resume-Point","0").c_str()));
112 }
aa0e1101
AL
113
114 if (FileSize == 0)
115 FileSize= Size;
c88edf1d
AL
116 Status = StatDone;
117 ErrorText = string();
118 Owner->Dequeue(this);
119}
120 /*}}}*/
8b89e57f
AL
121// Acquire::Item::Rename - Rename a file /*{{{*/
122// ---------------------------------------------------------------------
123/* This helper function is used by alot of item methods as thier final
124 step */
125void pkgAcquire::Item::Rename(string From,string To)
126{
127 if (rename(From.c_str(),To.c_str()) != 0)
128 {
129 char S[300];
0fcd01de 130 snprintf(S,sizeof(S),_("rename failed, %s (%s -> %s)."),strerror(errno),
8b89e57f
AL
131 From.c_str(),To.c_str());
132 Status = StatError;
133 ErrorText = S;
7a3c2ab0 134 }
8b89e57f
AL
135}
136 /*}}}*/
0118833a 137
36280399
MV
138void pkgAcquire::Item::ReportMirrorFailure(string FailCode)
139{
140 // report that Queue->Uri failed
141#if 0
142 std::cerr << "\nReportMirrorFailure: "
143 << UsedMirror
144 << " FailCode: "
145 << FailCode << std::endl;
146#endif
147 const char *Args[40];
148 unsigned int i = 0;
149 string report = _config->Find("Methods::Mirror::ProblemReporting",
150 "/usr/bin/apt-report-mirror-failure");
151 if(!FileExists(report))
152 return;
153 Args[i++] = report.c_str();
154 Args[i++] = UsedMirror.c_str();
155 Args[i++] = FailCode.c_str();
156 pid_t pid = ExecFork();
157 if(pid < 0)
158 {
159 _error->Error("ReportMirrorFailure Fork failed");
160 return;
161 }
162 else if(pid == 0)
163 {
164 execvp(report.c_str(), (char**)Args);
165 }
166 if(!ExecWait(pid, "report-mirror-failure"))
167 {
168 _error->Warning("Couldn't report problem to '%s'",
169 _config->Find("Acquire::Mirror::ReportFailures").c_str());
170 }
171}
172
173
0118833a
AL
174// AcqIndex::AcqIndex - Constructor /*{{{*/
175// ---------------------------------------------------------------------
176/* The package file is added to the queue and a second class is
b2e465d6
AL
177 instantiated to fetch the revision file */
178pkgAcqIndex::pkgAcqIndex(pkgAcquire *Owner,
b3d44315
MV
179 string URI,string URIDesc,string ShortDesc,
180 string ExpectedMD5, string comprExt) :
181 Item(Owner), RealURI(URI), ExpectedMD5(ExpectedMD5)
0118833a 182{
8b89e57f 183 Decompression = false;
bfd22fc0 184 Erase = false;
13e8426f 185
0a8a80e5 186 DestFile = _config->FindDir("Dir::State::lists") + "partial/";
b2e465d6 187 DestFile += URItoFileName(URI);
8267fe24 188
b3d44315
MV
189 if(comprExt.empty())
190 {
13e8426f 191 // autoselect the compression method
4577fda2 192 if(FileExists("/bin/bzip2"))
13e8426f
MV
193 CompressionExtension = ".bz2";
194 else
195 CompressionExtension = ".gz";
b3d44315 196 } else {
13e8426f 197 CompressionExtension = comprExt;
b3d44315 198 }
13e8426f 199 Desc.URI = URI + CompressionExtension;
b3d44315 200
b2e465d6 201 Desc.Description = URIDesc;
8267fe24 202 Desc.Owner = this;
b2e465d6 203 Desc.ShortDesc = ShortDesc;
8267fe24
AL
204
205 QueueURI(Desc);
0118833a
AL
206}
207 /*}}}*/
0a8a80e5 208// AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
0118833a 209// ---------------------------------------------------------------------
0a8a80e5
AL
210/* The only header we use is the last-modified header. */
211string pkgAcqIndex::Custom600Headers()
0118833a 212{
0a8a80e5 213 string Final = _config->FindDir("Dir::State::lists");
b2e465d6 214 Final += URItoFileName(RealURI);
0a8a80e5
AL
215
216 struct stat Buf;
217 if (stat(Final.c_str(),&Buf) != 0)
a72ace20 218 return "\nIndex-File: true";
a72ace20 219 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
0118833a
AL
220}
221 /*}}}*/
debc84b2
MZ
222
223void pkgAcqIndex::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
224{
225 // no .bz2 found, retry with .gz
46e00f9d 226 if(Desc.URI.substr(Desc.URI.size()-3) == "bz2") {
debc84b2 227 Desc.URI = Desc.URI.substr(0,Desc.URI.size()-3) + "gz";
b3d44315
MV
228
229 // retry with a gzip one
230 new pkgAcqIndex(Owner, RealURI, Desc.Description,Desc.ShortDesc,
231 ExpectedMD5, string(".gz"));
232 Status = StatDone;
233 Complete = false;
234 Dequeue();
debc84b2
MZ
235 return;
236 }
237
238
239 Item::Failed(Message,Cnf);
240}
241
242
8b89e57f
AL
243// AcqIndex::Done - Finished a fetch /*{{{*/
244// ---------------------------------------------------------------------
245/* This goes through a number of states.. On the initial fetch the
246 method could possibly return an alternate filename which points
247 to the uncompressed version of the file. If this is so the file
248 is copied into the partial directory. In all other cases the file
249 is decompressed with a gzip uri. */
459681d3
AL
250void pkgAcqIndex::Done(string Message,unsigned long Size,string MD5,
251 pkgAcquire::MethodConfig *Cfg)
8b89e57f 252{
459681d3 253 Item::Done(Message,Size,MD5,Cfg);
8b89e57f
AL
254
255 if (Decompression == true)
256 {
b3d44315
MV
257 if (_config->FindB("Debug::pkgAcquire::Auth", false))
258 {
259 std::cerr << std::endl << RealURI << ": Computed MD5: " << MD5;
260 std::cerr << " Expected MD5: " << ExpectedMD5 << std::endl;
261 }
262
263 if (MD5.empty())
264 {
265 MD5Summation sum;
266 FileFd Fd(DestFile, FileFd::ReadOnly);
267 sum.AddFD(Fd.Fd(), Fd.Size());
268 Fd.Close();
269 MD5 = (string)sum.Result();
270 }
271
272 if (!ExpectedMD5.empty() && MD5 != ExpectedMD5)
273 {
274 Status = StatAuthError;
275 ErrorText = _("MD5Sum mismatch");
276 Rename(DestFile,DestFile + ".FAILED");
277 return;
278 }
8b89e57f
AL
279 // Done, move it into position
280 string FinalFile = _config->FindDir("Dir::State::lists");
b2e465d6 281 FinalFile += URItoFileName(RealURI);
8b89e57f 282 Rename(DestFile,FinalFile);
7a3c2ab0 283 chmod(FinalFile.c_str(),0644);
bfd22fc0 284
7a7fa5f0
AL
285 /* We restore the original name to DestFile so that the clean operation
286 will work OK */
287 DestFile = _config->FindDir("Dir::State::lists") + "partial/";
b2e465d6 288 DestFile += URItoFileName(RealURI);
7a7fa5f0 289
bfd22fc0
AL
290 // Remove the compressed version.
291 if (Erase == true)
bfd22fc0 292 unlink(DestFile.c_str());
8b89e57f
AL
293 return;
294 }
bfd22fc0
AL
295
296 Erase = false;
8267fe24 297 Complete = true;
bfd22fc0 298
8b89e57f
AL
299 // Handle the unzipd case
300 string FileName = LookupTag(Message,"Alt-Filename");
301 if (FileName.empty() == false)
302 {
303 // The files timestamp matches
304 if (StringToBool(LookupTag(Message,"Alt-IMS-Hit"),false) == true)
305 return;
b3d44315 306
8b89e57f 307 Decompression = true;
a6568219 308 Local = true;
8b89e57f 309 DestFile += ".decomp";
8267fe24
AL
310 Desc.URI = "copy:" + FileName;
311 QueueURI(Desc);
b98f2859 312 Mode = "copy";
8b89e57f
AL
313 return;
314 }
315
316 FileName = LookupTag(Message,"Filename");
317 if (FileName.empty() == true)
318 {
319 Status = StatError;
320 ErrorText = "Method gave a blank filename";
321 }
322
323 // The files timestamp matches
324 if (StringToBool(LookupTag(Message,"IMS-Hit"),false) == true)
325 return;
bfd22fc0
AL
326
327 if (FileName == DestFile)
328 Erase = true;
8267fe24 329 else
a6568219 330 Local = true;
8b89e57f 331
46e00f9d 332 string compExt = Desc.URI.substr(Desc.URI.size()-3);
debc84b2
MZ
333 char *decompProg;
334 if(compExt == "bz2")
335 decompProg = "bzip2";
336 else if(compExt == ".gz")
337 decompProg = "gzip";
338 else {
339 _error->Error("Unsupported extension: %s", compExt.c_str());
340 return;
341 }
342
8b89e57f
AL
343 Decompression = true;
344 DestFile += ".decomp";
debc84b2 345 Desc.URI = string(decompProg) + ":" + FileName;
8267fe24 346 QueueURI(Desc);
debc84b2 347 Mode = decompProg;
8b89e57f 348}
8b89e57f 349
b3d44315
MV
350pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire *Owner,
351 string URI,string URIDesc,string ShortDesc,
352 string MetaIndexURI, string MetaIndexURIDesc,
353 string MetaIndexShortDesc,
354 const vector<IndexTarget*>* IndexTargets,
355 indexRecords* MetaIndexParser) :
356 Item(Owner), RealURI(URI), MetaIndexURI(MetaIndexURI),
46e00f9d
MV
357 MetaIndexURIDesc(MetaIndexURIDesc), MetaIndexShortDesc(MetaIndexShortDesc),
358 MetaIndexParser(MetaIndexParser), IndexTargets(IndexTargets)
0118833a 359{
0a8a80e5 360 DestFile = _config->FindDir("Dir::State::lists") + "partial/";
b2e465d6 361 DestFile += URItoFileName(URI);
b3d44315 362
f6237efd
MV
363 // remove any partial downloaded sig-file. it may confuse proxies
364 // and is too small to warrant a partial download anyway
365 unlink(DestFile.c_str());
366
8267fe24 367 // Create the item
b2e465d6 368 Desc.Description = URIDesc;
8267fe24 369 Desc.Owner = this;
b3d44315
MV
370 Desc.ShortDesc = ShortDesc;
371 Desc.URI = URI;
372
373
374 string Final = _config->FindDir("Dir::State::lists");
375 Final += URItoFileName(RealURI);
376 struct stat Buf;
377 if (stat(Final.c_str(),&Buf) == 0)
378 {
379 // File was already in place. It needs to be re-verified
380 // because Release might have changed, so Move it into partial
381 Rename(Final,DestFile);
382 }
8267fe24 383
8267fe24 384 QueueURI(Desc);
0118833a
AL
385}
386 /*}}}*/
b3d44315 387// pkgAcqMetaSig::Custom600Headers - Insert custom request headers /*{{{*/
0118833a 388// ---------------------------------------------------------------------
0a8a80e5 389/* The only header we use is the last-modified header. */
b3d44315 390string pkgAcqMetaSig::Custom600Headers()
0118833a 391{
0a8a80e5 392 struct stat Buf;
2aab5956 393 if (stat(DestFile.c_str(),&Buf) != 0)
a72ace20 394 return "\nIndex-File: true";
a789b983 395
a72ace20 396 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
0118833a 397}
b3d44315
MV
398
399void pkgAcqMetaSig::Done(string Message,unsigned long Size,string MD5,
400 pkgAcquire::MethodConfig *Cfg)
c88edf1d 401{
459681d3 402 Item::Done(Message,Size,MD5,Cfg);
c88edf1d
AL
403
404 string FileName = LookupTag(Message,"Filename");
405 if (FileName.empty() == true)
406 {
407 Status = StatError;
408 ErrorText = "Method gave a blank filename";
8b89e57f 409 return;
c88edf1d 410 }
8b89e57f 411
c88edf1d
AL
412 if (FileName != DestFile)
413 {
b3d44315 414 // We have to copy it into place
a6568219 415 Local = true;
8267fe24
AL
416 Desc.URI = "copy:" + FileName;
417 QueueURI(Desc);
c88edf1d
AL
418 return;
419 }
b3d44315
MV
420
421 Complete = true;
422
423 // queue a pkgAcqMetaIndex to be verified against the sig we just retrieved
424 new pkgAcqMetaIndex(Owner, MetaIndexURI, MetaIndexURIDesc, MetaIndexShortDesc,
425 DestFile, IndexTargets, MetaIndexParser);
426
c88edf1d
AL
427}
428 /*}}}*/
b3d44315 429void pkgAcqMetaSig::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
681d76d0 430{
a789b983 431
75dd8af1 432 // if we get a network error we fail gracefully
25182152 433 if(LookupTag(Message,"FailReason") == "Timeout" ||
0c1b7be9 434 LookupTag(Message,"FailReason") == "TmpResolveFailure" ||
75dd8af1 435 LookupTag(Message,"FailReason") == "ConnectionRefused") {
24057ad6
MV
436 Item::Failed(Message,Cnf);
437 return;
438 }
439
75dd8af1
MV
440 // Delete any existing sigfile when the acquire failed
441 string Final = _config->FindDir("Dir::State::lists") + URItoFileName(RealURI);
442 unlink(Final.c_str());
443
b3d44315
MV
444 // queue a pkgAcqMetaIndex with no sigfile
445 new pkgAcqMetaIndex(Owner, MetaIndexURI, MetaIndexURIDesc, MetaIndexShortDesc,
446 "", IndexTargets, MetaIndexParser);
447
681d76d0
AL
448 if (Cnf->LocalOnly == true ||
449 StringToBool(LookupTag(Message,"Transient-Failure"),false) == false)
450 {
2b154e53
AL
451 // Ignore this
452 Status = StatDone;
453 Complete = false;
681d76d0
AL
454 Dequeue();
455 return;
456 }
457
458 Item::Failed(Message,Cnf);
459}
b3d44315
MV
460
461pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire *Owner,
462 string URI,string URIDesc,string ShortDesc,
463 string SigFile,
464 const vector<struct IndexTarget*>* IndexTargets,
465 indexRecords* MetaIndexParser) :
46e00f9d 466 Item(Owner), RealURI(URI), SigFile(SigFile), AuthPass(false),
f381d68d 467 MetaIndexParser(MetaIndexParser), IndexTargets(IndexTargets), IMSHit(false)
b3d44315 468{
b3d44315
MV
469 DestFile = _config->FindDir("Dir::State::lists") + "partial/";
470 DestFile += URItoFileName(URI);
471
472 // Create the item
473 Desc.Description = URIDesc;
474 Desc.Owner = this;
475 Desc.ShortDesc = ShortDesc;
476 Desc.URI = URI;
477
478 QueueURI(Desc);
479}
480
481 /*}}}*/
482// pkgAcqMetaIndex::Custom600Headers - Insert custom request headers /*{{{*/
483// ---------------------------------------------------------------------
484/* The only header we use is the last-modified header. */
485string pkgAcqMetaIndex::Custom600Headers()
486{
487 string Final = _config->FindDir("Dir::State::lists");
488 Final += URItoFileName(RealURI);
489
490 struct stat Buf;
491 if (stat(Final.c_str(),&Buf) != 0)
492 return "\nIndex-File: true";
493
494 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
495}
496
497void pkgAcqMetaIndex::Done(string Message,unsigned long Size,string MD5,
498 pkgAcquire::MethodConfig *Cfg)
499{
500 Item::Done(Message,Size,MD5,Cfg);
501
502 // MetaIndexes are done in two passes: one to download the
503 // metaindex with an appropriate method, and a second to verify it
504 // with the gpgv method
505
506 if (AuthPass == true)
507 {
508 AuthDone(Message);
509 }
510 else
511 {
512 RetrievalDone(Message);
513 if (!Complete)
514 // Still more retrieving to do
515 return;
516
517 if (SigFile == "")
518 {
519 // There was no signature file, so we are finished. Download
520 // the indexes without verification.
521 QueueIndexes(false);
522 }
523 else
524 {
525 // There was a signature file, so pass it to gpgv for
526 // verification
527
528 if (_config->FindB("Debug::pkgAcquire::Auth", false))
529 std::cerr << "Metaindex acquired, queueing gpg verification ("
530 << SigFile << "," << DestFile << ")\n";
531 AuthPass = true;
532 Desc.URI = "gpgv:" + SigFile;
533 QueueURI(Desc);
534 Mode = "gpgv";
535 }
536 }
537}
538
539void pkgAcqMetaIndex::RetrievalDone(string Message)
540{
541 // We have just finished downloading a Release file (it is not
542 // verified yet)
543
544 string FileName = LookupTag(Message,"Filename");
545 if (FileName.empty() == true)
546 {
547 Status = StatError;
548 ErrorText = "Method gave a blank filename";
549 return;
550 }
551
552 if (FileName != DestFile)
553 {
554 Local = true;
555 Desc.URI = "copy:" + FileName;
556 QueueURI(Desc);
557 return;
558 }
559
f381d68d
MV
560 // see if the download was a IMSHit
561 IMSHit = StringToBool(LookupTag(Message,"IMS-Hit"),false);
562
b3d44315
MV
563 Complete = true;
564
565 string FinalFile = _config->FindDir("Dir::State::lists");
566 FinalFile += URItoFileName(RealURI);
567
568 // The files timestamp matches
569 if (StringToBool(LookupTag(Message,"IMS-Hit"),false) == false)
570 {
571 // Move it into position
572 Rename(DestFile,FinalFile);
573 }
574 DestFile = FinalFile;
575}
576
577void pkgAcqMetaIndex::AuthDone(string Message)
578{
579 // At this point, the gpgv method has succeeded, so there is a
580 // valid signature from a key in the trusted keyring. We
581 // perform additional verification of its contents, and use them
582 // to verify the indexes we are about to download
583
584 if (!MetaIndexParser->Load(DestFile))
585 {
586 Status = StatAuthError;
587 ErrorText = MetaIndexParser->ErrorText;
588 return;
589 }
590
ce424cd4 591 if (!VerifyVendor(Message))
b3d44315
MV
592 {
593 return;
594 }
595
596 if (_config->FindB("Debug::pkgAcquire::Auth", false))
597 std::cerr << "Signature verification succeeded: "
598 << DestFile << std::endl;
599
600 // Download further indexes with verification
601 QueueIndexes(true);
602
603 // Done, move signature file into position
604
605 string VerifiedSigFile = _config->FindDir("Dir::State::lists") +
606 URItoFileName(RealURI) + ".gpg";
607 Rename(SigFile,VerifiedSigFile);
608 chmod(VerifiedSigFile.c_str(),0644);
609}
610
611void pkgAcqMetaIndex::QueueIndexes(bool verify)
612{
613 for (vector <struct IndexTarget*>::const_iterator Target = IndexTargets->begin();
614 Target != IndexTargets->end();
615 Target++)
616 {
617 string ExpectedIndexMD5;
618 if (verify)
619 {
620 const indexRecords::checkSum *Record = MetaIndexParser->Lookup((*Target)->MetaKey);
621 if (!Record)
622 {
623 Status = StatAuthError;
624 ErrorText = "Unable to find expected entry "
625 + (*Target)->MetaKey + " in Meta-index file (malformed Release file?)";
626 return;
627 }
628 ExpectedIndexMD5 = Record->MD5Hash;
629 if (_config->FindB("Debug::pkgAcquire::Auth", false))
630 {
631 std::cerr << "Queueing: " << (*Target)->URI << std::endl;
632 std::cerr << "Expected MD5: " << ExpectedIndexMD5 << std::endl;
633 }
634 if (ExpectedIndexMD5.empty())
635 {
636 Status = StatAuthError;
637 ErrorText = "Unable to find MD5 sum for "
638 + (*Target)->MetaKey + " in Meta-index file";
639 return;
640 }
641 }
642
643 // Queue Packages file
644 new pkgAcqIndex(Owner, (*Target)->URI, (*Target)->Description,
645 (*Target)->ShortDesc, ExpectedIndexMD5);
646 }
647}
648
ce424cd4 649bool pkgAcqMetaIndex::VerifyVendor(string Message)
b3d44315
MV
650{
651// // Maybe this should be made available from above so we don't have
652// // to read and parse it every time?
653// pkgVendorList List;
654// List.ReadMainList();
655
656// const Vendor* Vndr = NULL;
657// for (std::vector<string>::const_iterator I = GPGVOutput.begin(); I != GPGVOutput.end(); I++)
658// {
659// string::size_type pos = (*I).find("VALIDSIG ");
660// if (_config->FindB("Debug::Vendor", false))
661// std::cerr << "Looking for VALIDSIG in \"" << (*I) << "\": pos " << pos
662// << std::endl;
663// if (pos != std::string::npos)
664// {
665// string Fingerprint = (*I).substr(pos+sizeof("VALIDSIG"));
666// if (_config->FindB("Debug::Vendor", false))
667// std::cerr << "Looking for \"" << Fingerprint << "\" in vendor..." <<
668// std::endl;
669// Vndr = List.FindVendor(Fingerprint) != "";
670// if (Vndr != NULL);
671// break;
672// }
673// }
ce424cd4
MV
674 string::size_type pos;
675
676 // check for missing sigs (that where not fatal because otherwise we had
677 // bombed earlier)
678 string missingkeys;
400ad7a4 679 string msg = _("There is no public key available for the "
ce424cd4
MV
680 "following key IDs:\n");
681 pos = Message.find("NO_PUBKEY ");
682 if (pos != std::string::npos)
683 {
684 string::size_type start = pos+strlen("NO_PUBKEY ");
685 string Fingerprint = Message.substr(start, Message.find("\n")-start);
686 missingkeys += (Fingerprint);
687 }
688 if(!missingkeys.empty())
689 _error->Warning("%s", string(msg+missingkeys).c_str());
b3d44315
MV
690
691 string Transformed = MetaIndexParser->GetExpectedDist();
692
693 if (Transformed == "../project/experimental")
694 {
695 Transformed = "experimental";
696 }
697
ce424cd4 698 pos = Transformed.rfind('/');
b3d44315
MV
699 if (pos != string::npos)
700 {
701 Transformed = Transformed.substr(0, pos);
702 }
703
704 if (Transformed == ".")
705 {
706 Transformed = "";
707 }
708
709 if (_config->FindB("Debug::pkgAcquire::Auth", false))
710 {
711 std::cerr << "Got Codename: " << MetaIndexParser->GetDist() << std::endl;
712 std::cerr << "Expecting Dist: " << MetaIndexParser->GetExpectedDist() << std::endl;
713 std::cerr << "Transformed Dist: " << Transformed << std::endl;
714 }
715
716 if (MetaIndexParser->CheckDist(Transformed) == false)
717 {
718 // This might become fatal one day
719// Status = StatAuthError;
720// ErrorText = "Conflicting distribution; expected "
721// + MetaIndexParser->GetExpectedDist() + " but got "
722// + MetaIndexParser->GetDist();
723// return false;
724 if (!Transformed.empty())
725 {
726 _error->Warning("Conflicting distribution: %s (expected %s but got %s)",
727 Desc.Description.c_str(),
728 Transformed.c_str(),
729 MetaIndexParser->GetDist().c_str());
730 }
731 }
732
733 return true;
734}
735 /*}}}*/
736// pkgAcqMetaIndex::Failed - no Release file present or no signature
737// file present /*{{{*/
738// ---------------------------------------------------------------------
739/* */
740void pkgAcqMetaIndex::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
741{
742 if (AuthPass == true)
743 {
f381d68d
MV
744 // if we fail the authentication but got the file via a IMS-Hit
745 // this means that the file wasn't downloaded and that it might be
746 // just stale (server problem, proxy etc). we delete what we have
747 // queue it again without i-m-s
748 // alternatively we could just unlink the file and let the user try again
749 if (IMSHit)
750 {
751 Complete = false;
752 Local = false;
753 AuthPass = false;
754 unlink(DestFile.c_str());
755
756 DestFile = _config->FindDir("Dir::State::lists") + "partial/";
757 DestFile += URItoFileName(RealURI);
758 Desc.URI = RealURI;
759 QueueURI(Desc);
760 return;
761 }
762
763 // gpgv method failed
b3d44315
MV
764 _error->Warning("GPG error: %s: %s",
765 Desc.Description.c_str(),
766 LookupTag(Message,"Message").c_str());
f381d68d 767
b3d44315
MV
768 }
769
770 // No Release file was present, or verification failed, so fall
771 // back to queueing Packages files without verification
772 QueueIndexes(false);
773}
774
681d76d0 775 /*}}}*/
03e39e59
AL
776
777// AcqArchive::AcqArchive - Constructor /*{{{*/
778// ---------------------------------------------------------------------
17caf1b1
AL
779/* This just sets up the initial fetch environment and queues the first
780 possibilitiy */
03e39e59 781pkgAcqArchive::pkgAcqArchive(pkgAcquire *Owner,pkgSourceList *Sources,
30e1eab5
AL
782 pkgRecords *Recs,pkgCache::VerIterator const &Version,
783 string &StoreFilename) :
784 Item(Owner), Version(Version), Sources(Sources), Recs(Recs),
b3d44315
MV
785 StoreFilename(StoreFilename), Vf(Version.FileList()),
786 Trusted(false)
03e39e59 787{
7d8afa39 788 Retries = _config->FindI("Acquire::Retries",0);
813c8eea
AL
789
790 if (Version.Arch() == 0)
bdae53f1 791 {
d1f1f6a8 792 _error->Error(_("I wasn't able to locate a file for the %s package. "
7a3c2ab0
AL
793 "This might mean you need to manually fix this package. "
794 "(due to missing arch)"),
813c8eea 795 Version.ParentPkg().Name());
bdae53f1
AL
796 return;
797 }
813c8eea 798
b2e465d6
AL
799 /* We need to find a filename to determine the extension. We make the
800 assumption here that all the available sources for this version share
801 the same extension.. */
802 // Skip not source sources, they do not have file fields.
803 for (; Vf.end() == false; Vf++)
804 {
805 if ((Vf.File()->Flags & pkgCache::Flag::NotSource) != 0)
806 continue;
807 break;
808 }
809
810 // Does not really matter here.. we are going to fail out below
811 if (Vf.end() != true)
812 {
813 // If this fails to get a file name we will bomb out below.
814 pkgRecords::Parser &Parse = Recs->Lookup(Vf);
815 if (_error->PendingError() == true)
816 return;
817
818 // Generate the final file name as: package_version_arch.foo
819 StoreFilename = QuoteString(Version.ParentPkg().Name(),"_:") + '_' +
820 QuoteString(Version.VerStr(),"_:") + '_' +
821 QuoteString(Version.Arch(),"_:.") +
822 "." + flExtension(Parse.FileName());
823 }
b3d44315
MV
824
825 // check if we have one trusted source for the package. if so, switch
826 // to "TrustedOnly" mode
827 for (pkgCache::VerFileIterator i = Version.FileList(); i.end() == false; i++)
828 {
829 pkgIndexFile *Index;
830 if (Sources->FindIndex(i.File(),Index) == false)
831 continue;
832 if (_config->FindB("Debug::pkgAcquire::Auth", false))
833 {
834 std::cerr << "Checking index: " << Index->Describe()
835 << "(Trusted=" << Index->IsTrusted() << ")\n";
836 }
837 if (Index->IsTrusted()) {
838 Trusted = true;
839 break;
840 }
841 }
842
a3371852
MV
843 // "allow-unauthenticated" restores apts old fetching behaviour
844 // that means that e.g. unauthenticated file:// uris are higher
845 // priority than authenticated http:// uris
846 if (_config->FindB("APT::Get::AllowUnauthenticated",false) == true)
847 Trusted = false;
848
03e39e59 849 // Select a source
b185acc2 850 if (QueueNext() == false && _error->PendingError() == false)
b2e465d6
AL
851 _error->Error(_("I wasn't able to locate file for the %s package. "
852 "This might mean you need to manually fix this package."),
b185acc2
AL
853 Version.ParentPkg().Name());
854}
855 /*}}}*/
856// AcqArchive::QueueNext - Queue the next file source /*{{{*/
857// ---------------------------------------------------------------------
17caf1b1
AL
858/* This queues the next available file version for download. It checks if
859 the archive is already available in the cache and stashs the MD5 for
860 checking later. */
b185acc2 861bool pkgAcqArchive::QueueNext()
b2e465d6 862{
03e39e59
AL
863 for (; Vf.end() == false; Vf++)
864 {
865 // Ignore not source sources
866 if ((Vf.File()->Flags & pkgCache::Flag::NotSource) != 0)
867 continue;
868
869 // Try to cross match against the source list
b2e465d6
AL
870 pkgIndexFile *Index;
871 if (Sources->FindIndex(Vf.File(),Index) == false)
872 continue;
03e39e59 873
b3d44315
MV
874 // only try to get a trusted package from another source if that source
875 // is also trusted
876 if(Trusted && !Index->IsTrusted())
877 continue;
878
03e39e59
AL
879 // Grab the text package record
880 pkgRecords::Parser &Parse = Recs->Lookup(Vf);
881 if (_error->PendingError() == true)
b185acc2 882 return false;
03e39e59 883
b2e465d6 884 string PkgFile = Parse.FileName();
03e39e59
AL
885 MD5 = Parse.MD5Hash();
886 if (PkgFile.empty() == true)
b2e465d6
AL
887 return _error->Error(_("The package index files are corrupted. No Filename: "
888 "field for package %s."),
889 Version.ParentPkg().Name());
a6568219 890
b3d44315
MV
891 Desc.URI = Index->ArchiveURI(PkgFile);
892 Desc.Description = Index->ArchiveInfo(Version);
893 Desc.Owner = this;
894 Desc.ShortDesc = Version.ParentPkg().Name();
895
17caf1b1 896 // See if we already have the file. (Legacy filenames)
a6568219
AL
897 FileSize = Version->Size;
898 string FinalFile = _config->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile);
899 struct stat Buf;
900 if (stat(FinalFile.c_str(),&Buf) == 0)
901 {
902 // Make sure the size matches
903 if ((unsigned)Buf.st_size == Version->Size)
904 {
905 Complete = true;
906 Local = true;
907 Status = StatDone;
30e1eab5 908 StoreFilename = DestFile = FinalFile;
b185acc2 909 return true;
a6568219
AL
910 }
911
6b1ff003
AL
912 /* Hmm, we have a file and its size does not match, this means it is
913 an old style mismatched arch */
a6568219
AL
914 unlink(FinalFile.c_str());
915 }
17caf1b1
AL
916
917 // Check it again using the new style output filenames
918 FinalFile = _config->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename);
919 if (stat(FinalFile.c_str(),&Buf) == 0)
920 {
921 // Make sure the size matches
922 if ((unsigned)Buf.st_size == Version->Size)
923 {
924 Complete = true;
925 Local = true;
926 Status = StatDone;
927 StoreFilename = DestFile = FinalFile;
928 return true;
929 }
930
931 /* Hmm, we have a file and its size does not match, this shouldnt
932 happen.. */
933 unlink(FinalFile.c_str());
934 }
935
936 DestFile = _config->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename);
6b1ff003
AL
937
938 // Check the destination file
939 if (stat(DestFile.c_str(),&Buf) == 0)
940 {
941 // Hmm, the partial file is too big, erase it
942 if ((unsigned)Buf.st_size > Version->Size)
943 unlink(DestFile.c_str());
944 else
945 PartialSize = Buf.st_size;
946 }
947
03e39e59 948 // Create the item
b2e465d6
AL
949 Local = false;
950 Desc.URI = Index->ArchiveURI(PkgFile);
951 Desc.Description = Index->ArchiveInfo(Version);
03e39e59
AL
952 Desc.Owner = this;
953 Desc.ShortDesc = Version.ParentPkg().Name();
954 QueueURI(Desc);
b185acc2
AL
955
956 Vf++;
957 return true;
03e39e59 958 }
b185acc2
AL
959 return false;
960}
03e39e59
AL
961 /*}}}*/
962// AcqArchive::Done - Finished fetching /*{{{*/
963// ---------------------------------------------------------------------
964/* */
459681d3
AL
965void pkgAcqArchive::Done(string Message,unsigned long Size,string Md5Hash,
966 pkgAcquire::MethodConfig *Cfg)
03e39e59 967{
459681d3 968 Item::Done(Message,Size,Md5Hash,Cfg);
03e39e59
AL
969
970 // Check the size
971 if (Size != Version->Size)
972 {
bdae53f1 973 Status = StatError;
b2e465d6 974 ErrorText = _("Size mismatch");
03e39e59
AL
975 return;
976 }
977
978 // Check the md5
979 if (Md5Hash.empty() == false && MD5.empty() == false)
980 {
981 if (Md5Hash != MD5)
982 {
bdae53f1 983 Status = StatError;
b2e465d6 984 ErrorText = _("MD5Sum mismatch");
13e8426f
MV
985 if(FileExists(DestFile))
986 Rename(DestFile,DestFile + ".FAILED");
03e39e59
AL
987 return;
988 }
989 }
a6568219
AL
990
991 // Grab the output filename
03e39e59
AL
992 string FileName = LookupTag(Message,"Filename");
993 if (FileName.empty() == true)
994 {
995 Status = StatError;
996 ErrorText = "Method gave a blank filename";
997 return;
998 }
a6568219
AL
999
1000 Complete = true;
30e1eab5
AL
1001
1002 // Reference filename
a6568219
AL
1003 if (FileName != DestFile)
1004 {
30e1eab5 1005 StoreFilename = DestFile = FileName;
a6568219
AL
1006 Local = true;
1007 return;
1008 }
1009
1010 // Done, move it into position
1011 string FinalFile = _config->FindDir("Dir::Cache::Archives");
17caf1b1 1012 FinalFile += flNotDir(StoreFilename);
a6568219 1013 Rename(DestFile,FinalFile);
03e39e59 1014
30e1eab5 1015 StoreFilename = DestFile = FinalFile;
03e39e59
AL
1016 Complete = true;
1017}
1018 /*}}}*/
db890fdb
AL
1019// AcqArchive::Failed - Failure handler /*{{{*/
1020// ---------------------------------------------------------------------
1021/* Here we try other sources */
7d8afa39 1022void pkgAcqArchive::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
db890fdb
AL
1023{
1024 ErrorText = LookupTag(Message,"Message");
b2e465d6
AL
1025
1026 /* We don't really want to retry on failed media swaps, this prevents
1027 that. An interesting observation is that permanent failures are not
1028 recorded. */
1029 if (Cnf->Removable == true &&
1030 StringToBool(LookupTag(Message,"Transient-Failure"),false) == true)
1031 {
1032 // Vf = Version.FileList();
1033 while (Vf.end() == false) Vf++;
1034 StoreFilename = string();
1035 Item::Failed(Message,Cnf);
1036 return;
1037 }
1038
db890fdb 1039 if (QueueNext() == false)
7d8afa39
AL
1040 {
1041 // This is the retry counter
1042 if (Retries != 0 &&
1043 Cnf->LocalOnly == false &&
1044 StringToBool(LookupTag(Message,"Transient-Failure"),false) == true)
1045 {
1046 Retries--;
1047 Vf = Version.FileList();
1048 if (QueueNext() == true)
1049 return;
1050 }
1051
9dbb421f 1052 StoreFilename = string();
7d8afa39
AL
1053 Item::Failed(Message,Cnf);
1054 }
db890fdb
AL
1055}
1056 /*}}}*/
b3d44315
MV
1057// AcqArchive::IsTrusted - Determine whether this archive comes from a
1058// trusted source /*{{{*/
1059// ---------------------------------------------------------------------
1060bool pkgAcqArchive::IsTrusted()
1061{
1062 return Trusted;
1063}
1064
ab559b35
AL
1065// AcqArchive::Finished - Fetching has finished, tidy up /*{{{*/
1066// ---------------------------------------------------------------------
1067/* */
1068void pkgAcqArchive::Finished()
1069{
1070 if (Status == pkgAcquire::Item::StatDone &&
1071 Complete == true)
1072 return;
1073 StoreFilename = string();
1074}
1075 /*}}}*/
36375005
AL
1076
1077// AcqFile::pkgAcqFile - Constructor /*{{{*/
1078// ---------------------------------------------------------------------
1079/* The file is added to the queue */
1080pkgAcqFile::pkgAcqFile(pkgAcquire *Owner,string URI,string MD5,
46e00f9d
MV
1081 unsigned long Size,string Dsc,string ShortDesc,
1082 const string &DestDir, const string &DestFilename) :
b3c39978 1083 Item(Owner), Md5Hash(MD5)
36375005 1084{
08cfc005
AL
1085 Retries = _config->FindI("Acquire::Retries",0);
1086
46e00f9d
MV
1087 if(!DestFilename.empty())
1088 DestFile = DestFilename;
1089 else if(!DestDir.empty())
1090 DestFile = DestDir + "/" + flNotDir(URI);
1091 else
1092 DestFile = flNotDir(URI);
1093
36375005
AL
1094 // Create the item
1095 Desc.URI = URI;
1096 Desc.Description = Dsc;
1097 Desc.Owner = this;
1098
1099 // Set the short description to the archive component
1100 Desc.ShortDesc = ShortDesc;
1101
1102 // Get the transfer sizes
1103 FileSize = Size;
1104 struct stat Buf;
1105 if (stat(DestFile.c_str(),&Buf) == 0)
1106 {
1107 // Hmm, the partial file is too big, erase it
1108 if ((unsigned)Buf.st_size > Size)
1109 unlink(DestFile.c_str());
1110 else
1111 PartialSize = Buf.st_size;
1112 }
092ae175 1113
36375005
AL
1114 QueueURI(Desc);
1115}
1116 /*}}}*/
1117// AcqFile::Done - Item downloaded OK /*{{{*/
1118// ---------------------------------------------------------------------
1119/* */
459681d3
AL
1120void pkgAcqFile::Done(string Message,unsigned long Size,string MD5,
1121 pkgAcquire::MethodConfig *Cnf)
36375005 1122{
b3c39978
AL
1123 // Check the md5
1124 if (Md5Hash.empty() == false && MD5.empty() == false)
1125 {
1126 if (Md5Hash != MD5)
1127 {
1128 Status = StatError;
1129 ErrorText = "MD5Sum mismatch";
1130 Rename(DestFile,DestFile + ".FAILED");
1131 return;
1132 }
1133 }
1134
459681d3 1135 Item::Done(Message,Size,MD5,Cnf);
36375005
AL
1136
1137 string FileName = LookupTag(Message,"Filename");
1138 if (FileName.empty() == true)
1139 {
1140 Status = StatError;
1141 ErrorText = "Method gave a blank filename";
1142 return;
1143 }
1144
1145 Complete = true;
1146
1147 // The files timestamp matches
1148 if (StringToBool(LookupTag(Message,"IMS-Hit"),false) == true)
1149 return;
1150
1151 // We have to copy it into place
1152 if (FileName != DestFile)
1153 {
1154 Local = true;
459681d3
AL
1155 if (_config->FindB("Acquire::Source-Symlinks",true) == false ||
1156 Cnf->Removable == true)
917ae805
AL
1157 {
1158 Desc.URI = "copy:" + FileName;
1159 QueueURI(Desc);
1160 return;
1161 }
1162
83ab33fc
AL
1163 // Erase the file if it is a symlink so we can overwrite it
1164 struct stat St;
1165 if (lstat(DestFile.c_str(),&St) == 0)
1166 {
1167 if (S_ISLNK(St.st_mode) != 0)
1168 unlink(DestFile.c_str());
1169 }
1170
1171 // Symlink the file
917ae805
AL
1172 if (symlink(FileName.c_str(),DestFile.c_str()) != 0)
1173 {
83ab33fc 1174 ErrorText = "Link to " + DestFile + " failure ";
917ae805
AL
1175 Status = StatError;
1176 Complete = false;
1177 }
36375005
AL
1178 }
1179}
1180 /*}}}*/
08cfc005
AL
1181// AcqFile::Failed - Failure handler /*{{{*/
1182// ---------------------------------------------------------------------
1183/* Here we try other sources */
1184void pkgAcqFile::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
1185{
1186 ErrorText = LookupTag(Message,"Message");
1187
1188 // This is the retry counter
1189 if (Retries != 0 &&
1190 Cnf->LocalOnly == false &&
1191 StringToBool(LookupTag(Message,"Transient-Failure"),false) == true)
1192 {
1193 Retries--;
1194 QueueURI(Desc);
1195 return;
1196 }
1197
1198 Item::Failed(Message,Cnf);
1199}
1200 /*}}}*/