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