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