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