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