]> git.saurik.com Git - apt.git/blame_incremental - apt-pkg/acquire-item.cc
* commited the latest mirror failure detection code
[apt.git] / apt-pkg / acquire-item.cc
... / ...
CommitLineData
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
3// $Id: acquire-item.cc,v 1.46.2.9 2004/01/16 18:51:11 mdz Exp $
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.
12
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>
21#include <apt-pkg/sourcelist.h>
22#include <apt-pkg/vendorlist.h>
23#include <apt-pkg/error.h>
24#include <apt-pkg/strutl.h>
25#include <apt-pkg/fileutl.h>
26#include <apt-pkg/md5.h>
27
28#include <apti18n.h>
29
30#include <sys/stat.h>
31#include <unistd.h>
32#include <errno.h>
33#include <string>
34#include <stdio.h>
35 /*}}}*/
36
37using namespace std;
38
39// Acquire::Item::Item - Constructor /*{{{*/
40// ---------------------------------------------------------------------
41/* */
42pkgAcquire::Item::Item(pkgAcquire *Owner) : Owner(Owner), FileSize(0),
43 PartialSize(0), Mode(0), ID(0), Complete(false),
44 Local(false), QueueCounter(0)
45{
46 Owner->Add(this);
47 Status = StatIdle;
48}
49 /*}}}*/
50// Acquire::Item::~Item - Destructor /*{{{*/
51// ---------------------------------------------------------------------
52/* */
53pkgAcquire::Item::~Item()
54{
55 Owner->Remove(this);
56}
57 /*}}}*/
58// Acquire::Item::Failed - Item failed to download /*{{{*/
59// ---------------------------------------------------------------------
60/* We return to an idle state if there are still other queues that could
61 fetch this object */
62void pkgAcquire::Item::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
63{
64 Status = StatIdle;
65 ErrorText = LookupTag(Message,"Message");
66 if (QueueCounter <= 1)
67 {
68 /* This indicates that the file is not available right now but might
69 be sometime later. If we do a retry cycle then this should be
70 retried [CDROMs] */
71 if (Cnf->LocalOnly == true &&
72 StringToBool(LookupTag(Message,"Transient-Failure"),false) == true)
73 {
74 Status = StatIdle;
75 Dequeue();
76 return;
77 }
78
79 Status = StatError;
80 Dequeue();
81 }
82
83 // report mirror failure back to LP if we actually use a mirror
84 if(!UsedMirror.empty())
85 ReportMirrorFailure(ErrorText);
86}
87 /*}}}*/
88// Acquire::Item::Start - Item has begun to download /*{{{*/
89// ---------------------------------------------------------------------
90/* Stash status and the file size. Note that setting Complete means
91 sub-phases of the acquire process such as decompresion are operating */
92void pkgAcquire::Item::Start(string /*Message*/,unsigned long Size)
93{
94 Status = StatFetching;
95 if (FileSize == 0 && Complete == false)
96 FileSize = Size;
97}
98 /*}}}*/
99// Acquire::Item::Done - Item downloaded OK /*{{{*/
100// ---------------------------------------------------------------------
101/* */
102void pkgAcquire::Item::Done(string Message,unsigned long Size,string,
103 pkgAcquire::MethodConfig *Cnf)
104{
105 // We just downloaded something..
106 string FileName = LookupTag(Message,"Filename");
107 UsedMirror = LookupTag(Message,"UsedMirror");
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 }
113
114 if (FileSize == 0)
115 FileSize= Size;
116 Status = StatDone;
117 ErrorText = string();
118 Owner->Dequeue(this);
119}
120 /*}}}*/
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];
130 snprintf(S,sizeof(S),_("rename failed, %s (%s -> %s)."),strerror(errno),
131 From.c_str(),To.c_str());
132 Status = StatError;
133 ErrorText = S;
134 }
135}
136 /*}}}*/
137
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
174// AcqIndex::AcqIndex - Constructor /*{{{*/
175// ---------------------------------------------------------------------
176/* The package file is added to the queue and a second class is
177 instantiated to fetch the revision file */
178pkgAcqIndex::pkgAcqIndex(pkgAcquire *Owner,
179 string URI,string URIDesc,string ShortDesc,
180 string ExpectedMD5, string comprExt) :
181 Item(Owner), RealURI(URI), ExpectedMD5(ExpectedMD5)
182{
183 Decompression = false;
184 Erase = false;
185
186 DestFile = _config->FindDir("Dir::State::lists") + "partial/";
187 DestFile += URItoFileName(URI);
188
189 if(comprExt.empty())
190 {
191 // autoselect the compression method
192 if(FileExists("/bin/bzip2"))
193 CompressionExtension = ".bz2";
194 else
195 CompressionExtension = ".gz";
196 } else {
197 CompressionExtension = comprExt;
198 }
199 Desc.URI = URI + CompressionExtension;
200
201 Desc.Description = URIDesc;
202 Desc.Owner = this;
203 Desc.ShortDesc = ShortDesc;
204
205 QueueURI(Desc);
206}
207 /*}}}*/
208// AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
209// ---------------------------------------------------------------------
210/* The only header we use is the last-modified header. */
211string pkgAcqIndex::Custom600Headers()
212{
213 string Final = _config->FindDir("Dir::State::lists");
214 Final += URItoFileName(RealURI);
215
216 struct stat Buf;
217 if (stat(Final.c_str(),&Buf) != 0)
218 return "\nIndex-File: true";
219 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
220}
221 /*}}}*/
222
223void pkgAcqIndex::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
224{
225 // no .bz2 found, retry with .gz
226 if(Desc.URI.substr(Desc.URI.size()-3) == "bz2") {
227 Desc.URI = Desc.URI.substr(0,Desc.URI.size()-3) + "gz";
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();
235 return;
236 }
237
238
239 Item::Failed(Message,Cnf);
240}
241
242
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. */
250void pkgAcqIndex::Done(string Message,unsigned long Size,string MD5,
251 pkgAcquire::MethodConfig *Cfg)
252{
253 Item::Done(Message,Size,MD5,Cfg);
254
255 if (Decompression == true)
256 {
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 }
279 // Done, move it into position
280 string FinalFile = _config->FindDir("Dir::State::lists");
281 FinalFile += URItoFileName(RealURI);
282 Rename(DestFile,FinalFile);
283 chmod(FinalFile.c_str(),0644);
284
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/";
288 DestFile += URItoFileName(RealURI);
289
290 // Remove the compressed version.
291 if (Erase == true)
292 unlink(DestFile.c_str());
293 return;
294 }
295
296 Erase = false;
297 Complete = true;
298
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;
306
307 Decompression = true;
308 Local = true;
309 DestFile += ".decomp";
310 Desc.URI = "copy:" + FileName;
311 QueueURI(Desc);
312 Mode = "copy";
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;
326
327 if (FileName == DestFile)
328 Erase = true;
329 else
330 Local = true;
331
332 string compExt = Desc.URI.substr(Desc.URI.size()-3);
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
343 Decompression = true;
344 DestFile += ".decomp";
345 Desc.URI = string(decompProg) + ":" + FileName;
346 QueueURI(Desc);
347 Mode = decompProg;
348}
349
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),
357 MetaIndexURIDesc(MetaIndexURIDesc), MetaIndexShortDesc(MetaIndexShortDesc),
358 MetaIndexParser(MetaIndexParser), IndexTargets(IndexTargets)
359{
360 DestFile = _config->FindDir("Dir::State::lists") + "partial/";
361 DestFile += URItoFileName(URI);
362
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
367 // Create the item
368 Desc.Description = URIDesc;
369 Desc.Owner = this;
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 }
383
384 QueueURI(Desc);
385}
386 /*}}}*/
387// pkgAcqMetaSig::Custom600Headers - Insert custom request headers /*{{{*/
388// ---------------------------------------------------------------------
389/* The only header we use is the last-modified header. */
390string pkgAcqMetaSig::Custom600Headers()
391{
392 struct stat Buf;
393 if (stat(DestFile.c_str(),&Buf) != 0)
394 return "\nIndex-File: true";
395
396 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
397}
398
399void pkgAcqMetaSig::Done(string Message,unsigned long Size,string MD5,
400 pkgAcquire::MethodConfig *Cfg)
401{
402 Item::Done(Message,Size,MD5,Cfg);
403
404 string FileName = LookupTag(Message,"Filename");
405 if (FileName.empty() == true)
406 {
407 Status = StatError;
408 ErrorText = "Method gave a blank filename";
409 return;
410 }
411
412 if (FileName != DestFile)
413 {
414 // We have to copy it into place
415 Local = true;
416 Desc.URI = "copy:" + FileName;
417 QueueURI(Desc);
418 return;
419 }
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
427}
428 /*}}}*/
429void pkgAcqMetaSig::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
430{
431
432 // if we get a network error we fail gracefully
433 if(LookupTag(Message,"FailReason") == "Timeout" ||
434 LookupTag(Message,"FailReason") == "TmpResolveFailure" ||
435 LookupTag(Message,"FailReason") == "ConnectionRefused") {
436 Item::Failed(Message,Cnf);
437 return;
438 }
439
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
444 // queue a pkgAcqMetaIndex with no sigfile
445 new pkgAcqMetaIndex(Owner, MetaIndexURI, MetaIndexURIDesc, MetaIndexShortDesc,
446 "", IndexTargets, MetaIndexParser);
447
448 if (Cnf->LocalOnly == true ||
449 StringToBool(LookupTag(Message,"Transient-Failure"),false) == false)
450 {
451 // Ignore this
452 Status = StatDone;
453 Complete = false;
454 Dequeue();
455 return;
456 }
457
458 Item::Failed(Message,Cnf);
459}
460
461pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire *Owner,
462 string URI,string URIDesc,string ShortDesc,
463 string SigFile,
464 const vector<struct IndexTarget*>* IndexTargets,
465 indexRecords* MetaIndexParser) :
466 Item(Owner), RealURI(URI), SigFile(SigFile), AuthPass(false),
467 MetaIndexParser(MetaIndexParser), IndexTargets(IndexTargets), IMSHit(false)
468{
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
560 // see if the download was a IMSHit
561 IMSHit = StringToBool(LookupTag(Message,"IMS-Hit"),false);
562
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
591 if (!VerifyVendor(Message))
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
649bool pkgAcqMetaIndex::VerifyVendor(string Message)
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// }
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;
679 string msg = _("There is no public key available for the "
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());
690
691 string Transformed = MetaIndexParser->GetExpectedDist();
692
693 if (Transformed == "../project/experimental")
694 {
695 Transformed = "experimental";
696 }
697
698 pos = Transformed.rfind('/');
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 {
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
764 _error->Warning("GPG error: %s: %s",
765 Desc.Description.c_str(),
766 LookupTag(Message,"Message").c_str());
767
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
775 /*}}}*/
776
777// AcqArchive::AcqArchive - Constructor /*{{{*/
778// ---------------------------------------------------------------------
779/* This just sets up the initial fetch environment and queues the first
780 possibilitiy */
781pkgAcqArchive::pkgAcqArchive(pkgAcquire *Owner,pkgSourceList *Sources,
782 pkgRecords *Recs,pkgCache::VerIterator const &Version,
783 string &StoreFilename) :
784 Item(Owner), Version(Version), Sources(Sources), Recs(Recs),
785 StoreFilename(StoreFilename), Vf(Version.FileList()),
786 Trusted(false)
787{
788 Retries = _config->FindI("Acquire::Retries",0);
789
790 if (Version.Arch() == 0)
791 {
792 _error->Error(_("I wasn't able to locate a file for the %s package. "
793 "This might mean you need to manually fix this package. "
794 "(due to missing arch)"),
795 Version.ParentPkg().Name());
796 return;
797 }
798
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 }
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
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
849 // Select a source
850 if (QueueNext() == false && _error->PendingError() == false)
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."),
853 Version.ParentPkg().Name());
854}
855 /*}}}*/
856// AcqArchive::QueueNext - Queue the next file source /*{{{*/
857// ---------------------------------------------------------------------
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. */
861bool pkgAcqArchive::QueueNext()
862{
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
870 pkgIndexFile *Index;
871 if (Sources->FindIndex(Vf.File(),Index) == false)
872 continue;
873
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
879 // Grab the text package record
880 pkgRecords::Parser &Parse = Recs->Lookup(Vf);
881 if (_error->PendingError() == true)
882 return false;
883
884 string PkgFile = Parse.FileName();
885 MD5 = Parse.MD5Hash();
886 if (PkgFile.empty() == true)
887 return _error->Error(_("The package index files are corrupted. No Filename: "
888 "field for package %s."),
889 Version.ParentPkg().Name());
890
891 Desc.URI = Index->ArchiveURI(PkgFile);
892 Desc.Description = Index->ArchiveInfo(Version);
893 Desc.Owner = this;
894 Desc.ShortDesc = Version.ParentPkg().Name();
895
896 // See if we already have the file. (Legacy filenames)
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;
908 StoreFilename = DestFile = FinalFile;
909 return true;
910 }
911
912 /* Hmm, we have a file and its size does not match, this means it is
913 an old style mismatched arch */
914 unlink(FinalFile.c_str());
915 }
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);
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
948 // Create the item
949 Local = false;
950 Desc.URI = Index->ArchiveURI(PkgFile);
951 Desc.Description = Index->ArchiveInfo(Version);
952 Desc.Owner = this;
953 Desc.ShortDesc = Version.ParentPkg().Name();
954 QueueURI(Desc);
955
956 Vf++;
957 return true;
958 }
959 return false;
960}
961 /*}}}*/
962// AcqArchive::Done - Finished fetching /*{{{*/
963// ---------------------------------------------------------------------
964/* */
965void pkgAcqArchive::Done(string Message,unsigned long Size,string Md5Hash,
966 pkgAcquire::MethodConfig *Cfg)
967{
968 Item::Done(Message,Size,Md5Hash,Cfg);
969
970 // Check the size
971 if (Size != Version->Size)
972 {
973 Status = StatError;
974 ErrorText = _("Size mismatch");
975 return;
976 }
977
978 // Check the md5
979 if (Md5Hash.empty() == false && MD5.empty() == false)
980 {
981 if (Md5Hash != MD5)
982 {
983 Status = StatError;
984 ErrorText = _("MD5Sum mismatch");
985 if(FileExists(DestFile))
986 Rename(DestFile,DestFile + ".FAILED");
987 return;
988 }
989 }
990
991 // Grab the output filename
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 }
999
1000 Complete = true;
1001
1002 // Reference filename
1003 if (FileName != DestFile)
1004 {
1005 StoreFilename = DestFile = FileName;
1006 Local = true;
1007 return;
1008 }
1009
1010 // Done, move it into position
1011 string FinalFile = _config->FindDir("Dir::Cache::Archives");
1012 FinalFile += flNotDir(StoreFilename);
1013 Rename(DestFile,FinalFile);
1014
1015 StoreFilename = DestFile = FinalFile;
1016 Complete = true;
1017}
1018 /*}}}*/
1019// AcqArchive::Failed - Failure handler /*{{{*/
1020// ---------------------------------------------------------------------
1021/* Here we try other sources */
1022void pkgAcqArchive::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
1023{
1024 ErrorText = LookupTag(Message,"Message");
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
1039 if (QueueNext() == false)
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
1052 StoreFilename = string();
1053 Item::Failed(Message,Cnf);
1054 }
1055}
1056 /*}}}*/
1057// AcqArchive::IsTrusted - Determine whether this archive comes from a
1058// trusted source /*{{{*/
1059// ---------------------------------------------------------------------
1060bool pkgAcqArchive::IsTrusted()
1061{
1062 return Trusted;
1063}
1064
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 /*}}}*/
1076
1077// AcqFile::pkgAcqFile - Constructor /*{{{*/
1078// ---------------------------------------------------------------------
1079/* The file is added to the queue */
1080pkgAcqFile::pkgAcqFile(pkgAcquire *Owner,string URI,string MD5,
1081 unsigned long Size,string Dsc,string ShortDesc,
1082 const string &DestDir, const string &DestFilename) :
1083 Item(Owner), Md5Hash(MD5)
1084{
1085 Retries = _config->FindI("Acquire::Retries",0);
1086
1087 if(!DestFilename.empty())
1088 DestFile = DestFilename;
1089 else if(!DestDir.empty())
1090 DestFile = DestDir + "/" + flNotDir(URI);
1091 else
1092 DestFile = flNotDir(URI);
1093
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 }
1113
1114 QueueURI(Desc);
1115}
1116 /*}}}*/
1117// AcqFile::Done - Item downloaded OK /*{{{*/
1118// ---------------------------------------------------------------------
1119/* */
1120void pkgAcqFile::Done(string Message,unsigned long Size,string MD5,
1121 pkgAcquire::MethodConfig *Cnf)
1122{
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
1135 Item::Done(Message,Size,MD5,Cnf);
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;
1155 if (_config->FindB("Acquire::Source-Symlinks",true) == false ||
1156 Cnf->Removable == true)
1157 {
1158 Desc.URI = "copy:" + FileName;
1159 QueueURI(Desc);
1160 return;
1161 }
1162
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
1172 if (symlink(FileName.c_str(),DestFile.c_str()) != 0)
1173 {
1174 ErrorText = "Link to " + DestFile + " failure ";
1175 Status = StatError;
1176 Complete = false;
1177 }
1178 }
1179}
1180 /*}}}*/
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 /*}}}*/