]> git.saurik.com Git - apt.git/blame - apt-pkg/acquire-item.cc
* apt-pkg/indexfile.cc:
[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
a52f938b
OS
311// AcqIndexTrans::pkgAcqIndexTrans - Constructor /*{{{*/
312// ---------------------------------------------------------------------
313/* The Translation file is added to the queue */
314pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire *Owner,
315 string URI,string URIDesc,string ShortDesc) :
a7a5b0d9 316 pkgAcqIndex(Owner, URI, URIDesc, ShortDesc, "", "")
a52f938b
OS
317{
318}
319
320 /*}}}*/
321// AcqIndexTrans::Failed - Silence failure messages for missing files /*{{{*/
322// ---------------------------------------------------------------------
323/* */
324void pkgAcqIndexTrans::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
325{
326 if (Cnf->LocalOnly == true ||
327 StringToBool(LookupTag(Message,"Transient-Failure"),false) == false)
328 {
329 // Ignore this
330 Status = StatDone;
331 Complete = false;
332 Dequeue();
333 return;
334 }
335
336 Item::Failed(Message,Cnf);
337}
338 /*}}}*/
339
b3d44315
MV
340pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire *Owner,
341 string URI,string URIDesc,string ShortDesc,
342 string MetaIndexURI, string MetaIndexURIDesc,
343 string MetaIndexShortDesc,
344 const vector<IndexTarget*>* IndexTargets,
345 indexRecords* MetaIndexParser) :
346 Item(Owner), RealURI(URI), MetaIndexURI(MetaIndexURI),
347 MetaIndexURIDesc(MetaIndexURIDesc), MetaIndexShortDesc(MetaIndexShortDesc)
0118833a 348{
b3d44315
MV
349 this->MetaIndexParser = MetaIndexParser;
350 this->IndexTargets = IndexTargets;
0a8a80e5 351 DestFile = _config->FindDir("Dir::State::lists") + "partial/";
b2e465d6 352 DestFile += URItoFileName(URI);
b3d44315 353
f6237efd
MV
354 // remove any partial downloaded sig-file. it may confuse proxies
355 // and is too small to warrant a partial download anyway
356 unlink(DestFile.c_str());
357
8267fe24 358 // Create the item
b2e465d6 359 Desc.Description = URIDesc;
8267fe24 360 Desc.Owner = this;
b3d44315
MV
361 Desc.ShortDesc = ShortDesc;
362 Desc.URI = URI;
363
364
365 string Final = _config->FindDir("Dir::State::lists");
366 Final += URItoFileName(RealURI);
367 struct stat Buf;
368 if (stat(Final.c_str(),&Buf) == 0)
369 {
370 // File was already in place. It needs to be re-verified
371 // because Release might have changed, so Move it into partial
372 Rename(Final,DestFile);
284c8bbc
MV
373 // unlink the file and do not try to use I-M-S and Last-Modified
374 // if the users proxy is broken
375 if(_config->FindB("Acquire::BrokenProxy", false) == true) {
376 std::cerr << "forcing re-get of the signature file as requested" << std::endl;
377 unlink(DestFile.c_str());
378 }
b3d44315 379 }
8267fe24 380
8267fe24 381 QueueURI(Desc);
0118833a
AL
382}
383 /*}}}*/
b3d44315 384// pkgAcqMetaSig::Custom600Headers - Insert custom request headers /*{{{*/
0118833a 385// ---------------------------------------------------------------------
0a8a80e5 386/* The only header we use is the last-modified header. */
b3d44315 387string pkgAcqMetaSig::Custom600Headers()
0118833a 388{
0a8a80e5 389 struct stat Buf;
2aab5956 390 if (stat(DestFile.c_str(),&Buf) != 0)
a72ace20 391 return "\nIndex-File: true";
a789b983 392
a72ace20 393 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
0118833a 394}
b3d44315
MV
395
396void pkgAcqMetaSig::Done(string Message,unsigned long Size,string MD5,
397 pkgAcquire::MethodConfig *Cfg)
c88edf1d 398{
459681d3 399 Item::Done(Message,Size,MD5,Cfg);
c88edf1d
AL
400
401 string FileName = LookupTag(Message,"Filename");
402 if (FileName.empty() == true)
403 {
404 Status = StatError;
405 ErrorText = "Method gave a blank filename";
8b89e57f 406 return;
c88edf1d 407 }
8b89e57f 408
c88edf1d
AL
409 if (FileName != DestFile)
410 {
b3d44315 411 // We have to copy it into place
a6568219 412 Local = true;
8267fe24
AL
413 Desc.URI = "copy:" + FileName;
414 QueueURI(Desc);
c88edf1d
AL
415 return;
416 }
b3d44315
MV
417
418 Complete = true;
419
420 // queue a pkgAcqMetaIndex to be verified against the sig we just retrieved
421 new pkgAcqMetaIndex(Owner, MetaIndexURI, MetaIndexURIDesc, MetaIndexShortDesc,
422 DestFile, IndexTargets, MetaIndexParser);
423
c88edf1d
AL
424}
425 /*}}}*/
b3d44315 426void pkgAcqMetaSig::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
681d76d0 427{
b3d44315
MV
428 // Delete any existing sigfile, so that this source isn't
429 // mistakenly trusted
430 string Final = _config->FindDir("Dir::State::lists") + URItoFileName(RealURI);
431 unlink(Final.c_str());
a789b983 432
24057ad6 433 // if we get a timeout if fail
25182152
MV
434 if(LookupTag(Message,"FailReason") == "Timeout" ||
435 LookupTag(Message,"FailReason") == "TmpResolveFailure") {
24057ad6
MV
436 Item::Failed(Message,Cnf);
437 return;
438 }
439
b3d44315
MV
440 // queue a pkgAcqMetaIndex with no sigfile
441 new pkgAcqMetaIndex(Owner, MetaIndexURI, MetaIndexURIDesc, MetaIndexShortDesc,
442 "", IndexTargets, MetaIndexParser);
443
681d76d0
AL
444 if (Cnf->LocalOnly == true ||
445 StringToBool(LookupTag(Message,"Transient-Failure"),false) == false)
446 {
2b154e53
AL
447 // Ignore this
448 Status = StatDone;
449 Complete = false;
681d76d0
AL
450 Dequeue();
451 return;
452 }
453
454 Item::Failed(Message,Cnf);
455}
b3d44315
MV
456
457pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire *Owner,
458 string URI,string URIDesc,string ShortDesc,
459 string SigFile,
460 const vector<struct IndexTarget*>* IndexTargets,
461 indexRecords* MetaIndexParser) :
462 Item(Owner), RealURI(URI), SigFile(SigFile)
463{
464 this->AuthPass = false;
465 this->MetaIndexParser = MetaIndexParser;
466 this->IndexTargets = IndexTargets;
467 DestFile = _config->FindDir("Dir::State::lists") + "partial/";
468 DestFile += URItoFileName(URI);
469
470 // Create the item
471 Desc.Description = URIDesc;
472 Desc.Owner = this;
473 Desc.ShortDesc = ShortDesc;
474 Desc.URI = URI;
475
476 QueueURI(Desc);
477}
478
479 /*}}}*/
480// pkgAcqMetaIndex::Custom600Headers - Insert custom request headers /*{{{*/
481// ---------------------------------------------------------------------
482/* The only header we use is the last-modified header. */
483string pkgAcqMetaIndex::Custom600Headers()
484{
485 string Final = _config->FindDir("Dir::State::lists");
486 Final += URItoFileName(RealURI);
487
488 struct stat Buf;
489 if (stat(Final.c_str(),&Buf) != 0)
490 return "\nIndex-File: true";
491
492 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
493}
494
495void pkgAcqMetaIndex::Done(string Message,unsigned long Size,string MD5,
496 pkgAcquire::MethodConfig *Cfg)
497{
498 Item::Done(Message,Size,MD5,Cfg);
499
500 // MetaIndexes are done in two passes: one to download the
501 // metaindex with an appropriate method, and a second to verify it
502 // with the gpgv method
503
504 if (AuthPass == true)
505 {
506 AuthDone(Message);
507 }
508 else
509 {
510 RetrievalDone(Message);
511 if (!Complete)
512 // Still more retrieving to do
513 return;
514
515 if (SigFile == "")
516 {
517 // There was no signature file, so we are finished. Download
518 // the indexes without verification.
519 QueueIndexes(false);
520 }
521 else
522 {
523 // There was a signature file, so pass it to gpgv for
524 // verification
525
526 if (_config->FindB("Debug::pkgAcquire::Auth", false))
527 std::cerr << "Metaindex acquired, queueing gpg verification ("
528 << SigFile << "," << DestFile << ")\n";
529 AuthPass = true;
530 Desc.URI = "gpgv:" + SigFile;
531 QueueURI(Desc);
532 Mode = "gpgv";
533 }
534 }
535}
536
537void pkgAcqMetaIndex::RetrievalDone(string Message)
538{
539 // We have just finished downloading a Release file (it is not
540 // verified yet)
541
542 string FileName = LookupTag(Message,"Filename");
543 if (FileName.empty() == true)
544 {
545 Status = StatError;
546 ErrorText = "Method gave a blank filename";
547 return;
548 }
549
550 if (FileName != DestFile)
551 {
552 Local = true;
553 Desc.URI = "copy:" + FileName;
554 QueueURI(Desc);
555 return;
556 }
557
558 Complete = true;
559
560 string FinalFile = _config->FindDir("Dir::State::lists");
561 FinalFile += URItoFileName(RealURI);
562
563 // The files timestamp matches
564 if (StringToBool(LookupTag(Message,"IMS-Hit"),false) == false)
565 {
566 // Move it into position
567 Rename(DestFile,FinalFile);
568 }
569 DestFile = FinalFile;
570}
571
572void pkgAcqMetaIndex::AuthDone(string Message)
573{
574 // At this point, the gpgv method has succeeded, so there is a
575 // valid signature from a key in the trusted keyring. We
576 // perform additional verification of its contents, and use them
577 // to verify the indexes we are about to download
578
579 if (!MetaIndexParser->Load(DestFile))
580 {
581 Status = StatAuthError;
582 ErrorText = MetaIndexParser->ErrorText;
583 return;
584 }
585
586 if (!VerifyVendor())
587 {
588 return;
589 }
590
591 if (_config->FindB("Debug::pkgAcquire::Auth", false))
592 std::cerr << "Signature verification succeeded: "
593 << DestFile << std::endl;
594
595 // Download further indexes with verification
596 QueueIndexes(true);
597
598 // Done, move signature file into position
599
600 string VerifiedSigFile = _config->FindDir("Dir::State::lists") +
601 URItoFileName(RealURI) + ".gpg";
602 Rename(SigFile,VerifiedSigFile);
603 chmod(VerifiedSigFile.c_str(),0644);
604}
605
606void pkgAcqMetaIndex::QueueIndexes(bool verify)
607{
608 for (vector <struct IndexTarget*>::const_iterator Target = IndexTargets->begin();
609 Target != IndexTargets->end();
610 Target++)
611 {
612 string ExpectedIndexMD5;
613 if (verify)
614 {
615 const indexRecords::checkSum *Record = MetaIndexParser->Lookup((*Target)->MetaKey);
616 if (!Record)
617 {
618 Status = StatAuthError;
619 ErrorText = "Unable to find expected entry "
620 + (*Target)->MetaKey + " in Meta-index file (malformed Release file?)";
621 return;
622 }
623 ExpectedIndexMD5 = Record->MD5Hash;
624 if (_config->FindB("Debug::pkgAcquire::Auth", false))
625 {
626 std::cerr << "Queueing: " << (*Target)->URI << std::endl;
627 std::cerr << "Expected MD5: " << ExpectedIndexMD5 << std::endl;
628 }
629 if (ExpectedIndexMD5.empty())
630 {
631 Status = StatAuthError;
632 ErrorText = "Unable to find MD5 sum for "
633 + (*Target)->MetaKey + " in Meta-index file";
634 return;
635 }
636 }
637
638 // Queue Packages file
639 new pkgAcqIndex(Owner, (*Target)->URI, (*Target)->Description,
640 (*Target)->ShortDesc, ExpectedIndexMD5);
641 }
642}
643
644bool pkgAcqMetaIndex::VerifyVendor()
645{
646// // Maybe this should be made available from above so we don't have
647// // to read and parse it every time?
648// pkgVendorList List;
649// List.ReadMainList();
650
651// const Vendor* Vndr = NULL;
652// for (std::vector<string>::const_iterator I = GPGVOutput.begin(); I != GPGVOutput.end(); I++)
653// {
654// string::size_type pos = (*I).find("VALIDSIG ");
655// if (_config->FindB("Debug::Vendor", false))
656// std::cerr << "Looking for VALIDSIG in \"" << (*I) << "\": pos " << pos
657// << std::endl;
658// if (pos != std::string::npos)
659// {
660// string Fingerprint = (*I).substr(pos+sizeof("VALIDSIG"));
661// if (_config->FindB("Debug::Vendor", false))
662// std::cerr << "Looking for \"" << Fingerprint << "\" in vendor..." <<
663// std::endl;
664// Vndr = List.FindVendor(Fingerprint) != "";
665// if (Vndr != NULL);
666// break;
667// }
668// }
669
670 string Transformed = MetaIndexParser->GetExpectedDist();
671
672 if (Transformed == "../project/experimental")
673 {
674 Transformed = "experimental";
675 }
676
677 string::size_type pos = Transformed.rfind('/');
678 if (pos != string::npos)
679 {
680 Transformed = Transformed.substr(0, pos);
681 }
682
683 if (Transformed == ".")
684 {
685 Transformed = "";
686 }
687
688 if (_config->FindB("Debug::pkgAcquire::Auth", false))
689 {
690 std::cerr << "Got Codename: " << MetaIndexParser->GetDist() << std::endl;
691 std::cerr << "Expecting Dist: " << MetaIndexParser->GetExpectedDist() << std::endl;
692 std::cerr << "Transformed Dist: " << Transformed << std::endl;
693 }
694
695 if (MetaIndexParser->CheckDist(Transformed) == false)
696 {
697 // This might become fatal one day
698// Status = StatAuthError;
699// ErrorText = "Conflicting distribution; expected "
700// + MetaIndexParser->GetExpectedDist() + " but got "
701// + MetaIndexParser->GetDist();
702// return false;
703 if (!Transformed.empty())
704 {
705 _error->Warning("Conflicting distribution: %s (expected %s but got %s)",
706 Desc.Description.c_str(),
707 Transformed.c_str(),
708 MetaIndexParser->GetDist().c_str());
709 }
710 }
711
712 return true;
713}
714 /*}}}*/
715// pkgAcqMetaIndex::Failed - no Release file present or no signature
716// file present /*{{{*/
717// ---------------------------------------------------------------------
718/* */
719void pkgAcqMetaIndex::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
720{
721 if (AuthPass == true)
722 {
723 // gpgv method failed
724 _error->Warning("GPG error: %s: %s",
725 Desc.Description.c_str(),
726 LookupTag(Message,"Message").c_str());
727 }
728
729 // No Release file was present, or verification failed, so fall
730 // back to queueing Packages files without verification
731 QueueIndexes(false);
732}
733
681d76d0 734 /*}}}*/
03e39e59
AL
735
736// AcqArchive::AcqArchive - Constructor /*{{{*/
737// ---------------------------------------------------------------------
17caf1b1
AL
738/* This just sets up the initial fetch environment and queues the first
739 possibilitiy */
03e39e59 740pkgAcqArchive::pkgAcqArchive(pkgAcquire *Owner,pkgSourceList *Sources,
30e1eab5
AL
741 pkgRecords *Recs,pkgCache::VerIterator const &Version,
742 string &StoreFilename) :
743 Item(Owner), Version(Version), Sources(Sources), Recs(Recs),
b3d44315
MV
744 StoreFilename(StoreFilename), Vf(Version.FileList()),
745 Trusted(false)
03e39e59 746{
7d8afa39 747 Retries = _config->FindI("Acquire::Retries",0);
813c8eea
AL
748
749 if (Version.Arch() == 0)
bdae53f1 750 {
d1f1f6a8 751 _error->Error(_("I wasn't able to locate a file for the %s package. "
7a3c2ab0
AL
752 "This might mean you need to manually fix this package. "
753 "(due to missing arch)"),
813c8eea 754 Version.ParentPkg().Name());
bdae53f1
AL
755 return;
756 }
813c8eea 757
b2e465d6
AL
758 /* We need to find a filename to determine the extension. We make the
759 assumption here that all the available sources for this version share
760 the same extension.. */
761 // Skip not source sources, they do not have file fields.
762 for (; Vf.end() == false; Vf++)
763 {
764 if ((Vf.File()->Flags & pkgCache::Flag::NotSource) != 0)
765 continue;
766 break;
767 }
768
769 // Does not really matter here.. we are going to fail out below
770 if (Vf.end() != true)
771 {
772 // If this fails to get a file name we will bomb out below.
773 pkgRecords::Parser &Parse = Recs->Lookup(Vf);
774 if (_error->PendingError() == true)
775 return;
776
777 // Generate the final file name as: package_version_arch.foo
778 StoreFilename = QuoteString(Version.ParentPkg().Name(),"_:") + '_' +
779 QuoteString(Version.VerStr(),"_:") + '_' +
780 QuoteString(Version.Arch(),"_:.") +
781 "." + flExtension(Parse.FileName());
782 }
b3d44315
MV
783
784 // check if we have one trusted source for the package. if so, switch
785 // to "TrustedOnly" mode
786 for (pkgCache::VerFileIterator i = Version.FileList(); i.end() == false; i++)
787 {
788 pkgIndexFile *Index;
789 if (Sources->FindIndex(i.File(),Index) == false)
790 continue;
791 if (_config->FindB("Debug::pkgAcquire::Auth", false))
792 {
793 std::cerr << "Checking index: " << Index->Describe()
794 << "(Trusted=" << Index->IsTrusted() << ")\n";
795 }
796 if (Index->IsTrusted()) {
797 Trusted = true;
798 break;
799 }
800 }
801
03e39e59 802 // Select a source
b185acc2 803 if (QueueNext() == false && _error->PendingError() == false)
b2e465d6
AL
804 _error->Error(_("I wasn't able to locate file for the %s package. "
805 "This might mean you need to manually fix this package."),
b185acc2
AL
806 Version.ParentPkg().Name());
807}
808 /*}}}*/
809// AcqArchive::QueueNext - Queue the next file source /*{{{*/
810// ---------------------------------------------------------------------
17caf1b1
AL
811/* This queues the next available file version for download. It checks if
812 the archive is already available in the cache and stashs the MD5 for
813 checking later. */
b185acc2 814bool pkgAcqArchive::QueueNext()
b2e465d6 815{
03e39e59
AL
816 for (; Vf.end() == false; Vf++)
817 {
818 // Ignore not source sources
819 if ((Vf.File()->Flags & pkgCache::Flag::NotSource) != 0)
820 continue;
821
822 // Try to cross match against the source list
b2e465d6
AL
823 pkgIndexFile *Index;
824 if (Sources->FindIndex(Vf.File(),Index) == false)
825 continue;
03e39e59 826
b3d44315
MV
827 // only try to get a trusted package from another source if that source
828 // is also trusted
829 if(Trusted && !Index->IsTrusted())
830 continue;
831
03e39e59
AL
832 // Grab the text package record
833 pkgRecords::Parser &Parse = Recs->Lookup(Vf);
834 if (_error->PendingError() == true)
b185acc2 835 return false;
03e39e59 836
b2e465d6 837 string PkgFile = Parse.FileName();
03e39e59
AL
838 MD5 = Parse.MD5Hash();
839 if (PkgFile.empty() == true)
b2e465d6
AL
840 return _error->Error(_("The package index files are corrupted. No Filename: "
841 "field for package %s."),
842 Version.ParentPkg().Name());
a6568219 843
b3d44315
MV
844 Desc.URI = Index->ArchiveURI(PkgFile);
845 Desc.Description = Index->ArchiveInfo(Version);
846 Desc.Owner = this;
847 Desc.ShortDesc = Version.ParentPkg().Name();
848
17caf1b1 849 // See if we already have the file. (Legacy filenames)
a6568219
AL
850 FileSize = Version->Size;
851 string FinalFile = _config->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile);
852 struct stat Buf;
853 if (stat(FinalFile.c_str(),&Buf) == 0)
854 {
855 // Make sure the size matches
856 if ((unsigned)Buf.st_size == Version->Size)
857 {
858 Complete = true;
859 Local = true;
860 Status = StatDone;
30e1eab5 861 StoreFilename = DestFile = FinalFile;
b185acc2 862 return true;
a6568219
AL
863 }
864
6b1ff003
AL
865 /* Hmm, we have a file and its size does not match, this means it is
866 an old style mismatched arch */
a6568219
AL
867 unlink(FinalFile.c_str());
868 }
17caf1b1
AL
869
870 // Check it again using the new style output filenames
871 FinalFile = _config->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename);
872 if (stat(FinalFile.c_str(),&Buf) == 0)
873 {
874 // Make sure the size matches
875 if ((unsigned)Buf.st_size == Version->Size)
876 {
877 Complete = true;
878 Local = true;
879 Status = StatDone;
880 StoreFilename = DestFile = FinalFile;
881 return true;
882 }
883
884 /* Hmm, we have a file and its size does not match, this shouldnt
885 happen.. */
886 unlink(FinalFile.c_str());
887 }
888
889 DestFile = _config->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename);
6b1ff003
AL
890
891 // Check the destination file
892 if (stat(DestFile.c_str(),&Buf) == 0)
893 {
894 // Hmm, the partial file is too big, erase it
895 if ((unsigned)Buf.st_size > Version->Size)
896 unlink(DestFile.c_str());
897 else
898 PartialSize = Buf.st_size;
899 }
900
03e39e59 901 // Create the item
b2e465d6
AL
902 Local = false;
903 Desc.URI = Index->ArchiveURI(PkgFile);
904 Desc.Description = Index->ArchiveInfo(Version);
03e39e59
AL
905 Desc.Owner = this;
906 Desc.ShortDesc = Version.ParentPkg().Name();
907 QueueURI(Desc);
b185acc2
AL
908
909 Vf++;
910 return true;
03e39e59 911 }
b185acc2
AL
912 return false;
913}
03e39e59
AL
914 /*}}}*/
915// AcqArchive::Done - Finished fetching /*{{{*/
916// ---------------------------------------------------------------------
917/* */
459681d3
AL
918void pkgAcqArchive::Done(string Message,unsigned long Size,string Md5Hash,
919 pkgAcquire::MethodConfig *Cfg)
03e39e59 920{
459681d3 921 Item::Done(Message,Size,Md5Hash,Cfg);
03e39e59
AL
922
923 // Check the size
924 if (Size != Version->Size)
925 {
bdae53f1 926 Status = StatError;
b2e465d6 927 ErrorText = _("Size mismatch");
03e39e59
AL
928 return;
929 }
930
931 // Check the md5
932 if (Md5Hash.empty() == false && MD5.empty() == false)
933 {
934 if (Md5Hash != MD5)
935 {
bdae53f1 936 Status = StatError;
b2e465d6 937 ErrorText = _("MD5Sum mismatch");
13e8426f
MV
938 if(FileExists(DestFile))
939 Rename(DestFile,DestFile + ".FAILED");
03e39e59
AL
940 return;
941 }
942 }
a6568219
AL
943
944 // Grab the output filename
03e39e59
AL
945 string FileName = LookupTag(Message,"Filename");
946 if (FileName.empty() == true)
947 {
948 Status = StatError;
949 ErrorText = "Method gave a blank filename";
950 return;
951 }
a6568219
AL
952
953 Complete = true;
30e1eab5
AL
954
955 // Reference filename
a6568219
AL
956 if (FileName != DestFile)
957 {
30e1eab5 958 StoreFilename = DestFile = FileName;
a6568219
AL
959 Local = true;
960 return;
961 }
962
963 // Done, move it into position
964 string FinalFile = _config->FindDir("Dir::Cache::Archives");
17caf1b1 965 FinalFile += flNotDir(StoreFilename);
a6568219 966 Rename(DestFile,FinalFile);
03e39e59 967
30e1eab5 968 StoreFilename = DestFile = FinalFile;
03e39e59
AL
969 Complete = true;
970}
971 /*}}}*/
db890fdb
AL
972// AcqArchive::Failed - Failure handler /*{{{*/
973// ---------------------------------------------------------------------
974/* Here we try other sources */
7d8afa39 975void pkgAcqArchive::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
db890fdb
AL
976{
977 ErrorText = LookupTag(Message,"Message");
b2e465d6
AL
978
979 /* We don't really want to retry on failed media swaps, this prevents
980 that. An interesting observation is that permanent failures are not
981 recorded. */
982 if (Cnf->Removable == true &&
983 StringToBool(LookupTag(Message,"Transient-Failure"),false) == true)
984 {
985 // Vf = Version.FileList();
986 while (Vf.end() == false) Vf++;
987 StoreFilename = string();
988 Item::Failed(Message,Cnf);
989 return;
990 }
991
db890fdb 992 if (QueueNext() == false)
7d8afa39
AL
993 {
994 // This is the retry counter
995 if (Retries != 0 &&
996 Cnf->LocalOnly == false &&
997 StringToBool(LookupTag(Message,"Transient-Failure"),false) == true)
998 {
999 Retries--;
1000 Vf = Version.FileList();
1001 if (QueueNext() == true)
1002 return;
1003 }
1004
9dbb421f 1005 StoreFilename = string();
7d8afa39
AL
1006 Item::Failed(Message,Cnf);
1007 }
db890fdb
AL
1008}
1009 /*}}}*/
b3d44315
MV
1010// AcqArchive::IsTrusted - Determine whether this archive comes from a
1011// trusted source /*{{{*/
1012// ---------------------------------------------------------------------
1013bool pkgAcqArchive::IsTrusted()
1014{
1015 return Trusted;
1016}
1017
ab559b35
AL
1018// AcqArchive::Finished - Fetching has finished, tidy up /*{{{*/
1019// ---------------------------------------------------------------------
1020/* */
1021void pkgAcqArchive::Finished()
1022{
1023 if (Status == pkgAcquire::Item::StatDone &&
1024 Complete == true)
1025 return;
1026 StoreFilename = string();
1027}
1028 /*}}}*/
36375005
AL
1029
1030// AcqFile::pkgAcqFile - Constructor /*{{{*/
1031// ---------------------------------------------------------------------
1032/* The file is added to the queue */
1033pkgAcqFile::pkgAcqFile(pkgAcquire *Owner,string URI,string MD5,
1034 unsigned long Size,string Dsc,string ShortDesc) :
b3c39978 1035 Item(Owner), Md5Hash(MD5)
36375005 1036{
08cfc005
AL
1037 Retries = _config->FindI("Acquire::Retries",0);
1038
36375005
AL
1039 DestFile = flNotDir(URI);
1040
1041 // Create the item
1042 Desc.URI = URI;
1043 Desc.Description = Dsc;
1044 Desc.Owner = this;
1045
1046 // Set the short description to the archive component
1047 Desc.ShortDesc = ShortDesc;
1048
1049 // Get the transfer sizes
1050 FileSize = Size;
1051 struct stat Buf;
1052 if (stat(DestFile.c_str(),&Buf) == 0)
1053 {
1054 // Hmm, the partial file is too big, erase it
1055 if ((unsigned)Buf.st_size > Size)
1056 unlink(DestFile.c_str());
1057 else
1058 PartialSize = Buf.st_size;
1059 }
1060
1061 QueueURI(Desc);
1062}
1063 /*}}}*/
1064// AcqFile::Done - Item downloaded OK /*{{{*/
1065// ---------------------------------------------------------------------
1066/* */
459681d3
AL
1067void pkgAcqFile::Done(string Message,unsigned long Size,string MD5,
1068 pkgAcquire::MethodConfig *Cnf)
36375005 1069{
b3c39978
AL
1070 // Check the md5
1071 if (Md5Hash.empty() == false && MD5.empty() == false)
1072 {
1073 if (Md5Hash != MD5)
1074 {
1075 Status = StatError;
1076 ErrorText = "MD5Sum mismatch";
1077 Rename(DestFile,DestFile + ".FAILED");
1078 return;
1079 }
1080 }
1081
459681d3 1082 Item::Done(Message,Size,MD5,Cnf);
36375005
AL
1083
1084 string FileName = LookupTag(Message,"Filename");
1085 if (FileName.empty() == true)
1086 {
1087 Status = StatError;
1088 ErrorText = "Method gave a blank filename";
1089 return;
1090 }
1091
1092 Complete = true;
1093
1094 // The files timestamp matches
1095 if (StringToBool(LookupTag(Message,"IMS-Hit"),false) == true)
1096 return;
1097
1098 // We have to copy it into place
1099 if (FileName != DestFile)
1100 {
1101 Local = true;
459681d3
AL
1102 if (_config->FindB("Acquire::Source-Symlinks",true) == false ||
1103 Cnf->Removable == true)
917ae805
AL
1104 {
1105 Desc.URI = "copy:" + FileName;
1106 QueueURI(Desc);
1107 return;
1108 }
1109
83ab33fc
AL
1110 // Erase the file if it is a symlink so we can overwrite it
1111 struct stat St;
1112 if (lstat(DestFile.c_str(),&St) == 0)
1113 {
1114 if (S_ISLNK(St.st_mode) != 0)
1115 unlink(DestFile.c_str());
1116 }
1117
1118 // Symlink the file
917ae805
AL
1119 if (symlink(FileName.c_str(),DestFile.c_str()) != 0)
1120 {
83ab33fc 1121 ErrorText = "Link to " + DestFile + " failure ";
917ae805
AL
1122 Status = StatError;
1123 Complete = false;
1124 }
36375005
AL
1125 }
1126}
1127 /*}}}*/
08cfc005
AL
1128// AcqFile::Failed - Failure handler /*{{{*/
1129// ---------------------------------------------------------------------
1130/* Here we try other sources */
1131void pkgAcqFile::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
1132{
1133 ErrorText = LookupTag(Message,"Message");
1134
1135 // This is the retry counter
1136 if (Retries != 0 &&
1137 Cnf->LocalOnly == false &&
1138 StringToBool(LookupTag(Message,"Transient-Failure"),false) == true)
1139 {
1140 Retries--;
1141 QueueURI(Desc);
1142 return;
1143 }
1144
1145 Item::Failed(Message,Cnf);
1146}
1147 /*}}}*/