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