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