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