]> git.saurik.com Git - apt.git/blame - apt-pkg/acquire-item.cc
skip .diff/Index acquire if Release file was a hit
[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>
5ad0096a 27#include <apt-pkg/metaindex.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>
d56e2917 34#include <apt-pkg/gpgv.h>
453b82a3
DK
35
36#include <stddef.h>
37#include <stdlib.h>
38#include <string.h>
39#include <iostream>
40#include <vector>
0a8a80e5
AL
41#include <sys/stat.h>
42#include <unistd.h>
c88edf1d 43#include <errno.h>
5819a761 44#include <string>
ac5b205a 45#include <sstream>
c88edf1d 46#include <stdio.h>
1ddb8596 47#include <ctime>
ea542140
DK
48
49#include <apti18n.h>
0118833a
AL
50 /*}}}*/
51
b3d44315 52using namespace std;
5819a761 53
b3501edb
DK
54static void printHashSumComparision(std::string const &URI, HashStringList const &Expected, HashStringList const &Actual) /*{{{*/
55{
56 if (_config->FindB("Debug::Acquire::HashSumMismatch", false) == false)
57 return;
58 std::cerr << std::endl << URI << ":" << std::endl << " Expected Hash: " << std::endl;
59 for (HashStringList::const_iterator hs = Expected.begin(); hs != Expected.end(); ++hs)
60 std::cerr << "\t- " << hs->toStr() << std::endl;
61 std::cerr << " Actual Hash: " << std::endl;
62 for (HashStringList::const_iterator hs = Actual.begin(); hs != Actual.end(); ++hs)
63 std::cerr << "\t- " << hs->toStr() << std::endl;
64}
65 /*}}}*/
70b63c57 66static std::string GetPartialFileName(std::string const &file) /*{{{*/
5684f71f
DK
67{
68 std::string DestFile = _config->FindDir("Dir::State::lists") + "partial/";
69 DestFile += file;
70 return DestFile;
71}
70b63c57
DK
72 /*}}}*/
73static std::string GetPartialFileNameFromURI(std::string const &uri) /*{{{*/
5684f71f 74{
ea7682a0 75 return GetPartialFileName(URItoFileName(uri));
5684f71f 76}
70b63c57 77 /*}}}*/
295d848b
DK
78static std::string GetFinalFileNameFromURI(std::string const &uri) /*{{{*/
79{
80 return _config->FindDir("Dir::State::lists") + URItoFileName(uri);
81}
82 /*}}}*/
653ef26c 83static std::string GetCompressedFileName(IndexTarget const &Target, std::string const &Name, std::string const &Ext) /*{{{*/
70b63c57
DK
84{
85 if (Ext.empty() || Ext == "uncompressed")
86 return Name;
87
88 // do not reverify cdrom sources as apt-cdrom may rewrite the Packages
89 // file when its doing the indexcopy
653ef26c 90 if (Target.URI.substr(0,6) == "cdrom:")
70b63c57 91 return Name;
5684f71f 92
70b63c57 93 // adjust DestFile if its compressed on disk
653ef26c 94 if (Target.KeepCompressed == true)
70b63c57
DK
95 return Name + '.' + Ext;
96 return Name;
97}
98 /*}}}*/
36795154
DK
99static std::string GetMergeDiffsPatchFileName(std::string const &Final, std::string const &Patch)/*{{{*/
100{
101 // rred expects the patch as $FinalFile.ed.$patchname.gz
102 return Final + ".ed." + Patch + ".gz";
103}
104 /*}}}*/
105static std::string GetDiffsPatchFileName(std::string const &Final) /*{{{*/
106{
107 // rred expects the patch as $FinalFile.ed
108 return Final + ".ed";
109}
110 /*}}}*/
111
5ad0096a 112static bool AllowInsecureRepositories(metaIndex const * const MetaIndexParser, pkgAcqMetaClearSig * const TransactionManager, pkgAcquire::Item * const I) /*{{{*/
32532943 113{
5ad0096a 114 if(MetaIndexParser->GetTrusted() == metaIndex::TRI_YES || _config->FindB("Acquire::AllowInsecureRepositories") == true)
32532943
DK
115 return true;
116
117 _error->Error(_("Use --allow-insecure-repositories to force the update"));
118 TransactionManager->AbortTransaction();
119 I->Status = pkgAcquire::Item::StatError;
120 return false;
121}
122 /*}}}*/
5ad0096a 123static HashStringList GetExpectedHashesFromFor(metaIndex * const Parser, std::string const &MetaKey)/*{{{*/
8d041b4f
DK
124{
125 if (Parser == NULL)
126 return HashStringList();
5ad0096a 127 metaIndex::checkSum * const R = Parser->Lookup(MetaKey);
8d041b4f
DK
128 if (R == NULL)
129 return HashStringList();
130 return R->Hashes;
131}
132 /*}}}*/
32532943 133
448c38bd
DK
134// all ::HashesRequired and ::GetExpectedHashes implementations /*{{{*/
135/* ::GetExpectedHashes is abstract and has to be implemented by all subclasses.
136 It is best to implement it as broadly as possible, while ::HashesRequired defaults
137 to true and should be as restrictive as possible for false cases. Note that if
138 a hash is returned by ::GetExpectedHashes it must match. Only if it doesn't
139 ::HashesRequired is called to evaluate if its okay to have no hashes. */
140APT_CONST bool pkgAcqTransactionItem::HashesRequired() const
141{
142 /* signed repositories obviously have a parser and good hashes.
143 unsigned repositories, too, as even if we can't trust them for security,
144 we can at least trust them for integrity of the download itself.
145 Only repositories without a Release file can (obviously) not have
146 hashes – and they are very uncommon and strongly discouraged */
5ad0096a
DK
147 return TransactionManager->MetaIndexParser != NULL &&
148 TransactionManager->MetaIndexParser->GetLoadedSuccessfully() != metaIndex::TRI_UNSET;
448c38bd
DK
149}
150HashStringList pkgAcqTransactionItem::GetExpectedHashes() const
151{
152 return GetExpectedHashesFor(GetMetaKey());
153}
154
155APT_CONST bool pkgAcqMetaBase::HashesRequired() const
156{
157 // Release and co have no hashes 'by design'.
158 return false;
159}
160HashStringList pkgAcqMetaBase::GetExpectedHashes() const
161{
162 return HashStringList();
163}
164
165APT_CONST bool pkgAcqIndexDiffs::HashesRequired() const
166{
4f51fd86
DK
167 /* We don't always have the diff of the downloaded pdiff file.
168 What we have for sure is hashes for the uncompressed file,
169 but rred uncompresses them on the fly while parsing, so not handled here.
170 Hashes are (also) checked while searching for (next) patch to apply. */
171 if (State == StateFetchDiff)
172 return available_patches[0].download_hashes.empty() == false;
448c38bd
DK
173 return false;
174}
175HashStringList pkgAcqIndexDiffs::GetExpectedHashes() const
176{
4f51fd86
DK
177 if (State == StateFetchDiff)
178 return available_patches[0].download_hashes;
448c38bd
DK
179 return HashStringList();
180}
181
182APT_CONST bool pkgAcqIndexMergeDiffs::HashesRequired() const
183{
184 /* @see #pkgAcqIndexDiffs::HashesRequired, with the difference that
185 we can check the rred result after all patches are applied as
186 we know the expected result rather than potentially apply more patches */
4f51fd86
DK
187 if (State == StateFetchDiff)
188 return patch.download_hashes.empty() == false;
448c38bd
DK
189 return State == StateApplyDiff;
190}
191HashStringList pkgAcqIndexMergeDiffs::GetExpectedHashes() const
192{
4f51fd86
DK
193 if (State == StateFetchDiff)
194 return patch.download_hashes;
195 else if (State == StateApplyDiff)
dcbbb14d 196 return GetExpectedHashesFor(Target.MetaKey);
448c38bd
DK
197 return HashStringList();
198}
199
200APT_CONST bool pkgAcqArchive::HashesRequired() const
201{
202 return LocalSource == false;
203}
204HashStringList pkgAcqArchive::GetExpectedHashes() const
205{
206 // figured out while parsing the records
207 return ExpectedHashes;
208}
209
210APT_CONST bool pkgAcqFile::HashesRequired() const
211{
212 // supplied as parameter at creation time, so the caller decides
213 return ExpectedHashes.usable();
214}
215HashStringList pkgAcqFile::GetExpectedHashes() const
216{
217 return ExpectedHashes;
218}
219 /*}}}*/
220// Acquire::Item::QueueURI and specialisations from child classes /*{{{*/
221bool pkgAcquire::Item::QueueURI(pkgAcquire::ItemDesc &Item)
222{
223 Owner->Enqueue(Item);
224 return true;
225}
226/* The idea here is that an item isn't queued if it exists on disk and the
227 transition manager was a hit as this means that the files it contains
228 the checksums for can't be updated either (or they are and we are asking
229 for a hashsum mismatch to happen which helps nobody) */
230bool pkgAcqTransactionItem::QueueURI(pkgAcquire::ItemDesc &Item)
231{
232 std::string const FinalFile = GetFinalFilename();
233 if (TransactionManager != NULL && TransactionManager->IMSHit == true &&
234 FileExists(FinalFile) == true)
235 {
236 PartialFile = DestFile = FinalFile;
237 Status = StatDone;
238 return false;
239 }
240 return pkgAcquire::Item::QueueURI(Item);
241}
242/* The transition manager InRelease itself (or its older sisters-in-law
243 Release & Release.gpg) is always queued as this allows us to rerun gpgv
244 on it to verify that we aren't stalled with old files */
245bool pkgAcqMetaBase::QueueURI(pkgAcquire::ItemDesc &Item)
246{
247 return pkgAcquire::Item::QueueURI(Item);
248}
249/* the Diff/Index needs to queue also the up-to-date complete index file
250 to ensure that the list cleaner isn't eating it */
251bool pkgAcqDiffIndex::QueueURI(pkgAcquire::ItemDesc &Item)
252{
253 if (pkgAcqTransactionItem::QueueURI(Item) == true)
254 return true;
255 QueueOnIMSHit();
256 return false;
257}
258 /*}}}*/
259// Acquire::Item::GetFinalFilename and specialisations for child classes /*{{{*/
260std::string pkgAcquire::Item::GetFinalFilename() const
261{
262 return GetFinalFileNameFromURI(Desc.URI);
263}
264std::string pkgAcqDiffIndex::GetFinalFilename() const
265{
266 // the logic we inherent from pkgAcqBaseIndex isn't what we need here
267 return pkgAcquire::Item::GetFinalFilename();
268}
269std::string pkgAcqIndex::GetFinalFilename() const
270{
dcbbb14d 271 std::string const FinalFile = GetFinalFileNameFromURI(Target.URI);
653ef26c 272 return GetCompressedFileName(Target, FinalFile, CurrentCompressionExtension);
448c38bd
DK
273}
274std::string pkgAcqMetaSig::GetFinalFilename() const
275{
dcbbb14d 276 return GetFinalFileNameFromURI(Target.URI);
448c38bd
DK
277}
278std::string pkgAcqBaseIndex::GetFinalFilename() const
279{
dcbbb14d 280 return GetFinalFileNameFromURI(Target.URI);
448c38bd
DK
281}
282std::string pkgAcqMetaBase::GetFinalFilename() const
283{
dcbbb14d 284 return GetFinalFileNameFromURI(Target.URI);
448c38bd
DK
285}
286std::string pkgAcqArchive::GetFinalFilename() const
287{
288 return _config->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename);
289}
290 /*}}}*/
291// pkgAcqTransactionItem::GetMetaKey and specialisations for child classes /*{{{*/
292std::string pkgAcqTransactionItem::GetMetaKey() const
293{
dcbbb14d 294 return Target.MetaKey;
448c38bd
DK
295}
296std::string pkgAcqIndex::GetMetaKey() const
297{
298 if (Stage == STAGE_DECOMPRESS_AND_VERIFY || CurrentCompressionExtension == "uncompressed")
dcbbb14d
DK
299 return Target.MetaKey;
300 return Target.MetaKey + "." + CurrentCompressionExtension;
448c38bd
DK
301}
302std::string pkgAcqDiffIndex::GetMetaKey() const
303{
dcbbb14d 304 return Target.MetaKey + ".diff/Index";
448c38bd
DK
305}
306 /*}}}*/
307//pkgAcqTransactionItem::TransactionState and specialisations for child classes /*{{{*/
308bool pkgAcqTransactionItem::TransactionState(TransactionStates const state)
309{
310 bool const Debug = _config->FindB("Debug::Acquire::Transaction", false);
311 switch(state)
312 {
313 case TransactionAbort:
314 if(Debug == true)
315 std::clog << " Cancel: " << DestFile << std::endl;
316 if (Status == pkgAcquire::Item::StatIdle)
317 {
318 Status = pkgAcquire::Item::StatDone;
319 Dequeue();
320 }
321 break;
322 case TransactionCommit:
323 if(PartialFile != "")
324 {
325 if(Debug == true)
326 std::clog << "mv " << PartialFile << " -> "<< DestFile << " # " << DescURI() << std::endl;
327
328 Rename(PartialFile, DestFile);
329 } else {
330 if(Debug == true)
331 std::clog << "rm " << DestFile << " # " << DescURI() << std::endl;
332 unlink(DestFile.c_str());
333 }
334 break;
335 }
336 return true;
337}
338bool pkgAcqMetaBase::TransactionState(TransactionStates const state)
339{
340 // Do not remove InRelease on IMSHit of Release.gpg [yes, this is very edgecasey]
341 if (TransactionManager->IMSHit == false)
342 return pkgAcqTransactionItem::TransactionState(state);
343 return true;
344}
345bool pkgAcqIndex::TransactionState(TransactionStates const state)
346{
347 if (pkgAcqTransactionItem::TransactionState(state) == false)
348 return false;
349
350 switch (state)
351 {
352 case TransactionAbort:
353 if (Stage == STAGE_DECOMPRESS_AND_VERIFY)
354 {
355 // keep the compressed file, but drop the decompressed
356 EraseFileName.clear();
357 if (PartialFile.empty() == false && flExtension(PartialFile) == "decomp")
358 unlink(PartialFile.c_str());
359 }
360 break;
361 case TransactionCommit:
362 if (EraseFileName.empty() == false)
363 unlink(EraseFileName.c_str());
364 break;
365 }
366 return true;
367}
368bool pkgAcqDiffIndex::TransactionState(TransactionStates const state)
369{
370 if (pkgAcqTransactionItem::TransactionState(state) == false)
371 return false;
372
373 switch (state)
374 {
375 case TransactionCommit:
376 break;
377 case TransactionAbort:
dcbbb14d 378 std::string const Partial = GetPartialFileNameFromURI(Target.URI);
448c38bd
DK
379 unlink(Partial.c_str());
380 break;
381 }
382
383 return true;
384}
385 /*}}}*/
b3501edb 386
8d041b4f
DK
387class APT_HIDDEN NoActionItem : public pkgAcquire::Item /*{{{*/
388/* The sole purpose of this class is having an item which does nothing to
389 reach its done state to prevent cleanup deleting the mentioned file.
390 Handy in cases in which we know we have the file already, like IMS-Hits. */
391{
dcbbb14d 392 IndexTarget const Target;
8d041b4f 393 public:
3b302846
DK
394 virtual std::string DescURI() const APT_OVERRIDE {return Target.URI;};
395 virtual HashStringList GetExpectedHashes() const APT_OVERRIDE {return HashStringList();};
8d041b4f 396
e8afd168 397 NoActionItem(pkgAcquire * const Owner, IndexTarget const &Target) :
8d041b4f
DK
398 pkgAcquire::Item(Owner), Target(Target)
399 {
400 Status = StatDone;
dcbbb14d 401 DestFile = GetFinalFileNameFromURI(Target.URI);
8d041b4f
DK
402 }
403};
404 /*}}}*/
405
0118833a 406// Acquire::Item::Item - Constructor /*{{{*/
586d8704 407APT_IGNORE_DEPRECATED_PUSH
e8afd168 408pkgAcquire::Item::Item(pkgAcquire * const owner) :
1eb1836f 409 FileSize(0), PartialSize(0), Mode(0), ID(0), Complete(false), Local(false),
6c55f07a 410 QueueCounter(0), ExpectedAdditionalItems(0), Owner(owner), d(NULL)
0118833a
AL
411{
412 Owner->Add(this);
c88edf1d 413 Status = StatIdle;
0118833a 414}
586d8704 415APT_IGNORE_DEPRECATED_POP
0118833a
AL
416 /*}}}*/
417// Acquire::Item::~Item - Destructor /*{{{*/
0118833a
AL
418pkgAcquire::Item::~Item()
419{
420 Owner->Remove(this);
421}
422 /*}}}*/
448c38bd
DK
423std::string pkgAcquire::Item::Custom600Headers() const /*{{{*/
424{
425 return std::string();
426}
427 /*}}}*/
428std::string pkgAcquire::Item::ShortDesc() const /*{{{*/
429{
430 return DescURI();
431}
432 /*}}}*/
433APT_CONST void pkgAcquire::Item::Finished() /*{{{*/
434{
435}
436 /*}}}*/
437APT_PURE pkgAcquire * pkgAcquire::Item::GetOwner() const /*{{{*/
438{
439 return Owner;
440}
441 /*}}}*/
c8a4ce6c 442APT_CONST pkgAcquire::ItemDesc &pkgAcquire::Item::GetItemDesc() /*{{{*/
08ea7806
DK
443{
444 return Desc;
445}
446 /*}}}*/
448c38bd
DK
447APT_CONST bool pkgAcquire::Item::IsTrusted() const /*{{{*/
448{
449 return false;
450}
451 /*}}}*/
c88edf1d
AL
452// Acquire::Item::Failed - Item failed to download /*{{{*/
453// ---------------------------------------------------------------------
93bf083d
AL
454/* We return to an idle state if there are still other queues that could
455 fetch this object */
448c38bd 456void pkgAcquire::Item::Failed(string const &Message,pkgAcquire::MethodConfig const * const Cnf)
c88edf1d 457{
03aa0847 458 if(ErrorText.empty())
2737f28a 459 ErrorText = LookupTag(Message,"Message");
361593e9 460 UsedMirror = LookupTag(Message,"UsedMirror");
c88edf1d 461 if (QueueCounter <= 1)
93bf083d 462 {
a72ace20 463 /* This indicates that the file is not available right now but might
7d8afa39 464 be sometime later. If we do a retry cycle then this should be
17caf1b1 465 retried [CDROMs] */
4dbfe436 466 if (Cnf != NULL && Cnf->LocalOnly == true &&
7d8afa39 467 StringToBool(LookupTag(Message,"Transient-Failure"),false) == true)
a72ace20
AL
468 {
469 Status = StatIdle;
681d76d0 470 Dequeue();
a72ace20
AL
471 return;
472 }
7e5f33eb 473
58702f85
DK
474 switch (Status)
475 {
476 case StatIdle:
477 case StatFetching:
478 case StatDone:
479 Status = StatError;
480 break;
481 case StatAuthError:
482 case StatError:
483 case StatTransientNetworkError:
484 break;
485 }
4dbfe436 486 Complete = false;
681d76d0 487 Dequeue();
4dbfe436 488 }
23c5897c 489
03aa0847 490 string const FailReason = LookupTag(Message, "FailReason");
448c38bd 491 if (FailReason == "MaximumSizeExceeded")
03aa0847 492 RenameOnError(MaximumSizeExceeded);
448c38bd
DK
493 else if (Status == StatAuthError)
494 RenameOnError(HashSumMismatch);
ee279506
MV
495
496 // report mirror failure back to LP if we actually use a mirror
448c38bd 497 if (FailReason.empty() == false)
f0b509cd
MV
498 ReportMirrorFailure(FailReason);
499 else
500 ReportMirrorFailure(ErrorText);
146f7715 501
448c38bd
DK
502 if (QueueCounter > 1)
503 Status = StatIdle;
146f7715
DK
504}
505 /*}}}*/
8267fe24
AL
506// Acquire::Item::Start - Item has begun to download /*{{{*/
507// ---------------------------------------------------------------------
448c38bd 508/* Stash status and the file size. Note that setting Complete means
17caf1b1 509 sub-phases of the acquire process such as decompresion are operating */
448c38bd 510void pkgAcquire::Item::Start(string const &/*Message*/, unsigned long long const Size)
8267fe24
AL
511{
512 Status = StatFetching;
03aa0847 513 ErrorText.clear();
8267fe24
AL
514 if (FileSize == 0 && Complete == false)
515 FileSize = Size;
516}
517 /*}}}*/
c88edf1d 518// Acquire::Item::Done - Item downloaded OK /*{{{*/
448c38bd
DK
519void pkgAcquire::Item::Done(string const &Message, HashStringList const &Hashes,
520 pkgAcquire::MethodConfig const * const /*Cnf*/)
c88edf1d 521{
b98f2859 522 // We just downloaded something..
1f4dd8fd 523 UsedMirror = LookupTag(Message,"UsedMirror");
ff86d7df 524 if (FileSize == 0)
b98f2859 525 {
ff86d7df
DK
526 unsigned long long const downloadedSize = Hashes.FileSize();
527 if (downloadedSize != 0)
448c38bd 528 {
ff86d7df 529 FileSize = downloadedSize;
448c38bd 530 }
448c38bd 531 }
c88edf1d
AL
532 Status = StatDone;
533 ErrorText = string();
534 Owner->Dequeue(this);
535}
536 /*}}}*/
8b89e57f
AL
537// Acquire::Item::Rename - Rename a file /*{{{*/
538// ---------------------------------------------------------------------
1e3f4083 539/* This helper function is used by a lot of item methods as their final
8b89e57f 540 step */
448c38bd 541bool pkgAcquire::Item::Rename(string const &From,string const &To)
8b89e57f 542{
ba6b79bd 543 if (From == To || rename(From.c_str(),To.c_str()) == 0)
cecc5532
DK
544 return true;
545
546 std::string S;
547 strprintf(S, _("rename failed, %s (%s -> %s)."), strerror(errno),
548 From.c_str(),To.c_str());
549 Status = StatError;
8eafc759
DK
550 if (ErrorText.empty())
551 ErrorText = S;
552 else
553 ErrorText = ErrorText + ": " + S;
cecc5532 554 return false;
8b89e57f
AL
555}
556 /*}}}*/
448c38bd 557void pkgAcquire::Item::Dequeue() /*{{{*/
5684f71f 558{
448c38bd 559 Owner->Dequeue(this);
ba6b79bd 560}
448c38bd
DK
561 /*}}}*/
562bool pkgAcquire::Item::RenameOnError(pkgAcquire::Item::RenameOnErrorState const error)/*{{{*/
3c8030a4 563{
03aa0847 564 if (RealFileExists(DestFile))
3c8030a4
DK
565 Rename(DestFile, DestFile + ".FAILED");
566
448c38bd 567 std::string errtext;
3c8030a4
DK
568 switch (error)
569 {
570 case HashSumMismatch:
448c38bd 571 errtext = _("Hash Sum mismatch");
3c8030a4
DK
572 Status = StatAuthError;
573 ReportMirrorFailure("HashChecksumFailure");
574 break;
575 case SizeMismatch:
448c38bd 576 errtext = _("Size mismatch");
3c8030a4
DK
577 Status = StatAuthError;
578 ReportMirrorFailure("SizeFailure");
579 break;
580 case InvalidFormat:
448c38bd 581 errtext = _("Invalid file format");
3c8030a4
DK
582 Status = StatError;
583 // do not report as usually its not the mirrors fault, but Portal/Proxy
584 break;
631a7dc7 585 case SignatureError:
448c38bd 586 errtext = _("Signature error");
631a7dc7
MV
587 Status = StatError;
588 break;
589 case NotClearsigned:
448c38bd 590 errtext = _("Does not start with a cleartext signature");
03aa0847
DK
591 Status = StatError;
592 break;
593 case MaximumSizeExceeded:
594 // the method is expected to report a good error for this
631a7dc7
MV
595 Status = StatError;
596 break;
146f7715
DK
597 case PDiffError:
598 // no handling here, done by callers
599 break;
3c8030a4 600 }
448c38bd
DK
601 if (ErrorText.empty())
602 ErrorText = errtext;
3c8030a4
DK
603 return false;
604}
605 /*}}}*/
8267fbd9 606void pkgAcquire::Item::SetActiveSubprocess(const std::string &subprocess)/*{{{*/
eeac6897
MV
607{
608 ActiveSubprocess = subprocess;
586d8704 609 APT_IGNORE_DEPRECATED(Mode = ActiveSubprocess.c_str();)
eeac6897 610}
8267fbd9 611 /*}}}*/
c91d9a63 612// Acquire::Item::ReportMirrorFailure /*{{{*/
448c38bd 613void pkgAcquire::Item::ReportMirrorFailure(string const &FailCode)
36280399 614{
59271f62
MV
615 // we only act if a mirror was used at all
616 if(UsedMirror.empty())
617 return;
36280399
MV
618#if 0
619 std::cerr << "\nReportMirrorFailure: "
620 << UsedMirror
59271f62 621 << " Uri: " << DescURI()
36280399
MV
622 << " FailCode: "
623 << FailCode << std::endl;
624#endif
36280399 625 string report = _config->Find("Methods::Mirror::ProblemReporting",
3f599bb7 626 "/usr/lib/apt/apt-report-mirror-failure");
36280399
MV
627 if(!FileExists(report))
628 return;
cecc5532
DK
629
630 std::vector<char const*> Args;
631 Args.push_back(report.c_str());
632 Args.push_back(UsedMirror.c_str());
633 Args.push_back(DescURI().c_str());
634 Args.push_back(FailCode.c_str());
635 Args.push_back(NULL);
636
36280399 637 pid_t pid = ExecFork();
cecc5532 638 if(pid < 0)
36280399
MV
639 {
640 _error->Error("ReportMirrorFailure Fork failed");
641 return;
642 }
cecc5532 643 else if(pid == 0)
36280399 644 {
cecc5532 645 execvp(Args[0], (char**)Args.data());
361593e9
MV
646 std::cerr << "Could not exec " << Args[0] << std::endl;
647 _exit(100);
36280399 648 }
cecc5532 649 if(!ExecWait(pid, "report-mirror-failure"))
36280399
MV
650 {
651 _error->Warning("Couldn't report problem to '%s'",
361593e9 652 _config->Find("Methods::Mirror::ProblemReporting").c_str());
36280399
MV
653 }
654}
c91d9a63 655 /*}}}*/
448c38bd 656std::string pkgAcquire::Item::HashSum() const /*{{{*/
ac5b205a 657{
448c38bd
DK
658 HashStringList const hashes = GetExpectedHashes();
659 HashString const * const hs = hashes.find(NULL);
660 return hs != NULL ? hs->toStr() : "";
661}
662 /*}}}*/
2237bd01 663
448c38bd 664pkgAcqTransactionItem::pkgAcqTransactionItem(pkgAcquire * const Owner, /*{{{*/
3d8232bf 665 pkgAcqMetaClearSig * const transactionManager, IndexTarget const &target) :
6c55f07a 666 pkgAcquire::Item(Owner), d(NULL), Target(target), TransactionManager(transactionManager)
448c38bd
DK
667{
668 if (TransactionManager != this)
669 TransactionManager->Add(this);
670}
671 /*}}}*/
672pkgAcqTransactionItem::~pkgAcqTransactionItem() /*{{{*/
673{
674}
675 /*}}}*/
e8afd168 676HashStringList pkgAcqTransactionItem::GetExpectedHashesFor(std::string const &MetaKey) const /*{{{*/
448c38bd 677{
8d041b4f 678 return GetExpectedHashesFromFor(TransactionManager->MetaIndexParser, MetaKey);
448c38bd
DK
679}
680 /*}}}*/
ac5b205a 681
448c38bd
DK
682// AcqMetaBase - Constructor /*{{{*/
683pkgAcqMetaBase::pkgAcqMetaBase(pkgAcquire * const Owner,
3d8232bf 684 pkgAcqMetaClearSig * const TransactionManager,
e8afd168 685 std::vector<IndexTarget> const &IndexTargets,
3d8232bf 686 IndexTarget const &DataTarget)
6c55f07a 687: pkgAcqTransactionItem(Owner, TransactionManager, DataTarget), d(NULL),
3d8232bf 688 IndexTargets(IndexTargets),
448c38bd
DK
689 AuthPass(false), IMSHit(false)
690{
691}
692 /*}}}*/
693// AcqMetaBase::Add - Add a item to the current Transaction /*{{{*/
694void pkgAcqMetaBase::Add(pkgAcqTransactionItem * const I)
695{
696 Transaction.push_back(I);
697}
698 /*}}}*/
699// AcqMetaBase::AbortTransaction - Abort the current Transaction /*{{{*/
700void pkgAcqMetaBase::AbortTransaction()
701{
702 if(_config->FindB("Debug::Acquire::Transaction", false) == true)
703 std::clog << "AbortTransaction: " << TransactionManager << std::endl;
ac5b205a 704
448c38bd
DK
705 // ensure the toplevel is in error state too
706 for (std::vector<pkgAcqTransactionItem*>::iterator I = Transaction.begin();
707 I != Transaction.end(); ++I)
2ac3eeb6 708 {
448c38bd 709 (*I)->TransactionState(TransactionAbort);
ac5b205a 710 }
448c38bd
DK
711 Transaction.clear();
712}
713 /*}}}*/
714// AcqMetaBase::TransactionHasError - Check for errors in Transaction /*{{{*/
715APT_PURE bool pkgAcqMetaBase::TransactionHasError() const
716{
717 for (std::vector<pkgAcqTransactionItem*>::const_iterator I = Transaction.begin();
718 I != Transaction.end(); ++I)
719 {
720 switch((*I)->Status) {
721 case StatDone: break;
722 case StatIdle: break;
723 case StatAuthError: return true;
724 case StatError: return true;
725 case StatTransientNetworkError: return true;
726 case StatFetching: break;
727 }
728 }
729 return false;
730}
731 /*}}}*/
732// AcqMetaBase::CommitTransaction - Commit a transaction /*{{{*/
733void pkgAcqMetaBase::CommitTransaction()
734{
735 if(_config->FindB("Debug::Acquire::Transaction", false) == true)
736 std::clog << "CommitTransaction: " << this << std::endl;
ac5b205a 737
448c38bd
DK
738 // move new files into place *and* remove files that are not
739 // part of the transaction but are still on disk
740 for (std::vector<pkgAcqTransactionItem*>::iterator I = Transaction.begin();
741 I != Transaction.end(); ++I)
742 {
743 (*I)->TransactionState(TransactionCommit);
744 }
745 Transaction.clear();
295d848b
DK
746}
747 /*}}}*/
448c38bd
DK
748// AcqMetaBase::TransactionStageCopy - Stage a file for copying /*{{{*/
749void pkgAcqMetaBase::TransactionStageCopy(pkgAcqTransactionItem * const I,
750 const std::string &From,
751 const std::string &To)
295d848b 752{
448c38bd
DK
753 I->PartialFile = From;
754 I->DestFile = To;
ac5b205a 755}
92fcbfc1 756 /*}}}*/
448c38bd
DK
757// AcqMetaBase::TransactionStageRemoval - Stage a file for removal /*{{{*/
758void pkgAcqMetaBase::TransactionStageRemoval(pkgAcqTransactionItem * const I,
759 const std::string &FinalFile)
760{
761 I->PartialFile = "";
762 I->DestFile = FinalFile;
763}
764 /*}}}*/
765// AcqMetaBase::GenerateAuthWarning - Check gpg authentication error /*{{{*/
766bool pkgAcqMetaBase::CheckStopAuthentication(pkgAcquire::Item * const I, const std::string &Message)
767{
768 // FIXME: this entire function can do now that we disallow going to
769 // a unauthenticated state and can cleanly rollback
770
771 string const Final = I->GetFinalFilename();
772 if(FileExists(Final))
773 {
774 I->Status = StatTransientNetworkError;
775 _error->Warning(_("An error occurred during the signature "
776 "verification. The repository is not updated "
777 "and the previous index files will be used. "
778 "GPG error: %s: %s\n"),
779 Desc.Description.c_str(),
780 LookupTag(Message,"Message").c_str());
781 RunScripts("APT::Update::Auth-Failure");
782 return true;
783 } else if (LookupTag(Message,"Message").find("NODATA") != string::npos) {
784 /* Invalid signature file, reject (LP: #346386) (Closes: #627642) */
785 _error->Error(_("GPG error: %s: %s"),
786 Desc.Description.c_str(),
787 LookupTag(Message,"Message").c_str());
788 I->Status = StatError;
789 return true;
790 } else {
791 _error->Warning(_("GPG error: %s: %s"),
792 Desc.Description.c_str(),
793 LookupTag(Message,"Message").c_str());
794 }
795 // gpgv method failed
796 ReportMirrorFailure("GPGFailure");
797 return false;
798}
799 /*}}}*/
800// AcqMetaBase::Custom600Headers - Get header for AcqMetaBase /*{{{*/
6cb30d01 801// ---------------------------------------------------------------------
448c38bd 802string pkgAcqMetaBase::Custom600Headers() const
6cb30d01 803{
448c38bd
DK
804 std::string Header = "\nIndex-File: true";
805 std::string MaximumSize;
806 strprintf(MaximumSize, "\nMaximum-Size: %i",
807 _config->FindI("Acquire::MaxReleaseFileSize", 10*1000*1000));
808 Header += MaximumSize;
4d0818cc 809
448c38bd 810 string const FinalFile = GetFinalFilename();
6cb30d01 811 struct stat Buf;
448c38bd
DK
812 if (stat(FinalFile.c_str(),&Buf) == 0)
813 Header += "\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
814
815 return Header;
6cb30d01 816}
92fcbfc1 817 /*}}}*/
448c38bd
DK
818// AcqMetaBase::QueueForSignatureVerify /*{{{*/
819void pkgAcqMetaBase::QueueForSignatureVerify(pkgAcqTransactionItem * const I, std::string const &File, std::string const &Signature)
ba6b79bd 820{
448c38bd
DK
821 AuthPass = true;
822 I->Desc.URI = "gpgv:" + Signature;
823 I->DestFile = File;
824 QueueURI(I->Desc);
825 I->SetActiveSubprocess("gpgv");
ba6b79bd
DK
826}
827 /*}}}*/
448c38bd
DK
828// AcqMetaBase::CheckDownloadDone /*{{{*/
829bool pkgAcqMetaBase::CheckDownloadDone(pkgAcqTransactionItem * const I, const std::string &Message, HashStringList const &Hashes) const
2237bd01 830{
448c38bd
DK
831 // We have just finished downloading a Release file (it is not
832 // verified yet)
f6d4ab9a 833
448c38bd
DK
834 string const FileName = LookupTag(Message,"Filename");
835 if (FileName.empty() == true)
f6d4ab9a 836 {
448c38bd
DK
837 I->Status = StatError;
838 I->ErrorText = "Method gave a blank filename";
839 return false;
f6d4ab9a 840 }
2237bd01 841
08ea7806 842 if (FileName != I->DestFile && RealFileExists(I->DestFile) == false)
f6d4ab9a 843 {
448c38bd
DK
844 I->Local = true;
845 I->Desc.URI = "copy:" + FileName;
846 I->QueueURI(I->Desc);
f6d4ab9a
DK
847 return false;
848 }
2237bd01 849
448c38bd
DK
850 // make sure to verify against the right file on I-M-S hit
851 bool IMSHit = StringToBool(LookupTag(Message,"IMS-Hit"), false);
852 if (IMSHit == false && Hashes.usable())
f6d4ab9a 853 {
448c38bd
DK
854 // detect IMS-Hits servers haven't detected by Hash comparison
855 std::string const FinalFile = I->GetFinalFilename();
856 if (RealFileExists(FinalFile) && Hashes.VerifyFile(FinalFile) == true)
2ac3eeb6 857 {
448c38bd
DK
858 IMSHit = true;
859 unlink(I->DestFile.c_str());
5e1ed088 860 }
f6d4ab9a
DK
861 }
862
448c38bd 863 if(IMSHit == true)
f6d4ab9a 864 {
448c38bd
DK
865 // for simplicity, the transaction manager is always InRelease
866 // even if it doesn't exist.
867 if (TransactionManager != NULL)
868 TransactionManager->IMSHit = true;
869 I->PartialFile = I->DestFile = I->GetFinalFilename();
f6d4ab9a
DK
870 }
871
448c38bd
DK
872 // set Item to complete as the remaining work is all local (verify etc)
873 I->Complete = true;
f6d4ab9a 874
448c38bd
DK
875 return true;
876}
877 /*}}}*/
878bool pkgAcqMetaBase::CheckAuthDone(string const &Message) /*{{{*/
879{
880 // At this point, the gpgv method has succeeded, so there is a
881 // valid signature from a key in the trusted keyring. We
882 // perform additional verification of its contents, and use them
883 // to verify the indexes we are about to download
f6d4ab9a 884
448c38bd 885 if (TransactionManager->IMSHit == false)
f6d4ab9a 886 {
448c38bd
DK
887 // open the last (In)Release if we have it
888 std::string const FinalFile = GetFinalFilename();
889 std::string FinalRelease;
890 std::string FinalInRelease;
891 if (APT::String::Endswith(FinalFile, "InRelease"))
2ac3eeb6 892 {
448c38bd
DK
893 FinalInRelease = FinalFile;
894 FinalRelease = FinalFile.substr(0, FinalFile.length() - strlen("InRelease")) + "Release";
895 }
896 else
897 {
898 FinalInRelease = FinalFile.substr(0, FinalFile.length() - strlen("Release")) + "InRelease";
899 FinalRelease = FinalFile;
900 }
901 if (RealFileExists(FinalInRelease) || RealFileExists(FinalRelease))
902 {
5ad0096a
DK
903 TransactionManager->LastMetaIndexParser = TransactionManager->MetaIndexParser->UnloadedClone();
904 if (TransactionManager->LastMetaIndexParser != NULL)
02dceb31 905 {
5ad0096a
DK
906 _error->PushToStack();
907 if (RealFileExists(FinalInRelease))
908 TransactionManager->LastMetaIndexParser->Load(FinalInRelease, NULL);
909 else
910 TransactionManager->LastMetaIndexParser->Load(FinalRelease, NULL);
911 // its unlikely to happen, but if what we have is bad ignore it
912 if (_error->PendingError())
913 {
914 delete TransactionManager->LastMetaIndexParser;
915 TransactionManager->LastMetaIndexParser = NULL;
916 }
917 _error->RevertToStack();
2237bd01
MV
918 }
919 }
f6d4ab9a
DK
920 }
921
5ad0096a 922 if (TransactionManager->MetaIndexParser->Load(DestFile, &ErrorText) == false)
f6d4ab9a 923 {
448c38bd 924 Status = StatAuthError;
f6d4ab9a
DK
925 return false;
926 }
927
448c38bd 928 if (!VerifyVendor(Message))
f6d4ab9a 929 {
448c38bd
DK
930 Status = StatAuthError;
931 return false;
932 }
f6d4ab9a 933
448c38bd
DK
934 if (_config->FindB("Debug::pkgAcquire::Auth", false))
935 std::cerr << "Signature verification succeeded: "
936 << DestFile << std::endl;
2237bd01 937
448c38bd
DK
938 // Download further indexes with verification
939 QueueIndexes(true);
2237bd01 940
448c38bd
DK
941 return true;
942}
943 /*}}}*/
944void pkgAcqMetaBase::QueueIndexes(bool const verify) /*{{{*/
945{
946 // at this point the real Items are loaded in the fetcher
947 ExpectedAdditionalItems = 0;
948
dcbbb14d
DK
949 for (std::vector <IndexTarget>::const_iterator Target = IndexTargets.begin();
950 Target != IndexTargets.end();
448c38bd
DK
951 ++Target)
952 {
9b8c28f4
DK
953 bool trypdiff = _config->FindB("Acquire::PDiffs", true);
954 if (verify == true)
2ac3eeb6 955 {
dcbbb14d 956 if (TransactionManager->MetaIndexParser->Exists(Target->MetaKey) == false)
9b8c28f4
DK
957 {
958 // optional targets that we do not have in the Release file are skipped
dcbbb14d 959 if (Target->IsOptional)
9b8c28f4 960 continue;
47d2bc78 961
9b8c28f4 962 Status = StatAuthError;
dcbbb14d 963 strprintf(ErrorText, _("Unable to find expected entry '%s' in Release file (Wrong sources.list entry or malformed file)"), Target->MetaKey.c_str());
9b8c28f4
DK
964 return;
965 }
966
dcbbb14d 967 if (RealFileExists(GetFinalFileNameFromURI(Target->URI)))
8d041b4f
DK
968 {
969 if (TransactionManager->LastMetaIndexParser != NULL)
970 {
dcbbb14d
DK
971 HashStringList const newFile = GetExpectedHashesFromFor(TransactionManager->MetaIndexParser, Target->MetaKey);
972 HashStringList const oldFile = GetExpectedHashesFromFor(TransactionManager->LastMetaIndexParser, Target->MetaKey);
8d041b4f
DK
973 if (newFile == oldFile)
974 {
975 // we have the file already, no point in trying to acquire it again
976 new NoActionItem(Owner, *Target);
977 continue;
978 }
979 }
1196da2e
DK
980 else if (TransactionManager->IMSHit == true)
981 {
982 // we have the file already, no point in trying to acquire it again
983 new NoActionItem(Owner, *Target);
984 continue;
985 }
8d041b4f
DK
986 }
987 else
988 trypdiff = false; // no file to patch
989
9b8c28f4 990 // check if we have patches available
dcbbb14d 991 trypdiff &= TransactionManager->MetaIndexParser->Exists(Target->MetaKey + ".diff/Index");
2237bd01 992 }
9b8c28f4 993 // if we have no file to patch, no point in trying
dcbbb14d 994 trypdiff &= RealFileExists(GetFinalFileNameFromURI(Target->URI));
448c38bd 995
9b8c28f4
DK
996 // no point in patching from local sources
997 if (trypdiff)
998 {
dcbbb14d 999 std::string const proto = Target->URI.substr(0, strlen("file:/"));
9b8c28f4
DK
1000 if (proto == "file:/" || proto == "copy:/" || proto == "cdrom:")
1001 trypdiff = false;
1002 }
1003
1004 // Queue the Index file (Packages, Sources, Translation-$foo, …)
1005 if (trypdiff)
448c38bd
DK
1006 new pkgAcqDiffIndex(Owner, TransactionManager, *Target);
1007 else
1008 new pkgAcqIndex(Owner, TransactionManager, *Target);
2237bd01 1009 }
448c38bd
DK
1010}
1011 /*}}}*/
1012bool pkgAcqMetaBase::VerifyVendor(string const &Message) /*{{{*/
1013{
1014 string::size_type pos;
f6d4ab9a 1015
448c38bd
DK
1016 // check for missing sigs (that where not fatal because otherwise we had
1017 // bombed earlier)
1018 string missingkeys;
1019 string msg = _("There is no public key available for the "
1020 "following key IDs:\n");
1021 pos = Message.find("NO_PUBKEY ");
1022 if (pos != std::string::npos)
f6d4ab9a 1023 {
448c38bd
DK
1024 string::size_type start = pos+strlen("NO_PUBKEY ");
1025 string Fingerprint = Message.substr(start, Message.find("\n")-start);
1026 missingkeys += (Fingerprint);
f6d4ab9a 1027 }
448c38bd
DK
1028 if(!missingkeys.empty())
1029 _error->Warning("%s", (msg + missingkeys).c_str());
f6d4ab9a 1030
448c38bd
DK
1031 string Transformed = TransactionManager->MetaIndexParser->GetExpectedDist();
1032
1033 if (Transformed == "../project/experimental")
f6d4ab9a 1034 {
448c38bd 1035 Transformed = "experimental";
f6d4ab9a
DK
1036 }
1037
448c38bd
DK
1038 pos = Transformed.rfind('/');
1039 if (pos != string::npos)
f6d4ab9a 1040 {
448c38bd 1041 Transformed = Transformed.substr(0, pos);
f6d4ab9a
DK
1042 }
1043
448c38bd 1044 if (Transformed == ".")
f6d4ab9a 1045 {
448c38bd 1046 Transformed = "";
f6d4ab9a
DK
1047 }
1048
0741daeb
DK
1049 if (TransactionManager->MetaIndexParser->GetValidUntil() > 0)
1050 {
448c38bd
DK
1051 time_t const invalid_since = time(NULL) - TransactionManager->MetaIndexParser->GetValidUntil();
1052 if (invalid_since > 0)
1053 {
1054 std::string errmsg;
1055 strprintf(errmsg,
1056 // TRANSLATOR: The first %s is the URL of the bad Release file, the second is
3d8232bf 1057 // the time since then the file is invalid - formatted in the same way as in
448c38bd
DK
1058 // the download progress display (e.g. 7d 3h 42min 1s)
1059 _("Release file for %s is expired (invalid since %s). "
1060 "Updates for this repository will not be applied."),
dcbbb14d 1061 Target.URI.c_str(), TimeToStr(invalid_since).c_str());
448c38bd
DK
1062 if (ErrorText.empty())
1063 ErrorText = errmsg;
1064 return _error->Error("%s", errmsg.c_str());
1065 }
1066 }
f6d4ab9a 1067
448c38bd
DK
1068 /* Did we get a file older than what we have? This is a last minute IMS hit and doubles
1069 as a prevention of downgrading us to older (still valid) files */
1070 if (TransactionManager->IMSHit == false && TransactionManager->LastMetaIndexParser != NULL &&
1071 TransactionManager->LastMetaIndexParser->GetDate() > TransactionManager->MetaIndexParser->GetDate())
f6d4ab9a 1072 {
448c38bd
DK
1073 TransactionManager->IMSHit = true;
1074 unlink(DestFile.c_str());
1075 PartialFile = DestFile = GetFinalFilename();
5ad0096a
DK
1076 // load the 'old' file in the 'new' one instead of flipping pointers as
1077 // the new one isn't owned by us, while the old one is so cleanup would be confused.
1078 TransactionManager->MetaIndexParser->swapLoad(TransactionManager->LastMetaIndexParser);
1079 delete TransactionManager->LastMetaIndexParser;
448c38bd 1080 TransactionManager->LastMetaIndexParser = NULL;
f6d4ab9a
DK
1081 }
1082
448c38bd 1083 if (_config->FindB("Debug::pkgAcquire::Auth", false))
f6d4ab9a 1084 {
5ad0096a 1085 std::cerr << "Got Codename: " << TransactionManager->MetaIndexParser->GetCodename() << std::endl;
448c38bd
DK
1086 std::cerr << "Expecting Dist: " << TransactionManager->MetaIndexParser->GetExpectedDist() << std::endl;
1087 std::cerr << "Transformed Dist: " << Transformed << std::endl;
f6d4ab9a 1088 }
448c38bd
DK
1089
1090 if (TransactionManager->MetaIndexParser->CheckDist(Transformed) == false)
f6d4ab9a 1091 {
448c38bd
DK
1092 // This might become fatal one day
1093// Status = StatAuthError;
1094// ErrorText = "Conflicting distribution; expected "
1095// + MetaIndexParser->GetExpectedDist() + " but got "
5ad0096a 1096// + MetaIndexParser->GetCodename();
448c38bd
DK
1097// return false;
1098 if (!Transformed.empty())
1099 {
1100 _error->Warning(_("Conflicting distribution: %s (expected %s but got %s)"),
1101 Desc.Description.c_str(),
1102 Transformed.c_str(),
5ad0096a 1103 TransactionManager->MetaIndexParser->GetCodename().c_str());
448c38bd 1104 }
f6d4ab9a
DK
1105 }
1106
f6d4ab9a 1107 return true;
2237bd01 1108}
92fcbfc1 1109 /*}}}*/
3d8232bf
DK
1110pkgAcqMetaBase::~pkgAcqMetaBase()
1111{
1112}
2237bd01 1113
448c38bd
DK
1114pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire * const Owner, /*{{{*/
1115 IndexTarget const &ClearsignedTarget,
1116 IndexTarget const &DetachedDataTarget, IndexTarget const &DetachedSigTarget,
e8afd168 1117 std::vector<IndexTarget> const &IndexTargets,
5ad0096a 1118 metaIndex * const MetaIndexParser) :
3d8232bf 1119 pkgAcqMetaIndex(Owner, this, ClearsignedTarget, DetachedSigTarget, IndexTargets),
6c55f07a 1120 d(NULL), ClearsignedTarget(ClearsignedTarget),
3d8232bf
DK
1121 DetachedDataTarget(DetachedDataTarget),
1122 MetaIndexParser(MetaIndexParser), LastMetaIndexParser(NULL)
448c38bd
DK
1123{
1124 // index targets + (worst case:) Release/Release.gpg
dcbbb14d 1125 ExpectedAdditionalItems = IndexTargets.size() + 2;
448c38bd 1126 TransactionManager->Add(this);
2237bd01 1127}
92fcbfc1 1128 /*}}}*/
448c38bd 1129pkgAcqMetaClearSig::~pkgAcqMetaClearSig() /*{{{*/
146f7715 1130{
3d8232bf
DK
1131 if (LastMetaIndexParser != NULL)
1132 delete LastMetaIndexParser;
146f7715
DK
1133}
1134 /*}}}*/
448c38bd
DK
1135// pkgAcqMetaClearSig::Custom600Headers - Insert custom request headers /*{{{*/
1136string pkgAcqMetaClearSig::Custom600Headers() const
2237bd01 1137{
448c38bd
DK
1138 string Header = pkgAcqMetaBase::Custom600Headers();
1139 Header += "\nFail-Ignore: true";
b0d40854
DK
1140 std::string const key = TransactionManager->MetaIndexParser->GetSignedBy();
1141 if (key.empty() == false)
1142 Header += "\nSigned-By: " + key;
1143
448c38bd
DK
1144 return Header;
1145}
1146 /*}}}*/
1147// pkgAcqMetaClearSig::Done - We got a file /*{{{*/
448c38bd
DK
1148void pkgAcqMetaClearSig::Done(std::string const &Message,
1149 HashStringList const &Hashes,
1150 pkgAcquire::MethodConfig const * const Cnf)
1151{
1152 Item::Done(Message, Hashes, Cnf);
8d266656 1153
448c38bd
DK
1154 // if we expect a ClearTextSignature (InRelease), ensure that
1155 // this is what we get and if not fail to queue a
1156 // Release/Release.gpg, see #346386
1157 if (FileExists(DestFile) && !StartsWithGPGClearTextSignature(DestFile))
146f7715 1158 {
448c38bd
DK
1159 pkgAcquire::Item::Failed(Message, Cnf);
1160 RenameOnError(NotClearsigned);
1161 TransactionManager->AbortTransaction();
146f7715
DK
1162 return;
1163 }
22b2ef9d 1164
448c38bd
DK
1165 if(AuthPass == false)
1166 {
1167 if(CheckDownloadDone(this, Message, Hashes) == true)
1168 QueueForSignatureVerify(this, DestFile, DestFile);
1169 return;
1170 }
1171 else if(CheckAuthDone(Message) == true)
1172 {
1173 if (TransactionManager->IMSHit == false)
1174 TransactionManager->TransactionStageCopy(this, DestFile, GetFinalFilename());
1175 else if (RealFileExists(GetFinalFilename()) == false)
1176 {
1177 // We got an InRelease file IMSHit, but we haven't one, which means
1178 // we had a valid Release/Release.gpg combo stepping in, which we have
1179 // to 'acquire' now to ensure list cleanup isn't removing them
dcbbb14d
DK
1180 new NoActionItem(Owner, DetachedDataTarget);
1181 new NoActionItem(Owner, DetachedSigTarget);
448c38bd
DK
1182 }
1183 }
2237bd01 1184}
92fcbfc1 1185 /*}}}*/
448c38bd 1186void pkgAcqMetaClearSig::Failed(string const &Message,pkgAcquire::MethodConfig const * const Cnf) /*{{{*/
2237bd01 1187{
448c38bd 1188 Item::Failed(Message, Cnf);
2237bd01 1189
448c38bd
DK
1190 // we failed, we will not get additional items from this method
1191 ExpectedAdditionalItems = 0;
2237bd01 1192
448c38bd 1193 if (AuthPass == false)
2ac3eeb6 1194 {
448c38bd
DK
1195 // Queue the 'old' InRelease file for removal if we try Release.gpg
1196 // as otherwise the file will stay around and gives a false-auth
1197 // impression (CVE-2012-0214)
1198 TransactionManager->TransactionStageRemoval(this, GetFinalFilename());
1199 Status = StatDone;
1200
3d8232bf 1201 new pkgAcqMetaIndex(Owner, TransactionManager, DetachedDataTarget, DetachedSigTarget, IndexTargets);
2ac3eeb6
MV
1202 }
1203 else
1204 {
448c38bd
DK
1205 if(CheckStopAuthentication(this, Message))
1206 return;
1207
1208 _error->Warning(_("The data from '%s' is not signed. Packages "
1209 "from that repository can not be authenticated."),
1210 ClearsignedTarget.Description.c_str());
1211
1212 // No Release file was present, or verification failed, so fall
1213 // back to queueing Packages files without verification
1214 // only allow going further if the users explicitely wants it
1215 if(AllowInsecureRepositories(TransactionManager->MetaIndexParser, TransactionManager, this) == true)
146f7715 1216 {
448c38bd
DK
1217 Status = StatDone;
1218
1219 /* InRelease files become Release files, otherwise
1220 * they would be considered as trusted later on */
1221 string const FinalRelease = GetFinalFileNameFromURI(DetachedDataTarget.URI);
1222 string const PartialRelease = GetPartialFileNameFromURI(DetachedDataTarget.URI);
1223 string const FinalReleasegpg = GetFinalFileNameFromURI(DetachedSigTarget.URI);
1224 string const FinalInRelease = GetFinalFilename();
1225 Rename(DestFile, PartialRelease);
1226 TransactionManager->TransactionStageCopy(this, PartialRelease, FinalRelease);
1227
1228 if (RealFileExists(FinalReleasegpg) || RealFileExists(FinalInRelease))
146f7715 1229 {
448c38bd
DK
1230 // open the last Release if we have it
1231 if (TransactionManager->IMSHit == false)
1232 {
5ad0096a
DK
1233 TransactionManager->LastMetaIndexParser = TransactionManager->MetaIndexParser->UnloadedClone();
1234 if (TransactionManager->LastMetaIndexParser != NULL)
448c38bd 1235 {
5ad0096a
DK
1236 _error->PushToStack();
1237 if (RealFileExists(FinalInRelease))
1238 TransactionManager->LastMetaIndexParser->Load(FinalInRelease, NULL);
1239 else
1240 TransactionManager->LastMetaIndexParser->Load(FinalRelease, NULL);
1241 // its unlikely to happen, but if what we have is bad ignore it
1242 if (_error->PendingError())
1243 {
1244 delete TransactionManager->LastMetaIndexParser;
1245 TransactionManager->LastMetaIndexParser = NULL;
1246 }
1247 _error->RevertToStack();
448c38bd 1248 }
448c38bd 1249 }
146f7715 1250 }
146f7715 1251
448c38bd
DK
1252 // we parse the indexes here because at this point the user wanted
1253 // a repository that may potentially harm him
5ad0096a 1254 if (TransactionManager->MetaIndexParser->Load(PartialRelease, &ErrorText) == false || VerifyVendor(Message) == false)
448c38bd
DK
1255 /* expired Release files are still a problem you need extra force for */;
1256 else
1257 QueueIndexes(true);
1258 }
2237bd01
MV
1259 }
1260}
92fcbfc1 1261 /*}}}*/
03aa0847 1262
448c38bd 1263pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire * const Owner, /*{{{*/
3d8232bf 1264 pkgAcqMetaClearSig * const TransactionManager,
448c38bd
DK
1265 IndexTarget const &DataTarget,
1266 IndexTarget const &DetachedSigTarget,
3d8232bf
DK
1267 vector<IndexTarget> const &IndexTargets) :
1268 pkgAcqMetaBase(Owner, TransactionManager, IndexTargets, DataTarget), d(NULL),
448c38bd 1269 DetachedSigTarget(DetachedSigTarget)
ac5b205a 1270{
448c38bd
DK
1271 if(_config->FindB("Debug::Acquire::Transaction", false) == true)
1272 std::clog << "New pkgAcqMetaIndex with TransactionManager "
1273 << this->TransactionManager << std::endl;
2d4722e2 1274
448c38bd 1275 DestFile = GetPartialFileNameFromURI(DataTarget.URI);
fa3a96a1 1276
448c38bd
DK
1277 // Create the item
1278 Desc.Description = DataTarget.Description;
1279 Desc.Owner = this;
1280 Desc.ShortDesc = DataTarget.ShortDesc;
1281 Desc.URI = DataTarget.URI;
ac5b205a 1282
448c38bd 1283 // we expect more item
dcbbb14d 1284 ExpectedAdditionalItems = IndexTargets.size();
448c38bd 1285 QueueURI(Desc);
ac5b205a 1286}
92fcbfc1 1287 /*}}}*/
448c38bd
DK
1288void pkgAcqMetaIndex::Done(string const &Message, /*{{{*/
1289 HashStringList const &Hashes,
1290 pkgAcquire::MethodConfig const * const Cfg)
ac5b205a 1291{
448c38bd 1292 Item::Done(Message,Hashes,Cfg);
03bfbc96 1293
448c38bd 1294 if(CheckDownloadDone(this, Message, Hashes))
03bfbc96 1295 {
448c38bd
DK
1296 // we have a Release file, now download the Signature, all further
1297 // verify/queue for additional downloads will be done in the
1298 // pkgAcqMetaSig::Done() code
dcbbb14d 1299 new pkgAcqMetaSig(Owner, TransactionManager, DetachedSigTarget, this);
03bfbc96 1300 }
448c38bd
DK
1301}
1302 /*}}}*/
1303// pkgAcqMetaIndex::Failed - no Release file present /*{{{*/
1304void pkgAcqMetaIndex::Failed(string const &Message,
1305 pkgAcquire::MethodConfig const * const Cnf)
1306{
1307 pkgAcquire::Item::Failed(Message, Cnf);
1308 Status = StatDone;
94dc9d7d 1309
448c38bd
DK
1310 _error->Warning(_("The repository '%s' does not have a Release file. "
1311 "This is deprecated, please contact the owner of the "
dcbbb14d 1312 "repository."), Target.Description.c_str());
f6d4ab9a 1313
448c38bd
DK
1314 // No Release file was present so fall
1315 // back to queueing Packages files without verification
1316 // only allow going further if the users explicitely wants it
1317 if(AllowInsecureRepositories(TransactionManager->MetaIndexParser, TransactionManager, this) == true)
f6d4ab9a 1318 {
448c38bd
DK
1319 // ensure old Release files are removed
1320 TransactionManager->TransactionStageRemoval(this, GetFinalFilename());
03bfbc96 1321
448c38bd
DK
1322 // queue without any kind of hashsum support
1323 QueueIndexes(false);
59a704f0 1324 }
448c38bd
DK
1325}
1326 /*}}}*/
1327void pkgAcqMetaIndex::Finished() /*{{{*/
1328{
1329 if(_config->FindB("Debug::Acquire::Transaction", false) == true)
1330 std::clog << "Finished: " << DestFile <<std::endl;
1331 if(TransactionManager != NULL &&
1332 TransactionManager->TransactionHasError() == false)
1333 TransactionManager->CommitTransaction();
1334}
1335 /*}}}*/
1336std::string pkgAcqMetaIndex::DescURI() const /*{{{*/
1337{
dcbbb14d 1338 return Target.URI;
448c38bd
DK
1339}
1340 /*}}}*/
c8a4ce6c 1341pkgAcqMetaIndex::~pkgAcqMetaIndex() {}
94dc9d7d 1342
448c38bd
DK
1343// AcqMetaSig::AcqMetaSig - Constructor /*{{{*/
1344pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire * const Owner,
3d8232bf 1345 pkgAcqMetaClearSig * const TransactionManager,
e8afd168 1346 IndexTarget const &Target,
448c38bd 1347 pkgAcqMetaIndex * const MetaIndex) :
6c55f07a 1348 pkgAcqTransactionItem(Owner, TransactionManager, Target), d(NULL), MetaIndex(MetaIndex)
448c38bd 1349{
dcbbb14d 1350 DestFile = GetPartialFileNameFromURI(Target.URI);
6cb30d01 1351
448c38bd
DK
1352 // remove any partial downloaded sig-file in partial/.
1353 // it may confuse proxies and is too small to warrant a
1354 // partial download anyway
1355 unlink(DestFile.c_str());
ac5b205a 1356
448c38bd
DK
1357 // set the TransactionManager
1358 if(_config->FindB("Debug::Acquire::Transaction", false) == true)
1359 std::clog << "New pkgAcqMetaSig with TransactionManager "
1360 << TransactionManager << std::endl;
f6d4ab9a 1361
448c38bd 1362 // Create the item
dcbbb14d 1363 Desc.Description = Target.Description;
448c38bd 1364 Desc.Owner = this;
dcbbb14d
DK
1365 Desc.ShortDesc = Target.ShortDesc;
1366 Desc.URI = Target.URI;
ac5b205a 1367
448c38bd
DK
1368 // If we got a hit for Release, we will get one for Release.gpg too (or obscure errors),
1369 // so we skip the download step and go instantly to verification
1370 if (TransactionManager->IMSHit == true && RealFileExists(GetFinalFilename()))
1371 {
1372 Complete = true;
1373 Status = StatDone;
1374 PartialFile = DestFile = GetFinalFilename();
1375 MetaIndexFileSignature = DestFile;
1376 MetaIndex->QueueForSignatureVerify(this, MetaIndex->DestFile, DestFile);
1377 }
1378 else
1379 QueueURI(Desc);
ac5b205a 1380}
92fcbfc1 1381 /*}}}*/
448c38bd 1382pkgAcqMetaSig::~pkgAcqMetaSig() /*{{{*/
ac5b205a 1383{
b0d40854
DK
1384}
1385 /*}}}*/
1386// pkgAcqMetaSig::Custom600Headers - Insert custom request headers /*{{{*/
1387std::string pkgAcqMetaSig::Custom600Headers() const
1388{
1389 std::string Header = pkgAcqTransactionItem::Custom600Headers();
1390 std::string const key = TransactionManager->MetaIndexParser->GetSignedBy();
1391 if (key.empty() == false)
1392 Header += "\nSigned-By: " + key;
1393 return Header;
448c38bd
DK
1394}
1395 /*}}}*/
1396// AcqMetaSig::Done - The signature was downloaded/verified /*{{{*/
1397void pkgAcqMetaSig::Done(string const &Message, HashStringList const &Hashes,
1398 pkgAcquire::MethodConfig const * const Cfg)
1399{
1400 if (MetaIndexFileSignature.empty() == false)
4a0a786f 1401 {
448c38bd
DK
1402 DestFile = MetaIndexFileSignature;
1403 MetaIndexFileSignature.clear();
1404 }
1405 Item::Done(Message, Hashes, Cfg);
f6d4ab9a 1406
448c38bd
DK
1407 if(MetaIndex->AuthPass == false)
1408 {
1409 if(MetaIndex->CheckDownloadDone(this, Message, Hashes) == true)
f6d4ab9a 1410 {
448c38bd
DK
1411 // destfile will be modified to point to MetaIndexFile for the
1412 // gpgv method, so we need to save it here
1413 MetaIndexFileSignature = DestFile;
1414 MetaIndex->QueueForSignatureVerify(this, MetaIndex->DestFile, DestFile);
1415 }
1416 return;
1417 }
1418 else if(MetaIndex->CheckAuthDone(Message) == true)
1419 {
1420 if (TransactionManager->IMSHit == false)
1421 {
1422 TransactionManager->TransactionStageCopy(this, DestFile, GetFinalFilename());
1423 TransactionManager->TransactionStageCopy(MetaIndex, MetaIndex->DestFile, MetaIndex->GetFinalFilename());
f6d4ab9a 1424 }
448c38bd
DK
1425 }
1426}
1427 /*}}}*/
1428void pkgAcqMetaSig::Failed(string const &Message,pkgAcquire::MethodConfig const * const Cnf)/*{{{*/
1429{
1430 Item::Failed(Message,Cnf);
4a0a786f 1431
448c38bd
DK
1432 // check if we need to fail at this point
1433 if (MetaIndex->AuthPass == true && MetaIndex->CheckStopAuthentication(this, Message))
1434 return;
4a0a786f 1435
448c38bd
DK
1436 string const FinalRelease = MetaIndex->GetFinalFilename();
1437 string const FinalReleasegpg = GetFinalFilename();
1438 string const FinalInRelease = TransactionManager->GetFinalFilename();
4a0a786f 1439
448c38bd
DK
1440 if (RealFileExists(FinalReleasegpg) || RealFileExists(FinalInRelease))
1441 {
1442 std::string downgrade_msg;
1443 strprintf(downgrade_msg, _("The repository '%s' is no longer signed."),
dcbbb14d 1444 MetaIndex->Target.Description.c_str());
448c38bd
DK
1445 if(_config->FindB("Acquire::AllowDowngradeToInsecureRepositories"))
1446 {
1447 // meh, the users wants to take risks (we still mark the packages
1448 // from this repository as unauthenticated)
1449 _error->Warning("%s", downgrade_msg.c_str());
1450 _error->Warning(_("This is normally not allowed, but the option "
1451 "Acquire::AllowDowngradeToInsecureRepositories was "
1452 "given to override it."));
1453 Status = StatDone;
1454 } else {
1455 _error->Error("%s", downgrade_msg.c_str());
1456 if (TransactionManager->IMSHit == false)
1457 Rename(MetaIndex->DestFile, MetaIndex->DestFile + ".FAILED");
1458 Item::Failed("Message: " + downgrade_msg, Cnf);
1459 TransactionManager->AbortTransaction();
1460 return;
1461 }
1462 }
1463 else
1464 _error->Warning(_("The data from '%s' is not signed. Packages "
1465 "from that repository can not be authenticated."),
dcbbb14d 1466 MetaIndex->Target.Description.c_str());
4a0a786f 1467
448c38bd
DK
1468 // ensures that a Release.gpg file in the lists/ is removed by the transaction
1469 TransactionManager->TransactionStageRemoval(this, DestFile);
4a0a786f 1470
448c38bd
DK
1471 // only allow going further if the users explicitely wants it
1472 if(AllowInsecureRepositories(TransactionManager->MetaIndexParser, TransactionManager, this) == true)
4a0a786f 1473 {
448c38bd 1474 if (RealFileExists(FinalReleasegpg) || RealFileExists(FinalInRelease))
59a704f0 1475 {
448c38bd
DK
1476 // open the last Release if we have it
1477 if (TransactionManager->IMSHit == false)
1478 {
5ad0096a
DK
1479 TransactionManager->LastMetaIndexParser = TransactionManager->MetaIndexParser->UnloadedClone();
1480 if (TransactionManager->LastMetaIndexParser != NULL)
448c38bd 1481 {
5ad0096a
DK
1482 _error->PushToStack();
1483 if (RealFileExists(FinalInRelease))
1484 TransactionManager->LastMetaIndexParser->Load(FinalInRelease, NULL);
1485 else
1486 TransactionManager->LastMetaIndexParser->Load(FinalRelease, NULL);
1487 // its unlikely to happen, but if what we have is bad ignore it
1488 if (_error->PendingError())
1489 {
1490 delete TransactionManager->LastMetaIndexParser;
1491 TransactionManager->LastMetaIndexParser = NULL;
1492 }
1493 _error->RevertToStack();
448c38bd 1494 }
448c38bd 1495 }
59a704f0 1496 }
4a0a786f 1497
448c38bd
DK
1498 // we parse the indexes here because at this point the user wanted
1499 // a repository that may potentially harm him
5ad0096a 1500 if (TransactionManager->MetaIndexParser->Load(MetaIndex->DestFile, &ErrorText) == false || MetaIndex->VerifyVendor(Message) == false)
448c38bd
DK
1501 /* expired Release files are still a problem you need extra force for */;
1502 else
1503 MetaIndex->QueueIndexes(true);
1504
1505 TransactionManager->TransactionStageCopy(MetaIndex, MetaIndex->DestFile, MetaIndex->GetFinalFilename());
1506 }
1507
1508 // FIXME: this is used often (e.g. in pkgAcqIndexTrans) so refactor
1509 if (Cnf->LocalOnly == true ||
1510 StringToBool(LookupTag(Message,"Transient-Failure"),false) == false)
1511 {
1512 // Ignore this
1513 Status = StatDone;
ac5b205a 1514 }
ac5b205a 1515}
92fcbfc1 1516 /*}}}*/
448c38bd
DK
1517
1518
1519// AcqBaseIndex - Constructor /*{{{*/
1520pkgAcqBaseIndex::pkgAcqBaseIndex(pkgAcquire * const Owner,
3d8232bf 1521 pkgAcqMetaClearSig * const TransactionManager,
e8afd168 1522 IndexTarget const &Target)
6c55f07a 1523: pkgAcqTransactionItem(Owner, TransactionManager, Target), d(NULL)
448c38bd
DK
1524{
1525}
1526 /*}}}*/
c8a4ce6c 1527pkgAcqBaseIndex::~pkgAcqBaseIndex() {}
448c38bd
DK
1528
1529// AcqDiffIndex::AcqDiffIndex - Constructor /*{{{*/
1530// ---------------------------------------------------------------------
1531/* Get the DiffIndex file first and see if there are patches available
1532 * If so, create a pkgAcqIndexDiffs fetcher that will get and apply the
1533 * patches. If anything goes wrong in that process, it will fall back to
1534 * the original packages file
1535 */
1536pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire * const Owner,
3d8232bf 1537 pkgAcqMetaClearSig * const TransactionManager,
e8afd168 1538 IndexTarget const &Target)
3d8232bf 1539 : pkgAcqBaseIndex(Owner, TransactionManager, Target), d(NULL), diffs(NULL)
47d2bc78 1540{
47d2bc78
DK
1541 Debug = _config->FindB("Debug::pkgAcquire::Diffs",false);
1542
47d2bc78 1543 Desc.Owner = this;
dcbbb14d
DK
1544 Desc.Description = Target.Description + ".diff/Index";
1545 Desc.ShortDesc = Target.ShortDesc;
1546 Desc.URI = Target.URI + ".diff/Index";
47d2bc78 1547
448c38bd
DK
1548 DestFile = GetPartialFileNameFromURI(Desc.URI);
1549
1550 if(Debug)
1551 std::clog << "pkgAcqDiffIndex: " << Desc.URI << std::endl;
5684f71f 1552
47d2bc78
DK
1553 QueueURI(Desc);
1554}
1555 /*}}}*/
448c38bd
DK
1556// AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
1557// ---------------------------------------------------------------------
1558/* The only header we use is the last-modified header. */
1559string pkgAcqDiffIndex::Custom600Headers() const
47d2bc78 1560{
448c38bd 1561 string const Final = GetFinalFilename();
47d2bc78 1562
448c38bd
DK
1563 if(Debug)
1564 std::clog << "Custom600Header-IMS: " << Final << std::endl;
47d2bc78 1565
448c38bd
DK
1566 struct stat Buf;
1567 if (stat(Final.c_str(),&Buf) != 0)
1568 return "\nIndex-File: true";
1569
1570 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
1571}
1572 /*}}}*/
1573void pkgAcqDiffIndex::QueueOnIMSHit() const /*{{{*/
1574{
1575 // list cleanup needs to know that this file as well as the already
1576 // present index is ours, so we create an empty diff to save it for us
1577 new pkgAcqIndexDiffs(Owner, TransactionManager, Target);
47d2bc78
DK
1578}
1579 /*}}}*/
448c38bd 1580bool pkgAcqDiffIndex::ParseDiffIndex(string const &IndexDiffFile) /*{{{*/
47d2bc78 1581{
448c38bd
DK
1582 // failing here is fine: our caller will take care of trying to
1583 // get the complete file if patching fails
47d2bc78 1584 if(Debug)
448c38bd
DK
1585 std::clog << "pkgAcqDiffIndex::ParseIndexDiff() " << IndexDiffFile
1586 << std::endl;
f6d4ab9a 1587
448c38bd
DK
1588 FileFd Fd(IndexDiffFile,FileFd::ReadOnly);
1589 pkgTagFile TF(&Fd);
1590 if (_error->PendingError() == true)
1591 return false;
47d2bc78 1592
448c38bd
DK
1593 pkgTagSection Tags;
1594 if(unlikely(TF.Step(Tags) == false))
1595 return false;
47d2bc78 1596
448c38bd
DK
1597 HashStringList ServerHashes;
1598 unsigned long long ServerSize = 0;
47d2bc78 1599
448c38bd
DK
1600 for (char const * const * type = HashString::SupportedHashes(); *type != NULL; ++type)
1601 {
1602 std::string tagname = *type;
1603 tagname.append("-Current");
1604 std::string const tmp = Tags.FindS(tagname.c_str());
1605 if (tmp.empty() == true)
1606 continue;
146f7715 1607
448c38bd
DK
1608 string hash;
1609 unsigned long long size;
1610 std::stringstream ss(tmp);
1611 ss >> hash >> size;
1612 if (unlikely(hash.empty() == true))
1613 continue;
1614 if (unlikely(ServerSize != 0 && ServerSize != size))
1615 continue;
1616 ServerHashes.push_back(HashString(*type, hash));
1617 ServerSize = size;
1618 }
47d2bc78 1619
448c38bd
DK
1620 if (ServerHashes.usable() == false)
1621 {
1622 if (Debug == true)
1623 std::clog << "pkgAcqDiffIndex: " << IndexDiffFile << ": Did not find a good hashsum in the index" << std::endl;
1624 return false;
47d2bc78 1625 }
448c38bd 1626
dcbbb14d
DK
1627 std::string const CurrentPackagesFile = GetFinalFileNameFromURI(Target.URI);
1628 HashStringList const TargetFileHashes = GetExpectedHashesFor(Target.MetaKey);
448c38bd 1629 if (TargetFileHashes.usable() == false || ServerHashes != TargetFileHashes)
47d2bc78 1630 {
448c38bd 1631 if (Debug == true)
47d2bc78 1632 {
448c38bd
DK
1633 std::clog << "pkgAcqDiffIndex: " << IndexDiffFile << ": Index has different hashes than parser, probably older, so fail pdiffing" << std::endl;
1634 printHashSumComparision(CurrentPackagesFile, ServerHashes, TargetFileHashes);
47d2bc78 1635 }
448c38bd
DK
1636 return false;
1637 }
47d2bc78 1638
9b8c28f4
DK
1639 HashStringList LocalHashes;
1640 // try avoiding calculating the hash here as this is costly
1641 if (TransactionManager->LastMetaIndexParser != NULL)
dcbbb14d 1642 LocalHashes = GetExpectedHashesFromFor(TransactionManager->LastMetaIndexParser, Target.MetaKey);
9b8c28f4
DK
1643 if (LocalHashes.usable() == false)
1644 {
1645 FileFd fd(CurrentPackagesFile, FileFd::ReadOnly);
1646 Hashes LocalHashesCalc(ServerHashes);
1647 LocalHashesCalc.AddFD(fd);
1648 LocalHashes = LocalHashesCalc.GetHashStringList();
1649 }
1650
1651 if (ServerHashes == LocalHashes)
448c38bd
DK
1652 {
1653 // we have the same sha1 as the server so we are done here
47d2bc78 1654 if(Debug)
448c38bd
DK
1655 std::clog << "pkgAcqDiffIndex: Package file " << CurrentPackagesFile << " is up-to-date" << std::endl;
1656 QueueOnIMSHit();
1657 return true;
1658 }
47d2bc78 1659
448c38bd
DK
1660 if(Debug)
1661 std::clog << "Server-Current: " << ServerHashes.find(NULL)->toStr() << " and we start at "
9b8c28f4 1662 << CurrentPackagesFile << " " << LocalHashes.FileSize() << " " << LocalHashes.find(NULL)->toStr() << std::endl;
34d6ece7 1663
448c38bd
DK
1664 // parse all of (provided) history
1665 vector<DiffInfo> available_patches;
1666 bool firstAcceptedHashes = true;
1667 for (char const * const * type = HashString::SupportedHashes(); *type != NULL; ++type)
651bddad 1668 {
448c38bd
DK
1669 if (LocalHashes.find(*type) == NULL)
1670 continue;
21638c3a 1671
448c38bd
DK
1672 std::string tagname = *type;
1673 tagname.append("-History");
1674 std::string const tmp = Tags.FindS(tagname.c_str());
1675 if (tmp.empty() == true)
1676 continue;
a64bf0eb 1677
448c38bd
DK
1678 string hash, filename;
1679 unsigned long long size;
1680 std::stringstream ss(tmp);
56472095 1681
448c38bd 1682 while (ss >> hash >> size >> filename)
651bddad 1683 {
448c38bd
DK
1684 if (unlikely(hash.empty() == true || filename.empty() == true))
1685 continue;
1686
1687 // see if we have a record for this file already
1688 std::vector<DiffInfo>::iterator cur = available_patches.begin();
1689 for (; cur != available_patches.end(); ++cur)
1690 {
4f51fd86 1691 if (cur->file != filename)
448c38bd
DK
1692 continue;
1693 cur->result_hashes.push_back(HashString(*type, hash));
1694 break;
1695 }
1696 if (cur != available_patches.end())
1697 continue;
1698 if (firstAcceptedHashes == true)
1699 {
1700 DiffInfo next;
1701 next.file = filename;
1702 next.result_hashes.push_back(HashString(*type, hash));
4f51fd86 1703 next.result_hashes.FileSize(size);
448c38bd
DK
1704 available_patches.push_back(next);
1705 }
1706 else
1707 {
1708 if (Debug == true)
1709 std::clog << "pkgAcqDiffIndex: " << IndexDiffFile << ": File " << filename
1710 << " wasn't in the list for the first parsed hash! (history)" << std::endl;
1711 break;
1712 }
651bddad 1713 }
448c38bd 1714 firstAcceptedHashes = false;
5d885723 1715 }
448c38bd
DK
1716
1717 if (unlikely(available_patches.empty() == true))
5d885723 1718 {
448c38bd
DK
1719 if (Debug)
1720 std::clog << "pkgAcqDiffIndex: " << IndexDiffFile << ": "
1721 << "Couldn't find any patches for the patch series." << std::endl;
1722 return false;
5d885723 1723 }
8267fe24 1724
448c38bd 1725 for (char const * const * type = HashString::SupportedHashes(); *type != NULL; ++type)
b11f9599 1726 {
448c38bd
DK
1727 if (LocalHashes.find(*type) == NULL)
1728 continue;
97b65b10 1729
448c38bd
DK
1730 std::string tagname = *type;
1731 tagname.append("-Patches");
1732 std::string const tmp = Tags.FindS(tagname.c_str());
1733 if (tmp.empty() == true)
1734 continue;
18593cf7 1735
448c38bd
DK
1736 string hash, filename;
1737 unsigned long long size;
1738 std::stringstream ss(tmp);
03aa0847 1739
448c38bd 1740 while (ss >> hash >> size >> filename)
58702f85 1741 {
448c38bd
DK
1742 if (unlikely(hash.empty() == true || filename.empty() == true))
1743 continue;
146f7715 1744
448c38bd
DK
1745 // see if we have a record for this file already
1746 std::vector<DiffInfo>::iterator cur = available_patches.begin();
1747 for (; cur != available_patches.end(); ++cur)
146f7715 1748 {
448c38bd
DK
1749 if (cur->file != filename)
1750 continue;
4f51fd86
DK
1751 if (cur->patch_hashes.empty())
1752 cur->patch_hashes.FileSize(size);
448c38bd 1753 cur->patch_hashes.push_back(HashString(*type, hash));
448c38bd 1754 break;
146f7715 1755 }
448c38bd
DK
1756 if (cur != available_patches.end())
1757 continue;
1758 if (Debug == true)
1759 std::clog << "pkgAcqDiffIndex: " << IndexDiffFile << ": File " << filename
1760 << " wasn't in the list for the first parsed hash! (patches)" << std::endl;
146f7715 1761 break;
146f7715
DK
1762 }
1763 }
2d0a7bb4 1764
4f51fd86
DK
1765 for (char const * const * type = HashString::SupportedHashes(); *type != NULL; ++type)
1766 {
1767 std::string tagname = *type;
1768 tagname.append("-Download");
1769 std::string const tmp = Tags.FindS(tagname.c_str());
1770 if (tmp.empty() == true)
1771 continue;
1772
1773 string hash, filename;
1774 unsigned long long size;
1775 std::stringstream ss(tmp);
1776
1777 // FIXME: all of pdiff supports only .gz compressed patches
1778 while (ss >> hash >> size >> filename)
1779 {
1780 if (unlikely(hash.empty() == true || filename.empty() == true))
1781 continue;
1782 if (unlikely(APT::String::Endswith(filename, ".gz") == false))
1783 continue;
1784 filename.erase(filename.length() - 3);
1785
1786 // see if we have a record for this file already
1787 std::vector<DiffInfo>::iterator cur = available_patches.begin();
1788 for (; cur != available_patches.end(); ++cur)
1789 {
1790 if (cur->file != filename)
1791 continue;
1792 if (cur->download_hashes.empty())
1793 cur->download_hashes.FileSize(size);
1794 cur->download_hashes.push_back(HashString(*type, hash));
1795 break;
1796 }
1797 if (cur != available_patches.end())
1798 continue;
1799 if (Debug == true)
1800 std::clog << "pkgAcqDiffIndex: " << IndexDiffFile << ": File " << filename
1801 << " wasn't in the list for the first parsed hash! (download)" << std::endl;
1802 break;
1803 }
1804 }
1805
1806
448c38bd
DK
1807 bool foundStart = false;
1808 for (std::vector<DiffInfo>::iterator cur = available_patches.begin();
1809 cur != available_patches.end(); ++cur)
1810 {
1811 if (LocalHashes != cur->result_hashes)
1812 continue;
1813
1814 available_patches.erase(available_patches.begin(), cur);
1815 foundStart = true;
1816 break;
e6e89390 1817 }
b3d44315 1818
448c38bd
DK
1819 if (foundStart == false || unlikely(available_patches.empty() == true))
1820 {
1821 if (Debug)
1822 std::clog << "pkgAcqDiffIndex: " << IndexDiffFile << ": "
1823 << "Couldn't find the start of the patch series." << std::endl;
1824 return false;
1825 }
f6237efd 1826
448c38bd
DK
1827 // patching with too many files is rather slow compared to a fast download
1828 unsigned long const fileLimit = _config->FindI("Acquire::PDiffs::FileLimit", 0);
1829 if (fileLimit != 0 && fileLimit < available_patches.size())
1830 {
1831 if (Debug)
1832 std::clog << "Need " << available_patches.size() << " diffs (Limit is " << fileLimit
1833 << ") so fallback to complete download" << std::endl;
1834 return false;
1835 }
1f4dd8fd 1836
448c38bd
DK
1837 // calculate the size of all patches we have to get
1838 // note that all sizes are uncompressed, while we download compressed files
1839 unsigned long long patchesSize = 0;
1840 for (std::vector<DiffInfo>::const_iterator cur = available_patches.begin();
1841 cur != available_patches.end(); ++cur)
4f51fd86 1842 patchesSize += cur->patch_hashes.FileSize();
448c38bd
DK
1843 unsigned long long const sizeLimit = ServerSize * _config->FindI("Acquire::PDiffs::SizeLimit", 100);
1844 if (sizeLimit > 0 && (sizeLimit/100) < patchesSize)
1845 {
1846 if (Debug)
1847 std::clog << "Need " << patchesSize << " bytes (Limit is " << sizeLimit/100
1848 << ") so fallback to complete download" << std::endl;
1849 return false;
1850 }
2737f28a 1851
448c38bd
DK
1852 // we have something, queue the diffs
1853 string::size_type const last_space = Description.rfind(" ");
1854 if(last_space != string::npos)
1855 Description.erase(last_space, Description.size()-last_space);
1856
1857 /* decide if we should download patches one by one or in one go:
1858 The first is good if the server merges patches, but many don't so client
1859 based merging can be attempt in which case the second is better.
1860 "bad things" will happen if patches are merged on the server,
1861 but client side merging is attempt as well */
1862 bool pdiff_merge = _config->FindB("Acquire::PDiffs::Merge", true);
1863 if (pdiff_merge == true)
6bf93605 1864 {
448c38bd
DK
1865 // reprepro adds this flag if it has merged patches on the server
1866 std::string const precedence = Tags.FindS("X-Patch-Precedence");
1867 pdiff_merge = (precedence != "merged");
6bf93605 1868 }
448c38bd
DK
1869
1870 if (pdiff_merge == false)
1871 new pkgAcqIndexDiffs(Owner, TransactionManager, Target, available_patches);
6bf93605 1872 else
448c38bd 1873 {
3d8232bf 1874 diffs = new std::vector<pkgAcqIndexMergeDiffs*>(available_patches.size());
448c38bd
DK
1875 for(size_t i = 0; i < available_patches.size(); ++i)
1876 (*diffs)[i] = new pkgAcqIndexMergeDiffs(Owner, TransactionManager,
1877 Target,
1878 available_patches[i],
1879 diffs);
1880 }
1881
1882 Complete = false;
1883 Status = StatDone;
1884 Dequeue();
1885 return true;
6bf93605
DK
1886}
1887 /*}}}*/
448c38bd 1888void pkgAcqDiffIndex::Failed(string const &Message,pkgAcquire::MethodConfig const * const Cnf)/*{{{*/
6bf93605 1889{
448c38bd
DK
1890 Item::Failed(Message,Cnf);
1891 Status = StatDone;
1892
1893 if(Debug)
1894 std::clog << "pkgAcqDiffIndex failed: " << Desc.URI << " with " << Message << std::endl
1895 << "Falling back to normal index file acquire" << std::endl;
1896
1897 new pkgAcqIndex(Owner, TransactionManager, Target);
0118833a 1898}
61aea84d 1899 /*}}}*/
448c38bd
DK
1900void pkgAcqDiffIndex::Done(string const &Message,HashStringList const &Hashes, /*{{{*/
1901 pkgAcquire::MethodConfig const * const Cnf)
c88edf1d 1902{
448c38bd
DK
1903 if(Debug)
1904 std::clog << "pkgAcqDiffIndex::Done(): " << Desc.URI << std::endl;
c88edf1d 1905
448c38bd
DK
1906 Item::Done(Message, Hashes, Cnf);
1907
1908 string const FinalFile = GetFinalFilename();
1909 if(StringToBool(LookupTag(Message,"IMS-Hit"),false))
1910 DestFile = FinalFile;
1911
1912 if(ParseDiffIndex(DestFile) == false)
c88edf1d 1913 {
448c38bd
DK
1914 Failed("Message: Couldn't parse pdiff index", Cnf);
1915 // queue for final move - this should happen even if we fail
1916 // while parsing (e.g. on sizelimit) and download the complete file.
1917 TransactionManager->TransactionStageCopy(this, DestFile, FinalFile);
2737f28a
MV
1918 return;
1919 }
448c38bd
DK
1920
1921 TransactionManager->TransactionStageCopy(this, DestFile, FinalFile);
1922
1923 Complete = true;
1924 Status = StatDone;
1925 Dequeue();
1926
1927 return;
c88edf1d
AL
1928}
1929 /*}}}*/
3d8232bf
DK
1930pkgAcqDiffIndex::~pkgAcqDiffIndex()
1931{
1932 if (diffs != NULL)
1933 delete diffs;
1934}
448c38bd
DK
1935
1936// AcqIndexDiffs::AcqIndexDiffs - Constructor /*{{{*/
1937// ---------------------------------------------------------------------
1938/* The package diff is added to the queue. one object is constructed
1939 * for each diff and the index
1940 */
1941pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire * const Owner,
3d8232bf 1942 pkgAcqMetaClearSig * const TransactionManager,
e8afd168 1943 IndexTarget const &Target,
448c38bd 1944 vector<DiffInfo> const &diffs)
6c55f07a 1945 : pkgAcqBaseIndex(Owner, TransactionManager, Target), d(NULL),
448c38bd 1946 available_patches(diffs)
681d76d0 1947{
dcbbb14d 1948 DestFile = GetPartialFileNameFromURI(Target.URI);
e8b1db38 1949
448c38bd 1950 Debug = _config->FindB("Debug::pkgAcquire::Diffs",false);
e8b1db38 1951
448c38bd 1952 Desc.Owner = this;
dcbbb14d
DK
1953 Description = Target.Description;
1954 Desc.ShortDesc = Target.ShortDesc;
631a7dc7 1955
448c38bd 1956 if(available_patches.empty() == true)
631a7dc7 1957 {
448c38bd 1958 // we are done (yeah!), check hashes against the final file
dcbbb14d 1959 DestFile = GetFinalFileNameFromURI(Target.URI);
448c38bd 1960 Finish(true);
631a7dc7 1961 }
9d653a6d 1962 else
631a7dc7 1963 {
448c38bd 1964 // patching needs to be bootstrapped with the 'old' version
dcbbb14d 1965 std::string const PartialFile = GetPartialFileNameFromURI(Target.URI);
448c38bd 1966 if (RealFileExists(PartialFile) == false)
6bf93605 1967 {
448c38bd 1968 if (symlink(GetFinalFilename().c_str(), PartialFile.c_str()) != 0)
6bf93605 1969 {
448c38bd
DK
1970 Failed("Link creation of " + PartialFile + " to " + GetFinalFilename() + " failed", NULL);
1971 return;
6bf93605
DK
1972 }
1973 }
1974
448c38bd
DK
1975 // get the next diff
1976 State = StateFetchDiff;
1977 QueueNextDiff();
631a7dc7 1978 }
448c38bd
DK
1979}
1980 /*}}}*/
1981void pkgAcqIndexDiffs::Failed(string const &Message,pkgAcquire::MethodConfig const * const Cnf)/*{{{*/
1982{
1983 Item::Failed(Message,Cnf);
1984 Status = StatDone;
631a7dc7 1985
448c38bd
DK
1986 if(Debug)
1987 std::clog << "pkgAcqIndexDiffs failed: " << Desc.URI << " with " << Message << std::endl
1988 << "Falling back to normal index file acquire" << std::endl;
dcbbb14d 1989 DestFile = GetPartialFileNameFromURI(Target.URI);
448c38bd 1990 RenameOnError(PDiffError);
36795154
DK
1991 std::string const patchname = GetDiffsPatchFileName(DestFile);
1992 if (RealFileExists(patchname))
1993 rename(patchname.c_str(), std::string(patchname + ".FAILED").c_str());
448c38bd
DK
1994 new pkgAcqIndex(Owner, TransactionManager, Target);
1995 Finish();
1996}
1997 /*}}}*/
1998// Finish - helper that cleans the item out of the fetcher queue /*{{{*/
1999void pkgAcqIndexDiffs::Finish(bool allDone)
2000{
2001 if(Debug)
2002 std::clog << "pkgAcqIndexDiffs::Finish(): "
2003 << allDone << " "
2004 << Desc.URI << std::endl;
2005
2006 // we restore the original name, this is required, otherwise
2007 // the file will be cleaned
2008 if(allDone)
4dbfe436 2009 {
448c38bd
DK
2010 TransactionManager->TransactionStageCopy(this, DestFile, GetFinalFilename());
2011
2012 // this is for the "real" finish
2013 Complete = true;
e05672e8 2014 Status = StatDone;
448c38bd
DK
2015 Dequeue();
2016 if(Debug)
2017 std::clog << "\n\nallDone: " << DestFile << "\n" << std::endl;
2018 return;
e05672e8 2019 }
448c38bd
DK
2020
2021 if(Debug)
2022 std::clog << "Finishing: " << Desc.URI << std::endl;
2023 Complete = false;
2024 Status = StatDone;
2025 Dequeue();
2026 return;
681d76d0 2027}
92fcbfc1 2028 /*}}}*/
448c38bd 2029bool pkgAcqIndexDiffs::QueueNextDiff() /*{{{*/
b3d44315 2030{
448c38bd 2031 // calc sha1 of the just patched file
dcbbb14d 2032 std::string const FinalFile = GetPartialFileNameFromURI(Target.URI);
448c38bd
DK
2033
2034 if(!FileExists(FinalFile))
715c65de 2035 {
448c38bd
DK
2036 Failed("Message: No FinalFile " + FinalFile + " available", NULL);
2037 return false;
715c65de 2038 }
e05672e8 2039
448c38bd
DK
2040 FileFd fd(FinalFile, FileFd::ReadOnly);
2041 Hashes LocalHashesCalc;
2042 LocalHashesCalc.AddFD(fd);
2043 HashStringList const LocalHashes = LocalHashesCalc.GetHashStringList();
b3d44315 2044
448c38bd
DK
2045 if(Debug)
2046 std::clog << "QueueNextDiff: " << FinalFile << " (" << LocalHashes.find(NULL)->toStr() << ")" << std::endl;
b3d44315 2047
dcbbb14d 2048 HashStringList const TargetFileHashes = GetExpectedHashesFor(Target.MetaKey);
448c38bd 2049 if (unlikely(LocalHashes.usable() == false || TargetFileHashes.usable() == false))
b3d44315 2050 {
448c38bd
DK
2051 Failed("Local/Expected hashes are not usable", NULL);
2052 return false;
b3d44315 2053 }
b3d44315 2054
448c38bd
DK
2055
2056 // final file reached before all patches are applied
2057 if(LocalHashes == TargetFileHashes)
6bf93605 2058 {
448c38bd
DK
2059 Finish(true);
2060 return true;
6bf93605
DK
2061 }
2062
448c38bd
DK
2063 // remove all patches until the next matching patch is found
2064 // this requires the Index file to be ordered
2065 for(vector<DiffInfo>::iterator I = available_patches.begin();
2066 available_patches.empty() == false &&
2067 I != available_patches.end() &&
2068 I->result_hashes != LocalHashes;
2069 ++I)
f3097647 2070 {
448c38bd 2071 available_patches.erase(I);
b3d44315 2072 }
56bc3358 2073
448c38bd
DK
2074 // error checking and falling back if no patch was found
2075 if(available_patches.empty() == true)
56bc3358 2076 {
448c38bd 2077 Failed("No patches left to reach target", NULL);
f3097647 2078 return false;
56bc3358 2079 }
f3097647 2080
448c38bd 2081 // queue the right diff
dcbbb14d 2082 Desc.URI = Target.URI + ".diff/" + available_patches[0].file + ".gz";
448c38bd 2083 Desc.Description = Description + " " + available_patches[0].file + string(".pdiff");
dcbbb14d 2084 DestFile = GetPartialFileNameFromURI(Target.URI + ".diff/" + available_patches[0].file);
f3097647 2085
448c38bd
DK
2086 if(Debug)
2087 std::clog << "pkgAcqIndexDiffs::QueueNextDiff(): " << Desc.URI << std::endl;
2088
2089 QueueURI(Desc);
f3097647
MV
2090
2091 return true;
2092}
2093 /*}}}*/
448c38bd
DK
2094void pkgAcqIndexDiffs::Done(string const &Message, HashStringList const &Hashes, /*{{{*/
2095 pkgAcquire::MethodConfig const * const Cnf)
27e6c17a 2096{
448c38bd
DK
2097 if(Debug)
2098 std::clog << "pkgAcqIndexDiffs::Done(): " << Desc.URI << std::endl;
27e6c17a 2099
448c38bd 2100 Item::Done(Message, Hashes, Cnf);
27e6c17a 2101
dcbbb14d 2102 std::string const FinalFile = GetPartialFileNameFromURI(Target.URI);
36795154 2103 std::string const PatchFile = GetDiffsPatchFileName(FinalFile);
b3d44315 2104
448c38bd
DK
2105 // success in downloading a diff, enter ApplyDiff state
2106 if(State == StateFetchDiff)
b3d44315 2107 {
36795154 2108 Rename(DestFile, PatchFile);
448c38bd
DK
2109
2110 if(Debug)
2111 std::clog << "Sending to rred method: " << FinalFile << std::endl;
2112
2113 State = StateApplyDiff;
2114 Local = true;
2115 Desc.URI = "rred:" + FinalFile;
2116 QueueURI(Desc);
2117 SetActiveSubprocess("rred");
2118 return;
36795154 2119 }
448c38bd
DK
2120
2121 // success in download/apply a diff, queue next (if needed)
2122 if(State == StateApplyDiff)
8eafc759 2123 {
448c38bd
DK
2124 // remove the just applied patch
2125 available_patches.erase(available_patches.begin());
36795154 2126 unlink(PatchFile.c_str());
448c38bd
DK
2127
2128 // move into place
36795154 2129 if(Debug)
8eafc759 2130 {
448c38bd
DK
2131 std::clog << "Moving patched file in place: " << std::endl
2132 << DestFile << " -> " << FinalFile << std::endl;
8eafc759 2133 }
448c38bd
DK
2134 Rename(DestFile,FinalFile);
2135 chmod(FinalFile.c_str(),0644);
8eafc759 2136
448c38bd
DK
2137 // see if there is more to download
2138 if(available_patches.empty() == false) {
2139 new pkgAcqIndexDiffs(Owner, TransactionManager, Target,
2140 available_patches);
2141 return Finish();
2142 } else
2143 // update
2144 DestFile = FinalFile;
2145 return Finish(true);
ba6b79bd 2146 }
448c38bd
DK
2147}
2148 /*}}}*/
36795154
DK
2149std::string pkgAcqIndexDiffs::Custom600Headers() const /*{{{*/
2150{
2151 if(State != StateApplyDiff)
2152 return pkgAcqBaseIndex::Custom600Headers();
2153 std::ostringstream patchhashes;
2154 HashStringList const ExpectedHashes = available_patches[0].patch_hashes;
2155 for (HashStringList::const_iterator hs = ExpectedHashes.begin(); hs != ExpectedHashes.end(); ++hs)
2156 patchhashes << "\nPatch-0-" << hs->HashType() << "-Hash: " << hs->HashValue();
2157 patchhashes << pkgAcqBaseIndex::Custom600Headers();
2158 return patchhashes.str();
2159}
2160 /*}}}*/
c8a4ce6c 2161pkgAcqIndexDiffs::~pkgAcqIndexDiffs() {}
448c38bd
DK
2162
2163// AcqIndexMergeDiffs::AcqIndexMergeDiffs - Constructor /*{{{*/
2164pkgAcqIndexMergeDiffs::pkgAcqIndexMergeDiffs(pkgAcquire * const Owner,
3d8232bf 2165 pkgAcqMetaClearSig * const TransactionManager,
e8afd168 2166 IndexTarget const &Target,
448c38bd
DK
2167 DiffInfo const &patch,
2168 std::vector<pkgAcqIndexMergeDiffs*> const * const allPatches)
6c55f07a 2169 : pkgAcqBaseIndex(Owner, TransactionManager, Target), d(NULL),
448c38bd
DK
2170 patch(patch), allPatches(allPatches), State(StateFetchDiff)
2171{
2172 Debug = _config->FindB("Debug::pkgAcquire::Diffs",false);
2173
2174 Desc.Owner = this;
dcbbb14d
DK
2175 Description = Target.Description;
2176 Desc.ShortDesc = Target.ShortDesc;
448c38bd 2177
dcbbb14d 2178 Desc.URI = Target.URI + ".diff/" + patch.file + ".gz";
448c38bd
DK
2179 Desc.Description = Description + " " + patch.file + string(".pdiff");
2180
dcbbb14d 2181 DestFile = GetPartialFileNameFromURI(Target.URI + ".diff/" + patch.file);
448c38bd
DK
2182
2183 if(Debug)
2184 std::clog << "pkgAcqIndexMergeDiffs: " << Desc.URI << std::endl;
2185
2186 QueueURI(Desc);
2187}
2188 /*}}}*/
2189void pkgAcqIndexMergeDiffs::Failed(string const &Message,pkgAcquire::MethodConfig const * const Cnf)/*{{{*/
2190{
2191 if(Debug)
2192 std::clog << "pkgAcqIndexMergeDiffs failed: " << Desc.URI << " with " << Message << std::endl;
2737f28a 2193
448c38bd
DK
2194 Item::Failed(Message,Cnf);
2195 Status = StatDone;
b3d44315 2196
448c38bd
DK
2197 // check if we are the first to fail, otherwise we are done here
2198 State = StateDoneDiff;
2199 for (std::vector<pkgAcqIndexMergeDiffs *>::const_iterator I = allPatches->begin();
2200 I != allPatches->end(); ++I)
2201 if ((*I)->State == StateErrorDiff)
2202 return;
2203
2204 // first failure means we should fallback
2205 State = StateErrorDiff;
2206 if (Debug)
2207 std::clog << "Falling back to normal index file acquire" << std::endl;
dcbbb14d 2208 DestFile = GetPartialFileNameFromURI(Target.URI);
448c38bd 2209 RenameOnError(PDiffError);
36795154
DK
2210 std::string const patchname = GetMergeDiffsPatchFileName(DestFile, patch.file);
2211 if (RealFileExists(patchname))
2212 rename(patchname.c_str(), std::string(patchname + ".FAILED").c_str());
448c38bd 2213 new pkgAcqIndex(Owner, TransactionManager, Target);
b3d44315 2214}
92fcbfc1 2215 /*}}}*/
448c38bd
DK
2216void pkgAcqIndexMergeDiffs::Done(string const &Message, HashStringList const &Hashes, /*{{{*/
2217 pkgAcquire::MethodConfig const * const Cnf)
b3d44315 2218{
448c38bd
DK
2219 if(Debug)
2220 std::clog << "pkgAcqIndexMergeDiffs::Done(): " << Desc.URI << std::endl;
18593cf7 2221
448c38bd 2222 Item::Done(Message, Hashes, Cnf);
18593cf7 2223
dcbbb14d 2224 string const FinalFile = GetPartialFileNameFromURI(Target.URI);
448c38bd
DK
2225 if (State == StateFetchDiff)
2226 {
36795154 2227 Rename(DestFile, GetMergeDiffsPatchFileName(FinalFile, patch.file));
448c38bd
DK
2228
2229 // check if this is the last completed diff
2230 State = StateDoneDiff;
2231 for (std::vector<pkgAcqIndexMergeDiffs *>::const_iterator I = allPatches->begin();
2232 I != allPatches->end(); ++I)
2233 if ((*I)->State != StateDoneDiff)
2234 {
2235 if(Debug)
2236 std::clog << "Not the last done diff in the batch: " << Desc.URI << std::endl;
2237 return;
2238 }
2239
2240 // this is the last completed diff, so we are ready to apply now
2241 State = StateApplyDiff;
ab53c018 2242
448c38bd
DK
2243 // patching needs to be bootstrapped with the 'old' version
2244 if (symlink(GetFinalFilename().c_str(), FinalFile.c_str()) != 0)
2245 {
2246 Failed("Link creation of " + FinalFile + " to " + GetFinalFilename() + " failed", NULL);
2247 return;
18593cf7 2248 }
448c38bd
DK
2249
2250 if(Debug)
2251 std::clog << "Sending to rred method: " << FinalFile << std::endl;
2252
2253 Local = true;
2254 Desc.URI = "rred:" + FinalFile;
2255 QueueURI(Desc);
2256 SetActiveSubprocess("rred");
2257 return;
2258 }
2259 // success in download/apply all diffs, clean up
2260 else if (State == StateApplyDiff)
2261 {
2262 // move the result into place
2263 std::string const Final = GetFinalFilename();
2264 if(Debug)
2265 std::clog << "Queue patched file in place: " << std::endl
2266 << DestFile << " -> " << Final << std::endl;
2267
2268 // queue for copy by the transaction manager
2269 TransactionManager->TransactionStageCopy(this, DestFile, Final);
2270
2271 // ensure the ed's are gone regardless of list-cleanup
2272 for (std::vector<pkgAcqIndexMergeDiffs *>::const_iterator I = allPatches->begin();
2273 I != allPatches->end(); ++I)
ab53c018 2274 {
dcbbb14d 2275 std::string const PartialFile = GetPartialFileNameFromURI(Target.URI);
36795154 2276 std::string const patch = GetMergeDiffsPatchFileName(PartialFile, (*I)->patch.file);
448c38bd 2277 unlink(patch.c_str());
b3d44315 2278 }
448c38bd 2279 unlink(FinalFile.c_str());
e1430400 2280
448c38bd
DK
2281 // all set and done
2282 Complete = true;
2283 if(Debug)
2284 std::clog << "allDone: " << DestFile << "\n" << std::endl;
b3d44315
MV
2285 }
2286}
92fcbfc1 2287 /*}}}*/
36795154
DK
2288std::string pkgAcqIndexMergeDiffs::Custom600Headers() const /*{{{*/
2289{
2290 if(State != StateApplyDiff)
2291 return pkgAcqBaseIndex::Custom600Headers();
2292 std::ostringstream patchhashes;
2293 unsigned int seen_patches = 0;
2294 for (std::vector<pkgAcqIndexMergeDiffs *>::const_iterator I = allPatches->begin();
2295 I != allPatches->end(); ++I)
2296 {
2297 HashStringList const ExpectedHashes = (*I)->patch.patch_hashes;
2298 for (HashStringList::const_iterator hs = ExpectedHashes.begin(); hs != ExpectedHashes.end(); ++hs)
2299 patchhashes << "\nPatch-" << seen_patches << "-" << hs->HashType() << "-Hash: " << hs->HashValue();
2300 ++seen_patches;
2301 }
2302 patchhashes << pkgAcqBaseIndex::Custom600Headers();
2303 return patchhashes.str();
2304}
2305 /*}}}*/
c8a4ce6c 2306pkgAcqIndexMergeDiffs::~pkgAcqIndexMergeDiffs() {}
448c38bd
DK
2307
2308// AcqIndex::AcqIndex - Constructor /*{{{*/
2309pkgAcqIndex::pkgAcqIndex(pkgAcquire * const Owner,
3d8232bf 2310 pkgAcqMetaClearSig * const TransactionManager,
e8afd168 2311 IndexTarget const &Target)
6c55f07a 2312 : pkgAcqBaseIndex(Owner, TransactionManager, Target), d(NULL), Stage(STAGE_DOWNLOAD)
b3d44315 2313{
448c38bd
DK
2314 // autoselect the compression method
2315 AutoSelectCompression();
dcbbb14d 2316 Init(Target.URI, Target.Description, Target.ShortDesc);
ce424cd4 2317
448c38bd
DK
2318 if(_config->FindB("Debug::Acquire::Transaction", false) == true)
2319 std::clog << "New pkgIndex with TransactionManager "
2320 << TransactionManager << std::endl;
2321}
2322 /*}}}*/
2323// AcqIndex::AutoSelectCompression - Select compression /*{{{*/
2324void pkgAcqIndex::AutoSelectCompression()
2325{
2326 std::vector<std::string> types = APT::Configuration::getCompressionTypes();
2327 CompressionExtensions = "";
dcbbb14d 2328 if (TransactionManager->MetaIndexParser != NULL && TransactionManager->MetaIndexParser->Exists(Target.MetaKey))
ce424cd4 2329 {
448c38bd
DK
2330 for (std::vector<std::string>::const_iterator t = types.begin();
2331 t != types.end(); ++t)
2332 {
dcbbb14d 2333 std::string CompressedMetaKey = string(Target.MetaKey).append(".").append(*t);
448c38bd
DK
2334 if (*t == "uncompressed" ||
2335 TransactionManager->MetaIndexParser->Exists(CompressedMetaKey) == true)
2336 CompressionExtensions.append(*t).append(" ");
2337 }
ce424cd4 2338 }
448c38bd 2339 else
b3d44315 2340 {
448c38bd
DK
2341 for (std::vector<std::string>::const_iterator t = types.begin(); t != types.end(); ++t)
2342 CompressionExtensions.append(*t).append(" ");
b3d44315 2343 }
448c38bd
DK
2344 if (CompressionExtensions.empty() == false)
2345 CompressionExtensions.erase(CompressionExtensions.end()-1);
2346}
2347 /*}}}*/
2348// AcqIndex::Init - defered Constructor /*{{{*/
2349void pkgAcqIndex::Init(string const &URI, string const &URIDesc,
2350 string const &ShortDesc)
2351{
2352 Stage = STAGE_DOWNLOAD;
b3d44315 2353
448c38bd 2354 DestFile = GetPartialFileNameFromURI(URI);
b3d44315 2355
448c38bd
DK
2356 size_t const nextExt = CompressionExtensions.find(' ');
2357 if (nextExt == std::string::npos)
b3d44315 2358 {
448c38bd
DK
2359 CurrentCompressionExtension = CompressionExtensions;
2360 CompressionExtensions.clear();
b3d44315 2361 }
448c38bd
DK
2362 else
2363 {
2364 CurrentCompressionExtension = CompressionExtensions.substr(0, nextExt);
2365 CompressionExtensions = CompressionExtensions.substr(nextExt+1);
1ddb8596
DK
2366 }
2367
448c38bd 2368 if (CurrentCompressionExtension == "uncompressed")
6bf93605 2369 {
448c38bd 2370 Desc.URI = URI;
6bf93605 2371 }
448c38bd
DK
2372 else if (unlikely(CurrentCompressionExtension.empty()))
2373 return;
2374 else
b3d44315 2375 {
448c38bd
DK
2376 Desc.URI = URI + '.' + CurrentCompressionExtension;
2377 DestFile = DestFile + '.' + CurrentCompressionExtension;
b3d44315
MV
2378 }
2379
448c38bd
DK
2380 if(TransactionManager->MetaIndexParser != NULL)
2381 InitByHashIfNeeded();
2382
2383 Desc.Description = URIDesc;
2384 Desc.Owner = this;
2385 Desc.ShortDesc = ShortDesc;
2386
2387 QueueURI(Desc);
2388}
2389 /*}}}*/
2390// AcqIndex::AdjustForByHash - modify URI for by-hash support /*{{{*/
2391void pkgAcqIndex::InitByHashIfNeeded()
2392{
2393 // TODO:
2394 // - (maybe?) add support for by-hash into the sources.list as flag
2395 // - make apt-ftparchive generate the hashes (and expire?)
2396 std::string HostKnob = "APT::Acquire::" + ::URI(Desc.URI).Host + "::By-Hash";
2397 if(_config->FindB("APT::Acquire::By-Hash", false) == true ||
2398 _config->FindB(HostKnob, false) == true ||
2399 TransactionManager->MetaIndexParser->GetSupportsAcquireByHash())
b3d44315 2400 {
448c38bd
DK
2401 HashStringList const Hashes = GetExpectedHashes();
2402 if(Hashes.usable())
b3d44315 2403 {
448c38bd
DK
2404 // FIXME: should we really use the best hash here? or a fixed one?
2405 HashString const * const TargetHash = Hashes.find("");
2406 std::string const ByHash = "/by-hash/" + TargetHash->HashType() + "/" + TargetHash->HashValue();
2407 size_t const trailing_slash = Desc.URI.find_last_of("/");
2408 Desc.URI = Desc.URI.replace(
2409 trailing_slash,
2410 Desc.URI.substr(trailing_slash+1).size()+1,
2411 ByHash);
2412 } else {
2413 _error->Warning(
2414 "Fetching ByHash requested but can not find record for %s",
2415 GetMetaKey().c_str());
b3d44315
MV
2416 }
2417 }
b3d44315 2418}
92fcbfc1 2419 /*}}}*/
448c38bd
DK
2420// AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
2421// ---------------------------------------------------------------------
2422/* The only header we use is the last-modified header. */
2423string pkgAcqIndex::Custom600Headers() const
b3d44315 2424{
448c38bd 2425 string Final = GetFinalFilename();
c5fced38 2426
448c38bd
DK
2427 string msg = "\nIndex-File: true";
2428 struct stat Buf;
2429 if (stat(Final.c_str(),&Buf) == 0)
2430 msg += "\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
1d970e6c 2431
dcbbb14d 2432 if(Target.IsOptional)
448c38bd
DK
2433 msg += "\nFail-Ignore: true";
2434
2435 return msg;
b3d44315 2436}
681d76d0 2437 /*}}}*/
448c38bd
DK
2438// AcqIndex::Failed - getting the indexfile failed /*{{{*/
2439void pkgAcqIndex::Failed(string const &Message,pkgAcquire::MethodConfig const * const Cnf)
56472095 2440{
448c38bd
DK
2441 Item::Failed(Message,Cnf);
2442
2443 // authorisation matches will not be fixed by other compression types
2444 if (Status != StatAuthError)
2445 {
2446 if (CompressionExtensions.empty() == false)
2447 {
dcbbb14d 2448 Init(Target.URI, Desc.Description, Desc.ShortDesc);
448c38bd
DK
2449 Status = StatIdle;
2450 return;
2451 }
2452 }
2453
dcbbb14d 2454 if(Target.IsOptional && GetExpectedHashes().empty() && Stage == STAGE_DOWNLOAD)
448c38bd
DK
2455 Status = StatDone;
2456 else
2457 TransactionManager->AbortTransaction();
56472095 2458}
8267fbd9 2459 /*}}}*/
448c38bd
DK
2460// AcqIndex::ReverifyAfterIMS - Reverify index after an ims-hit /*{{{*/
2461void pkgAcqIndex::ReverifyAfterIMS()
fe0f7911 2462{
448c38bd
DK
2463 // update destfile to *not* include the compression extension when doing
2464 // a reverify (as its uncompressed on disk already)
653ef26c 2465 DestFile = GetCompressedFileName(Target, GetPartialFileNameFromURI(Target.URI), CurrentCompressionExtension);
448c38bd
DK
2466
2467 // copy FinalFile into partial/ so that we check the hash again
2468 string FinalFile = GetFinalFilename();
2469 Stage = STAGE_DECOMPRESS_AND_VERIFY;
2470 Desc.URI = "copy:" + FinalFile;
2471 QueueURI(Desc);
fe0f7911
DK
2472}
2473 /*}}}*/
448c38bd
DK
2474// AcqIndex::Done - Finished a fetch /*{{{*/
2475// ---------------------------------------------------------------------
2476/* This goes through a number of states.. On the initial fetch the
2477 method could possibly return an alternate filename which points
2478 to the uncompressed version of the file. If this is so the file
2479 is copied into the partial directory. In all other cases the file
2480 is decompressed with a compressed uri. */
2481void pkgAcqIndex::Done(string const &Message,
2482 HashStringList const &Hashes,
2483 pkgAcquire::MethodConfig const * const Cfg)
8d6c5839 2484{
448c38bd
DK
2485 Item::Done(Message,Hashes,Cfg);
2486
2487 switch(Stage)
2488 {
2489 case STAGE_DOWNLOAD:
2490 StageDownloadDone(Message, Hashes, Cfg);
2491 break;
2492 case STAGE_DECOMPRESS_AND_VERIFY:
2493 StageDecompressDone(Message, Hashes, Cfg);
2494 break;
2495 }
8d6c5839
MV
2496}
2497 /*}}}*/
448c38bd
DK
2498// AcqIndex::StageDownloadDone - Queue for decompress and verify /*{{{*/
2499void pkgAcqIndex::StageDownloadDone(string const &Message, HashStringList const &,
2500 pkgAcquire::MethodConfig const * const)
6bf93605 2501{
448c38bd 2502 Complete = true;
6bf93605 2503
448c38bd
DK
2504 // Handle the unzipd case
2505 string FileName = LookupTag(Message,"Alt-Filename");
2506 if (FileName.empty() == false)
6bf93605 2507 {
448c38bd
DK
2508 Stage = STAGE_DECOMPRESS_AND_VERIFY;
2509 Local = true;
2510 DestFile += ".decomp";
2511 Desc.URI = "copy:" + FileName;
2512 QueueURI(Desc);
2513 SetActiveSubprocess("copy");
2514 return;
6bf93605 2515 }
03aa0847 2516
448c38bd
DK
2517 FileName = LookupTag(Message,"Filename");
2518 if (FileName.empty() == true)
e84d3803 2519 {
448c38bd
DK
2520 Status = StatError;
2521 ErrorText = "Method gave a blank filename";
e84d3803 2522 }
f3097647 2523
448c38bd
DK
2524 // Methods like e.g. "file:" will give us a (compressed) FileName that is
2525 // not the "DestFile" we set, in this case we uncompress from the local file
08ea7806 2526 if (FileName != DestFile && RealFileExists(DestFile) == false)
448c38bd
DK
2527 Local = true;
2528 else
2529 EraseFileName = FileName;
2530
2531 // we need to verify the file against the current Release file again
2532 // on if-modfied-since hit to avoid a stale attack against us
2533 if(StringToBool(LookupTag(Message,"IMS-Hit"),false) == true)
f3097647 2534 {
448c38bd
DK
2535 // The files timestamp matches, reverify by copy into partial/
2536 EraseFileName = "";
2537 ReverifyAfterIMS();
f3097647
MV
2538 return;
2539 }
448c38bd 2540
653ef26c
DK
2541 // If we want compressed indexes, just copy in place for hash verification
2542 if (Target.KeepCompressed == true)
6bf93605 2543 {
dcbbb14d 2544 DestFile = GetPartialFileNameFromURI(Target.URI + '.' + CurrentCompressionExtension);
448c38bd
DK
2545 EraseFileName = "";
2546 Stage = STAGE_DECOMPRESS_AND_VERIFY;
2547 Desc.URI = "copy:" + FileName;
2548 QueueURI(Desc);
2549 SetActiveSubprocess("copy");
2550 return;
2551 }
2552
2553 // get the binary name for your used compression type
2554 string decompProg;
2555 if(CurrentCompressionExtension == "uncompressed")
2556 decompProg = "copy";
2557 else
2558 decompProg = _config->Find(string("Acquire::CompressionTypes::").append(CurrentCompressionExtension),"");
2559 if(decompProg.empty() == true)
2560 {
2561 _error->Error("Unsupported extension: %s", CurrentCompressionExtension.c_str());
2562 return;
6bf93605 2563 }
448c38bd
DK
2564
2565 // queue uri for the next stage
2566 Stage = STAGE_DECOMPRESS_AND_VERIFY;
2567 DestFile += ".decomp";
2568 Desc.URI = decompProg + ":" + FileName;
2569 QueueURI(Desc);
2570 SetActiveSubprocess(decompProg);
a9bb651a
MV
2571}
2572 /*}}}*/
448c38bd 2573// AcqIndex::StageDecompressDone - Final verification /*{{{*/
4cd86fc6 2574void pkgAcqIndex::StageDecompressDone(string const &,
448c38bd 2575 HashStringList const &,
4cd86fc6 2576 pkgAcquire::MethodConfig const * const)
a9bb651a 2577{
448c38bd
DK
2578 // Done, queue for rename on transaction finished
2579 TransactionManager->TransactionStageCopy(this, DestFile, GetFinalFilename());
448c38bd 2580 return;
fe0f7911
DK
2581}
2582 /*}}}*/
c8a4ce6c 2583pkgAcqIndex::~pkgAcqIndex() {}
448c38bd
DK
2584
2585
03e39e59
AL
2586// AcqArchive::AcqArchive - Constructor /*{{{*/
2587// ---------------------------------------------------------------------
17caf1b1
AL
2588/* This just sets up the initial fetch environment and queues the first
2589 possibilitiy */
448c38bd
DK
2590pkgAcqArchive::pkgAcqArchive(pkgAcquire * const Owner,pkgSourceList * const Sources,
2591 pkgRecords * const Recs,pkgCache::VerIterator const &Version,
30e1eab5 2592 string &StoreFilename) :
6c55f07a 2593 Item(Owner), d(NULL), LocalSource(false), Version(Version), Sources(Sources), Recs(Recs),
448c38bd 2594 StoreFilename(StoreFilename), Vf(Version.FileList()),
b3d44315 2595 Trusted(false)
03e39e59 2596{
7d8afa39 2597 Retries = _config->FindI("Acquire::Retries",0);
813c8eea
AL
2598
2599 if (Version.Arch() == 0)
bdae53f1 2600 {
d1f1f6a8 2601 _error->Error(_("I wasn't able to locate a file for the %s package. "
7a3c2ab0
AL
2602 "This might mean you need to manually fix this package. "
2603 "(due to missing arch)"),
40f8a8ba 2604 Version.ParentPkg().FullName().c_str());
bdae53f1
AL
2605 return;
2606 }
813c8eea 2607
b2e465d6
AL
2608 /* We need to find a filename to determine the extension. We make the
2609 assumption here that all the available sources for this version share
2610 the same extension.. */
2611 // Skip not source sources, they do not have file fields.
69c2ecbd 2612 for (; Vf.end() == false; ++Vf)
b2e465d6 2613 {
b07aeb1a 2614 if (Vf.File().Flagged(pkgCache::Flag::NotSource))
b2e465d6
AL
2615 continue;
2616 break;
2617 }
2618
2619 // Does not really matter here.. we are going to fail out below
2620 if (Vf.end() != true)
2621 {
2622 // If this fails to get a file name we will bomb out below.
2623 pkgRecords::Parser &Parse = Recs->Lookup(Vf);
2624 if (_error->PendingError() == true)
2625 return;
2626
2627 // Generate the final file name as: package_version_arch.foo
2628 StoreFilename = QuoteString(Version.ParentPkg().Name(),"_:") + '_' +
2629 QuoteString(Version.VerStr(),"_:") + '_' +
2630 QuoteString(Version.Arch(),"_:.") +
2631 "." + flExtension(Parse.FileName());
2632 }
b3d44315
MV
2633
2634 // check if we have one trusted source for the package. if so, switch
6c34ccca
DK
2635 // to "TrustedOnly" mode - but only if not in AllowUnauthenticated mode
2636 bool const allowUnauth = _config->FindB("APT::Get::AllowUnauthenticated", false);
2637 bool const debugAuth = _config->FindB("Debug::pkgAcquire::Auth", false);
2638 bool seenUntrusted = false;
f7f0d6c7 2639 for (pkgCache::VerFileIterator i = Version.FileList(); i.end() == false; ++i)
b3d44315
MV
2640 {
2641 pkgIndexFile *Index;
2642 if (Sources->FindIndex(i.File(),Index) == false)
2643 continue;
6c34ccca
DK
2644
2645 if (debugAuth == true)
b3d44315 2646 std::cerr << "Checking index: " << Index->Describe()
6c34ccca
DK
2647 << "(Trusted=" << Index->IsTrusted() << ")" << std::endl;
2648
2649 if (Index->IsTrusted() == true)
2650 {
b3d44315 2651 Trusted = true;
6c34ccca
DK
2652 if (allowUnauth == false)
2653 break;
b3d44315 2654 }
6c34ccca
DK
2655 else
2656 seenUntrusted = true;
b3d44315
MV
2657 }
2658
a3371852
MV
2659 // "allow-unauthenticated" restores apts old fetching behaviour
2660 // that means that e.g. unauthenticated file:// uris are higher
2661 // priority than authenticated http:// uris
6c34ccca 2662 if (allowUnauth == true && seenUntrusted == true)
a3371852
MV
2663 Trusted = false;
2664
03e39e59 2665 // Select a source
b185acc2 2666 if (QueueNext() == false && _error->PendingError() == false)
d57f6084
DK
2667 _error->Error(_("Can't find a source to download version '%s' of '%s'"),
2668 Version.VerStr(), Version.ParentPkg().FullName(false).c_str());
b185acc2
AL
2669}
2670 /*}}}*/
2671// AcqArchive::QueueNext - Queue the next file source /*{{{*/
2672// ---------------------------------------------------------------------
17caf1b1
AL
2673/* This queues the next available file version for download. It checks if
2674 the archive is already available in the cache and stashs the MD5 for
2675 checking later. */
b185acc2 2676bool pkgAcqArchive::QueueNext()
a722b2c5 2677{
f7f0d6c7 2678 for (; Vf.end() == false; ++Vf)
03e39e59 2679 {
448c38bd 2680 pkgCache::PkgFileIterator const PkgF = Vf.File();
03e39e59 2681 // Ignore not source sources
b07aeb1a 2682 if (PkgF.Flagged(pkgCache::Flag::NotSource))
03e39e59
AL
2683 continue;
2684
2685 // Try to cross match against the source list
b2e465d6 2686 pkgIndexFile *Index;
448c38bd 2687 if (Sources->FindIndex(PkgF, Index) == false)
b2e465d6 2688 continue;
b07aeb1a 2689 LocalSource = PkgF.Flagged(pkgCache::Flag::LocalSource);
448c38bd 2690
b3d44315
MV
2691 // only try to get a trusted package from another source if that source
2692 // is also trusted
2693 if(Trusted && !Index->IsTrusted())
2694 continue;
2695
03e39e59
AL
2696 // Grab the text package record
2697 pkgRecords::Parser &Parse = Recs->Lookup(Vf);
2698 if (_error->PendingError() == true)
b185acc2 2699 return false;
b3501edb 2700
b2e465d6 2701 string PkgFile = Parse.FileName();
b3501edb
DK
2702 ExpectedHashes = Parse.Hashes();
2703
03e39e59 2704 if (PkgFile.empty() == true)
b2e465d6
AL
2705 return _error->Error(_("The package index files are corrupted. No Filename: "
2706 "field for package %s."),
2707 Version.ParentPkg().Name());
a6568219 2708
b3d44315
MV
2709 Desc.URI = Index->ArchiveURI(PkgFile);
2710 Desc.Description = Index->ArchiveInfo(Version);
2711 Desc.Owner = this;
40f8a8ba 2712 Desc.ShortDesc = Version.ParentPkg().FullName(true);
b3d44315 2713
17caf1b1 2714 // See if we already have the file. (Legacy filenames)
a6568219
AL
2715 FileSize = Version->Size;
2716 string FinalFile = _config->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile);
2717 struct stat Buf;
2718 if (stat(FinalFile.c_str(),&Buf) == 0)
2719 {
2720 // Make sure the size matches
73da43e9 2721 if ((unsigned long long)Buf.st_size == Version->Size)
a6568219
AL
2722 {
2723 Complete = true;
2724 Local = true;
2725 Status = StatDone;
30e1eab5 2726 StoreFilename = DestFile = FinalFile;
b185acc2 2727 return true;
a6568219
AL
2728 }
2729
6b1ff003
AL
2730 /* Hmm, we have a file and its size does not match, this means it is
2731 an old style mismatched arch */
a6568219
AL
2732 unlink(FinalFile.c_str());
2733 }
17caf1b1
AL
2734
2735 // Check it again using the new style output filenames
2736 FinalFile = _config->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename);
2737 if (stat(FinalFile.c_str(),&Buf) == 0)
2738 {
2739 // Make sure the size matches
73da43e9 2740 if ((unsigned long long)Buf.st_size == Version->Size)
17caf1b1
AL
2741 {
2742 Complete = true;
2743 Local = true;
2744 Status = StatDone;
2745 StoreFilename = DestFile = FinalFile;
2746 return true;
2747 }
2748
1e3f4083 2749 /* Hmm, we have a file and its size does not match, this shouldn't
17caf1b1
AL
2750 happen.. */
2751 unlink(FinalFile.c_str());
2752 }
2753
2754 DestFile = _config->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename);
6b1ff003
AL
2755
2756 // Check the destination file
2757 if (stat(DestFile.c_str(),&Buf) == 0)
2758 {
2759 // Hmm, the partial file is too big, erase it
73da43e9 2760 if ((unsigned long long)Buf.st_size > Version->Size)
6b1ff003
AL
2761 unlink(DestFile.c_str());
2762 else
2763 PartialSize = Buf.st_size;
2764 }
de31189f
DK
2765
2766 // Disables download of archives - useful if no real installation follows,
2767 // e.g. if we are just interested in proposed installation order
2768 if (_config->FindB("Debug::pkgAcqArchive::NoQueue", false) == true)
2769 {
2770 Complete = true;
2771 Local = true;
2772 Status = StatDone;
2773 StoreFilename = DestFile = FinalFile;
2774 return true;
2775 }
2776
03e39e59 2777 // Create the item
b2e465d6 2778 Local = false;
03e39e59 2779 QueueURI(Desc);
b185acc2 2780
f7f0d6c7 2781 ++Vf;
b185acc2 2782 return true;
03e39e59 2783 }
b185acc2
AL
2784 return false;
2785}
03e39e59
AL
2786 /*}}}*/
2787// AcqArchive::Done - Finished fetching /*{{{*/
2788// ---------------------------------------------------------------------
2789/* */
448c38bd
DK
2790void pkgAcqArchive::Done(string const &Message, HashStringList const &Hashes,
2791 pkgAcquire::MethodConfig const * const Cfg)
03e39e59 2792{
448c38bd 2793 Item::Done(Message, Hashes, Cfg);
a6568219
AL
2794
2795 // Grab the output filename
03e39e59
AL
2796 string FileName = LookupTag(Message,"Filename");
2797 if (FileName.empty() == true)
2798 {
2799 Status = StatError;
2800 ErrorText = "Method gave a blank filename";
2801 return;
2802 }
a6568219 2803
30e1eab5 2804 // Reference filename
08ea7806 2805 if (DestFile != FileName && RealFileExists(DestFile) == false)
a6568219 2806 {
30e1eab5 2807 StoreFilename = DestFile = FileName;
a6568219 2808 Local = true;
5684f71f 2809 Complete = true;
a6568219
AL
2810 return;
2811 }
5684f71f 2812
a6568219 2813 // Done, move it into position
295d848b 2814 string const FinalFile = GetFinalFilename();
a6568219 2815 Rename(DestFile,FinalFile);
30e1eab5 2816 StoreFilename = DestFile = FinalFile;
03e39e59
AL
2817 Complete = true;
2818}
2819 /*}}}*/
db890fdb
AL
2820// AcqArchive::Failed - Failure handler /*{{{*/
2821// ---------------------------------------------------------------------
2822/* Here we try other sources */
448c38bd 2823void pkgAcqArchive::Failed(string const &Message,pkgAcquire::MethodConfig const * const Cnf)
db890fdb 2824{
03aa0847
DK
2825 Item::Failed(Message,Cnf);
2826
448c38bd 2827 /* We don't really want to retry on failed media swaps, this prevents
b2e465d6
AL
2828 that. An interesting observation is that permanent failures are not
2829 recorded. */
448c38bd 2830 if (Cnf->Removable == true &&
b2e465d6
AL
2831 StringToBool(LookupTag(Message,"Transient-Failure"),false) == true)
2832 {
2833 // Vf = Version.FileList();
f7f0d6c7 2834 while (Vf.end() == false) ++Vf;
b2e465d6 2835 StoreFilename = string();
b2e465d6
AL
2836 return;
2837 }
03aa0847
DK
2838
2839 Status = StatIdle;
db890fdb 2840 if (QueueNext() == false)
7d8afa39
AL
2841 {
2842 // This is the retry counter
2843 if (Retries != 0 &&
2844 Cnf->LocalOnly == false &&
2845 StringToBool(LookupTag(Message,"Transient-Failure"),false) == true)
2846 {
2847 Retries--;
2848 Vf = Version.FileList();
2849 if (QueueNext() == true)
2850 return;
2851 }
03aa0847 2852
9dbb421f 2853 StoreFilename = string();
03aa0847 2854 Status = StatError;
7d8afa39 2855 }
db890fdb
AL
2856}
2857 /*}}}*/
448c38bd 2858APT_PURE bool pkgAcqArchive::IsTrusted() const /*{{{*/
b3d44315
MV
2859{
2860 return Trusted;
2861}
92fcbfc1 2862 /*}}}*/
448c38bd 2863void pkgAcqArchive::Finished() /*{{{*/
ab559b35
AL
2864{
2865 if (Status == pkgAcquire::Item::StatDone &&
2866 Complete == true)
2867 return;
2868 StoreFilename = string();
2869}
2870 /*}}}*/
448c38bd
DK
2871std::string pkgAcqArchive::DescURI() const /*{{{*/
2872{
2873 return Desc.URI;
2874}
2875 /*}}}*/
2876std::string pkgAcqArchive::ShortDesc() const /*{{{*/
2877{
2878 return Desc.ShortDesc;
2879}
2880 /*}}}*/
c8a4ce6c 2881pkgAcqArchive::~pkgAcqArchive() {}
448c38bd 2882
d56e2917
DK
2883// AcqChangelog::pkgAcqChangelog - Constructors /*{{{*/
2884pkgAcqChangelog::pkgAcqChangelog(pkgAcquire * const Owner, pkgCache::VerIterator const &Ver,
2885 std::string const &DestDir, std::string const &DestFilename) :
2886 pkgAcquire::Item(Owner), d(NULL), SrcName(Ver.SourcePkgName()), SrcVersion(Ver.SourceVerStr())
2887{
2888 Desc.URI = URI(Ver);
2889 Init(DestDir, DestFilename);
2890}
2891// some parameters are char* here as they come likely from char* interfaces – which can also return NULL
2892pkgAcqChangelog::pkgAcqChangelog(pkgAcquire * const Owner, pkgCache::RlsFileIterator const &RlsFile,
2893 char const * const Component, char const * const SrcName, char const * const SrcVersion,
2894 const string &DestDir, const string &DestFilename) :
2895 pkgAcquire::Item(Owner), d(NULL), SrcName(SrcName), SrcVersion(SrcVersion)
2896{
2897 Desc.URI = URI(RlsFile, Component, SrcName, SrcVersion);
2898 Init(DestDir, DestFilename);
2899}
2900pkgAcqChangelog::pkgAcqChangelog(pkgAcquire * const Owner,
2901 std::string const &URI, char const * const SrcName, char const * const SrcVersion,
2902 const string &DestDir, const string &DestFilename) :
2903 pkgAcquire::Item(Owner), d(NULL), SrcName(SrcName), SrcVersion(SrcVersion)
2904{
2905 Desc.URI = URI;
2906 Init(DestDir, DestFilename);
2907}
2908void pkgAcqChangelog::Init(std::string const &DestDir, std::string const &DestFilename)
2909{
2910 if (Desc.URI.empty())
2911 {
2912 Status = StatError;
2913 // TRANSLATOR: %s=%s is sourcename=sourceversion, e.g. apt=1.1
2914 strprintf(ErrorText, _("Changelog unavailable for %s=%s"), SrcName.c_str(), SrcVersion.c_str());
2915 // Let the error message print something sensible rather than "Failed to fetch /"
2916 if (DestFilename.empty())
2917 DestFile = SrcName + ".changelog";
2918 else
2919 DestFile = DestFilename;
2920 Desc.URI = "changelog:/" + DestFile;
2921 return;
2922 }
2923
2924 if (DestDir.empty())
2925 {
2926 std::string const systemTemp = GetTempDir();
2927 char tmpname[100];
2928 snprintf(tmpname, sizeof(tmpname), "%s/apt-changelog-XXXXXX", systemTemp.c_str());
2929 if (NULL == mkdtemp(tmpname))
2930 {
2931 _error->Errno("mkdtemp", "mkdtemp failed in changelog acquire of %s %s", SrcName.c_str(), SrcVersion.c_str());
2932 Status = StatError;
2933 return;
2934 }
2935 DestFile = TemporaryDirectory = tmpname;
2936 }
2937 else
2938 DestFile = DestDir;
2939
2940 if (DestFilename.empty())
2941 DestFile = flCombine(DestFile, SrcName + ".changelog");
2942 else
2943 DestFile = flCombine(DestFile, DestFilename);
2944
2945 Desc.ShortDesc = "Changelog";
2946 strprintf(Desc.Description, "%s %s %s Changelog", URI::SiteOnly(Desc.URI).c_str(), SrcName.c_str(), SrcVersion.c_str());
2947 Desc.Owner = this;
2948 QueueURI(Desc);
d56e2917
DK
2949}
2950 /*}}}*/
2951std::string pkgAcqChangelog::URI(pkgCache::VerIterator const &Ver) /*{{{*/
2952{
2953 char const * const SrcName = Ver.SourcePkgName();
2954 char const * const SrcVersion = Ver.SourceVerStr();
2955 pkgCache::PkgFileIterator PkgFile;
2956 // find the first source for this version which promises a changelog
2957 for (pkgCache::VerFileIterator VF = Ver.FileList(); VF.end() == false; ++VF)
2958 {
2959 pkgCache::PkgFileIterator const PF = VF.File();
2960 if (PF.Flagged(pkgCache::Flag::NotSource) || PF->Release == 0)
2961 continue;
2962 PkgFile = PF;
2963 pkgCache::RlsFileIterator const RF = PF.ReleaseFile();
2964 std::string const uri = URI(RF, PF.Component(), SrcName, SrcVersion);
2965 if (uri.empty())
2966 continue;
2967 return uri;
2968 }
2969 return "";
2970}
2971std::string pkgAcqChangelog::URITemplate(pkgCache::RlsFileIterator const &Rls)
2972{
2973 if (Rls.end() == true || (Rls->Label == 0 && Rls->Origin == 0))
2974 return "";
2975 std::string const serverConfig = "Acquire::Changelogs::URI";
2976 std::string server;
2977#define APT_EMPTY_SERVER \
2978 if (server.empty() == false) \
2979 { \
2980 if (server != "no") \
2981 return server; \
2982 return ""; \
2983 }
2984#define APT_CHECK_SERVER(X, Y) \
2985 if (Rls->X != 0) \
2986 { \
2987 std::string const specialServerConfig = serverConfig + "::" + Y + #X + "::" + Rls.X(); \
2988 server = _config->Find(specialServerConfig); \
2989 APT_EMPTY_SERVER \
2990 }
2991 // this way e.g. Debian-Security can fallback to Debian
2992 APT_CHECK_SERVER(Label, "Override::")
2993 APT_CHECK_SERVER(Origin, "Override::")
2994
2995 if (RealFileExists(Rls.FileName()))
2996 {
2997 _error->PushToStack();
2998 FileFd rf;
2999 /* This can be costly. A caller wanting to get millions of URIs might
3000 want to do this on its own once and use Override settings.
3001 We don't do this here as Origin/Label are not as unique as they
3002 should be so this could produce request order-dependent anomalies */
3003 if (OpenMaybeClearSignedFile(Rls.FileName(), rf) == true)
3004 {
3005 pkgTagFile TagFile(&rf, rf.Size());
3006 pkgTagSection Section;
3007 if (TagFile.Step(Section) == true)
3008 server = Section.FindS("Changelogs");
3009 }
3010 _error->RevertToStack();
3011 APT_EMPTY_SERVER
3012 }
3013
3014 APT_CHECK_SERVER(Label, "")
3015 APT_CHECK_SERVER(Origin, "")
3016#undef APT_CHECK_SERVER
3017#undef APT_EMPTY_SERVER
3018 return "";
3019}
3020std::string pkgAcqChangelog::URI(pkgCache::RlsFileIterator const &Rls,
3021 char const * const Component, char const * const SrcName,
3022 char const * const SrcVersion)
3023{
3024 return URI(URITemplate(Rls), Component, SrcName, SrcVersion);
3025}
3026std::string pkgAcqChangelog::URI(std::string const &Template,
3027 char const * const Component, char const * const SrcName,
3028 char const * const SrcVersion)
3029{
3030 if (Template.find("CHANGEPATH") == std::string::npos)
3031 return "";
3032
3033 // the path is: COMPONENT/SRC/SRCNAME/SRCNAME_SRCVER, e.g. main/a/apt/1.1 or contrib/liba/libapt/2.0
3034 std::string Src = SrcName;
3035 std::string path = APT::String::Startswith(SrcName, "lib") ? Src.substr(0, 4) : Src.substr(0,1);
3036 path.append("/").append(Src).append("/");
3037 path.append(Src).append("_").append(StripEpoch(SrcVersion));
3038 // we omit component for releases without one (= flat-style repositories)
3039 if (Component != NULL && strlen(Component) != 0)
3040 path = std::string(Component) + "/" + path;
3041
3042 return SubstVar(Template, "CHANGEPATH", path);
3043}
3044 /*}}}*/
3045// AcqChangelog::Failed - Failure handler /*{{{*/
3046void pkgAcqChangelog::Failed(string const &Message, pkgAcquire::MethodConfig const * const Cnf)
3047{
3048 Item::Failed(Message,Cnf);
3049
3050 std::string errText;
3051 // TRANSLATOR: %s=%s is sourcename=sourceversion, e.g. apt=1.1
3052 strprintf(errText, _("Changelog unavailable for %s=%s"), SrcName.c_str(), SrcVersion.c_str());
3053
3054 // Error is probably something techy like 404 Not Found
3055 if (ErrorText.empty())
3056 ErrorText = errText;
3057 else
3058 ErrorText = errText + " (" + ErrorText + ")";
3059 return;
3060}
3061 /*}}}*/
3062// AcqChangelog::Done - Item downloaded OK /*{{{*/
3063void pkgAcqChangelog::Done(string const &Message,HashStringList const &CalcHashes,
3064 pkgAcquire::MethodConfig const * const Cnf)
3065{
3066 Item::Done(Message,CalcHashes,Cnf);
3067
3068 Complete = true;
3069}
3070 /*}}}*/
3071pkgAcqChangelog::~pkgAcqChangelog() /*{{{*/
3072{
3073 if (TemporaryDirectory.empty() == false)
3074 {
3075 unlink(DestFile.c_str());
3076 rmdir(TemporaryDirectory.c_str());
3077 }
3078}
3079 /*}}}*/
3080
36375005 3081// AcqFile::pkgAcqFile - Constructor /*{{{*/
448c38bd
DK
3082pkgAcqFile::pkgAcqFile(pkgAcquire * const Owner,string const &URI, HashStringList const &Hashes,
3083 unsigned long long const Size,string const &Dsc,string const &ShortDesc,
77278c2b 3084 const string &DestDir, const string &DestFilename,
448c38bd 3085 bool const IsIndexFile) :
6c55f07a 3086 Item(Owner), d(NULL), IsIndexFile(IsIndexFile), ExpectedHashes(Hashes)
36375005 3087{
08cfc005 3088 Retries = _config->FindI("Acquire::Retries",0);
448c38bd 3089
46e00f9d
MV
3090 if(!DestFilename.empty())
3091 DestFile = DestFilename;
3092 else if(!DestDir.empty())
3093 DestFile = DestDir + "/" + flNotDir(URI);
3094 else
3095 DestFile = flNotDir(URI);
3096
36375005
AL
3097 // Create the item
3098 Desc.URI = URI;
3099 Desc.Description = Dsc;
3100 Desc.Owner = this;
3101
3102 // Set the short description to the archive component
3103 Desc.ShortDesc = ShortDesc;
448c38bd 3104
36375005
AL
3105 // Get the transfer sizes
3106 FileSize = Size;
3107 struct stat Buf;
3108 if (stat(DestFile.c_str(),&Buf) == 0)
3109 {
3110 // Hmm, the partial file is too big, erase it
ed9665ae 3111 if ((Size > 0) && (unsigned long long)Buf.st_size > Size)
36375005
AL
3112 unlink(DestFile.c_str());
3113 else
3114 PartialSize = Buf.st_size;
3115 }
092ae175 3116
36375005
AL
3117 QueueURI(Desc);
3118}
3119 /*}}}*/
3120// AcqFile::Done - Item downloaded OK /*{{{*/
448c38bd
DK
3121void pkgAcqFile::Done(string const &Message,HashStringList const &CalcHashes,
3122 pkgAcquire::MethodConfig const * const Cnf)
36375005 3123{
448c38bd 3124 Item::Done(Message,CalcHashes,Cnf);
495e5cb2 3125
36375005
AL
3126 string FileName = LookupTag(Message,"Filename");
3127 if (FileName.empty() == true)
3128 {
3129 Status = StatError;
3130 ErrorText = "Method gave a blank filename";
3131 return;
3132 }
3133
3134 Complete = true;
448c38bd 3135
36375005
AL
3136 // The files timestamp matches
3137 if (StringToBool(LookupTag(Message,"IMS-Hit"),false) == true)
3138 return;
448c38bd 3139
36375005 3140 // We have to copy it into place
08ea7806 3141 if (RealFileExists(DestFile.c_str()) == false)
36375005
AL
3142 {
3143 Local = true;
459681d3
AL
3144 if (_config->FindB("Acquire::Source-Symlinks",true) == false ||
3145 Cnf->Removable == true)
917ae805
AL
3146 {
3147 Desc.URI = "copy:" + FileName;
3148 QueueURI(Desc);
3149 return;
3150 }
448c38bd 3151
83ab33fc
AL
3152 // Erase the file if it is a symlink so we can overwrite it
3153 struct stat St;
3154 if (lstat(DestFile.c_str(),&St) == 0)
3155 {
3156 if (S_ISLNK(St.st_mode) != 0)
3157 unlink(DestFile.c_str());
3158 }
448c38bd 3159
83ab33fc 3160 // Symlink the file
917ae805
AL
3161 if (symlink(FileName.c_str(),DestFile.c_str()) != 0)
3162 {
03aa0847
DK
3163 _error->PushToStack();
3164 _error->Errno("pkgAcqFile::Done", "Symlinking file %s failed", DestFile.c_str());
3165 std::stringstream msg;
3166 _error->DumpErrors(msg);
3167 _error->RevertToStack();
3168 ErrorText = msg.str();
917ae805
AL
3169 Status = StatError;
3170 Complete = false;
448c38bd 3171 }
36375005
AL
3172 }
3173}
3174 /*}}}*/
08cfc005
AL
3175// AcqFile::Failed - Failure handler /*{{{*/
3176// ---------------------------------------------------------------------
3177/* Here we try other sources */
448c38bd 3178void pkgAcqFile::Failed(string const &Message, pkgAcquire::MethodConfig const * const Cnf)
08cfc005 3179{
03aa0847
DK
3180 Item::Failed(Message,Cnf);
3181
08cfc005
AL
3182 // This is the retry counter
3183 if (Retries != 0 &&
3184 Cnf->LocalOnly == false &&
3185 StringToBool(LookupTag(Message,"Transient-Failure"),false) == true)
3186 {
03aa0847 3187 --Retries;
08cfc005 3188 QueueURI(Desc);
03aa0847 3189 Status = StatIdle;
08cfc005
AL
3190 return;
3191 }
03aa0847 3192
08cfc005
AL
3193}
3194 /*}}}*/
448c38bd 3195string pkgAcqFile::Custom600Headers() const /*{{{*/
77278c2b
MV
3196{
3197 if (IsIndexFile)
3198 return "\nIndex-File: true";
61a07c57 3199 return "";
77278c2b
MV
3200}
3201 /*}}}*/
c8a4ce6c 3202pkgAcqFile::~pkgAcqFile() {}