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