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