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