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