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