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