]> git.saurik.com Git - apt.git/blame - apt-pkg/acquire-item.cc
* merged the debian/experimental changes back
[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 /*{{{*/
0118833a
AL
16#include <apt-pkg/acquire-item.h>
17#include <apt-pkg/configuration.h>
b2e465d6 18#include <apt-pkg/sourcelist.h>
b3d44315 19#include <apt-pkg/vendorlist.h>
03e39e59 20#include <apt-pkg/error.h>
cdcc6d34 21#include <apt-pkg/strutl.h>
36375005 22#include <apt-pkg/fileutl.h>
b3d44315 23#include <apt-pkg/md5.h>
ac5b205a
MV
24#include <apt-pkg/sha1.h>
25#include <apt-pkg/tagfile.h>
0a8a80e5 26
b2e465d6
AL
27#include <apti18n.h>
28
0a8a80e5
AL
29#include <sys/stat.h>
30#include <unistd.h>
c88edf1d 31#include <errno.h>
5819a761 32#include <string>
ac5b205a 33#include <sstream>
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");
8f30ca30
MV
103 // we only inform the Log class if it was actually not a local thing
104 if (Complete == false && !Local && FileName == DestFile)
b98f2859
AL
105 {
106 if (Owner->Log != 0)
107 Owner->Log->Fetched(Size,atoi(LookupTag(Message,"Resume-Point","0").c_str()));
108 }
aa0e1101
AL
109
110 if (FileSize == 0)
111 FileSize= Size;
b98f2859 112
c88edf1d
AL
113 Status = StatDone;
114 ErrorText = string();
115 Owner->Dequeue(this);
116}
117 /*}}}*/
8b89e57f
AL
118// Acquire::Item::Rename - Rename a file /*{{{*/
119// ---------------------------------------------------------------------
120/* This helper function is used by alot of item methods as thier final
121 step */
122void pkgAcquire::Item::Rename(string From,string To)
123{
124 if (rename(From.c_str(),To.c_str()) != 0)
125 {
126 char S[300];
0fcd01de 127 snprintf(S,sizeof(S),_("rename failed, %s (%s -> %s)."),strerror(errno),
8b89e57f
AL
128 From.c_str(),To.c_str());
129 Status = StatError;
130 ErrorText = S;
7a3c2ab0 131 }
8b89e57f
AL
132}
133 /*}}}*/
0118833a 134
2237bd01
MV
135
136// AcqDiffIndex::AcqDiffIndex - Constructor
ac5b205a 137// ---------------------------------------------------------------------
2237bd01
MV
138/* Get the DiffIndex file first and see if there are patches availabe
139 * If so, create a pkgAcqIndexDiffs fetcher that will get and apply the
140 * patches. If anything goes wrong in that process, it will fall back to
141 * the original packages file
ac5b205a 142 */
2237bd01
MV
143pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire *Owner,
144 string URI,string URIDesc,string ShortDesc,
145 string ExpectedMD5)
146 : Item(Owner), RealURI(URI), ExpectedMD5(ExpectedMD5), Description(URIDesc)
ac5b205a
MV
147{
148
ac5b205a
MV
149 Debug = _config->FindB("Debug::pkgAcquire::Diffs",false);
150
2237bd01 151 Desc.Description = URIDesc + "/DiffIndex";
ac5b205a
MV
152 Desc.Owner = this;
153 Desc.ShortDesc = ShortDesc;
2237bd01
MV
154 Desc.URI = URI + ".diff/Index";
155
156 DestFile = _config->FindDir("Dir::State::lists") + "partial/";
157 DestFile += URItoFileName(URI) + string(".DiffIndex");
158
159 if(Debug)
160 std::clog << "pkgAcqDiffIndex: " << Desc.URI << std::endl;
ac5b205a 161
2237bd01 162 // look for the current package file
ac5b205a
MV
163 CurrentPackagesFile = _config->FindDir("Dir::State::lists");
164 CurrentPackagesFile += URItoFileName(RealURI);
165
b4e57d2d
MV
166 // FIXME: this file:/ check is a hack to prevent fetching
167 // from local sources. this is really silly, and
168 // should be fixed cleanly as soon as possible
ac5b205a 169 if(!FileExists(CurrentPackagesFile) ||
81fcf9e2 170 Desc.URI.substr(0,strlen("file:/")) == "file:/")
2ac3eeb6 171 {
ac5b205a
MV
172 // we don't have a pkg file or we don't want to queue
173 if(Debug)
b4e57d2d 174 std::clog << "No index file, local or canceld by user" << std::endl;
ac5b205a
MV
175 Failed("", NULL);
176 return;
177 }
178
2ac3eeb6 179 if(Debug)
2237bd01
MV
180 std::clog << "pkgAcqIndexDiffs::pkgAcqIndexDiffs(): "
181 << CurrentPackagesFile << std::endl;
2ac3eeb6 182
ac5b205a 183 QueueURI(Desc);
2237bd01 184
ac5b205a
MV
185}
186
6cb30d01
MV
187// AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
188// ---------------------------------------------------------------------
189/* The only header we use is the last-modified header. */
2237bd01 190string pkgAcqDiffIndex::Custom600Headers()
6cb30d01 191{
6cb30d01
MV
192 string Final = _config->FindDir("Dir::State::lists");
193 Final += URItoFileName(RealURI) + string(".IndexDiff");
194
195 if(Debug)
196 std::clog << "Custom600Header-IMS: " << Final << std::endl;
197
198 struct stat Buf;
199 if (stat(Final.c_str(),&Buf) != 0)
200 return "\nIndex-File: true";
201
202 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
203}
204
2237bd01
MV
205
206bool pkgAcqDiffIndex::ParseDiffIndex(string IndexDiffFile)
207{
208 if(Debug)
209 std::clog << "pkgAcqIndexDiffs::ParseIndexDiff() " << IndexDiffFile
210 << std::endl;
211
212 pkgTagSection Tags;
213 string ServerSha1;
214 vector<DiffInfo> available_patches;
215
216 FileFd Fd(IndexDiffFile,FileFd::ReadOnly);
217 pkgTagFile TF(&Fd);
218 if (_error->PendingError() == true)
219 return false;
220
221 if(TF.Step(Tags) == true)
222 {
223 string local_sha1;
002d9943
MV
224 bool found = false;
225 DiffInfo d;
226 string size;
227
2237bd01
MV
228 string tmp = Tags.FindS("SHA1-Current");
229 std::stringstream ss(tmp);
230 ss >> ServerSha1;
231
232 FileFd fd(CurrentPackagesFile, FileFd::ReadOnly);
233 SHA1Summation SHA1;
234 SHA1.AddFD(fd.Fd(), fd.Size());
235 local_sha1 = string(SHA1.Result());
236
2ac3eeb6
MV
237 if(local_sha1 == ServerSha1)
238 {
239 // we have the same sha1 as the server
2237bd01
MV
240 if(Debug)
241 std::clog << "Package file is up-to-date" << std::endl;
002d9943
MV
242 // set found to true, this will queue a pkgAcqIndexDiffs with
243 // a empty availabe_patches
244 found = true;
2ac3eeb6
MV
245 }
246 else
247 {
002d9943
MV
248 if(Debug)
249 std::clog << "SHA1-Current: " << ServerSha1 << std::endl;
250
251 // check the historie and see what patches we need
252 string history = Tags.FindS("SHA1-History");
253 std::stringstream hist(history);
2ac3eeb6
MV
254 while(hist >> d.sha1 >> size >> d.file)
255 {
002d9943
MV
256 d.size = atoi(size.c_str());
257 // read until the first match is found
258 if(d.sha1 == local_sha1)
259 found=true;
260 // from that point on, we probably need all diffs
2ac3eeb6
MV
261 if(found)
262 {
002d9943
MV
263 if(Debug)
264 std::clog << "Need to get diff: " << d.file << std::endl;
265 available_patches.push_back(d);
266 }
2237bd01
MV
267 }
268 }
269
270 // no information how to get the patches, bail out
2ac3eeb6
MV
271 if(!found)
272 {
2237bd01
MV
273 if(Debug)
274 std::clog << "Can't find a patch in the index file" << std::endl;
275 // Failed will queue a big package file
276 Failed("", NULL);
2ac3eeb6
MV
277 }
278 else
279 {
2237bd01
MV
280 // queue the diffs
281 new pkgAcqIndexDiffs(Owner, RealURI, Description, Desc.ShortDesc,
282 ExpectedMD5, available_patches);
283 Complete = false;
284 Status = StatDone;
285 Dequeue();
286 return true;
287 }
288 }
289
290 return false;
291}
292
293void pkgAcqDiffIndex::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
294{
295 if(Debug)
296 std::clog << "pkgAcqDiffIndex failed: " << Desc.URI << std::endl
297 << "Falling back to normal index file aquire" << std::endl;
298
002d9943 299 new pkgAcqIndex(Owner, RealURI, Description, Desc.ShortDesc,
2237bd01
MV
300 ExpectedMD5);
301
302 Complete = false;
303 Status = StatDone;
304 Dequeue();
305}
306
307void pkgAcqDiffIndex::Done(string Message,unsigned long Size,string Md5Hash,
308 pkgAcquire::MethodConfig *Cnf)
309{
310 if(Debug)
311 std::clog << "pkgAcqDiffIndex::Done(): " << Desc.URI << std::endl;
312
313 Item::Done(Message,Size,Md5Hash,Cnf);
314
315 string FinalFile;
316 FinalFile = _config->FindDir("Dir::State::lists")+URItoFileName(RealURI);
317
318 // sucess in downloading the index
319 // rename the index
320 FinalFile += string(".IndexDiff");
321 if(Debug)
322 std::clog << "Renaming: " << DestFile << " -> " << FinalFile
323 << std::endl;
324 Rename(DestFile,FinalFile);
325 chmod(FinalFile.c_str(),0644);
326 DestFile = FinalFile;
327
328 if(!ParseDiffIndex(DestFile))
329 return Failed("", NULL);
330
331 Complete = true;
332 Status = StatDone;
333 Dequeue();
334 return;
335}
336
337
338
339// AcqIndexDiffs::AcqIndexDiffs - Constructor
340// ---------------------------------------------------------------------
341/* The package diff is added to the queue. one object is constructed
342 * for each diff and the index
343 */
344pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire *Owner,
345 string URI,string URIDesc,string ShortDesc,
346 string ExpectedMD5, vector<DiffInfo> diffs)
347 : Item(Owner), RealURI(URI), ExpectedMD5(ExpectedMD5),
348 available_patches(diffs)
349{
350
351 DestFile = _config->FindDir("Dir::State::lists") + "partial/";
352 DestFile += URItoFileName(URI);
353
354 Debug = _config->FindB("Debug::pkgAcquire::Diffs",false);
355
356 Desc.Description = URIDesc;
357 Desc.Owner = this;
358 Desc.ShortDesc = ShortDesc;
359
2ac3eeb6
MV
360 if(available_patches.size() == 0)
361 {
2237bd01
MV
362 // we are done (yeah!)
363 Finish(true);
2ac3eeb6
MV
364 }
365 else
366 {
2237bd01
MV
367 // get the next diff
368 State = StateFetchDiff;
369 QueueNextDiff();
370 }
371}
372
373
ac5b205a
MV
374void pkgAcqIndexDiffs::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
375{
2237bd01
MV
376 if(Debug)
377 std::clog << "pkgAcqIndexDiffs failed: " << Desc.URI << std::endl
378 << "Falling back to normal index file aquire" << std::endl;
379 new pkgAcqIndex(Owner, RealURI, Description,Desc.ShortDesc,
ac5b205a
MV
380 ExpectedMD5);
381 Finish();
382}
383
384
385// helper that cleans the item out of the fetcher queue
386void pkgAcqIndexDiffs::Finish(bool allDone)
387{
388 // we restore the original name, this is required, otherwise
389 // the file will be cleaned
2ac3eeb6
MV
390 if(allDone)
391 {
ac5b205a
MV
392 DestFile = _config->FindDir("Dir::State::lists");
393 DestFile += URItoFileName(RealURI);
2d4722e2
MV
394
395 // do the final md5sum checking
396 MD5Summation sum;
397 FileFd Fd(DestFile, FileFd::ReadOnly);
398 sum.AddFD(Fd.Fd(), Fd.Size());
399 Fd.Close();
400 string MD5 = (string)sum.Result();
401
402 if (!ExpectedMD5.empty() && MD5 != ExpectedMD5)
403 {
404 Status = StatAuthError;
405 ErrorText = _("MD5Sum mismatch");
406 Rename(DestFile,DestFile + ".FAILED");
407 Dequeue();
408 return;
409 }
410
411 // this is for the "real" finish
ac5b205a 412 Complete = true;
cffc2ddd 413 Status = StatDone;
ac5b205a
MV
414 Dequeue();
415 if(Debug)
416 std::clog << "\n\nallDone: " << DestFile << "\n" << std::endl;
417 return;
ac5b205a
MV
418 }
419
420 if(Debug)
421 std::clog << "Finishing: " << Desc.URI << std::endl;
422 Complete = false;
423 Status = StatDone;
424 Dequeue();
425 return;
426}
427
428
ac5b205a
MV
429
430bool pkgAcqIndexDiffs::QueueNextDiff()
431{
3de9ff77 432
94dc9d7d
MV
433 // calc sha1 of the just patched file
434 string FinalFile = _config->FindDir("Dir::State::lists");
435 FinalFile += URItoFileName(RealURI);
436
437 FileFd fd(FinalFile, FileFd::ReadOnly);
438 SHA1Summation SHA1;
439 SHA1.AddFD(fd.Fd(), fd.Size());
440 string local_sha1 = string(SHA1.Result());
3de9ff77
MV
441 if(Debug)
442 std::clog << "QueueNextDiff: "
443 << FinalFile << " (" << local_sha1 << ")"<<std::endl;
94dc9d7d 444
26d27645
MV
445 // remove all patches until the next matching patch is found
446 // this requires the Index file to be ordered
94dc9d7d 447 for(vector<DiffInfo>::iterator I=available_patches.begin();
2ac3eeb6
MV
448 available_patches.size() > 0 &&
449 I != available_patches.end() &&
450 (*I).sha1 != local_sha1;
451 I++)
452 {
26d27645 453 available_patches.erase(I);
59a704f0 454 }
94dc9d7d
MV
455
456 // error checking and falling back if no patch was found
2ac3eeb6
MV
457 if(available_patches.size() == 0)
458 {
94dc9d7d
MV
459 Failed("", NULL);
460 return false;
461 }
6cb30d01 462
94dc9d7d 463 // queue the right diff
2237bd01 464 Desc.URI = string(RealURI) + ".diff/" + available_patches[0].file + ".gz";
94dc9d7d 465 Desc.Description = available_patches[0].file + string(".pdiff");
ac5b205a
MV
466
467 DestFile = _config->FindDir("Dir::State::lists") + "partial/";
2237bd01 468 DestFile += URItoFileName(RealURI + ".diff/" + available_patches[0].file);
ac5b205a
MV
469
470 if(Debug)
471 std::clog << "pkgAcqIndexDiffs::QueueNextDiff(): " << Desc.URI << std::endl;
472
473 QueueURI(Desc);
474
475 return true;
476}
477
ac5b205a
MV
478
479
480void pkgAcqIndexDiffs::Done(string Message,unsigned long Size,string Md5Hash,
481 pkgAcquire::MethodConfig *Cnf)
482{
483 if(Debug)
484 std::clog << "pkgAcqIndexDiffs::Done(): " << Desc.URI << std::endl;
485
486 Item::Done(Message,Size,Md5Hash,Cnf);
487
4a0a786f
MV
488 string FinalFile;
489 FinalFile = _config->FindDir("Dir::State::lists")+URItoFileName(RealURI);
6cb30d01 490
4a0a786f
MV
491 // sucess in downloading a diff, enter ApplyDiff state
492 if(State == StateFetchDiff)
493 {
494
495 if(Debug)
496 std::clog << "Sending to gzip method: " << FinalFile << std::endl;
497
498 string FileName = LookupTag(Message,"Filename");
499 State = StateUnzipDiff;
b7347826 500 Local = true;
4a0a786f
MV
501 Desc.URI = "gzip:" + FileName;
502 DestFile += ".decomp";
503 QueueURI(Desc);
504 Mode = "gzip";
505 return;
506 }
507
508 // sucess in downloading a diff, enter ApplyDiff state
509 if(State == StateUnzipDiff)
510 {
511
512 // rred excepts the patch as $FinalFile.ed
513 Rename(DestFile,FinalFile+".ed");
514
515 if(Debug)
516 std::clog << "Sending to rred method: " << FinalFile << std::endl;
517
518 State = StateApplyDiff;
b7347826 519 Local = true;
4a0a786f
MV
520 Desc.URI = "rred:" + FinalFile;
521 QueueURI(Desc);
522 Mode = "rred";
523 return;
524 }
525
526
527 // success in download/apply a diff, queue next (if needed)
528 if(State == StateApplyDiff)
529 {
530 // remove the just applied patch
94dc9d7d 531 available_patches.erase(available_patches.begin());
ac5b205a 532
4a0a786f 533 // move into place
59a704f0
MV
534 if(Debug)
535 {
4a0a786f
MV
536 std::clog << "Moving patched file in place: " << std::endl
537 << DestFile << " -> " << FinalFile << std::endl;
59a704f0 538 }
4a0a786f 539 Rename(DestFile,FinalFile);
1790e0cf 540 chmod(FinalFile.c_str(),0644);
4a0a786f
MV
541
542 // see if there is more to download
94dc9d7d 543 if(available_patches.size() > 0) {
ac5b205a 544 new pkgAcqIndexDiffs(Owner, RealURI, Description, Desc.ShortDesc,
94dc9d7d 545 ExpectedMD5, available_patches);
4a0a786f
MV
546 return Finish();
547 } else
548 return Finish(true);
ac5b205a 549 }
ac5b205a
MV
550}
551
552
0118833a
AL
553// AcqIndex::AcqIndex - Constructor /*{{{*/
554// ---------------------------------------------------------------------
555/* The package file is added to the queue and a second class is
b2e465d6
AL
556 instantiated to fetch the revision file */
557pkgAcqIndex::pkgAcqIndex(pkgAcquire *Owner,
b3d44315 558 string URI,string URIDesc,string ShortDesc,
ac5b205a
MV
559 string ExpectedMD5, string comprExt)
560 : Item(Owner), RealURI(URI), ExpectedMD5(ExpectedMD5)
0118833a 561{
8b89e57f 562 Decompression = false;
bfd22fc0 563 Erase = false;
13e8426f 564
0a8a80e5 565 DestFile = _config->FindDir("Dir::State::lists") + "partial/";
b2e465d6 566 DestFile += URItoFileName(URI);
8267fe24 567
b3d44315
MV
568 if(comprExt.empty())
569 {
13e8426f 570 // autoselect the compression method
4577fda2 571 if(FileExists("/bin/bzip2"))
13e8426f
MV
572 CompressionExtension = ".bz2";
573 else
574 CompressionExtension = ".gz";
b3d44315 575 } else {
13e8426f 576 CompressionExtension = comprExt;
b3d44315 577 }
13e8426f 578 Desc.URI = URI + CompressionExtension;
b3d44315 579
b2e465d6 580 Desc.Description = URIDesc;
8267fe24 581 Desc.Owner = this;
b2e465d6 582 Desc.ShortDesc = ShortDesc;
8267fe24
AL
583
584 QueueURI(Desc);
0118833a
AL
585}
586 /*}}}*/
0a8a80e5 587// AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
0118833a 588// ---------------------------------------------------------------------
0a8a80e5
AL
589/* The only header we use is the last-modified header. */
590string pkgAcqIndex::Custom600Headers()
0118833a 591{
0a8a80e5 592 string Final = _config->FindDir("Dir::State::lists");
b2e465d6 593 Final += URItoFileName(RealURI);
0a8a80e5
AL
594
595 struct stat Buf;
596 if (stat(Final.c_str(),&Buf) != 0)
a72ace20 597 return "\nIndex-File: true";
0118833a 598
a72ace20 599 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
0118833a
AL
600}
601 /*}}}*/
debc84b2
MZ
602
603void pkgAcqIndex::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
604{
17ff0930 605
debc84b2 606 // no .bz2 found, retry with .gz
46e00f9d 607 if(Desc.URI.substr(Desc.URI.size()-3) == "bz2") {
debc84b2 608 Desc.URI = Desc.URI.substr(0,Desc.URI.size()-3) + "gz";
b3d44315
MV
609
610 // retry with a gzip one
611 new pkgAcqIndex(Owner, RealURI, Desc.Description,Desc.ShortDesc,
612 ExpectedMD5, string(".gz"));
613 Status = StatDone;
614 Complete = false;
615 Dequeue();
debc84b2 616 return;
17ff0930
MV
617 }
618
619 // on decompression failure, remove bad versions in partial/
620 if(Decompression && Erase) {
621 string s = _config->FindDir("Dir::State::lists") + "partial/";
622 s += URItoFileName(RealURI);
623 unlink(s.c_str());
debc84b2
MZ
624 }
625
debc84b2
MZ
626 Item::Failed(Message,Cnf);
627}
628
629
8b89e57f
AL
630// AcqIndex::Done - Finished a fetch /*{{{*/
631// ---------------------------------------------------------------------
632/* This goes through a number of states.. On the initial fetch the
633 method could possibly return an alternate filename which points
634 to the uncompressed version of the file. If this is so the file
635 is copied into the partial directory. In all other cases the file
636 is decompressed with a gzip uri. */
459681d3
AL
637void pkgAcqIndex::Done(string Message,unsigned long Size,string MD5,
638 pkgAcquire::MethodConfig *Cfg)
8b89e57f 639{
459681d3 640 Item::Done(Message,Size,MD5,Cfg);
8b89e57f
AL
641
642 if (Decompression == true)
643 {
b3d44315
MV
644 if (_config->FindB("Debug::pkgAcquire::Auth", false))
645 {
646 std::cerr << std::endl << RealURI << ": Computed MD5: " << MD5;
647 std::cerr << " Expected MD5: " << ExpectedMD5 << std::endl;
648 }
649
650 if (MD5.empty())
651 {
652 MD5Summation sum;
653 FileFd Fd(DestFile, FileFd::ReadOnly);
654 sum.AddFD(Fd.Fd(), Fd.Size());
655 Fd.Close();
656 MD5 = (string)sum.Result();
657 }
658
659 if (!ExpectedMD5.empty() && MD5 != ExpectedMD5)
660 {
661 Status = StatAuthError;
662 ErrorText = _("MD5Sum mismatch");
663 Rename(DestFile,DestFile + ".FAILED");
664 return;
665 }
8b89e57f
AL
666 // Done, move it into position
667 string FinalFile = _config->FindDir("Dir::State::lists");
b2e465d6 668 FinalFile += URItoFileName(RealURI);
8b89e57f 669 Rename(DestFile,FinalFile);
7a3c2ab0 670 chmod(FinalFile.c_str(),0644);
bfd22fc0 671
7a7fa5f0
AL
672 /* We restore the original name to DestFile so that the clean operation
673 will work OK */
674 DestFile = _config->FindDir("Dir::State::lists") + "partial/";
b2e465d6 675 DestFile += URItoFileName(RealURI);
7a7fa5f0 676
bfd22fc0
AL
677 // Remove the compressed version.
678 if (Erase == true)
bfd22fc0 679 unlink(DestFile.c_str());
8b89e57f
AL
680 return;
681 }
bfd22fc0
AL
682
683 Erase = false;
8267fe24 684 Complete = true;
bfd22fc0 685
8b89e57f
AL
686 // Handle the unzipd case
687 string FileName = LookupTag(Message,"Alt-Filename");
688 if (FileName.empty() == false)
689 {
690 // The files timestamp matches
691 if (StringToBool(LookupTag(Message,"Alt-IMS-Hit"),false) == true)
692 return;
b3d44315 693
8b89e57f 694 Decompression = true;
a6568219 695 Local = true;
8b89e57f 696 DestFile += ".decomp";
8267fe24
AL
697 Desc.URI = "copy:" + FileName;
698 QueueURI(Desc);
b98f2859 699 Mode = "copy";
8b89e57f
AL
700 return;
701 }
702
703 FileName = LookupTag(Message,"Filename");
704 if (FileName.empty() == true)
705 {
706 Status = StatError;
707 ErrorText = "Method gave a blank filename";
708 }
709
710 // The files timestamp matches
711 if (StringToBool(LookupTag(Message,"IMS-Hit"),false) == true)
712 return;
bfd22fc0
AL
713
714 if (FileName == DestFile)
715 Erase = true;
8267fe24 716 else
a6568219 717 Local = true;
8b89e57f 718
46e00f9d 719 string compExt = Desc.URI.substr(Desc.URI.size()-3);
debc84b2
MZ
720 char *decompProg;
721 if(compExt == "bz2")
722 decompProg = "bzip2";
723 else if(compExt == ".gz")
724 decompProg = "gzip";
725 else {
726 _error->Error("Unsupported extension: %s", compExt.c_str());
727 return;
728 }
729
8b89e57f
AL
730 Decompression = true;
731 DestFile += ".decomp";
debc84b2 732 Desc.URI = string(decompProg) + ":" + FileName;
8267fe24 733 QueueURI(Desc);
debc84b2 734 Mode = decompProg;
8b89e57f 735}
8b89e57f 736
a52f938b
OS
737// AcqIndexTrans::pkgAcqIndexTrans - Constructor /*{{{*/
738// ---------------------------------------------------------------------
739/* The Translation file is added to the queue */
740pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire *Owner,
741 string URI,string URIDesc,string ShortDesc) :
a7a5b0d9 742 pkgAcqIndex(Owner, URI, URIDesc, ShortDesc, "", "")
a52f938b
OS
743{
744}
745
746 /*}}}*/
747// AcqIndexTrans::Failed - Silence failure messages for missing files /*{{{*/
748// ---------------------------------------------------------------------
749/* */
750void pkgAcqIndexTrans::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
751{
752 if (Cnf->LocalOnly == true ||
753 StringToBool(LookupTag(Message,"Transient-Failure"),false) == false)
754 {
755 // Ignore this
756 Status = StatDone;
757 Complete = false;
758 Dequeue();
759 return;
760 }
761
762 Item::Failed(Message,Cnf);
763}
764 /*}}}*/
765
b3d44315
MV
766pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire *Owner,
767 string URI,string URIDesc,string ShortDesc,
768 string MetaIndexURI, string MetaIndexURIDesc,
769 string MetaIndexShortDesc,
770 const vector<IndexTarget*>* IndexTargets,
771 indexRecords* MetaIndexParser) :
772 Item(Owner), RealURI(URI), MetaIndexURI(MetaIndexURI),
46e00f9d
MV
773 MetaIndexURIDesc(MetaIndexURIDesc), MetaIndexShortDesc(MetaIndexShortDesc),
774 MetaIndexParser(MetaIndexParser), IndexTargets(IndexTargets)
0118833a 775{
0a8a80e5 776 DestFile = _config->FindDir("Dir::State::lists") + "partial/";
b2e465d6 777 DestFile += URItoFileName(URI);
b3d44315 778
47eb38f4
MV
779 // remove any partial downloaded sig-file in partial/.
780 // it may confuse proxies and is too small to warrant a
781 // partial download anyway
f6237efd
MV
782 unlink(DestFile.c_str());
783
8267fe24 784 // Create the item
b2e465d6 785 Desc.Description = URIDesc;
8267fe24 786 Desc.Owner = this;
b3d44315
MV
787 Desc.ShortDesc = ShortDesc;
788 Desc.URI = URI;
789
790
791 string Final = _config->FindDir("Dir::State::lists");
792 Final += URItoFileName(RealURI);
793 struct stat Buf;
794 if (stat(Final.c_str(),&Buf) == 0)
795 {
796 // File was already in place. It needs to be re-verified
797 // because Release might have changed, so Move it into partial
798 Rename(Final,DestFile);
799 }
8267fe24 800
8267fe24 801 QueueURI(Desc);
0118833a
AL
802}
803 /*}}}*/
b3d44315 804// pkgAcqMetaSig::Custom600Headers - Insert custom request headers /*{{{*/
0118833a 805// ---------------------------------------------------------------------
0a8a80e5 806/* The only header we use is the last-modified header. */
b3d44315 807string pkgAcqMetaSig::Custom600Headers()
0118833a 808{
0a8a80e5 809 struct stat Buf;
2aab5956 810 if (stat(DestFile.c_str(),&Buf) != 0)
a72ace20 811 return "\nIndex-File: true";
a789b983 812
a72ace20 813 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
0118833a 814}
b3d44315
MV
815
816void pkgAcqMetaSig::Done(string Message,unsigned long Size,string MD5,
817 pkgAcquire::MethodConfig *Cfg)
c88edf1d 818{
459681d3 819 Item::Done(Message,Size,MD5,Cfg);
c88edf1d
AL
820
821 string FileName = LookupTag(Message,"Filename");
822 if (FileName.empty() == true)
823 {
824 Status = StatError;
825 ErrorText = "Method gave a blank filename";
8b89e57f 826 return;
c88edf1d 827 }
8b89e57f 828
c88edf1d
AL
829 if (FileName != DestFile)
830 {
b3d44315 831 // We have to copy it into place
a6568219 832 Local = true;
8267fe24
AL
833 Desc.URI = "copy:" + FileName;
834 QueueURI(Desc);
c88edf1d
AL
835 return;
836 }
b3d44315
MV
837
838 Complete = true;
839
840 // queue a pkgAcqMetaIndex to be verified against the sig we just retrieved
841 new pkgAcqMetaIndex(Owner, MetaIndexURI, MetaIndexURIDesc, MetaIndexShortDesc,
842 DestFile, IndexTargets, MetaIndexParser);
843
c88edf1d
AL
844}
845 /*}}}*/
b3d44315 846void pkgAcqMetaSig::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
681d76d0 847{
47eb38f4 848 string Final = _config->FindDir("Dir::State::lists") + URItoFileName(RealURI);
a789b983 849
75dd8af1 850 // if we get a network error we fail gracefully
7e5f33eb
MV
851 if(Status == StatTransientNetworkError)
852 {
24057ad6 853 Item::Failed(Message,Cnf);
484dbb81 854 // move the sigfile back on transient network failures
47eb38f4
MV
855 if(FileExists(DestFile))
856 Rename(DestFile,Final);
7e5f33eb
MV
857
858 // set the status back to , Item::Failed likes to reset it
859 Status = pkgAcquire::Item::StatTransientNetworkError;
24057ad6
MV
860 return;
861 }
862
75dd8af1 863 // Delete any existing sigfile when the acquire failed
75dd8af1
MV
864 unlink(Final.c_str());
865
b3d44315
MV
866 // queue a pkgAcqMetaIndex with no sigfile
867 new pkgAcqMetaIndex(Owner, MetaIndexURI, MetaIndexURIDesc, MetaIndexShortDesc,
868 "", IndexTargets, MetaIndexParser);
869
681d76d0
AL
870 if (Cnf->LocalOnly == true ||
871 StringToBool(LookupTag(Message,"Transient-Failure"),false) == false)
872 {
2b154e53
AL
873 // Ignore this
874 Status = StatDone;
875 Complete = false;
681d76d0
AL
876 Dequeue();
877 return;
878 }
879
880 Item::Failed(Message,Cnf);
881}
b3d44315
MV
882
883pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire *Owner,
884 string URI,string URIDesc,string ShortDesc,
885 string SigFile,
886 const vector<struct IndexTarget*>* IndexTargets,
887 indexRecords* MetaIndexParser) :
46e00f9d 888 Item(Owner), RealURI(URI), SigFile(SigFile), AuthPass(false),
f381d68d 889 MetaIndexParser(MetaIndexParser), IndexTargets(IndexTargets), IMSHit(false)
b3d44315 890{
b3d44315
MV
891 DestFile = _config->FindDir("Dir::State::lists") + "partial/";
892 DestFile += URItoFileName(URI);
893
894 // Create the item
895 Desc.Description = URIDesc;
896 Desc.Owner = this;
897 Desc.ShortDesc = ShortDesc;
898 Desc.URI = URI;
899
900 QueueURI(Desc);
901}
902
903 /*}}}*/
904// pkgAcqMetaIndex::Custom600Headers - Insert custom request headers /*{{{*/
905// ---------------------------------------------------------------------
906/* The only header we use is the last-modified header. */
907string pkgAcqMetaIndex::Custom600Headers()
908{
909 string Final = _config->FindDir("Dir::State::lists");
910 Final += URItoFileName(RealURI);
911
912 struct stat Buf;
913 if (stat(Final.c_str(),&Buf) != 0)
914 return "\nIndex-File: true";
915
916 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
917}
918
919void pkgAcqMetaIndex::Done(string Message,unsigned long Size,string MD5,
920 pkgAcquire::MethodConfig *Cfg)
921{
922 Item::Done(Message,Size,MD5,Cfg);
923
924 // MetaIndexes are done in two passes: one to download the
925 // metaindex with an appropriate method, and a second to verify it
926 // with the gpgv method
927
928 if (AuthPass == true)
929 {
930 AuthDone(Message);
931 }
932 else
933 {
934 RetrievalDone(Message);
935 if (!Complete)
936 // Still more retrieving to do
937 return;
938
939 if (SigFile == "")
940 {
941 // There was no signature file, so we are finished. Download
942 // the indexes without verification.
943 QueueIndexes(false);
944 }
945 else
946 {
947 // There was a signature file, so pass it to gpgv for
948 // verification
949
950 if (_config->FindB("Debug::pkgAcquire::Auth", false))
951 std::cerr << "Metaindex acquired, queueing gpg verification ("
952 << SigFile << "," << DestFile << ")\n";
953 AuthPass = true;
954 Desc.URI = "gpgv:" + SigFile;
955 QueueURI(Desc);
956 Mode = "gpgv";
957 }
958 }
959}
960
961void pkgAcqMetaIndex::RetrievalDone(string Message)
962{
963 // We have just finished downloading a Release file (it is not
964 // verified yet)
965
966 string FileName = LookupTag(Message,"Filename");
967 if (FileName.empty() == true)
968 {
969 Status = StatError;
970 ErrorText = "Method gave a blank filename";
971 return;
972 }
973
974 if (FileName != DestFile)
975 {
976 Local = true;
977 Desc.URI = "copy:" + FileName;
978 QueueURI(Desc);
979 return;
980 }
981
f381d68d
MV
982 // see if the download was a IMSHit
983 IMSHit = StringToBool(LookupTag(Message,"IMS-Hit"),false);
984
b3d44315
MV
985 Complete = true;
986
987 string FinalFile = _config->FindDir("Dir::State::lists");
988 FinalFile += URItoFileName(RealURI);
989
990 // The files timestamp matches
991 if (StringToBool(LookupTag(Message,"IMS-Hit"),false) == false)
992 {
993 // Move it into position
994 Rename(DestFile,FinalFile);
995 }
1790e0cf 996 chmod(FinalFile.c_str(),0644);
b3d44315
MV
997 DestFile = FinalFile;
998}
999
1000void pkgAcqMetaIndex::AuthDone(string Message)
1001{
1002 // At this point, the gpgv method has succeeded, so there is a
1003 // valid signature from a key in the trusted keyring. We
1004 // perform additional verification of its contents, and use them
1005 // to verify the indexes we are about to download
1006
1007 if (!MetaIndexParser->Load(DestFile))
1008 {
1009 Status = StatAuthError;
1010 ErrorText = MetaIndexParser->ErrorText;
1011 return;
1012 }
1013
ce424cd4 1014 if (!VerifyVendor(Message))
b3d44315
MV
1015 {
1016 return;
1017 }
1018
1019 if (_config->FindB("Debug::pkgAcquire::Auth", false))
1020 std::cerr << "Signature verification succeeded: "
1021 << DestFile << std::endl;
1022
1023 // Download further indexes with verification
1024 QueueIndexes(true);
1025
1026 // Done, move signature file into position
1027
1028 string VerifiedSigFile = _config->FindDir("Dir::State::lists") +
1029 URItoFileName(RealURI) + ".gpg";
1030 Rename(SigFile,VerifiedSigFile);
1031 chmod(VerifiedSigFile.c_str(),0644);
1032}
1033
1034void pkgAcqMetaIndex::QueueIndexes(bool verify)
1035{
1036 for (vector <struct IndexTarget*>::const_iterator Target = IndexTargets->begin();
1037 Target != IndexTargets->end();
1038 Target++)
1039 {
1040 string ExpectedIndexMD5;
1041 if (verify)
1042 {
1043 const indexRecords::checkSum *Record = MetaIndexParser->Lookup((*Target)->MetaKey);
1044 if (!Record)
1045 {
1046 Status = StatAuthError;
1047 ErrorText = "Unable to find expected entry "
1048 + (*Target)->MetaKey + " in Meta-index file (malformed Release file?)";
1049 return;
1050 }
1051 ExpectedIndexMD5 = Record->MD5Hash;
1052 if (_config->FindB("Debug::pkgAcquire::Auth", false))
1053 {
1054 std::cerr << "Queueing: " << (*Target)->URI << std::endl;
1055 std::cerr << "Expected MD5: " << ExpectedIndexMD5 << std::endl;
1056 }
1057 if (ExpectedIndexMD5.empty())
1058 {
1059 Status = StatAuthError;
1060 ErrorText = "Unable to find MD5 sum for "
1061 + (*Target)->MetaKey + " in Meta-index file";
1062 return;
1063 }
1064 }
1065
2ac3eeb6
MV
1066 // Queue Packages file (either diff or full packages files, depending
1067 // on the users option)
27299daf 1068 if(_config->FindB("Acquire::PDiffs",true) == true)
2ac3eeb6
MV
1069 new pkgAcqDiffIndex(Owner, (*Target)->URI, (*Target)->Description,
1070 (*Target)->ShortDesc, ExpectedIndexMD5);
1071 else
81fcf9e2 1072 new pkgAcqIndex(Owner, (*Target)->URI, (*Target)->Description,
2ac3eeb6 1073 (*Target)->ShortDesc, ExpectedIndexMD5);
b3d44315
MV
1074 }
1075}
1076
ce424cd4 1077bool pkgAcqMetaIndex::VerifyVendor(string Message)
b3d44315
MV
1078{
1079// // Maybe this should be made available from above so we don't have
1080// // to read and parse it every time?
1081// pkgVendorList List;
1082// List.ReadMainList();
1083
1084// const Vendor* Vndr = NULL;
1085// for (std::vector<string>::const_iterator I = GPGVOutput.begin(); I != GPGVOutput.end(); I++)
1086// {
1087// string::size_type pos = (*I).find("VALIDSIG ");
1088// if (_config->FindB("Debug::Vendor", false))
1089// std::cerr << "Looking for VALIDSIG in \"" << (*I) << "\": pos " << pos
1090// << std::endl;
1091// if (pos != std::string::npos)
1092// {
1093// string Fingerprint = (*I).substr(pos+sizeof("VALIDSIG"));
1094// if (_config->FindB("Debug::Vendor", false))
1095// std::cerr << "Looking for \"" << Fingerprint << "\" in vendor..." <<
1096// std::endl;
1097// Vndr = List.FindVendor(Fingerprint) != "";
1098// if (Vndr != NULL);
1099// break;
1100// }
1101// }
ce424cd4
MV
1102 string::size_type pos;
1103
1104 // check for missing sigs (that where not fatal because otherwise we had
1105 // bombed earlier)
1106 string missingkeys;
400ad7a4 1107 string msg = _("There is no public key available for the "
ce424cd4
MV
1108 "following key IDs:\n");
1109 pos = Message.find("NO_PUBKEY ");
1110 if (pos != std::string::npos)
1111 {
1112 string::size_type start = pos+strlen("NO_PUBKEY ");
1113 string Fingerprint = Message.substr(start, Message.find("\n")-start);
1114 missingkeys += (Fingerprint);
1115 }
1116 if(!missingkeys.empty())
1117 _error->Warning("%s", string(msg+missingkeys).c_str());
b3d44315
MV
1118
1119 string Transformed = MetaIndexParser->GetExpectedDist();
1120
1121 if (Transformed == "../project/experimental")
1122 {
1123 Transformed = "experimental";
1124 }
1125
ce424cd4 1126 pos = Transformed.rfind('/');
b3d44315
MV
1127 if (pos != string::npos)
1128 {
1129 Transformed = Transformed.substr(0, pos);
1130 }
1131
1132 if (Transformed == ".")
1133 {
1134 Transformed = "";
1135 }
1136
1137 if (_config->FindB("Debug::pkgAcquire::Auth", false))
1138 {
1139 std::cerr << "Got Codename: " << MetaIndexParser->GetDist() << std::endl;
1140 std::cerr << "Expecting Dist: " << MetaIndexParser->GetExpectedDist() << std::endl;
1141 std::cerr << "Transformed Dist: " << Transformed << std::endl;
1142 }
1143
1144 if (MetaIndexParser->CheckDist(Transformed) == false)
1145 {
1146 // This might become fatal one day
1147// Status = StatAuthError;
1148// ErrorText = "Conflicting distribution; expected "
1149// + MetaIndexParser->GetExpectedDist() + " but got "
1150// + MetaIndexParser->GetDist();
1151// return false;
1152 if (!Transformed.empty())
1153 {
1154 _error->Warning("Conflicting distribution: %s (expected %s but got %s)",
1155 Desc.Description.c_str(),
1156 Transformed.c_str(),
1157 MetaIndexParser->GetDist().c_str());
1158 }
1159 }
1160
1161 return true;
1162}
1163 /*}}}*/
1164// pkgAcqMetaIndex::Failed - no Release file present or no signature
1165// file present /*{{{*/
1166// ---------------------------------------------------------------------
1167/* */
1168void pkgAcqMetaIndex::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
1169{
1170 if (AuthPass == true)
1171 {
f381d68d
MV
1172 // if we fail the authentication but got the file via a IMS-Hit
1173 // this means that the file wasn't downloaded and that it might be
1174 // just stale (server problem, proxy etc). we delete what we have
1175 // queue it again without i-m-s
1176 // alternatively we could just unlink the file and let the user try again
1177 if (IMSHit)
1178 {
1179 Complete = false;
1180 Local = false;
1181 AuthPass = false;
1182 unlink(DestFile.c_str());
1183
1184 DestFile = _config->FindDir("Dir::State::lists") + "partial/";
1185 DestFile += URItoFileName(RealURI);
1186 Desc.URI = RealURI;
1187 QueueURI(Desc);
1188 return;
1189 }
1190
1191 // gpgv method failed
b3d44315
MV
1192 _error->Warning("GPG error: %s: %s",
1193 Desc.Description.c_str(),
1194 LookupTag(Message,"Message").c_str());
f381d68d 1195
b3d44315
MV
1196 }
1197
1198 // No Release file was present, or verification failed, so fall
1199 // back to queueing Packages files without verification
1200 QueueIndexes(false);
1201}
1202
681d76d0 1203 /*}}}*/
03e39e59
AL
1204
1205// AcqArchive::AcqArchive - Constructor /*{{{*/
1206// ---------------------------------------------------------------------
17caf1b1
AL
1207/* This just sets up the initial fetch environment and queues the first
1208 possibilitiy */
03e39e59 1209pkgAcqArchive::pkgAcqArchive(pkgAcquire *Owner,pkgSourceList *Sources,
30e1eab5
AL
1210 pkgRecords *Recs,pkgCache::VerIterator const &Version,
1211 string &StoreFilename) :
1212 Item(Owner), Version(Version), Sources(Sources), Recs(Recs),
b3d44315
MV
1213 StoreFilename(StoreFilename), Vf(Version.FileList()),
1214 Trusted(false)
03e39e59 1215{
7d8afa39 1216 Retries = _config->FindI("Acquire::Retries",0);
813c8eea
AL
1217
1218 if (Version.Arch() == 0)
bdae53f1 1219 {
d1f1f6a8 1220 _error->Error(_("I wasn't able to locate a file for the %s package. "
7a3c2ab0
AL
1221 "This might mean you need to manually fix this package. "
1222 "(due to missing arch)"),
813c8eea 1223 Version.ParentPkg().Name());
bdae53f1
AL
1224 return;
1225 }
813c8eea 1226
b2e465d6
AL
1227 /* We need to find a filename to determine the extension. We make the
1228 assumption here that all the available sources for this version share
1229 the same extension.. */
1230 // Skip not source sources, they do not have file fields.
1231 for (; Vf.end() == false; Vf++)
1232 {
1233 if ((Vf.File()->Flags & pkgCache::Flag::NotSource) != 0)
1234 continue;
1235 break;
1236 }
1237
1238 // Does not really matter here.. we are going to fail out below
1239 if (Vf.end() != true)
1240 {
1241 // If this fails to get a file name we will bomb out below.
1242 pkgRecords::Parser &Parse = Recs->Lookup(Vf);
1243 if (_error->PendingError() == true)
1244 return;
1245
1246 // Generate the final file name as: package_version_arch.foo
1247 StoreFilename = QuoteString(Version.ParentPkg().Name(),"_:") + '_' +
1248 QuoteString(Version.VerStr(),"_:") + '_' +
1249 QuoteString(Version.Arch(),"_:.") +
1250 "." + flExtension(Parse.FileName());
1251 }
b3d44315
MV
1252
1253 // check if we have one trusted source for the package. if so, switch
1254 // to "TrustedOnly" mode
1255 for (pkgCache::VerFileIterator i = Version.FileList(); i.end() == false; i++)
1256 {
1257 pkgIndexFile *Index;
1258 if (Sources->FindIndex(i.File(),Index) == false)
1259 continue;
1260 if (_config->FindB("Debug::pkgAcquire::Auth", false))
1261 {
1262 std::cerr << "Checking index: " << Index->Describe()
1263 << "(Trusted=" << Index->IsTrusted() << ")\n";
1264 }
1265 if (Index->IsTrusted()) {
1266 Trusted = true;
1267 break;
1268 }
1269 }
1270
a3371852
MV
1271 // "allow-unauthenticated" restores apts old fetching behaviour
1272 // that means that e.g. unauthenticated file:// uris are higher
1273 // priority than authenticated http:// uris
1274 if (_config->FindB("APT::Get::AllowUnauthenticated",false) == true)
1275 Trusted = false;
1276
03e39e59 1277 // Select a source
b185acc2 1278 if (QueueNext() == false && _error->PendingError() == false)
b2e465d6
AL
1279 _error->Error(_("I wasn't able to locate file for the %s package. "
1280 "This might mean you need to manually fix this package."),
b185acc2
AL
1281 Version.ParentPkg().Name());
1282}
1283 /*}}}*/
1284// AcqArchive::QueueNext - Queue the next file source /*{{{*/
1285// ---------------------------------------------------------------------
17caf1b1
AL
1286/* This queues the next available file version for download. It checks if
1287 the archive is already available in the cache and stashs the MD5 for
1288 checking later. */
b185acc2 1289bool pkgAcqArchive::QueueNext()
b2e465d6 1290{
03e39e59
AL
1291 for (; Vf.end() == false; Vf++)
1292 {
1293 // Ignore not source sources
1294 if ((Vf.File()->Flags & pkgCache::Flag::NotSource) != 0)
1295 continue;
1296
1297 // Try to cross match against the source list
b2e465d6
AL
1298 pkgIndexFile *Index;
1299 if (Sources->FindIndex(Vf.File(),Index) == false)
1300 continue;
03e39e59 1301
b3d44315
MV
1302 // only try to get a trusted package from another source if that source
1303 // is also trusted
1304 if(Trusted && !Index->IsTrusted())
1305 continue;
1306
03e39e59
AL
1307 // Grab the text package record
1308 pkgRecords::Parser &Parse = Recs->Lookup(Vf);
1309 if (_error->PendingError() == true)
b185acc2 1310 return false;
03e39e59 1311
b2e465d6 1312 string PkgFile = Parse.FileName();
03e39e59
AL
1313 MD5 = Parse.MD5Hash();
1314 if (PkgFile.empty() == true)
b2e465d6
AL
1315 return _error->Error(_("The package index files are corrupted. No Filename: "
1316 "field for package %s."),
1317 Version.ParentPkg().Name());
a6568219 1318
b3d44315
MV
1319 Desc.URI = Index->ArchiveURI(PkgFile);
1320 Desc.Description = Index->ArchiveInfo(Version);
1321 Desc.Owner = this;
1322 Desc.ShortDesc = Version.ParentPkg().Name();
1323
17caf1b1 1324 // See if we already have the file. (Legacy filenames)
a6568219
AL
1325 FileSize = Version->Size;
1326 string FinalFile = _config->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile);
1327 struct stat Buf;
1328 if (stat(FinalFile.c_str(),&Buf) == 0)
1329 {
1330 // Make sure the size matches
1331 if ((unsigned)Buf.st_size == Version->Size)
1332 {
1333 Complete = true;
1334 Local = true;
1335 Status = StatDone;
30e1eab5 1336 StoreFilename = DestFile = FinalFile;
b185acc2 1337 return true;
a6568219
AL
1338 }
1339
6b1ff003
AL
1340 /* Hmm, we have a file and its size does not match, this means it is
1341 an old style mismatched arch */
a6568219
AL
1342 unlink(FinalFile.c_str());
1343 }
17caf1b1
AL
1344
1345 // Check it again using the new style output filenames
1346 FinalFile = _config->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename);
1347 if (stat(FinalFile.c_str(),&Buf) == 0)
1348 {
1349 // Make sure the size matches
1350 if ((unsigned)Buf.st_size == Version->Size)
1351 {
1352 Complete = true;
1353 Local = true;
1354 Status = StatDone;
1355 StoreFilename = DestFile = FinalFile;
1356 return true;
1357 }
1358
1359 /* Hmm, we have a file and its size does not match, this shouldnt
1360 happen.. */
1361 unlink(FinalFile.c_str());
1362 }
1363
1364 DestFile = _config->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename);
6b1ff003
AL
1365
1366 // Check the destination file
1367 if (stat(DestFile.c_str(),&Buf) == 0)
1368 {
1369 // Hmm, the partial file is too big, erase it
1370 if ((unsigned)Buf.st_size > Version->Size)
1371 unlink(DestFile.c_str());
1372 else
1373 PartialSize = Buf.st_size;
1374 }
1375
03e39e59 1376 // Create the item
b2e465d6
AL
1377 Local = false;
1378 Desc.URI = Index->ArchiveURI(PkgFile);
1379 Desc.Description = Index->ArchiveInfo(Version);
03e39e59
AL
1380 Desc.Owner = this;
1381 Desc.ShortDesc = Version.ParentPkg().Name();
1382 QueueURI(Desc);
b185acc2
AL
1383
1384 Vf++;
1385 return true;
03e39e59 1386 }
b185acc2
AL
1387 return false;
1388}
03e39e59
AL
1389 /*}}}*/
1390// AcqArchive::Done - Finished fetching /*{{{*/
1391// ---------------------------------------------------------------------
1392/* */
459681d3
AL
1393void pkgAcqArchive::Done(string Message,unsigned long Size,string Md5Hash,
1394 pkgAcquire::MethodConfig *Cfg)
03e39e59 1395{
459681d3 1396 Item::Done(Message,Size,Md5Hash,Cfg);
03e39e59
AL
1397
1398 // Check the size
1399 if (Size != Version->Size)
1400 {
bdae53f1 1401 Status = StatError;
b2e465d6 1402 ErrorText = _("Size mismatch");
03e39e59
AL
1403 return;
1404 }
1405
1406 // Check the md5
1407 if (Md5Hash.empty() == false && MD5.empty() == false)
1408 {
1409 if (Md5Hash != MD5)
1410 {
bdae53f1 1411 Status = StatError;
b2e465d6 1412 ErrorText = _("MD5Sum mismatch");
13e8426f
MV
1413 if(FileExists(DestFile))
1414 Rename(DestFile,DestFile + ".FAILED");
03e39e59
AL
1415 return;
1416 }
1417 }
a6568219
AL
1418
1419 // Grab the output filename
03e39e59
AL
1420 string FileName = LookupTag(Message,"Filename");
1421 if (FileName.empty() == true)
1422 {
1423 Status = StatError;
1424 ErrorText = "Method gave a blank filename";
1425 return;
1426 }
a6568219
AL
1427
1428 Complete = true;
30e1eab5
AL
1429
1430 // Reference filename
a6568219
AL
1431 if (FileName != DestFile)
1432 {
30e1eab5 1433 StoreFilename = DestFile = FileName;
a6568219
AL
1434 Local = true;
1435 return;
1436 }
1437
1438 // Done, move it into position
1439 string FinalFile = _config->FindDir("Dir::Cache::Archives");
17caf1b1 1440 FinalFile += flNotDir(StoreFilename);
a6568219 1441 Rename(DestFile,FinalFile);
03e39e59 1442
30e1eab5 1443 StoreFilename = DestFile = FinalFile;
03e39e59
AL
1444 Complete = true;
1445}
1446 /*}}}*/
db890fdb
AL
1447// AcqArchive::Failed - Failure handler /*{{{*/
1448// ---------------------------------------------------------------------
1449/* Here we try other sources */
7d8afa39 1450void pkgAcqArchive::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
db890fdb
AL
1451{
1452 ErrorText = LookupTag(Message,"Message");
b2e465d6
AL
1453
1454 /* We don't really want to retry on failed media swaps, this prevents
1455 that. An interesting observation is that permanent failures are not
1456 recorded. */
1457 if (Cnf->Removable == true &&
1458 StringToBool(LookupTag(Message,"Transient-Failure"),false) == true)
1459 {
1460 // Vf = Version.FileList();
1461 while (Vf.end() == false) Vf++;
1462 StoreFilename = string();
1463 Item::Failed(Message,Cnf);
1464 return;
1465 }
1466
db890fdb 1467 if (QueueNext() == false)
7d8afa39
AL
1468 {
1469 // This is the retry counter
1470 if (Retries != 0 &&
1471 Cnf->LocalOnly == false &&
1472 StringToBool(LookupTag(Message,"Transient-Failure"),false) == true)
1473 {
1474 Retries--;
1475 Vf = Version.FileList();
1476 if (QueueNext() == true)
1477 return;
1478 }
1479
9dbb421f 1480 StoreFilename = string();
7d8afa39
AL
1481 Item::Failed(Message,Cnf);
1482 }
db890fdb
AL
1483}
1484 /*}}}*/
b3d44315
MV
1485// AcqArchive::IsTrusted - Determine whether this archive comes from a
1486// trusted source /*{{{*/
1487// ---------------------------------------------------------------------
1488bool pkgAcqArchive::IsTrusted()
1489{
1490 return Trusted;
1491}
1492
ab559b35
AL
1493// AcqArchive::Finished - Fetching has finished, tidy up /*{{{*/
1494// ---------------------------------------------------------------------
1495/* */
1496void pkgAcqArchive::Finished()
1497{
1498 if (Status == pkgAcquire::Item::StatDone &&
1499 Complete == true)
1500 return;
1501 StoreFilename = string();
1502}
1503 /*}}}*/
36375005
AL
1504
1505// AcqFile::pkgAcqFile - Constructor /*{{{*/
1506// ---------------------------------------------------------------------
1507/* The file is added to the queue */
1508pkgAcqFile::pkgAcqFile(pkgAcquire *Owner,string URI,string MD5,
46e00f9d
MV
1509 unsigned long Size,string Dsc,string ShortDesc,
1510 const string &DestDir, const string &DestFilename) :
b3c39978 1511 Item(Owner), Md5Hash(MD5)
36375005 1512{
08cfc005
AL
1513 Retries = _config->FindI("Acquire::Retries",0);
1514
46e00f9d
MV
1515 if(!DestFilename.empty())
1516 DestFile = DestFilename;
1517 else if(!DestDir.empty())
1518 DestFile = DestDir + "/" + flNotDir(URI);
1519 else
1520 DestFile = flNotDir(URI);
1521
36375005
AL
1522 // Create the item
1523 Desc.URI = URI;
1524 Desc.Description = Dsc;
1525 Desc.Owner = this;
1526
1527 // Set the short description to the archive component
1528 Desc.ShortDesc = ShortDesc;
1529
1530 // Get the transfer sizes
1531 FileSize = Size;
1532 struct stat Buf;
1533 if (stat(DestFile.c_str(),&Buf) == 0)
1534 {
1535 // Hmm, the partial file is too big, erase it
1536 if ((unsigned)Buf.st_size > Size)
1537 unlink(DestFile.c_str());
1538 else
1539 PartialSize = Buf.st_size;
1540 }
092ae175 1541
36375005
AL
1542 QueueURI(Desc);
1543}
1544 /*}}}*/
1545// AcqFile::Done - Item downloaded OK /*{{{*/
1546// ---------------------------------------------------------------------
1547/* */
459681d3
AL
1548void pkgAcqFile::Done(string Message,unsigned long Size,string MD5,
1549 pkgAcquire::MethodConfig *Cnf)
36375005 1550{
b3c39978
AL
1551 // Check the md5
1552 if (Md5Hash.empty() == false && MD5.empty() == false)
1553 {
1554 if (Md5Hash != MD5)
1555 {
1556 Status = StatError;
1557 ErrorText = "MD5Sum mismatch";
1558 Rename(DestFile,DestFile + ".FAILED");
1559 return;
1560 }
1561 }
1562
459681d3 1563 Item::Done(Message,Size,MD5,Cnf);
36375005
AL
1564
1565 string FileName = LookupTag(Message,"Filename");
1566 if (FileName.empty() == true)
1567 {
1568 Status = StatError;
1569 ErrorText = "Method gave a blank filename";
1570 return;
1571 }
1572
1573 Complete = true;
1574
1575 // The files timestamp matches
1576 if (StringToBool(LookupTag(Message,"IMS-Hit"),false) == true)
1577 return;
1578
1579 // We have to copy it into place
1580 if (FileName != DestFile)
1581 {
1582 Local = true;
459681d3
AL
1583 if (_config->FindB("Acquire::Source-Symlinks",true) == false ||
1584 Cnf->Removable == true)
917ae805
AL
1585 {
1586 Desc.URI = "copy:" + FileName;
1587 QueueURI(Desc);
1588 return;
1589 }
1590
83ab33fc
AL
1591 // Erase the file if it is a symlink so we can overwrite it
1592 struct stat St;
1593 if (lstat(DestFile.c_str(),&St) == 0)
1594 {
1595 if (S_ISLNK(St.st_mode) != 0)
1596 unlink(DestFile.c_str());
1597 }
1598
1599 // Symlink the file
917ae805
AL
1600 if (symlink(FileName.c_str(),DestFile.c_str()) != 0)
1601 {
83ab33fc 1602 ErrorText = "Link to " + DestFile + " failure ";
917ae805
AL
1603 Status = StatError;
1604 Complete = false;
1605 }
36375005
AL
1606 }
1607}
1608 /*}}}*/
08cfc005
AL
1609// AcqFile::Failed - Failure handler /*{{{*/
1610// ---------------------------------------------------------------------
1611/* Here we try other sources */
1612void pkgAcqFile::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
1613{
1614 ErrorText = LookupTag(Message,"Message");
1615
1616 // This is the retry counter
1617 if (Retries != 0 &&
1618 Cnf->LocalOnly == false &&
1619 StringToBool(LookupTag(Message,"Transient-Failure"),false) == true)
1620 {
1621 Retries--;
1622 QueueURI(Desc);
1623 return;
1624 }
1625
1626 Item::Failed(Message,Cnf);
1627}
1628 /*}}}*/