]> git.saurik.com Git - apt.git/blame - apt-pkg/acquire-item.cc
check for UnfetchedReleaseFiles when calculating the update percent value
[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
949d2e98
DK
939 Verify = true;
940
5d885723
DK
941 Init(URI, URIDesc, ShortDesc);
942}
943pkgAcqIndex::pkgAcqIndex(pkgAcquire *Owner, IndexTarget const *Target,
1dca8dc5 944 HashString const &ExpectedHash, indexRecords *MetaIndexParser)
5d885723
DK
945 : Item(Owner), RealURI(Target->URI), ExpectedHash(ExpectedHash)
946{
947 // autoselect the compression method
948 std::vector<std::string> types = APT::Configuration::getCompressionTypes();
949 CompressionExtension = "";
950 if (ExpectedHash.empty() == false)
951 {
952 for (std::vector<std::string>::const_iterator t = types.begin(); t != types.end(); ++t)
953 if (*t == "uncompressed" || MetaIndexParser->Exists(string(Target->MetaKey).append(".").append(*t)) == true)
954 CompressionExtension.append(*t).append(" ");
955 }
956 else
957 {
958 for (std::vector<std::string>::const_iterator t = types.begin(); t != types.end(); ++t)
959 CompressionExtension.append(*t).append(" ");
960 }
961 if (CompressionExtension.empty() == false)
962 CompressionExtension.erase(CompressionExtension.end()-1);
963
97efc27f
MV
964 // only verify non-optional targets, see acquire-item.h for a FIXME
965 // to make this more flexible
c5f661b7
MV
966 if (Target->IsOptional())
967 Verify = false;
97efc27f
MV
968 else
969 Verify = true;
c5f661b7 970
b11f9599
MV
971 // we need this in Init()
972 this->Target = Target;
973 this->MetaIndexParser = MetaIndexParser;
974
5d885723
DK
975 Init(Target->URI, Target->Description, Target->ShortDesc);
976}
977 /*}}}*/
978// AcqIndex::Init - defered Constructor /*{{{*/
979void pkgAcqIndex::Init(string const &URI, string const &URIDesc, string const &ShortDesc) {
8b89e57f 980 Decompression = false;
bfd22fc0 981 Erase = false;
13e8426f 982
0a8a80e5 983 DestFile = _config->FindDir("Dir::State::lists") + "partial/";
b2e465d6 984 DestFile += URItoFileName(URI);
8267fe24 985
5d885723 986 std::string const comprExt = CompressionExtension.substr(0, CompressionExtension.find(' '));
b11f9599 987 std::string MetaKey;
5d885723 988 if (comprExt == "uncompressed")
b11f9599 989 {
5d885723 990 Desc.URI = URI;
e39698a4
MV
991 if(Target)
992 MetaKey = string(Target->MetaKey);
b11f9599 993 }
5d885723 994 else
b11f9599 995 {
5d885723 996 Desc.URI = URI + '.' + comprExt;
e39698a4
MV
997 if(Target)
998 MetaKey = string(Target->MetaKey) + '.' + comprExt;
b11f9599
MV
999 }
1000
1001 // load the filesize
e39698a4
MV
1002 if(MetaIndexParser)
1003 {
1004 indexRecords::checkSum *Record = MetaIndexParser->Lookup(MetaKey);
1005 if(Record)
1006 FileSize = Record->Size;
1007 }
b3d44315 1008
b2e465d6 1009 Desc.Description = URIDesc;
8267fe24 1010 Desc.Owner = this;
b2e465d6 1011 Desc.ShortDesc = ShortDesc;
5d885723 1012
8267fe24 1013 QueueURI(Desc);
0118833a
AL
1014}
1015 /*}}}*/
0a8a80e5 1016// AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
0118833a 1017// ---------------------------------------------------------------------
0a8a80e5
AL
1018/* The only header we use is the last-modified header. */
1019string pkgAcqIndex::Custom600Headers()
0118833a 1020{
0a8a80e5 1021 string Final = _config->FindDir("Dir::State::lists");
b2e465d6 1022 Final += URItoFileName(RealURI);
01606def 1023 if (_config->FindB("Acquire::GzipIndexes",false))
1024 Final += ".gz";
0a8a80e5 1025
97b65b10
MV
1026 string msg = "\nIndex-File: true";
1027 // FIXME: this really should use "IndexTarget::IsOptional()" but that
1028 // seems to be difficult without breaking ABI
1029 if (ShortDesc().find("Translation") != 0)
1030 msg += "\nFail-Ignore: true";
0a8a80e5 1031 struct stat Buf;
3a1f49c4 1032 if (stat(Final.c_str(),&Buf) == 0)
97b65b10
MV
1033 msg += "\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
1034
1035 return msg;
0118833a
AL
1036}
1037 /*}}}*/
92fcbfc1 1038void pkgAcqIndex::Failed(string Message,pkgAcquire::MethodConfig *Cnf) /*{{{*/
debc84b2 1039{
5d885723
DK
1040 size_t const nextExt = CompressionExtension.find(' ');
1041 if (nextExt != std::string::npos)
e85b4cd5 1042 {
5d885723
DK
1043 CompressionExtension = CompressionExtension.substr(nextExt+1);
1044 Init(RealURI, Desc.Description, Desc.ShortDesc);
6abe2699 1045 return;
0d7a243d
EL
1046 }
1047
17ff0930 1048 // on decompression failure, remove bad versions in partial/
5d885723 1049 if (Decompression && Erase) {
17ff0930 1050 string s = _config->FindDir("Dir::State::lists") + "partial/";
5d885723 1051 s.append(URItoFileName(RealURI));
17ff0930 1052 unlink(s.c_str());
debc84b2
MZ
1053 }
1054
debc84b2
MZ
1055 Item::Failed(Message,Cnf);
1056}
92fcbfc1 1057 /*}}}*/
8b89e57f
AL
1058// AcqIndex::Done - Finished a fetch /*{{{*/
1059// ---------------------------------------------------------------------
1060/* This goes through a number of states.. On the initial fetch the
1061 method could possibly return an alternate filename which points
1062 to the uncompressed version of the file. If this is so the file
1063 is copied into the partial directory. In all other cases the file
1064 is decompressed with a gzip uri. */
73da43e9 1065void pkgAcqIndex::Done(string Message,unsigned long long Size,string Hash,
459681d3 1066 pkgAcquire::MethodConfig *Cfg)
8b89e57f 1067{
495e5cb2 1068 Item::Done(Message,Size,Hash,Cfg);
8b89e57f
AL
1069
1070 if (Decompression == true)
1071 {
b3d44315
MV
1072 if (_config->FindB("Debug::pkgAcquire::Auth", false))
1073 {
495e5cb2
MV
1074 std::cerr << std::endl << RealURI << ": Computed Hash: " << Hash;
1075 std::cerr << " Expected Hash: " << ExpectedHash.toStr() << std::endl;
b3d44315
MV
1076 }
1077
8a8feb29 1078 if (!ExpectedHash.empty() && ExpectedHash.toStr() != Hash)
b3d44315 1079 {
3c8030a4 1080 RenameOnError(HashSumMismatch);
b3d44315
MV
1081 return;
1082 }
0901c5d0
JAK
1083
1084 /* Verify the index file for correctness (all indexes must
4fdb6123 1085 * have a Package field) (LP: #346386) (Closes: #627642) */
c5f661b7 1086 if (Verify == true)
0901c5d0
JAK
1087 {
1088 FileFd fd(DestFile, FileFd::ReadOnly);
3c8030a4
DK
1089 // Only test for correctness if the file is not empty (empty is ok)
1090 if (fd.FileSize() > 0)
1091 {
1092 pkgTagSection sec;
1093 pkgTagFile tag(&fd);
1094
1095 // all our current indexes have a field 'Package' in each section
1096 if (_error->PendingError() == true || tag.Step(sec) == false || sec.Exists("Package") == false)
1097 {
1098 RenameOnError(InvalidFormat);
1099 return;
1100 }
a0c3110e 1101 }
0901c5d0
JAK
1102 }
1103
8b89e57f
AL
1104 // Done, move it into position
1105 string FinalFile = _config->FindDir("Dir::State::lists");
b2e465d6 1106 FinalFile += URItoFileName(RealURI);
8b89e57f 1107 Rename(DestFile,FinalFile);
7a3c2ab0 1108 chmod(FinalFile.c_str(),0644);
b11f9599 1109
7a7fa5f0
AL
1110 /* We restore the original name to DestFile so that the clean operation
1111 will work OK */
1112 DestFile = _config->FindDir("Dir::State::lists") + "partial/";
b2e465d6 1113 DestFile += URItoFileName(RealURI);
7a7fa5f0 1114
bfd22fc0
AL
1115 // Remove the compressed version.
1116 if (Erase == true)
bfd22fc0 1117 unlink(DestFile.c_str());
b11f9599 1118
8b89e57f
AL
1119 return;
1120 }
bfd22fc0
AL
1121
1122 Erase = false;
8267fe24 1123 Complete = true;
bfd22fc0 1124
8b89e57f
AL
1125 // Handle the unzipd case
1126 string FileName = LookupTag(Message,"Alt-Filename");
1127 if (FileName.empty() == false)
1128 {
1129 // The files timestamp matches
1130 if (StringToBool(LookupTag(Message,"Alt-IMS-Hit"),false) == true)
1131 return;
8b89e57f 1132 Decompression = true;
a6568219 1133 Local = true;
8b89e57f 1134 DestFile += ".decomp";
8267fe24
AL
1135 Desc.URI = "copy:" + FileName;
1136 QueueURI(Desc);
b98f2859 1137 Mode = "copy";
8b89e57f
AL
1138 return;
1139 }
1140
1141 FileName = LookupTag(Message,"Filename");
1142 if (FileName.empty() == true)
1143 {
1144 Status = StatError;
1145 ErrorText = "Method gave a blank filename";
1146 }
5d885723
DK
1147
1148 std::string const compExt = CompressionExtension.substr(0, CompressionExtension.find(' '));
0b9032b1 1149
8b89e57f 1150 // The files timestamp matches
0b9032b1 1151 if (StringToBool(LookupTag(Message,"IMS-Hit"),false) == true) {
1152 if (_config->FindB("Acquire::GzipIndexes",false) && compExt == "gz")
1153 // Update DestFile for .gz suffix so that the clean operation keeps it
1154 DestFile += ".gz";
8b89e57f 1155 return;
0b9032b1 1156 }
bfd22fc0
AL
1157
1158 if (FileName == DestFile)
1159 Erase = true;
8267fe24 1160 else
a6568219 1161 Local = true;
8b89e57f 1162
e85b4cd5
DK
1163 string decompProg;
1164
bb109d0b 1165 // If we enable compressed indexes and already have gzip, keep it
7aeee365 1166 if (_config->FindB("Acquire::GzipIndexes",false) && compExt == "gz" && !Local) {
bb109d0b 1167 string FinalFile = _config->FindDir("Dir::State::lists");
1168 FinalFile += URItoFileName(RealURI) + ".gz";
bb109d0b 1169 Rename(DestFile,FinalFile);
1170 chmod(FinalFile.c_str(),0644);
1171
1172 // Update DestFile for .gz suffix so that the clean operation keeps it
1173 DestFile = _config->FindDir("Dir::State::lists") + "partial/";
1174 DestFile += URItoFileName(RealURI) + ".gz";
1175 return;
1176 }
1177
e85b4cd5
DK
1178 // get the binary name for your used compression type
1179 decompProg = _config->Find(string("Acquire::CompressionTypes::").append(compExt),"");
1180 if(decompProg.empty() == false);
5d885723 1181 else if(compExt == "uncompressed")
0d7a243d 1182 decompProg = "copy";
debc84b2
MZ
1183 else {
1184 _error->Error("Unsupported extension: %s", compExt.c_str());
1185 return;
1186 }
1187
8b89e57f
AL
1188 Decompression = true;
1189 DestFile += ".decomp";
e85b4cd5 1190 Desc.URI = decompProg + ":" + FileName;
8267fe24 1191 QueueURI(Desc);
70e0c168
MV
1192
1193 // FIXME: this points to a c++ string that goes out of scope
e85b4cd5 1194 Mode = decompProg.c_str();
8b89e57f 1195}
92fcbfc1 1196 /*}}}*/
a52f938b
OS
1197// AcqIndexTrans::pkgAcqIndexTrans - Constructor /*{{{*/
1198// ---------------------------------------------------------------------
1199/* The Translation file is added to the queue */
1200pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire *Owner,
495e5cb2
MV
1201 string URI,string URIDesc,string ShortDesc)
1202 : pkgAcqIndex(Owner, URI, URIDesc, ShortDesc, HashString(), "")
a52f938b 1203{
ab53c018
DK
1204}
1205pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire *Owner, IndexTarget const *Target,
1dca8dc5 1206 HashString const &ExpectedHash, indexRecords *MetaIndexParser)
ab53c018
DK
1207 : pkgAcqIndex(Owner, Target, ExpectedHash, MetaIndexParser)
1208{
1dca8dc5
MV
1209 // load the filesize
1210 indexRecords::checkSum *Record = MetaIndexParser->Lookup(string(Target->MetaKey));
1211 if(Record)
1212 FileSize = Record->Size;
963b16dc
MV
1213}
1214 /*}}}*/
1215// AcqIndexTrans::Custom600Headers - Insert custom request headers /*{{{*/
1216// ---------------------------------------------------------------------
1217string pkgAcqIndexTrans::Custom600Headers()
1218{
c91d9a63
DK
1219 string Final = _config->FindDir("Dir::State::lists");
1220 Final += URItoFileName(RealURI);
1221
1222 struct stat Buf;
1223 if (stat(Final.c_str(),&Buf) != 0)
a3f7fff8
MV
1224 return "\nFail-Ignore: true\nIndex-File: true";
1225 return "\nFail-Ignore: true\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
a52f938b 1226}
a52f938b
OS
1227 /*}}}*/
1228// AcqIndexTrans::Failed - Silence failure messages for missing files /*{{{*/
1229// ---------------------------------------------------------------------
1230/* */
1231void pkgAcqIndexTrans::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
1232{
5d885723
DK
1233 size_t const nextExt = CompressionExtension.find(' ');
1234 if (nextExt != std::string::npos)
1235 {
1236 CompressionExtension = CompressionExtension.substr(nextExt+1);
1237 Init(RealURI, Desc.Description, Desc.ShortDesc);
1238 Status = StatIdle;
1239 return;
1240 }
1241
a52f938b
OS
1242 if (Cnf->LocalOnly == true ||
1243 StringToBool(LookupTag(Message,"Transient-Failure"),false) == false)
1244 {
1245 // Ignore this
1246 Status = StatDone;
1247 Complete = false;
1248 Dequeue();
1249 return;
1250 }
5d885723 1251
a52f938b
OS
1252 Item::Failed(Message,Cnf);
1253}
1254 /*}}}*/
92fcbfc1 1255pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire *Owner, /*{{{*/
b3d44315
MV
1256 string URI,string URIDesc,string ShortDesc,
1257 string MetaIndexURI, string MetaIndexURIDesc,
1258 string MetaIndexShortDesc,
1259 const vector<IndexTarget*>* IndexTargets,
1260 indexRecords* MetaIndexParser) :
1261 Item(Owner), RealURI(URI), MetaIndexURI(MetaIndexURI),
46e00f9d
MV
1262 MetaIndexURIDesc(MetaIndexURIDesc), MetaIndexShortDesc(MetaIndexShortDesc),
1263 MetaIndexParser(MetaIndexParser), IndexTargets(IndexTargets)
0118833a 1264{
0a8a80e5 1265 DestFile = _config->FindDir("Dir::State::lists") + "partial/";
b2e465d6 1266 DestFile += URItoFileName(URI);
b3d44315 1267
47eb38f4
MV
1268 // remove any partial downloaded sig-file in partial/.
1269 // it may confuse proxies and is too small to warrant a
1270 // partial download anyway
f6237efd
MV
1271 unlink(DestFile.c_str());
1272
8267fe24 1273 // Create the item
b2e465d6 1274 Desc.Description = URIDesc;
8267fe24 1275 Desc.Owner = this;
b3d44315
MV
1276 Desc.ShortDesc = ShortDesc;
1277 Desc.URI = URI;
b3d44315
MV
1278
1279 string Final = _config->FindDir("Dir::State::lists");
1280 Final += URItoFileName(RealURI);
ffcccd62 1281 if (RealFileExists(Final) == true)
b3d44315 1282 {
ef942597 1283 // File was already in place. It needs to be re-downloaded/verified
1e3f4083 1284 // because Release might have changed, we do give it a different
ef942597
MV
1285 // name than DestFile because otherwise the http method will
1286 // send If-Range requests and there are too many broken servers
1287 // out there that do not understand them
1288 LastGoodSig = DestFile+".reverify";
1289 Rename(Final,LastGoodSig);
b3d44315 1290 }
8267fe24 1291
d0cfa8ad
MV
1292 // we expect the indextargets + one additional Release file
1293 ExpectedAdditionalItems = IndexTargets->size() + 1;
1294
8267fe24 1295 QueueURI(Desc);
ffcccd62
DK
1296}
1297 /*}}}*/
1298pkgAcqMetaSig::~pkgAcqMetaSig() /*{{{*/
1299{
1300 // if the file was never queued undo file-changes done in the constructor
1301 if (QueueCounter == 1 && Status == StatIdle && FileSize == 0 && Complete == false &&
1302 LastGoodSig.empty() == false)
1303 {
1304 string const Final = _config->FindDir("Dir::State::lists") + URItoFileName(RealURI);
1305 if (RealFileExists(Final) == false && RealFileExists(LastGoodSig) == true)
1306 Rename(LastGoodSig, Final);
1307 }
1308
0118833a
AL
1309}
1310 /*}}}*/
b3d44315 1311// pkgAcqMetaSig::Custom600Headers - Insert custom request headers /*{{{*/
0118833a 1312// ---------------------------------------------------------------------
0a8a80e5 1313/* The only header we use is the last-modified header. */
b3d44315 1314string pkgAcqMetaSig::Custom600Headers()
0118833a 1315{
0a8a80e5 1316 struct stat Buf;
ef942597 1317 if (stat(LastGoodSig.c_str(),&Buf) != 0)
a72ace20 1318 return "\nIndex-File: true";
a789b983 1319
a72ace20 1320 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
0118833a 1321}
b3d44315 1322
73da43e9 1323void pkgAcqMetaSig::Done(string Message,unsigned long long Size,string MD5,
b3d44315 1324 pkgAcquire::MethodConfig *Cfg)
c88edf1d 1325{
459681d3 1326 Item::Done(Message,Size,MD5,Cfg);
c88edf1d
AL
1327
1328 string FileName = LookupTag(Message,"Filename");
1329 if (FileName.empty() == true)
1330 {
1331 Status = StatError;
1332 ErrorText = "Method gave a blank filename";
8b89e57f 1333 return;
c88edf1d 1334 }
8b89e57f 1335
c88edf1d
AL
1336 if (FileName != DestFile)
1337 {
b3d44315 1338 // We have to copy it into place
a6568219 1339 Local = true;
8267fe24
AL
1340 Desc.URI = "copy:" + FileName;
1341 QueueURI(Desc);
c88edf1d
AL
1342 return;
1343 }
b3d44315
MV
1344
1345 Complete = true;
1346
d0cfa8ad
MV
1347 // at this point pkgAcqMetaIndex takes over
1348 ExpectedAdditionalItems = 0;
1349
ef942597
MV
1350 // put the last known good file back on i-m-s hit (it will
1351 // be re-verified again)
1352 // Else do nothing, we have the new file in DestFile then
1353 if(StringToBool(LookupTag(Message,"IMS-Hit"),false) == true)
1354 Rename(LastGoodSig, DestFile);
1355
b3d44315 1356 // queue a pkgAcqMetaIndex to be verified against the sig we just retrieved
fce72602
MV
1357 new pkgAcqMetaIndex(Owner, MetaIndexURI, MetaIndexURIDesc,
1358 MetaIndexShortDesc, DestFile, IndexTargets,
1359 MetaIndexParser);
b3d44315 1360
c88edf1d
AL
1361}
1362 /*}}}*/
92fcbfc1 1363void pkgAcqMetaSig::Failed(string Message,pkgAcquire::MethodConfig *Cnf)/*{{{*/
681d76d0 1364{
47eb38f4 1365 string Final = _config->FindDir("Dir::State::lists") + URItoFileName(RealURI);
a789b983 1366
d0cfa8ad
MV
1367 // at this point pkgAcqMetaIndex takes over
1368 ExpectedAdditionalItems = 0;
1369
75dd8af1 1370 // if we get a network error we fail gracefully
7e5f33eb
MV
1371 if(Status == StatTransientNetworkError)
1372 {
24057ad6 1373 Item::Failed(Message,Cnf);
484dbb81 1374 // move the sigfile back on transient network failures
7730e095 1375 if(FileExists(LastGoodSig))
ef942597 1376 Rename(LastGoodSig,Final);
7e5f33eb
MV
1377
1378 // set the status back to , Item::Failed likes to reset it
1379 Status = pkgAcquire::Item::StatTransientNetworkError;
24057ad6
MV
1380 return;
1381 }
1382
75dd8af1 1383 // Delete any existing sigfile when the acquire failed
75dd8af1
MV
1384 unlink(Final.c_str());
1385
b3d44315
MV
1386 // queue a pkgAcqMetaIndex with no sigfile
1387 new pkgAcqMetaIndex(Owner, MetaIndexURI, MetaIndexURIDesc, MetaIndexShortDesc,
1388 "", IndexTargets, MetaIndexParser);
1389
681d76d0
AL
1390 if (Cnf->LocalOnly == true ||
1391 StringToBool(LookupTag(Message,"Transient-Failure"),false) == false)
1392 {
2b154e53
AL
1393 // Ignore this
1394 Status = StatDone;
1395 Complete = false;
681d76d0
AL
1396 Dequeue();
1397 return;
1398 }
1399
1400 Item::Failed(Message,Cnf);
1401}
92fcbfc1
DK
1402 /*}}}*/
1403pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire *Owner, /*{{{*/
b3d44315
MV
1404 string URI,string URIDesc,string ShortDesc,
1405 string SigFile,
1406 const vector<struct IndexTarget*>* IndexTargets,
1407 indexRecords* MetaIndexParser) :
21fd1746
OS
1408 Item(Owner), RealURI(URI), SigFile(SigFile), IndexTargets(IndexTargets),
1409 MetaIndexParser(MetaIndexParser), AuthPass(false), IMSHit(false)
b3d44315 1410{
b3d44315
MV
1411 DestFile = _config->FindDir("Dir::State::lists") + "partial/";
1412 DestFile += URItoFileName(URI);
1413
1414 // Create the item
1415 Desc.Description = URIDesc;
1416 Desc.Owner = this;
1417 Desc.ShortDesc = ShortDesc;
1418 Desc.URI = URI;
1419
d0cfa8ad
MV
1420 // we expect more item
1421 ExpectedAdditionalItems = IndexTargets->size();
1422
b3d44315
MV
1423 QueueURI(Desc);
1424}
b3d44315
MV
1425 /*}}}*/
1426// pkgAcqMetaIndex::Custom600Headers - Insert custom request headers /*{{{*/
1427// ---------------------------------------------------------------------
1428/* The only header we use is the last-modified header. */
1429string pkgAcqMetaIndex::Custom600Headers()
1430{
1431 string Final = _config->FindDir("Dir::State::lists");
1432 Final += URItoFileName(RealURI);
1433
1434 struct stat Buf;
1435 if (stat(Final.c_str(),&Buf) != 0)
1436 return "\nIndex-File: true";
1437
1438 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
1439}
92fcbfc1 1440 /*}}}*/
73da43e9 1441void pkgAcqMetaIndex::Done(string Message,unsigned long long Size,string Hash, /*{{{*/
b3d44315
MV
1442 pkgAcquire::MethodConfig *Cfg)
1443{
495e5cb2 1444 Item::Done(Message,Size,Hash,Cfg);
b3d44315
MV
1445
1446 // MetaIndexes are done in two passes: one to download the
1447 // metaindex with an appropriate method, and a second to verify it
1448 // with the gpgv method
1449
1450 if (AuthPass == true)
1451 {
1452 AuthDone(Message);
fce72602
MV
1453
1454 // all cool, move Release file into place
1455 Complete = true;
b3d44315
MV
1456 }
1457 else
1458 {
1459 RetrievalDone(Message);
1460 if (!Complete)
1461 // Still more retrieving to do
1462 return;
1463
1464 if (SigFile == "")
1465 {
1466 // There was no signature file, so we are finished. Download
1207cf3f 1467 // the indexes and do only hashsum verification if possible
3568a640 1468 MetaIndexParser->Load(DestFile);
1207cf3f 1469 QueueIndexes(false);
b3d44315
MV
1470 }
1471 else
1472 {
1473 // There was a signature file, so pass it to gpgv for
1474 // verification
1475
1476 if (_config->FindB("Debug::pkgAcquire::Auth", false))
1477 std::cerr << "Metaindex acquired, queueing gpg verification ("
1478 << SigFile << "," << DestFile << ")\n";
1479 AuthPass = true;
1480 Desc.URI = "gpgv:" + SigFile;
1481 QueueURI(Desc);
1482 Mode = "gpgv";
56bc3358 1483 return;
b3d44315
MV
1484 }
1485 }
56bc3358
DK
1486
1487 if (Complete == true)
1488 {
1489 string FinalFile = _config->FindDir("Dir::State::lists");
1490 FinalFile += URItoFileName(RealURI);
fe0f7911
DK
1491 if (SigFile == DestFile)
1492 SigFile = FinalFile;
56bc3358
DK
1493 Rename(DestFile,FinalFile);
1494 chmod(FinalFile.c_str(),0644);
1495 DestFile = FinalFile;
1496 }
b3d44315 1497}
92fcbfc1
DK
1498 /*}}}*/
1499void pkgAcqMetaIndex::RetrievalDone(string Message) /*{{{*/
b3d44315
MV
1500{
1501 // We have just finished downloading a Release file (it is not
1502 // verified yet)
1503
1504 string FileName = LookupTag(Message,"Filename");
1505 if (FileName.empty() == true)
1506 {
1507 Status = StatError;
1508 ErrorText = "Method gave a blank filename";
1509 return;
1510 }
1511
1512 if (FileName != DestFile)
1513 {
1514 Local = true;
1515 Desc.URI = "copy:" + FileName;
1516 QueueURI(Desc);
1517 return;
1518 }
1519
fce72602 1520 // make sure to verify against the right file on I-M-S hit
f381d68d 1521 IMSHit = StringToBool(LookupTag(Message,"IMS-Hit"),false);
fce72602
MV
1522 if(IMSHit)
1523 {
1524 string FinalFile = _config->FindDir("Dir::State::lists");
1525 FinalFile += URItoFileName(RealURI);
fe0f7911 1526 if (SigFile == DestFile)
0aec7d5c 1527 {
fe0f7911 1528 SigFile = FinalFile;
0aec7d5c
DK
1529 // constructor of pkgAcqMetaClearSig moved it out of the way,
1530 // now move it back in on IMS hit for the 'old' file
1531 string const OldClearSig = DestFile + ".reverify";
1532 if (RealFileExists(OldClearSig) == true)
1533 Rename(OldClearSig, FinalFile);
1534 }
fce72602
MV
1535 DestFile = FinalFile;
1536 }
b3d44315 1537 Complete = true;
b3d44315 1538}
92fcbfc1
DK
1539 /*}}}*/
1540void pkgAcqMetaIndex::AuthDone(string Message) /*{{{*/
b3d44315
MV
1541{
1542 // At this point, the gpgv method has succeeded, so there is a
1543 // valid signature from a key in the trusted keyring. We
1544 // perform additional verification of its contents, and use them
1545 // to verify the indexes we are about to download
1546
1547 if (!MetaIndexParser->Load(DestFile))
1548 {
1549 Status = StatAuthError;
1550 ErrorText = MetaIndexParser->ErrorText;
1551 return;
1552 }
1553
ce424cd4 1554 if (!VerifyVendor(Message))
b3d44315
MV
1555 {
1556 return;
1557 }
1558
1559 if (_config->FindB("Debug::pkgAcquire::Auth", false))
1560 std::cerr << "Signature verification succeeded: "
1561 << DestFile << std::endl;
1562
1563 // Download further indexes with verification
1564 QueueIndexes(true);
1565
fe0f7911
DK
1566 // is it a clearsigned MetaIndex file?
1567 if (DestFile == SigFile)
1568 return;
1569
b3d44315 1570 // Done, move signature file into position
b3d44315
MV
1571 string VerifiedSigFile = _config->FindDir("Dir::State::lists") +
1572 URItoFileName(RealURI) + ".gpg";
1573 Rename(SigFile,VerifiedSigFile);
1574 chmod(VerifiedSigFile.c_str(),0644);
1575}
92fcbfc1
DK
1576 /*}}}*/
1577void pkgAcqMetaIndex::QueueIndexes(bool verify) /*{{{*/
b3d44315 1578{
0901c5d0 1579#if 0
4fdb6123 1580 /* Reject invalid, existing Release files (LP: #346386) (Closes: #627642)
0901c5d0
JAK
1581 * FIXME: Disabled; it breaks unsigned repositories without hashes */
1582 if (!verify && FileExists(DestFile) && !MetaIndexParser->Load(DestFile))
1583 {
1584 Status = StatError;
1585 ErrorText = MetaIndexParser->ErrorText;
1586 return;
1587 }
1588#endif
8e3900d0
DK
1589 bool transInRelease = false;
1590 {
1591 std::vector<std::string> const keys = MetaIndexParser->MetaKeys();
1592 for (std::vector<std::string>::const_iterator k = keys.begin(); k != keys.end(); ++k)
1593 // FIXME: Feels wrong to check for hardcoded string here, but what should we do else…
1594 if (k->find("Translation-") != std::string::npos)
1595 {
1596 transInRelease = true;
1597 break;
1598 }
1599 }
1600
d0cfa8ad
MV
1601 // at this point the real Items are loaded in the fetcher
1602 ExpectedAdditionalItems = 0;
1603
b3d44315
MV
1604 for (vector <struct IndexTarget*>::const_iterator Target = IndexTargets->begin();
1605 Target != IndexTargets->end();
f7f0d6c7 1606 ++Target)
b3d44315 1607 {
495e5cb2 1608 HashString ExpectedIndexHash;
1dca8dc5 1609 indexRecords::checkSum *Record = MetaIndexParser->Lookup((*Target)->MetaKey);
a5b9f489 1610 bool compressedAvailable = false;
1207cf3f 1611 if (Record == NULL)
b3d44315 1612 {
a5b9f489
DK
1613 if ((*Target)->IsOptional() == true)
1614 {
1615 std::vector<std::string> types = APT::Configuration::getCompressionTypes();
1616 for (std::vector<std::string>::const_iterator t = types.begin(); t != types.end(); ++t)
e788a834 1617 if (MetaIndexParser->Exists((*Target)->MetaKey + "." + *t) == true)
a5b9f489
DK
1618 {
1619 compressedAvailable = true;
1620 break;
1621 }
1622 }
1623 else if (verify == true)
ab53c018 1624 {
1207cf3f
DK
1625 Status = StatAuthError;
1626 strprintf(ErrorText, _("Unable to find expected entry '%s' in Release file (Wrong sources.list entry or malformed file)"), (*Target)->MetaKey.c_str());
1627 return;
ab53c018 1628 }
1207cf3f
DK
1629 }
1630 else
1631 {
1632 ExpectedIndexHash = Record->Hash;
1633 if (_config->FindB("Debug::pkgAcquire::Auth", false))
ab53c018 1634 {
1207cf3f
DK
1635 std::cerr << "Queueing: " << (*Target)->URI << std::endl;
1636 std::cerr << "Expected Hash: " << ExpectedIndexHash.toStr() << std::endl;
1637 std::cerr << "For: " << Record->MetaKeyFilename << std::endl;
1638 }
1639 if (verify == true && ExpectedIndexHash.empty() == true && (*Target)->IsOptional() == false)
1640 {
1641 Status = StatAuthError;
1642 strprintf(ErrorText, _("Unable to find hash sum for '%s' in Release file"), (*Target)->MetaKey.c_str());
1643 return;
ab53c018
DK
1644 }
1645 }
1646
1647 if ((*Target)->IsOptional() == true)
1648 {
1649 if ((*Target)->IsSubIndex() == true)
1650 new pkgAcqSubIndex(Owner, (*Target)->URI, (*Target)->Description,
1651 (*Target)->ShortDesc, ExpectedIndexHash);
a5b9f489 1652 else if (transInRelease == false || Record != NULL || compressedAvailable == true)
8e3900d0 1653 {
f55602cb 1654 if (_config->FindB("Acquire::PDiffs",true) == true && transInRelease == true &&
e788a834 1655 MetaIndexParser->Exists((*Target)->MetaKey + ".diff/Index") == true)
e39698a4 1656 new pkgAcqDiffIndex(Owner, *Target, ExpectedIndexHash, MetaIndexParser);
f55602cb
DK
1657 else
1658 new pkgAcqIndexTrans(Owner, *Target, ExpectedIndexHash, MetaIndexParser);
8e3900d0 1659 }
ab53c018 1660 continue;
b3d44315 1661 }
e1430400
DK
1662
1663 /* Queue Packages file (either diff or full packages files, depending
1664 on the users option) - we also check if the PDiff Index file is listed
1665 in the Meta-Index file. Ideal would be if pkgAcqDiffIndex would test this
1666 instead, but passing the required info to it is to much hassle */
1667 if(_config->FindB("Acquire::PDiffs",true) == true && (verify == false ||
e788a834 1668 MetaIndexParser->Exists((*Target)->MetaKey + ".diff/Index") == true))
e39698a4 1669 new pkgAcqDiffIndex(Owner, *Target, ExpectedIndexHash, MetaIndexParser);
e1430400 1670 else
5d885723 1671 new pkgAcqIndex(Owner, *Target, ExpectedIndexHash, MetaIndexParser);
b3d44315
MV
1672 }
1673}
92fcbfc1
DK
1674 /*}}}*/
1675bool pkgAcqMetaIndex::VerifyVendor(string Message) /*{{{*/
b3d44315 1676{
ce424cd4
MV
1677 string::size_type pos;
1678
1679 // check for missing sigs (that where not fatal because otherwise we had
1680 // bombed earlier)
1681 string missingkeys;
400ad7a4 1682 string msg = _("There is no public key available for the "
ce424cd4
MV
1683 "following key IDs:\n");
1684 pos = Message.find("NO_PUBKEY ");
1685 if (pos != std::string::npos)
1686 {
1687 string::size_type start = pos+strlen("NO_PUBKEY ");
1688 string Fingerprint = Message.substr(start, Message.find("\n")-start);
1689 missingkeys += (Fingerprint);
1690 }
1691 if(!missingkeys.empty())
e788a834 1692 _error->Warning("%s", (msg + missingkeys).c_str());
b3d44315
MV
1693
1694 string Transformed = MetaIndexParser->GetExpectedDist();
1695
1696 if (Transformed == "../project/experimental")
1697 {
1698 Transformed = "experimental";
1699 }
1700
ce424cd4 1701 pos = Transformed.rfind('/');
b3d44315
MV
1702 if (pos != string::npos)
1703 {
1704 Transformed = Transformed.substr(0, pos);
1705 }
1706
1707 if (Transformed == ".")
1708 {
1709 Transformed = "";
1710 }
1711
0323317c
DK
1712 if (_config->FindB("Acquire::Check-Valid-Until", true) == true &&
1713 MetaIndexParser->GetValidUntil() > 0) {
1714 time_t const invalid_since = time(NULL) - MetaIndexParser->GetValidUntil();
1715 if (invalid_since > 0)
1716 // TRANSLATOR: The first %s is the URL of the bad Release file, the second is
1717 // the time since then the file is invalid - formated in the same way as in
1718 // the download progress display (e.g. 7d 3h 42min 1s)
457bea86
MV
1719 return _error->Error(
1720 _("Release file for %s is expired (invalid since %s). "
1721 "Updates for this repository will not be applied."),
1722 RealURI.c_str(), TimeToStr(invalid_since).c_str());
1ddb8596
DK
1723 }
1724
b3d44315
MV
1725 if (_config->FindB("Debug::pkgAcquire::Auth", false))
1726 {
1727 std::cerr << "Got Codename: " << MetaIndexParser->GetDist() << std::endl;
1728 std::cerr << "Expecting Dist: " << MetaIndexParser->GetExpectedDist() << std::endl;
1729 std::cerr << "Transformed Dist: " << Transformed << std::endl;
1730 }
1731
1732 if (MetaIndexParser->CheckDist(Transformed) == false)
1733 {
1734 // This might become fatal one day
1735// Status = StatAuthError;
1736// ErrorText = "Conflicting distribution; expected "
1737// + MetaIndexParser->GetExpectedDist() + " but got "
1738// + MetaIndexParser->GetDist();
1739// return false;
1740 if (!Transformed.empty())
1741 {
1ddb8596 1742 _error->Warning(_("Conflicting distribution: %s (expected %s but got %s)"),
b3d44315
MV
1743 Desc.Description.c_str(),
1744 Transformed.c_str(),
1745 MetaIndexParser->GetDist().c_str());
1746 }
1747 }
1748
1749 return true;
1750}
92fcbfc1
DK
1751 /*}}}*/
1752// pkgAcqMetaIndex::Failed - no Release file present or no signature file present /*{{{*/
b3d44315
MV
1753// ---------------------------------------------------------------------
1754/* */
65512241 1755void pkgAcqMetaIndex::Failed(string Message,pkgAcquire::MethodConfig * /*Cnf*/)
b3d44315
MV
1756{
1757 if (AuthPass == true)
1758 {
fce72602 1759 // gpgv method failed, if we have a good signature
39f38a81
DK
1760 string LastGoodSigFile = _config->FindDir("Dir::State::lists").append("partial/").append(URItoFileName(RealURI));
1761 if (DestFile != SigFile)
1762 LastGoodSigFile.append(".gpg");
1763 LastGoodSigFile.append(".reverify");
fe0f7911 1764
fce72602 1765 if(FileExists(LastGoodSigFile))
f381d68d 1766 {
39f38a81 1767 string VerifiedSigFile = _config->FindDir("Dir::State::lists") + URItoFileName(RealURI);
fe0f7911 1768 if (DestFile != SigFile)
39f38a81
DK
1769 VerifiedSigFile.append(".gpg");
1770 Rename(LastGoodSigFile, VerifiedSigFile);
fce72602 1771 Status = StatTransientNetworkError;
b5595da9 1772 _error->Warning(_("An error occurred during the signature "
fce72602 1773 "verification. The repository is not updated "
2493f4b5 1774 "and the previous index files will be used. "
76b8e5a5 1775 "GPG error: %s: %s\n"),
fce72602
MV
1776 Desc.Description.c_str(),
1777 LookupTag(Message,"Message").c_str());
5d149bfc 1778 RunScripts("APT::Update::Auth-Failure");
f381d68d 1779 return;
0901c5d0 1780 } else if (LookupTag(Message,"Message").find("NODATA") != string::npos) {
4fdb6123 1781 /* Invalid signature file, reject (LP: #346386) (Closes: #627642) */
0901c5d0
JAK
1782 _error->Error(_("GPG error: %s: %s"),
1783 Desc.Description.c_str(),
1784 LookupTag(Message,"Message").c_str());
1785 return;
fce72602
MV
1786 } else {
1787 _error->Warning(_("GPG error: %s: %s"),
1788 Desc.Description.c_str(),
1789 LookupTag(Message,"Message").c_str());
f381d68d 1790 }
f381d68d 1791 // gpgv method failed
59271f62 1792 ReportMirrorFailure("GPGFailure");
b3d44315
MV
1793 }
1794
7ea7ac9e
JAK
1795 /* Always move the meta index, even if gpgv failed. This ensures
1796 * that PackageFile objects are correctly filled in */
a235ddf8 1797 if (FileExists(DestFile)) {
7ea7ac9e
JAK
1798 string FinalFile = _config->FindDir("Dir::State::lists");
1799 FinalFile += URItoFileName(RealURI);
1800 /* InRelease files become Release files, otherwise
1801 * they would be considered as trusted later on */
1802 if (SigFile == DestFile) {
1803 RealURI = RealURI.replace(RealURI.rfind("InRelease"), 9,
1804 "Release");
1805 FinalFile = FinalFile.replace(FinalFile.rfind("InRelease"), 9,
1806 "Release");
1807 SigFile = FinalFile;
1808 }
1809 Rename(DestFile,FinalFile);
1810 chmod(FinalFile.c_str(),0644);
1811
1812 DestFile = FinalFile;
1813 }
1814
b3d44315
MV
1815 // No Release file was present, or verification failed, so fall
1816 // back to queueing Packages files without verification
1817 QueueIndexes(false);
1818}
681d76d0 1819 /*}}}*/
fe0f7911
DK
1820pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire *Owner, /*{{{*/
1821 string const &URI, string const &URIDesc, string const &ShortDesc,
1822 string const &MetaIndexURI, string const &MetaIndexURIDesc, string const &MetaIndexShortDesc,
1823 string const &MetaSigURI, string const &MetaSigURIDesc, string const &MetaSigShortDesc,
1824 const vector<struct IndexTarget*>* IndexTargets,
1825 indexRecords* MetaIndexParser) :
1826 pkgAcqMetaIndex(Owner, URI, URIDesc, ShortDesc, "", IndexTargets, MetaIndexParser),
1827 MetaIndexURI(MetaIndexURI), MetaIndexURIDesc(MetaIndexURIDesc), MetaIndexShortDesc(MetaIndexShortDesc),
1828 MetaSigURI(MetaSigURI), MetaSigURIDesc(MetaSigURIDesc), MetaSigShortDesc(MetaSigShortDesc)
1829{
1830 SigFile = DestFile;
39f38a81 1831
d0cfa8ad
MV
1832 // index targets + (worst case:) Release/Release.gpg
1833 ExpectedAdditionalItems = IndexTargets->size() + 2;
1834
1835
39f38a81
DK
1836 // keep the old InRelease around in case of transistent network errors
1837 string const Final = _config->FindDir("Dir::State::lists") + URItoFileName(RealURI);
ffcccd62 1838 if (RealFileExists(Final) == true)
39f38a81
DK
1839 {
1840 string const LastGoodSig = DestFile + ".reverify";
1841 Rename(Final,LastGoodSig);
1842 }
fe0f7911
DK
1843}
1844 /*}}}*/
ffcccd62
DK
1845pkgAcqMetaClearSig::~pkgAcqMetaClearSig() /*{{{*/
1846{
1847 // if the file was never queued undo file-changes done in the constructor
1848 if (QueueCounter == 1 && Status == StatIdle && FileSize == 0 && Complete == false)
1849 {
1850 string const Final = _config->FindDir("Dir::State::lists") + URItoFileName(RealURI);
1851 string const LastGoodSig = DestFile + ".reverify";
1852 if (RealFileExists(Final) == false && RealFileExists(LastGoodSig) == true)
1853 Rename(LastGoodSig, Final);
1854 }
1855}
1856 /*}}}*/
8d6c5839
MV
1857// pkgAcqMetaClearSig::Custom600Headers - Insert custom request headers /*{{{*/
1858// ---------------------------------------------------------------------
1859// FIXME: this can go away once the InRelease file is used widely
1860string pkgAcqMetaClearSig::Custom600Headers()
1861{
1862 string Final = _config->FindDir("Dir::State::lists");
1863 Final += URItoFileName(RealURI);
1864
1865 struct stat Buf;
1866 if (stat(Final.c_str(),&Buf) != 0)
0aec7d5c
DK
1867 {
1868 Final = DestFile + ".reverify";
1869 if (stat(Final.c_str(),&Buf) != 0)
1870 return "\nIndex-File: true\nFail-Ignore: true\n";
1871 }
8d6c5839
MV
1872
1873 return "\nIndex-File: true\nFail-Ignore: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
1874}
1875 /*}}}*/
fe0f7911
DK
1876void pkgAcqMetaClearSig::Failed(string Message,pkgAcquire::MethodConfig *Cnf) /*{{{*/
1877{
d0cfa8ad
MV
1878 // we failed, we will not get additional items from this method
1879 ExpectedAdditionalItems = 0;
1880
fe0f7911
DK
1881 if (AuthPass == false)
1882 {
de498a52
DK
1883 // Remove the 'old' InRelease file if we try Release.gpg now as otherwise
1884 // the file will stay around and gives a false-auth impression (CVE-2012-0214)
1885 string FinalFile = _config->FindDir("Dir::State::lists");
1886 FinalFile.append(URItoFileName(RealURI));
1887 if (FileExists(FinalFile))
1888 unlink(FinalFile.c_str());
1889
fe0f7911
DK
1890 new pkgAcqMetaSig(Owner,
1891 MetaSigURI, MetaSigURIDesc, MetaSigShortDesc,
1892 MetaIndexURI, MetaIndexURIDesc, MetaIndexShortDesc,
1893 IndexTargets, MetaIndexParser);
1894 if (Cnf->LocalOnly == true ||
1895 StringToBool(LookupTag(Message, "Transient-Failure"), false) == false)
1896 Dequeue();
1897 }
1898 else
1899 pkgAcqMetaIndex::Failed(Message, Cnf);
1900}
1901 /*}}}*/
03e39e59
AL
1902// AcqArchive::AcqArchive - Constructor /*{{{*/
1903// ---------------------------------------------------------------------
17caf1b1
AL
1904/* This just sets up the initial fetch environment and queues the first
1905 possibilitiy */
03e39e59 1906pkgAcqArchive::pkgAcqArchive(pkgAcquire *Owner,pkgSourceList *Sources,
30e1eab5
AL
1907 pkgRecords *Recs,pkgCache::VerIterator const &Version,
1908 string &StoreFilename) :
1909 Item(Owner), Version(Version), Sources(Sources), Recs(Recs),
b3d44315
MV
1910 StoreFilename(StoreFilename), Vf(Version.FileList()),
1911 Trusted(false)
03e39e59 1912{
7d8afa39 1913 Retries = _config->FindI("Acquire::Retries",0);
813c8eea
AL
1914
1915 if (Version.Arch() == 0)
bdae53f1 1916 {
d1f1f6a8 1917 _error->Error(_("I wasn't able to locate a file for the %s package. "
7a3c2ab0
AL
1918 "This might mean you need to manually fix this package. "
1919 "(due to missing arch)"),
40f8a8ba 1920 Version.ParentPkg().FullName().c_str());
bdae53f1
AL
1921 return;
1922 }
813c8eea 1923
b2e465d6
AL
1924 /* We need to find a filename to determine the extension. We make the
1925 assumption here that all the available sources for this version share
1926 the same extension.. */
1927 // Skip not source sources, they do not have file fields.
69c2ecbd 1928 for (; Vf.end() == false; ++Vf)
b2e465d6
AL
1929 {
1930 if ((Vf.File()->Flags & pkgCache::Flag::NotSource) != 0)
1931 continue;
1932 break;
1933 }
1934
1935 // Does not really matter here.. we are going to fail out below
1936 if (Vf.end() != true)
1937 {
1938 // If this fails to get a file name we will bomb out below.
1939 pkgRecords::Parser &Parse = Recs->Lookup(Vf);
1940 if (_error->PendingError() == true)
1941 return;
1942
1943 // Generate the final file name as: package_version_arch.foo
1944 StoreFilename = QuoteString(Version.ParentPkg().Name(),"_:") + '_' +
1945 QuoteString(Version.VerStr(),"_:") + '_' +
1946 QuoteString(Version.Arch(),"_:.") +
1947 "." + flExtension(Parse.FileName());
1948 }
b3d44315
MV
1949
1950 // check if we have one trusted source for the package. if so, switch
6c34ccca
DK
1951 // to "TrustedOnly" mode - but only if not in AllowUnauthenticated mode
1952 bool const allowUnauth = _config->FindB("APT::Get::AllowUnauthenticated", false);
1953 bool const debugAuth = _config->FindB("Debug::pkgAcquire::Auth", false);
1954 bool seenUntrusted = false;
f7f0d6c7 1955 for (pkgCache::VerFileIterator i = Version.FileList(); i.end() == false; ++i)
b3d44315
MV
1956 {
1957 pkgIndexFile *Index;
1958 if (Sources->FindIndex(i.File(),Index) == false)
1959 continue;
6c34ccca
DK
1960
1961 if (debugAuth == true)
b3d44315 1962 std::cerr << "Checking index: " << Index->Describe()
6c34ccca
DK
1963 << "(Trusted=" << Index->IsTrusted() << ")" << std::endl;
1964
1965 if (Index->IsTrusted() == true)
1966 {
b3d44315 1967 Trusted = true;
6c34ccca
DK
1968 if (allowUnauth == false)
1969 break;
b3d44315 1970 }
6c34ccca
DK
1971 else
1972 seenUntrusted = true;
b3d44315
MV
1973 }
1974
a3371852
MV
1975 // "allow-unauthenticated" restores apts old fetching behaviour
1976 // that means that e.g. unauthenticated file:// uris are higher
1977 // priority than authenticated http:// uris
6c34ccca 1978 if (allowUnauth == true && seenUntrusted == true)
a3371852
MV
1979 Trusted = false;
1980
03e39e59 1981 // Select a source
b185acc2 1982 if (QueueNext() == false && _error->PendingError() == false)
d57f6084
DK
1983 _error->Error(_("Can't find a source to download version '%s' of '%s'"),
1984 Version.VerStr(), Version.ParentPkg().FullName(false).c_str());
b185acc2
AL
1985}
1986 /*}}}*/
1987// AcqArchive::QueueNext - Queue the next file source /*{{{*/
1988// ---------------------------------------------------------------------
17caf1b1
AL
1989/* This queues the next available file version for download. It checks if
1990 the archive is already available in the cache and stashs the MD5 for
1991 checking later. */
b185acc2 1992bool pkgAcqArchive::QueueNext()
a722b2c5
DK
1993{
1994 string const ForceHash = _config->Find("Acquire::ForceHash");
f7f0d6c7 1995 for (; Vf.end() == false; ++Vf)
03e39e59
AL
1996 {
1997 // Ignore not source sources
1998 if ((Vf.File()->Flags & pkgCache::Flag::NotSource) != 0)
1999 continue;
2000
2001 // Try to cross match against the source list
b2e465d6
AL
2002 pkgIndexFile *Index;
2003 if (Sources->FindIndex(Vf.File(),Index) == false)
2004 continue;
03e39e59 2005
b3d44315
MV
2006 // only try to get a trusted package from another source if that source
2007 // is also trusted
2008 if(Trusted && !Index->IsTrusted())
2009 continue;
2010
03e39e59
AL
2011 // Grab the text package record
2012 pkgRecords::Parser &Parse = Recs->Lookup(Vf);
2013 if (_error->PendingError() == true)
b185acc2 2014 return false;
03e39e59 2015
b2e465d6 2016 string PkgFile = Parse.FileName();
a722b2c5
DK
2017 if (ForceHash.empty() == false)
2018 {
d9b9e9e2
MV
2019 if(stringcasecmp(ForceHash, "sha512") == 0)
2020 ExpectedHash = HashString("SHA512", Parse.SHA512Hash());
ee5f5d25 2021 else if(stringcasecmp(ForceHash, "sha256") == 0)
a722b2c5
DK
2022 ExpectedHash = HashString("SHA256", Parse.SHA256Hash());
2023 else if (stringcasecmp(ForceHash, "sha1") == 0)
2024 ExpectedHash = HashString("SHA1", Parse.SHA1Hash());
2025 else
2026 ExpectedHash = HashString("MD5Sum", Parse.MD5Hash());
2027 }
2028 else
2029 {
2030 string Hash;
d9b9e9e2
MV
2031 if ((Hash = Parse.SHA512Hash()).empty() == false)
2032 ExpectedHash = HashString("SHA512", Hash);
2033 else if ((Hash = Parse.SHA256Hash()).empty() == false)
a722b2c5
DK
2034 ExpectedHash = HashString("SHA256", Hash);
2035 else if ((Hash = Parse.SHA1Hash()).empty() == false)
2036 ExpectedHash = HashString("SHA1", Hash);
2037 else
2038 ExpectedHash = HashString("MD5Sum", Parse.MD5Hash());
2039 }
03e39e59 2040 if (PkgFile.empty() == true)
b2e465d6
AL
2041 return _error->Error(_("The package index files are corrupted. No Filename: "
2042 "field for package %s."),
2043 Version.ParentPkg().Name());
a6568219 2044
b3d44315
MV
2045 Desc.URI = Index->ArchiveURI(PkgFile);
2046 Desc.Description = Index->ArchiveInfo(Version);
2047 Desc.Owner = this;
40f8a8ba 2048 Desc.ShortDesc = Version.ParentPkg().FullName(true);
b3d44315 2049
17caf1b1 2050 // See if we already have the file. (Legacy filenames)
a6568219
AL
2051 FileSize = Version->Size;
2052 string FinalFile = _config->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile);
2053 struct stat Buf;
2054 if (stat(FinalFile.c_str(),&Buf) == 0)
2055 {
2056 // Make sure the size matches
73da43e9 2057 if ((unsigned long long)Buf.st_size == Version->Size)
a6568219
AL
2058 {
2059 Complete = true;
2060 Local = true;
2061 Status = StatDone;
30e1eab5 2062 StoreFilename = DestFile = FinalFile;
b185acc2 2063 return true;
a6568219
AL
2064 }
2065
6b1ff003
AL
2066 /* Hmm, we have a file and its size does not match, this means it is
2067 an old style mismatched arch */
a6568219
AL
2068 unlink(FinalFile.c_str());
2069 }
17caf1b1
AL
2070
2071 // Check it again using the new style output filenames
2072 FinalFile = _config->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename);
2073 if (stat(FinalFile.c_str(),&Buf) == 0)
2074 {
2075 // Make sure the size matches
73da43e9 2076 if ((unsigned long long)Buf.st_size == Version->Size)
17caf1b1
AL
2077 {
2078 Complete = true;
2079 Local = true;
2080 Status = StatDone;
2081 StoreFilename = DestFile = FinalFile;
2082 return true;
2083 }
2084
1e3f4083 2085 /* Hmm, we have a file and its size does not match, this shouldn't
17caf1b1
AL
2086 happen.. */
2087 unlink(FinalFile.c_str());
2088 }
2089
2090 DestFile = _config->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename);
6b1ff003
AL
2091
2092 // Check the destination file
2093 if (stat(DestFile.c_str(),&Buf) == 0)
2094 {
2095 // Hmm, the partial file is too big, erase it
73da43e9 2096 if ((unsigned long long)Buf.st_size > Version->Size)
6b1ff003
AL
2097 unlink(DestFile.c_str());
2098 else
2099 PartialSize = Buf.st_size;
2100 }
de31189f
DK
2101
2102 // Disables download of archives - useful if no real installation follows,
2103 // e.g. if we are just interested in proposed installation order
2104 if (_config->FindB("Debug::pkgAcqArchive::NoQueue", false) == true)
2105 {
2106 Complete = true;
2107 Local = true;
2108 Status = StatDone;
2109 StoreFilename = DestFile = FinalFile;
2110 return true;
2111 }
2112
03e39e59 2113 // Create the item
b2e465d6 2114 Local = false;
03e39e59 2115 QueueURI(Desc);
b185acc2 2116
f7f0d6c7 2117 ++Vf;
b185acc2 2118 return true;
03e39e59 2119 }
b185acc2
AL
2120 return false;
2121}
03e39e59
AL
2122 /*}}}*/
2123// AcqArchive::Done - Finished fetching /*{{{*/
2124// ---------------------------------------------------------------------
2125/* */
73da43e9 2126void pkgAcqArchive::Done(string Message,unsigned long long Size,string CalcHash,
459681d3 2127 pkgAcquire::MethodConfig *Cfg)
03e39e59 2128{
495e5cb2 2129 Item::Done(Message,Size,CalcHash,Cfg);
03e39e59
AL
2130
2131 // Check the size
2132 if (Size != Version->Size)
2133 {
3c8030a4 2134 RenameOnError(SizeMismatch);
03e39e59
AL
2135 return;
2136 }
2137
495e5cb2 2138 // Check the hash
8a8feb29 2139 if(ExpectedHash.toStr() != CalcHash)
03e39e59 2140 {
3c8030a4 2141 RenameOnError(HashSumMismatch);
495e5cb2 2142 return;
03e39e59 2143 }
a6568219
AL
2144
2145 // Grab the output filename
03e39e59
AL
2146 string FileName = LookupTag(Message,"Filename");
2147 if (FileName.empty() == true)
2148 {
2149 Status = StatError;
2150 ErrorText = "Method gave a blank filename";
2151 return;
2152 }
a6568219
AL
2153
2154 Complete = true;
30e1eab5
AL
2155
2156 // Reference filename
a6568219
AL
2157 if (FileName != DestFile)
2158 {
30e1eab5 2159 StoreFilename = DestFile = FileName;
a6568219
AL
2160 Local = true;
2161 return;
2162 }
2163
2164 // Done, move it into position
2165 string FinalFile = _config->FindDir("Dir::Cache::Archives");
17caf1b1 2166 FinalFile += flNotDir(StoreFilename);
a6568219 2167 Rename(DestFile,FinalFile);
03e39e59 2168
30e1eab5 2169 StoreFilename = DestFile = FinalFile;
03e39e59
AL
2170 Complete = true;
2171}
2172 /*}}}*/
db890fdb
AL
2173// AcqArchive::Failed - Failure handler /*{{{*/
2174// ---------------------------------------------------------------------
2175/* Here we try other sources */
7d8afa39 2176void pkgAcqArchive::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
db890fdb
AL
2177{
2178 ErrorText = LookupTag(Message,"Message");
b2e465d6
AL
2179
2180 /* We don't really want to retry on failed media swaps, this prevents
2181 that. An interesting observation is that permanent failures are not
2182 recorded. */
2183 if (Cnf->Removable == true &&
2184 StringToBool(LookupTag(Message,"Transient-Failure"),false) == true)
2185 {
2186 // Vf = Version.FileList();
f7f0d6c7 2187 while (Vf.end() == false) ++Vf;
b2e465d6
AL
2188 StoreFilename = string();
2189 Item::Failed(Message,Cnf);
2190 return;
2191 }
2192
db890fdb 2193 if (QueueNext() == false)
7d8afa39
AL
2194 {
2195 // This is the retry counter
2196 if (Retries != 0 &&
2197 Cnf->LocalOnly == false &&
2198 StringToBool(LookupTag(Message,"Transient-Failure"),false) == true)
2199 {
2200 Retries--;
2201 Vf = Version.FileList();
2202 if (QueueNext() == true)
2203 return;
2204 }
2205
9dbb421f 2206 StoreFilename = string();
7d8afa39
AL
2207 Item::Failed(Message,Cnf);
2208 }
db890fdb
AL
2209}
2210 /*}}}*/
92fcbfc1 2211// AcqArchive::IsTrusted - Determine whether this archive comes from a trusted source /*{{{*/
b3d44315 2212// ---------------------------------------------------------------------
a02db58f 2213APT_PURE bool pkgAcqArchive::IsTrusted()
b3d44315
MV
2214{
2215 return Trusted;
2216}
92fcbfc1 2217 /*}}}*/
ab559b35
AL
2218// AcqArchive::Finished - Fetching has finished, tidy up /*{{{*/
2219// ---------------------------------------------------------------------
2220/* */
2221void pkgAcqArchive::Finished()
2222{
2223 if (Status == pkgAcquire::Item::StatDone &&
2224 Complete == true)
2225 return;
2226 StoreFilename = string();
2227}
2228 /*}}}*/
36375005
AL
2229// AcqFile::pkgAcqFile - Constructor /*{{{*/
2230// ---------------------------------------------------------------------
2231/* The file is added to the queue */
8a8feb29 2232pkgAcqFile::pkgAcqFile(pkgAcquire *Owner,string URI,string Hash,
73da43e9 2233 unsigned long long Size,string Dsc,string ShortDesc,
77278c2b
MV
2234 const string &DestDir, const string &DestFilename,
2235 bool IsIndexFile) :
2236 Item(Owner), ExpectedHash(Hash), IsIndexFile(IsIndexFile)
36375005 2237{
08cfc005
AL
2238 Retries = _config->FindI("Acquire::Retries",0);
2239
46e00f9d
MV
2240 if(!DestFilename.empty())
2241 DestFile = DestFilename;
2242 else if(!DestDir.empty())
2243 DestFile = DestDir + "/" + flNotDir(URI);
2244 else
2245 DestFile = flNotDir(URI);
2246
36375005
AL
2247 // Create the item
2248 Desc.URI = URI;
2249 Desc.Description = Dsc;
2250 Desc.Owner = this;
2251
2252 // Set the short description to the archive component
2253 Desc.ShortDesc = ShortDesc;
2254
2255 // Get the transfer sizes
2256 FileSize = Size;
2257 struct stat Buf;
2258 if (stat(DestFile.c_str(),&Buf) == 0)
2259 {
2260 // Hmm, the partial file is too big, erase it
ed9665ae 2261 if ((Size > 0) && (unsigned long long)Buf.st_size > Size)
36375005
AL
2262 unlink(DestFile.c_str());
2263 else
2264 PartialSize = Buf.st_size;
2265 }
092ae175 2266
36375005
AL
2267 QueueURI(Desc);
2268}
2269 /*}}}*/
2270// AcqFile::Done - Item downloaded OK /*{{{*/
2271// ---------------------------------------------------------------------
2272/* */
73da43e9 2273void pkgAcqFile::Done(string Message,unsigned long long Size,string CalcHash,
459681d3 2274 pkgAcquire::MethodConfig *Cnf)
36375005 2275{
495e5cb2
MV
2276 Item::Done(Message,Size,CalcHash,Cnf);
2277
8a8feb29 2278 // Check the hash
2c941d89 2279 if(!ExpectedHash.empty() && ExpectedHash.toStr() != CalcHash)
b3c39978 2280 {
3c8030a4 2281 RenameOnError(HashSumMismatch);
495e5cb2 2282 return;
b3c39978
AL
2283 }
2284
36375005
AL
2285 string FileName = LookupTag(Message,"Filename");
2286 if (FileName.empty() == true)
2287 {
2288 Status = StatError;
2289 ErrorText = "Method gave a blank filename";
2290 return;
2291 }
2292
2293 Complete = true;
2294
2295 // The files timestamp matches
2296 if (StringToBool(LookupTag(Message,"IMS-Hit"),false) == true)
2297 return;
2298
2299 // We have to copy it into place
2300 if (FileName != DestFile)
2301 {
2302 Local = true;
459681d3
AL
2303 if (_config->FindB("Acquire::Source-Symlinks",true) == false ||
2304 Cnf->Removable == true)
917ae805
AL
2305 {
2306 Desc.URI = "copy:" + FileName;
2307 QueueURI(Desc);
2308 return;
2309 }
2310
83ab33fc
AL
2311 // Erase the file if it is a symlink so we can overwrite it
2312 struct stat St;
2313 if (lstat(DestFile.c_str(),&St) == 0)
2314 {
2315 if (S_ISLNK(St.st_mode) != 0)
2316 unlink(DestFile.c_str());
2317 }
2318
2319 // Symlink the file
917ae805
AL
2320 if (symlink(FileName.c_str(),DestFile.c_str()) != 0)
2321 {
83ab33fc 2322 ErrorText = "Link to " + DestFile + " failure ";
917ae805
AL
2323 Status = StatError;
2324 Complete = false;
2325 }
36375005
AL
2326 }
2327}
2328 /*}}}*/
08cfc005
AL
2329// AcqFile::Failed - Failure handler /*{{{*/
2330// ---------------------------------------------------------------------
2331/* Here we try other sources */
2332void pkgAcqFile::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
2333{
2334 ErrorText = LookupTag(Message,"Message");
2335
2336 // This is the retry counter
2337 if (Retries != 0 &&
2338 Cnf->LocalOnly == false &&
2339 StringToBool(LookupTag(Message,"Transient-Failure"),false) == true)
2340 {
2341 Retries--;
2342 QueueURI(Desc);
2343 return;
2344 }
2345
2346 Item::Failed(Message,Cnf);
2347}
2348 /*}}}*/
77278c2b
MV
2349// AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
2350// ---------------------------------------------------------------------
2351/* The only header we use is the last-modified header. */
2352string pkgAcqFile::Custom600Headers()
2353{
2354 if (IsIndexFile)
2355 return "\nIndex-File: true";
61a07c57 2356 return "";
77278c2b
MV
2357}
2358 /*}}}*/