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