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