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