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