1 // -*- mode: cpp; mode: fold -*-
3 // $Id: acquire-item.cc,v 1.46.2.9 2004/01/16 18:51:11 mdz Exp $
4 /* ######################################################################
6 Acquire Item - Item to acquire
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.
13 ##################################################################### */
15 // Include Files /*{{{*/
18 #include <apt-pkg/acquire-item.h>
19 #include <apt-pkg/configuration.h>
20 #include <apt-pkg/aptconfiguration.h>
21 #include <apt-pkg/sourcelist.h>
22 #include <apt-pkg/error.h>
23 #include <apt-pkg/strutl.h>
24 #include <apt-pkg/fileutl.h>
25 #include <apt-pkg/sha1.h>
26 #include <apt-pkg/tagfile.h>
27 #include <apt-pkg/indexrecords.h>
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>
53 static void printHashSumComparision(std::string
const &URI
, HashStringList
const &Expected
, HashStringList
const &Actual
) /*{{{*/
55 if (_config
->FindB("Debug::Acquire::HashSumMismatch", false) == false)
57 std::cerr
<< std::endl
<< URI
<< ":" << std::endl
<< " Expected Hash: " << std::endl
;
58 for (HashStringList::const_iterator hs
= Expected
.begin(); hs
!= Expected
.end(); ++hs
)
59 std::cerr
<< "\t- " << hs
->toStr() << std::endl
;
60 std::cerr
<< " Actual Hash: " << std::endl
;
61 for (HashStringList::const_iterator hs
= Actual
.begin(); hs
!= Actual
.end(); ++hs
)
62 std::cerr
<< "\t- " << hs
->toStr() << std::endl
;
65 static std::string
GetPartialFileName(std::string
const &file
) /*{{{*/
67 std::string DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
72 static std::string
GetPartialFileNameFromURI(std::string
const &uri
) /*{{{*/
74 return GetPartialFileName(URItoFileName(uri
));
77 static std::string
GetFinalFileNameFromURI(std::string
const &uri
) /*{{{*/
79 return _config
->FindDir("Dir::State::lists") + URItoFileName(uri
);
82 static std::string
GetCompressedFileName(std::string
const &URI
, std::string
const &Name
, std::string
const &Ext
) /*{{{*/
84 if (Ext
.empty() || Ext
== "uncompressed")
87 // do not reverify cdrom sources as apt-cdrom may rewrite the Packages
88 // file when its doing the indexcopy
89 if (URI
.substr(0,6) == "cdrom:")
92 // adjust DestFile if its compressed on disk
93 if (_config
->FindB("Acquire::GzipIndexes",false) == true)
94 return Name
+ '.' + Ext
;
98 static bool AllowInsecureRepositories(indexRecords
const * const MetaIndexParser
, pkgAcqMetaBase
* const TransactionManager
, pkgAcquire::Item
* const I
) /*{{{*/
100 if(MetaIndexParser
->IsAlwaysTrusted() || _config
->FindB("Acquire::AllowInsecureRepositories") == true)
103 _error
->Error(_("Use --allow-insecure-repositories to force the update"));
104 TransactionManager
->AbortTransaction();
105 I
->Status
= pkgAcquire::Item::StatError
;
110 // all ::HashesRequired and ::GetExpectedHashes implementations /*{{{*/
111 /* ::GetExpectedHashes is abstract and has to be implemented by all subclasses.
112 It is best to implement it as broadly as possible, while ::HashesRequired defaults
113 to true and should be as restrictive as possible for false cases. Note that if
114 a hash is returned by ::GetExpectedHashes it must match. Only if it doesn't
115 ::HashesRequired is called to evaluate if its okay to have no hashes. */
116 APT_CONST
bool pkgAcqTransactionItem::HashesRequired() const
118 /* signed repositories obviously have a parser and good hashes.
119 unsigned repositories, too, as even if we can't trust them for security,
120 we can at least trust them for integrity of the download itself.
121 Only repositories without a Release file can (obviously) not have
122 hashes – and they are very uncommon and strongly discouraged */
123 return TransactionManager
->MetaIndexParser
!= NULL
;
125 HashStringList
pkgAcqTransactionItem::GetExpectedHashes() const
127 return GetExpectedHashesFor(GetMetaKey());
130 APT_CONST
bool pkgAcqMetaBase::HashesRequired() const
132 // Release and co have no hashes 'by design'.
135 HashStringList
pkgAcqMetaBase::GetExpectedHashes() const
137 return HashStringList();
140 APT_CONST
bool pkgAcqIndexDiffs::HashesRequired() const
142 /* FIXME: We have only hashes for uncompressed pdiffs.
143 rred uncompresses them on the fly while parsing.
144 In StateFetchDiff state we also uncompress on the fly for hash check.
145 Hashes are checked while searching for (next) patch to apply. */
148 HashStringList
pkgAcqIndexDiffs::GetExpectedHashes() const
150 return HashStringList();
153 APT_CONST
bool pkgAcqIndexMergeDiffs::HashesRequired() const
155 /* @see #pkgAcqIndexDiffs::HashesRequired, with the difference that
156 we can check the rred result after all patches are applied as
157 we know the expected result rather than potentially apply more patches */
158 return State
== StateApplyDiff
;
160 HashStringList
pkgAcqIndexMergeDiffs::GetExpectedHashes() const
162 if (State
== StateApplyDiff
)
163 return GetExpectedHashesFor(Target
->MetaKey
);
164 return HashStringList();
167 APT_CONST
bool pkgAcqArchive::HashesRequired() const
169 return LocalSource
== false;
171 HashStringList
pkgAcqArchive::GetExpectedHashes() const
173 // figured out while parsing the records
174 return ExpectedHashes
;
177 APT_CONST
bool pkgAcqFile::HashesRequired() const
179 // supplied as parameter at creation time, so the caller decides
180 return ExpectedHashes
.usable();
182 HashStringList
pkgAcqFile::GetExpectedHashes() const
184 return ExpectedHashes
;
187 // Acquire::Item::QueueURI and specialisations from child classes /*{{{*/
188 bool pkgAcquire::Item::QueueURI(pkgAcquire::ItemDesc
&Item
)
190 Owner
->Enqueue(Item
);
193 /* The idea here is that an item isn't queued if it exists on disk and the
194 transition manager was a hit as this means that the files it contains
195 the checksums for can't be updated either (or they are and we are asking
196 for a hashsum mismatch to happen which helps nobody) */
197 bool pkgAcqTransactionItem::QueueURI(pkgAcquire::ItemDesc
&Item
)
199 std::string
const FinalFile
= GetFinalFilename();
200 if (TransactionManager
!= NULL
&& TransactionManager
->IMSHit
== true &&
201 FileExists(FinalFile
) == true)
203 PartialFile
= DestFile
= FinalFile
;
207 return pkgAcquire::Item::QueueURI(Item
);
209 /* The transition manager InRelease itself (or its older sisters-in-law
210 Release & Release.gpg) is always queued as this allows us to rerun gpgv
211 on it to verify that we aren't stalled with old files */
212 bool pkgAcqMetaBase::QueueURI(pkgAcquire::ItemDesc
&Item
)
214 return pkgAcquire::Item::QueueURI(Item
);
216 /* the Diff/Index needs to queue also the up-to-date complete index file
217 to ensure that the list cleaner isn't eating it */
218 bool pkgAcqDiffIndex::QueueURI(pkgAcquire::ItemDesc
&Item
)
220 if (pkgAcqTransactionItem::QueueURI(Item
) == true)
226 // Acquire::Item::GetFinalFilename and specialisations for child classes /*{{{*/
227 std::string
pkgAcquire::Item::GetFinalFilename() const
229 return GetFinalFileNameFromURI(Desc
.URI
);
231 std::string
pkgAcqDiffIndex::GetFinalFilename() const
233 // the logic we inherent from pkgAcqBaseIndex isn't what we need here
234 return pkgAcquire::Item::GetFinalFilename();
236 std::string
pkgAcqIndex::GetFinalFilename() const
238 std::string
const FinalFile
= GetFinalFileNameFromURI(Target
->URI
);
239 return GetCompressedFileName(Target
->URI
, FinalFile
, CurrentCompressionExtension
);
241 std::string
pkgAcqMetaSig::GetFinalFilename() const
243 return GetFinalFileNameFromURI(Target
->URI
);
245 std::string
pkgAcqBaseIndex::GetFinalFilename() const
247 return GetFinalFileNameFromURI(Target
->URI
);
249 std::string
pkgAcqMetaBase::GetFinalFilename() const
251 return GetFinalFileNameFromURI(DataTarget
.URI
);
253 std::string
pkgAcqArchive::GetFinalFilename() const
255 return _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
258 // pkgAcqTransactionItem::GetMetaKey and specialisations for child classes /*{{{*/
259 std::string
pkgAcqTransactionItem::GetMetaKey() const
261 return Target
->MetaKey
;
263 std::string
pkgAcqIndex::GetMetaKey() const
265 if (Stage
== STAGE_DECOMPRESS_AND_VERIFY
|| CurrentCompressionExtension
== "uncompressed")
266 return Target
->MetaKey
;
267 return Target
->MetaKey
+ "." + CurrentCompressionExtension
;
269 std::string
pkgAcqDiffIndex::GetMetaKey() const
271 return Target
->MetaKey
+ ".diff/Index";
274 //pkgAcqTransactionItem::TransactionState and specialisations for child classes /*{{{*/
275 bool pkgAcqTransactionItem::TransactionState(TransactionStates
const state
)
277 bool const Debug
= _config
->FindB("Debug::Acquire::Transaction", false);
280 case TransactionAbort
:
282 std::clog
<< " Cancel: " << DestFile
<< std::endl
;
283 if (Status
== pkgAcquire::Item::StatIdle
)
285 Status
= pkgAcquire::Item::StatDone
;
289 case TransactionCommit
:
290 if(PartialFile
!= "")
293 std::clog
<< "mv " << PartialFile
<< " -> "<< DestFile
<< " # " << DescURI() << std::endl
;
295 Rename(PartialFile
, DestFile
);
298 std::clog
<< "rm " << DestFile
<< " # " << DescURI() << std::endl
;
299 unlink(DestFile
.c_str());
305 bool pkgAcqMetaBase::TransactionState(TransactionStates
const state
)
307 // Do not remove InRelease on IMSHit of Release.gpg [yes, this is very edgecasey]
308 if (TransactionManager
->IMSHit
== false)
309 return pkgAcqTransactionItem::TransactionState(state
);
312 bool pkgAcqIndex::TransactionState(TransactionStates
const state
)
314 if (pkgAcqTransactionItem::TransactionState(state
) == false)
319 case TransactionAbort
:
320 if (Stage
== STAGE_DECOMPRESS_AND_VERIFY
)
322 // keep the compressed file, but drop the decompressed
323 EraseFileName
.clear();
324 if (PartialFile
.empty() == false && flExtension(PartialFile
) == "decomp")
325 unlink(PartialFile
.c_str());
328 case TransactionCommit
:
329 if (EraseFileName
.empty() == false)
330 unlink(EraseFileName
.c_str());
335 bool pkgAcqDiffIndex::TransactionState(TransactionStates
const state
)
337 if (pkgAcqTransactionItem::TransactionState(state
) == false)
342 case TransactionCommit
:
344 case TransactionAbort
:
345 std::string
const Partial
= GetPartialFileNameFromURI(Target
->URI
);
346 unlink(Partial
.c_str());
354 // Acquire::Item::Item - Constructor /*{{{*/
355 APT_IGNORE_DEPRECATED_PUSH
356 pkgAcquire::Item::Item(pkgAcquire
* const Owner
) :
357 FileSize(0), PartialSize(0), Mode(0), Complete(false), Local(false),
358 QueueCounter(0), ExpectedAdditionalItems(0), Owner(Owner
)
363 APT_IGNORE_DEPRECATED_POP
365 // Acquire::Item::~Item - Destructor /*{{{*/
366 pkgAcquire::Item::~Item()
371 std::string
pkgAcquire::Item::Custom600Headers() const /*{{{*/
373 return std::string();
376 std::string
pkgAcquire::Item::ShortDesc() const /*{{{*/
381 APT_CONST
void pkgAcquire::Item::Finished() /*{{{*/
385 APT_PURE pkgAcquire
* pkgAcquire::Item::GetOwner() const /*{{{*/
390 APT_CONST
bool pkgAcquire::Item::IsTrusted() const /*{{{*/
395 // Acquire::Item::Failed - Item failed to download /*{{{*/
396 // ---------------------------------------------------------------------
397 /* We return to an idle state if there are still other queues that could
399 void pkgAcquire::Item::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)
401 if(ErrorText
.empty())
402 ErrorText
= LookupTag(Message
,"Message");
403 UsedMirror
= LookupTag(Message
,"UsedMirror");
404 if (QueueCounter
<= 1)
406 /* This indicates that the file is not available right now but might
407 be sometime later. If we do a retry cycle then this should be
409 if (Cnf
!= NULL
&& Cnf
->LocalOnly
== true &&
410 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
426 case StatTransientNetworkError
:
433 string
const FailReason
= LookupTag(Message
, "FailReason");
434 if (FailReason
== "MaximumSizeExceeded")
435 RenameOnError(MaximumSizeExceeded
);
436 else if (Status
== StatAuthError
)
437 RenameOnError(HashSumMismatch
);
439 // report mirror failure back to LP if we actually use a mirror
440 if (FailReason
.empty() == false)
441 ReportMirrorFailure(FailReason
);
443 ReportMirrorFailure(ErrorText
);
445 if (QueueCounter
> 1)
449 // Acquire::Item::Start - Item has begun to download /*{{{*/
450 // ---------------------------------------------------------------------
451 /* Stash status and the file size. Note that setting Complete means
452 sub-phases of the acquire process such as decompresion are operating */
453 void pkgAcquire::Item::Start(string
const &/*Message*/, unsigned long long const Size
)
455 Status
= StatFetching
;
457 if (FileSize
== 0 && Complete
== false)
461 // Acquire::Item::Done - Item downloaded OK /*{{{*/
462 void pkgAcquire::Item::Done(string
const &Message
, HashStringList
const &Hashes
,
463 pkgAcquire::MethodConfig
const * const /*Cnf*/)
465 // We just downloaded something..
466 string FileName
= LookupTag(Message
,"Filename");
467 UsedMirror
= LookupTag(Message
,"UsedMirror");
468 unsigned long long const downloadedSize
= Hashes
.FileSize();
469 if (downloadedSize
!= 0)
471 if (Complete
== false && !Local
&& FileName
== DestFile
)
474 Owner
->Log
->Fetched(Hashes
.FileSize(),atoi(LookupTag(Message
,"Resume-Point","0").c_str()));
478 FileSize
= downloadedSize
;
481 ErrorText
= string();
482 Owner
->Dequeue(this);
485 // Acquire::Item::Rename - Rename a file /*{{{*/
486 // ---------------------------------------------------------------------
487 /* This helper function is used by a lot of item methods as their final
489 bool pkgAcquire::Item::Rename(string
const &From
,string
const &To
)
491 if (From
== To
|| rename(From
.c_str(),To
.c_str()) == 0)
495 strprintf(S
, _("rename failed, %s (%s -> %s)."), strerror(errno
),
496 From
.c_str(),To
.c_str());
498 if (ErrorText
.empty())
501 ErrorText
= ErrorText
+ ": " + S
;
505 void pkgAcquire::Item::Dequeue() /*{{{*/
507 Owner
->Dequeue(this);
510 bool pkgAcquire::Item::RenameOnError(pkgAcquire::Item::RenameOnErrorState
const error
)/*{{{*/
512 if (RealFileExists(DestFile
))
513 Rename(DestFile
, DestFile
+ ".FAILED");
518 case HashSumMismatch
:
519 errtext
= _("Hash Sum mismatch");
520 Status
= StatAuthError
;
521 ReportMirrorFailure("HashChecksumFailure");
524 errtext
= _("Size mismatch");
525 Status
= StatAuthError
;
526 ReportMirrorFailure("SizeFailure");
529 errtext
= _("Invalid file format");
531 // do not report as usually its not the mirrors fault, but Portal/Proxy
534 errtext
= _("Signature error");
538 errtext
= _("Does not start with a cleartext signature");
541 case MaximumSizeExceeded
:
542 // the method is expected to report a good error for this
546 // no handling here, done by callers
549 if (ErrorText
.empty())
554 void pkgAcquire::Item::SetActiveSubprocess(const std::string
&subprocess
)/*{{{*/
556 ActiveSubprocess
= subprocess
;
557 APT_IGNORE_DEPRECATED(Mode
= ActiveSubprocess
.c_str();)
560 // Acquire::Item::ReportMirrorFailure /*{{{*/
561 void pkgAcquire::Item::ReportMirrorFailure(string
const &FailCode
)
563 // we only act if a mirror was used at all
564 if(UsedMirror
.empty())
567 std::cerr
<< "\nReportMirrorFailure: "
569 << " Uri: " << DescURI()
571 << FailCode
<< std::endl
;
573 string report
= _config
->Find("Methods::Mirror::ProblemReporting",
574 "/usr/lib/apt/apt-report-mirror-failure");
575 if(!FileExists(report
))
578 std::vector
<char const*> Args
;
579 Args
.push_back(report
.c_str());
580 Args
.push_back(UsedMirror
.c_str());
581 Args
.push_back(DescURI().c_str());
582 Args
.push_back(FailCode
.c_str());
583 Args
.push_back(NULL
);
585 pid_t pid
= ExecFork();
588 _error
->Error("ReportMirrorFailure Fork failed");
593 execvp(Args
[0], (char**)Args
.data());
594 std::cerr
<< "Could not exec " << Args
[0] << std::endl
;
597 if(!ExecWait(pid
, "report-mirror-failure"))
599 _error
->Warning("Couldn't report problem to '%s'",
600 _config
->Find("Methods::Mirror::ProblemReporting").c_str());
604 std::string
pkgAcquire::Item::HashSum() const /*{{{*/
606 HashStringList
const hashes
= GetExpectedHashes();
607 HashString
const * const hs
= hashes
.find(NULL
);
608 return hs
!= NULL
? hs
->toStr() : "";
612 pkgAcqTransactionItem::pkgAcqTransactionItem(pkgAcquire
* const Owner
, /*{{{*/
613 pkgAcqMetaBase
* const TransactionManager
, IndexTarget
const * const Target
) :
614 pkgAcquire::Item(Owner
), Target(Target
), TransactionManager(TransactionManager
)
616 if (TransactionManager
!= this)
617 TransactionManager
->Add(this);
620 pkgAcqTransactionItem::~pkgAcqTransactionItem() /*{{{*/
624 HashStringList
pkgAcqTransactionItem::GetExpectedHashesFor(std::string
const MetaKey
) const /*{{{*/
626 if (TransactionManager
->MetaIndexParser
== NULL
)
627 return HashStringList();
628 indexRecords::checkSum
* const R
= TransactionManager
->MetaIndexParser
->Lookup(MetaKey
);
630 return HashStringList();
635 // AcqMetaBase - Constructor /*{{{*/
636 pkgAcqMetaBase::pkgAcqMetaBase(pkgAcquire
* const Owner
,
637 pkgAcqMetaBase
* const TransactionManager
,
638 std::vector
<IndexTarget
*> const * const IndexTargets
,
639 IndexTarget
const &DataTarget
,
640 indexRecords
* const MetaIndexParser
)
641 : pkgAcqTransactionItem(Owner
, TransactionManager
, NULL
), DataTarget(DataTarget
),
642 MetaIndexParser(MetaIndexParser
), LastMetaIndexParser(NULL
), IndexTargets(IndexTargets
),
643 AuthPass(false), IMSHit(false)
647 // AcqMetaBase::Add - Add a item to the current Transaction /*{{{*/
648 void pkgAcqMetaBase::Add(pkgAcqTransactionItem
* const I
)
650 Transaction
.push_back(I
);
653 // AcqMetaBase::AbortTransaction - Abort the current Transaction /*{{{*/
654 void pkgAcqMetaBase::AbortTransaction()
656 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
657 std::clog
<< "AbortTransaction: " << TransactionManager
<< std::endl
;
659 // ensure the toplevel is in error state too
660 for (std::vector
<pkgAcqTransactionItem
*>::iterator I
= Transaction
.begin();
661 I
!= Transaction
.end(); ++I
)
663 (*I
)->TransactionState(TransactionAbort
);
668 // AcqMetaBase::TransactionHasError - Check for errors in Transaction /*{{{*/
669 APT_PURE
bool pkgAcqMetaBase::TransactionHasError() const
671 for (std::vector
<pkgAcqTransactionItem
*>::const_iterator I
= Transaction
.begin();
672 I
!= Transaction
.end(); ++I
)
674 switch((*I
)->Status
) {
675 case StatDone
: break;
676 case StatIdle
: break;
677 case StatAuthError
: return true;
678 case StatError
: return true;
679 case StatTransientNetworkError
: return true;
680 case StatFetching
: break;
686 // AcqMetaBase::CommitTransaction - Commit a transaction /*{{{*/
687 void pkgAcqMetaBase::CommitTransaction()
689 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
690 std::clog
<< "CommitTransaction: " << this << std::endl
;
692 // move new files into place *and* remove files that are not
693 // part of the transaction but are still on disk
694 for (std::vector
<pkgAcqTransactionItem
*>::iterator I
= Transaction
.begin();
695 I
!= Transaction
.end(); ++I
)
697 (*I
)->TransactionState(TransactionCommit
);
702 // AcqMetaBase::TransactionStageCopy - Stage a file for copying /*{{{*/
703 void pkgAcqMetaBase::TransactionStageCopy(pkgAcqTransactionItem
* const I
,
704 const std::string
&From
,
705 const std::string
&To
)
707 I
->PartialFile
= From
;
711 // AcqMetaBase::TransactionStageRemoval - Stage a file for removal /*{{{*/
712 void pkgAcqMetaBase::TransactionStageRemoval(pkgAcqTransactionItem
* const I
,
713 const std::string
&FinalFile
)
716 I
->DestFile
= FinalFile
;
719 // AcqMetaBase::GenerateAuthWarning - Check gpg authentication error /*{{{*/
720 bool pkgAcqMetaBase::CheckStopAuthentication(pkgAcquire::Item
* const I
, const std::string
&Message
)
722 // FIXME: this entire function can do now that we disallow going to
723 // a unauthenticated state and can cleanly rollback
725 string
const Final
= I
->GetFinalFilename();
726 if(FileExists(Final
))
728 I
->Status
= StatTransientNetworkError
;
729 _error
->Warning(_("An error occurred during the signature "
730 "verification. The repository is not updated "
731 "and the previous index files will be used. "
732 "GPG error: %s: %s\n"),
733 Desc
.Description
.c_str(),
734 LookupTag(Message
,"Message").c_str());
735 RunScripts("APT::Update::Auth-Failure");
737 } else if (LookupTag(Message
,"Message").find("NODATA") != string::npos
) {
738 /* Invalid signature file, reject (LP: #346386) (Closes: #627642) */
739 _error
->Error(_("GPG error: %s: %s"),
740 Desc
.Description
.c_str(),
741 LookupTag(Message
,"Message").c_str());
742 I
->Status
= StatError
;
745 _error
->Warning(_("GPG error: %s: %s"),
746 Desc
.Description
.c_str(),
747 LookupTag(Message
,"Message").c_str());
749 // gpgv method failed
750 ReportMirrorFailure("GPGFailure");
754 // AcqMetaBase::Custom600Headers - Get header for AcqMetaBase /*{{{*/
755 // ---------------------------------------------------------------------
756 string
pkgAcqMetaBase::Custom600Headers() const
758 std::string Header
= "\nIndex-File: true";
759 std::string MaximumSize
;
760 strprintf(MaximumSize
, "\nMaximum-Size: %i",
761 _config
->FindI("Acquire::MaxReleaseFileSize", 10*1000*1000));
762 Header
+= MaximumSize
;
764 string
const FinalFile
= GetFinalFilename();
767 if (stat(FinalFile
.c_str(),&Buf
) == 0)
768 Header
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
773 // AcqMetaBase::QueueForSignatureVerify /*{{{*/
774 void pkgAcqMetaBase::QueueForSignatureVerify(pkgAcqTransactionItem
* const I
, std::string
const &File
, std::string
const &Signature
)
777 I
->Desc
.URI
= "gpgv:" + Signature
;
780 I
->SetActiveSubprocess("gpgv");
783 // AcqMetaBase::CheckDownloadDone /*{{{*/
784 bool pkgAcqMetaBase::CheckDownloadDone(pkgAcqTransactionItem
* const I
, const std::string
&Message
, HashStringList
const &Hashes
) const
786 // We have just finished downloading a Release file (it is not
789 string
const FileName
= LookupTag(Message
,"Filename");
790 if (FileName
.empty() == true)
792 I
->Status
= StatError
;
793 I
->ErrorText
= "Method gave a blank filename";
797 if (FileName
!= I
->DestFile
)
800 I
->Desc
.URI
= "copy:" + FileName
;
801 I
->QueueURI(I
->Desc
);
805 // make sure to verify against the right file on I-M-S hit
806 bool IMSHit
= StringToBool(LookupTag(Message
,"IMS-Hit"), false);
807 if (IMSHit
== false && Hashes
.usable())
809 // detect IMS-Hits servers haven't detected by Hash comparison
810 std::string
const FinalFile
= I
->GetFinalFilename();
811 if (RealFileExists(FinalFile
) && Hashes
.VerifyFile(FinalFile
) == true)
814 unlink(I
->DestFile
.c_str());
820 // for simplicity, the transaction manager is always InRelease
821 // even if it doesn't exist.
822 if (TransactionManager
!= NULL
)
823 TransactionManager
->IMSHit
= true;
824 I
->PartialFile
= I
->DestFile
= I
->GetFinalFilename();
827 // set Item to complete as the remaining work is all local (verify etc)
833 bool pkgAcqMetaBase::CheckAuthDone(string
const &Message
) /*{{{*/
835 // At this point, the gpgv method has succeeded, so there is a
836 // valid signature from a key in the trusted keyring. We
837 // perform additional verification of its contents, and use them
838 // to verify the indexes we are about to download
840 if (TransactionManager
->IMSHit
== false)
842 // open the last (In)Release if we have it
843 std::string
const FinalFile
= GetFinalFilename();
844 std::string FinalRelease
;
845 std::string FinalInRelease
;
846 if (APT::String::Endswith(FinalFile
, "InRelease"))
848 FinalInRelease
= FinalFile
;
849 FinalRelease
= FinalFile
.substr(0, FinalFile
.length() - strlen("InRelease")) + "Release";
853 FinalInRelease
= FinalFile
.substr(0, FinalFile
.length() - strlen("Release")) + "InRelease";
854 FinalRelease
= FinalFile
;
856 if (RealFileExists(FinalInRelease
) || RealFileExists(FinalRelease
))
858 TransactionManager
->LastMetaIndexParser
= new indexRecords
;
859 _error
->PushToStack();
860 if (RealFileExists(FinalInRelease
))
861 TransactionManager
->LastMetaIndexParser
->Load(FinalInRelease
);
863 TransactionManager
->LastMetaIndexParser
->Load(FinalRelease
);
864 // its unlikely to happen, but if what we have is bad ignore it
865 if (_error
->PendingError())
867 delete TransactionManager
->LastMetaIndexParser
;
868 TransactionManager
->LastMetaIndexParser
= NULL
;
870 _error
->RevertToStack();
874 if (TransactionManager
->MetaIndexParser
->Load(DestFile
) == false)
876 Status
= StatAuthError
;
877 ErrorText
= TransactionManager
->MetaIndexParser
->ErrorText
;
881 if (!VerifyVendor(Message
))
883 Status
= StatAuthError
;
887 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
888 std::cerr
<< "Signature verification succeeded: "
889 << DestFile
<< std::endl
;
891 // Download further indexes with verification
897 void pkgAcqMetaBase::QueueIndexes(bool const verify
) /*{{{*/
899 // at this point the real Items are loaded in the fetcher
900 ExpectedAdditionalItems
= 0;
902 vector
<IndexTarget
*>::const_iterator Target
;
903 for (Target
= IndexTargets
->begin();
904 Target
!= IndexTargets
->end();
907 if (verify
== true && TransactionManager
->MetaIndexParser
->Exists((*Target
)->MetaKey
) == false)
909 // optional target that we do not have in the Release file are skipped
910 if ((*Target
)->IsOptional())
913 Status
= StatAuthError
;
914 strprintf(ErrorText
, _("Unable to find expected entry '%s' in Release file (Wrong sources.list entry or malformed file)"), (*Target
)->MetaKey
.c_str());
918 /* Queue the Index file (Packages, Sources, Translation-$foo
919 (either diff or full packages files, depending
920 on the users option) - we also check if the PDiff Index file is listed
921 in the Meta-Index file. Ideal would be if pkgAcqDiffIndex would test this
922 instead, but passing the required info to it is to much hassle */
923 if(_config
->FindB("Acquire::PDiffs",true) == true && (verify
== false ||
924 TransactionManager
->MetaIndexParser
->Exists((*Target
)->MetaKey
+ ".diff/Index") == true))
925 new pkgAcqDiffIndex(Owner
, TransactionManager
, *Target
);
927 new pkgAcqIndex(Owner
, TransactionManager
, *Target
);
931 bool pkgAcqMetaBase::VerifyVendor(string
const &Message
) /*{{{*/
933 string::size_type pos
;
935 // check for missing sigs (that where not fatal because otherwise we had
938 string msg
= _("There is no public key available for the "
939 "following key IDs:\n");
940 pos
= Message
.find("NO_PUBKEY ");
941 if (pos
!= std::string::npos
)
943 string::size_type start
= pos
+strlen("NO_PUBKEY ");
944 string Fingerprint
= Message
.substr(start
, Message
.find("\n")-start
);
945 missingkeys
+= (Fingerprint
);
947 if(!missingkeys
.empty())
948 _error
->Warning("%s", (msg
+ missingkeys
).c_str());
950 string Transformed
= TransactionManager
->MetaIndexParser
->GetExpectedDist();
952 if (Transformed
== "../project/experimental")
954 Transformed
= "experimental";
957 pos
= Transformed
.rfind('/');
958 if (pos
!= string::npos
)
960 Transformed
= Transformed
.substr(0, pos
);
963 if (Transformed
== ".")
968 if (_config
->FindB("Acquire::Check-Valid-Until", true) == true &&
969 TransactionManager
->MetaIndexParser
->GetValidUntil() > 0) {
970 time_t const invalid_since
= time(NULL
) - TransactionManager
->MetaIndexParser
->GetValidUntil();
971 if (invalid_since
> 0)
975 // TRANSLATOR: The first %s is the URL of the bad Release file, the second is
976 // the time since then the file is invalid - formated in the same way as in
977 // the download progress display (e.g. 7d 3h 42min 1s)
978 _("Release file for %s is expired (invalid since %s). "
979 "Updates for this repository will not be applied."),
980 DataTarget
.URI
.c_str(), TimeToStr(invalid_since
).c_str());
981 if (ErrorText
.empty())
983 return _error
->Error("%s", errmsg
.c_str());
987 /* Did we get a file older than what we have? This is a last minute IMS hit and doubles
988 as a prevention of downgrading us to older (still valid) files */
989 if (TransactionManager
->IMSHit
== false && TransactionManager
->LastMetaIndexParser
!= NULL
&&
990 TransactionManager
->LastMetaIndexParser
->GetDate() > TransactionManager
->MetaIndexParser
->GetDate())
992 TransactionManager
->IMSHit
= true;
993 unlink(DestFile
.c_str());
994 PartialFile
= DestFile
= GetFinalFilename();
995 delete TransactionManager
->MetaIndexParser
;
996 TransactionManager
->MetaIndexParser
= TransactionManager
->LastMetaIndexParser
;
997 TransactionManager
->LastMetaIndexParser
= NULL
;
1000 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1002 std::cerr
<< "Got Codename: " << TransactionManager
->MetaIndexParser
->GetDist() << std::endl
;
1003 std::cerr
<< "Expecting Dist: " << TransactionManager
->MetaIndexParser
->GetExpectedDist() << std::endl
;
1004 std::cerr
<< "Transformed Dist: " << Transformed
<< std::endl
;
1007 if (TransactionManager
->MetaIndexParser
->CheckDist(Transformed
) == false)
1009 // This might become fatal one day
1010 // Status = StatAuthError;
1011 // ErrorText = "Conflicting distribution; expected "
1012 // + MetaIndexParser->GetExpectedDist() + " but got "
1013 // + MetaIndexParser->GetDist();
1015 if (!Transformed
.empty())
1017 _error
->Warning(_("Conflicting distribution: %s (expected %s but got %s)"),
1018 Desc
.Description
.c_str(),
1019 Transformed
.c_str(),
1020 TransactionManager
->MetaIndexParser
->GetDist().c_str());
1028 pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire
* const Owner
, /*{{{*/
1029 IndexTarget
const &ClearsignedTarget
,
1030 IndexTarget
const &DetachedDataTarget
, IndexTarget
const &DetachedSigTarget
,
1031 const vector
<IndexTarget
*>* const IndexTargets
,
1032 indexRecords
* const MetaIndexParser
) :
1033 pkgAcqMetaIndex(Owner
, this, ClearsignedTarget
, DetachedSigTarget
, IndexTargets
, MetaIndexParser
),
1034 ClearsignedTarget(ClearsignedTarget
),
1035 DetachedDataTarget(DetachedDataTarget
), DetachedSigTarget(DetachedSigTarget
)
1037 // index targets + (worst case:) Release/Release.gpg
1038 ExpectedAdditionalItems
= IndexTargets
->size() + 2;
1039 TransactionManager
->Add(this);
1042 pkgAcqMetaClearSig::~pkgAcqMetaClearSig() /*{{{*/
1046 // pkgAcqMetaClearSig::Custom600Headers - Insert custom request headers /*{{{*/
1047 string
pkgAcqMetaClearSig::Custom600Headers() const
1049 string Header
= pkgAcqMetaBase::Custom600Headers();
1050 Header
+= "\nFail-Ignore: true";
1054 // pkgAcqMetaClearSig::Done - We got a file /*{{{*/
1055 class APT_HIDDEN DummyItem
: public pkgAcquire::Item
1057 IndexTarget
const * const Target
;
1059 virtual std::string
DescURI() const {return Target
->URI
;};
1060 virtual HashStringList
GetExpectedHashes() const {return HashStringList();};
1062 DummyItem(pkgAcquire
* const Owner
, IndexTarget
const * const Target
) :
1063 pkgAcquire::Item(Owner
), Target(Target
)
1066 DestFile
= GetFinalFileNameFromURI(Target
->URI
);
1069 void pkgAcqMetaClearSig::Done(std::string
const &Message
,
1070 HashStringList
const &Hashes
,
1071 pkgAcquire::MethodConfig
const * const Cnf
)
1073 Item::Done(Message
, Hashes
, Cnf
);
1075 // if we expect a ClearTextSignature (InRelease), ensure that
1076 // this is what we get and if not fail to queue a
1077 // Release/Release.gpg, see #346386
1078 if (FileExists(DestFile
) && !StartsWithGPGClearTextSignature(DestFile
))
1080 pkgAcquire::Item::Failed(Message
, Cnf
);
1081 RenameOnError(NotClearsigned
);
1082 TransactionManager
->AbortTransaction();
1086 if(AuthPass
== false)
1088 if(CheckDownloadDone(this, Message
, Hashes
) == true)
1089 QueueForSignatureVerify(this, DestFile
, DestFile
);
1092 else if(CheckAuthDone(Message
) == true)
1094 if (TransactionManager
->IMSHit
== false)
1095 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
1096 else if (RealFileExists(GetFinalFilename()) == false)
1098 // We got an InRelease file IMSHit, but we haven't one, which means
1099 // we had a valid Release/Release.gpg combo stepping in, which we have
1100 // to 'acquire' now to ensure list cleanup isn't removing them
1101 new DummyItem(Owner
, &DetachedDataTarget
);
1102 new DummyItem(Owner
, &DetachedSigTarget
);
1107 void pkgAcqMetaClearSig::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
) /*{{{*/
1109 Item::Failed(Message
, Cnf
);
1111 // we failed, we will not get additional items from this method
1112 ExpectedAdditionalItems
= 0;
1114 if (AuthPass
== false)
1116 // Queue the 'old' InRelease file for removal if we try Release.gpg
1117 // as otherwise the file will stay around and gives a false-auth
1118 // impression (CVE-2012-0214)
1119 TransactionManager
->TransactionStageRemoval(this, GetFinalFilename());
1122 new pkgAcqMetaIndex(Owner
, TransactionManager
, DetachedDataTarget
, DetachedSigTarget
, IndexTargets
, TransactionManager
->MetaIndexParser
);
1126 if(CheckStopAuthentication(this, Message
))
1129 _error
->Warning(_("The data from '%s' is not signed. Packages "
1130 "from that repository can not be authenticated."),
1131 ClearsignedTarget
.Description
.c_str());
1133 // No Release file was present, or verification failed, so fall
1134 // back to queueing Packages files without verification
1135 // only allow going further if the users explicitely wants it
1136 if(AllowInsecureRepositories(TransactionManager
->MetaIndexParser
, TransactionManager
, this) == true)
1140 /* InRelease files become Release files, otherwise
1141 * they would be considered as trusted later on */
1142 string
const FinalRelease
= GetFinalFileNameFromURI(DetachedDataTarget
.URI
);
1143 string
const PartialRelease
= GetPartialFileNameFromURI(DetachedDataTarget
.URI
);
1144 string
const FinalReleasegpg
= GetFinalFileNameFromURI(DetachedSigTarget
.URI
);
1145 string
const FinalInRelease
= GetFinalFilename();
1146 Rename(DestFile
, PartialRelease
);
1147 TransactionManager
->TransactionStageCopy(this, PartialRelease
, FinalRelease
);
1149 if (RealFileExists(FinalReleasegpg
) || RealFileExists(FinalInRelease
))
1151 // open the last Release if we have it
1152 if (TransactionManager
->IMSHit
== false)
1154 TransactionManager
->LastMetaIndexParser
= new indexRecords
;
1155 _error
->PushToStack();
1156 if (RealFileExists(FinalInRelease
))
1157 TransactionManager
->LastMetaIndexParser
->Load(FinalInRelease
);
1159 TransactionManager
->LastMetaIndexParser
->Load(FinalRelease
);
1160 // its unlikely to happen, but if what we have is bad ignore it
1161 if (_error
->PendingError())
1163 delete TransactionManager
->LastMetaIndexParser
;
1164 TransactionManager
->LastMetaIndexParser
= NULL
;
1166 _error
->RevertToStack();
1170 // we parse the indexes here because at this point the user wanted
1171 // a repository that may potentially harm him
1172 if (TransactionManager
->MetaIndexParser
->Load(PartialRelease
) == false || VerifyVendor(Message
) == false)
1173 /* expired Release files are still a problem you need extra force for */;
1181 pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire
* const Owner
, /*{{{*/
1182 pkgAcqMetaBase
* const TransactionManager
,
1183 IndexTarget
const &DataTarget
,
1184 IndexTarget
const &DetachedSigTarget
,
1185 vector
<IndexTarget
*> const * const IndexTargets
,
1186 indexRecords
* const MetaIndexParser
) :
1187 pkgAcqMetaBase(Owner
, TransactionManager
, IndexTargets
, DataTarget
, MetaIndexParser
),
1188 DetachedSigTarget(DetachedSigTarget
)
1190 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1191 std::clog
<< "New pkgAcqMetaIndex with TransactionManager "
1192 << this->TransactionManager
<< std::endl
;
1194 DestFile
= GetPartialFileNameFromURI(DataTarget
.URI
);
1197 Desc
.Description
= DataTarget
.Description
;
1199 Desc
.ShortDesc
= DataTarget
.ShortDesc
;
1200 Desc
.URI
= DataTarget
.URI
;
1202 // we expect more item
1203 ExpectedAdditionalItems
= IndexTargets
->size();
1207 void pkgAcqMetaIndex::Done(string
const &Message
, /*{{{*/
1208 HashStringList
const &Hashes
,
1209 pkgAcquire::MethodConfig
const * const Cfg
)
1211 Item::Done(Message
,Hashes
,Cfg
);
1213 if(CheckDownloadDone(this, Message
, Hashes
))
1215 // we have a Release file, now download the Signature, all further
1216 // verify/queue for additional downloads will be done in the
1217 // pkgAcqMetaSig::Done() code
1218 new pkgAcqMetaSig(Owner
, TransactionManager
, &DetachedSigTarget
, this);
1222 // pkgAcqMetaIndex::Failed - no Release file present /*{{{*/
1223 void pkgAcqMetaIndex::Failed(string
const &Message
,
1224 pkgAcquire::MethodConfig
const * const Cnf
)
1226 pkgAcquire::Item::Failed(Message
, Cnf
);
1229 _error
->Warning(_("The repository '%s' does not have a Release file. "
1230 "This is deprecated, please contact the owner of the "
1231 "repository."), DataTarget
.Description
.c_str());
1233 // No Release file was present so fall
1234 // back to queueing Packages files without verification
1235 // only allow going further if the users explicitely wants it
1236 if(AllowInsecureRepositories(TransactionManager
->MetaIndexParser
, TransactionManager
, this) == true)
1238 // ensure old Release files are removed
1239 TransactionManager
->TransactionStageRemoval(this, GetFinalFilename());
1240 delete TransactionManager
->MetaIndexParser
;
1241 TransactionManager
->MetaIndexParser
= NULL
;
1243 // queue without any kind of hashsum support
1244 QueueIndexes(false);
1248 void pkgAcqMetaIndex::Finished() /*{{{*/
1250 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1251 std::clog
<< "Finished: " << DestFile
<<std::endl
;
1252 if(TransactionManager
!= NULL
&&
1253 TransactionManager
->TransactionHasError() == false)
1254 TransactionManager
->CommitTransaction();
1257 std::string
pkgAcqMetaIndex::DescURI() const /*{{{*/
1259 return DataTarget
.URI
;
1263 // AcqMetaSig::AcqMetaSig - Constructor /*{{{*/
1264 pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire
* const Owner
,
1265 pkgAcqMetaBase
* const TransactionManager
,
1266 IndexTarget
const * const Target
,
1267 pkgAcqMetaIndex
* const MetaIndex
) :
1268 pkgAcqTransactionItem(Owner
, TransactionManager
, Target
), MetaIndex(MetaIndex
)
1270 DestFile
= GetPartialFileNameFromURI(Target
->URI
);
1272 // remove any partial downloaded sig-file in partial/.
1273 // it may confuse proxies and is too small to warrant a
1274 // partial download anyway
1275 unlink(DestFile
.c_str());
1277 // set the TransactionManager
1278 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1279 std::clog
<< "New pkgAcqMetaSig with TransactionManager "
1280 << TransactionManager
<< std::endl
;
1283 Desc
.Description
= Target
->Description
;
1285 Desc
.ShortDesc
= Target
->ShortDesc
;
1286 Desc
.URI
= Target
->URI
;
1288 // If we got a hit for Release, we will get one for Release.gpg too (or obscure errors),
1289 // so we skip the download step and go instantly to verification
1290 if (TransactionManager
->IMSHit
== true && RealFileExists(GetFinalFilename()))
1294 PartialFile
= DestFile
= GetFinalFilename();
1295 MetaIndexFileSignature
= DestFile
;
1296 MetaIndex
->QueueForSignatureVerify(this, MetaIndex
->DestFile
, DestFile
);
1302 pkgAcqMetaSig::~pkgAcqMetaSig() /*{{{*/
1306 // AcqMetaSig::Done - The signature was downloaded/verified /*{{{*/
1307 void pkgAcqMetaSig::Done(string
const &Message
, HashStringList
const &Hashes
,
1308 pkgAcquire::MethodConfig
const * const Cfg
)
1310 if (MetaIndexFileSignature
.empty() == false)
1312 DestFile
= MetaIndexFileSignature
;
1313 MetaIndexFileSignature
.clear();
1315 Item::Done(Message
, Hashes
, Cfg
);
1317 if(MetaIndex
->AuthPass
== false)
1319 if(MetaIndex
->CheckDownloadDone(this, Message
, Hashes
) == true)
1321 // destfile will be modified to point to MetaIndexFile for the
1322 // gpgv method, so we need to save it here
1323 MetaIndexFileSignature
= DestFile
;
1324 MetaIndex
->QueueForSignatureVerify(this, MetaIndex
->DestFile
, DestFile
);
1328 else if(MetaIndex
->CheckAuthDone(Message
) == true)
1330 if (TransactionManager
->IMSHit
== false)
1332 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
1333 TransactionManager
->TransactionStageCopy(MetaIndex
, MetaIndex
->DestFile
, MetaIndex
->GetFinalFilename());
1338 void pkgAcqMetaSig::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
1340 Item::Failed(Message
,Cnf
);
1342 // check if we need to fail at this point
1343 if (MetaIndex
->AuthPass
== true && MetaIndex
->CheckStopAuthentication(this, Message
))
1346 string
const FinalRelease
= MetaIndex
->GetFinalFilename();
1347 string
const FinalReleasegpg
= GetFinalFilename();
1348 string
const FinalInRelease
= TransactionManager
->GetFinalFilename();
1350 if (RealFileExists(FinalReleasegpg
) || RealFileExists(FinalInRelease
))
1352 std::string downgrade_msg
;
1353 strprintf(downgrade_msg
, _("The repository '%s' is no longer signed."),
1354 MetaIndex
->DataTarget
.Description
.c_str());
1355 if(_config
->FindB("Acquire::AllowDowngradeToInsecureRepositories"))
1357 // meh, the users wants to take risks (we still mark the packages
1358 // from this repository as unauthenticated)
1359 _error
->Warning("%s", downgrade_msg
.c_str());
1360 _error
->Warning(_("This is normally not allowed, but the option "
1361 "Acquire::AllowDowngradeToInsecureRepositories was "
1362 "given to override it."));
1365 _error
->Error("%s", downgrade_msg
.c_str());
1366 if (TransactionManager
->IMSHit
== false)
1367 Rename(MetaIndex
->DestFile
, MetaIndex
->DestFile
+ ".FAILED");
1368 Item::Failed("Message: " + downgrade_msg
, Cnf
);
1369 TransactionManager
->AbortTransaction();
1374 _error
->Warning(_("The data from '%s' is not signed. Packages "
1375 "from that repository can not be authenticated."),
1376 MetaIndex
->DataTarget
.Description
.c_str());
1378 // ensures that a Release.gpg file in the lists/ is removed by the transaction
1379 TransactionManager
->TransactionStageRemoval(this, DestFile
);
1381 // only allow going further if the users explicitely wants it
1382 if(AllowInsecureRepositories(TransactionManager
->MetaIndexParser
, TransactionManager
, this) == true)
1384 if (RealFileExists(FinalReleasegpg
) || RealFileExists(FinalInRelease
))
1386 // open the last Release if we have it
1387 if (TransactionManager
->IMSHit
== false)
1389 TransactionManager
->LastMetaIndexParser
= new indexRecords
;
1390 _error
->PushToStack();
1391 if (RealFileExists(FinalInRelease
))
1392 TransactionManager
->LastMetaIndexParser
->Load(FinalInRelease
);
1394 TransactionManager
->LastMetaIndexParser
->Load(FinalRelease
);
1395 // its unlikely to happen, but if what we have is bad ignore it
1396 if (_error
->PendingError())
1398 delete TransactionManager
->LastMetaIndexParser
;
1399 TransactionManager
->LastMetaIndexParser
= NULL
;
1401 _error
->RevertToStack();
1405 // we parse the indexes here because at this point the user wanted
1406 // a repository that may potentially harm him
1407 if (TransactionManager
->MetaIndexParser
->Load(MetaIndex
->DestFile
) == false || MetaIndex
->VerifyVendor(Message
) == false)
1408 /* expired Release files are still a problem you need extra force for */;
1410 MetaIndex
->QueueIndexes(true);
1412 TransactionManager
->TransactionStageCopy(MetaIndex
, MetaIndex
->DestFile
, MetaIndex
->GetFinalFilename());
1415 // FIXME: this is used often (e.g. in pkgAcqIndexTrans) so refactor
1416 if (Cnf
->LocalOnly
== true ||
1417 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1426 // AcqBaseIndex - Constructor /*{{{*/
1427 pkgAcqBaseIndex::pkgAcqBaseIndex(pkgAcquire
* const Owner
,
1428 pkgAcqMetaBase
* const TransactionManager
,
1429 IndexTarget
const * const Target
)
1430 : pkgAcqTransactionItem(Owner
, TransactionManager
, Target
)
1435 // AcqDiffIndex::AcqDiffIndex - Constructor /*{{{*/
1436 // ---------------------------------------------------------------------
1437 /* Get the DiffIndex file first and see if there are patches available
1438 * If so, create a pkgAcqIndexDiffs fetcher that will get and apply the
1439 * patches. If anything goes wrong in that process, it will fall back to
1440 * the original packages file
1442 pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire
* const Owner
,
1443 pkgAcqMetaBase
* const TransactionManager
,
1444 IndexTarget
const * const Target
)
1445 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
)
1447 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
1450 Desc
.Description
= Target
->Description
+ ".diff/Index";
1451 Desc
.ShortDesc
= Target
->ShortDesc
;
1452 Desc
.URI
= Target
->URI
+ ".diff/Index";
1454 DestFile
= GetPartialFileNameFromURI(Desc
.URI
);
1457 std::clog
<< "pkgAcqDiffIndex: " << Desc
.URI
<< std::endl
;
1459 // look for the current package file
1460 CurrentPackagesFile
= GetFinalFileNameFromURI(Target
->URI
);
1462 // FIXME: this file:/ check is a hack to prevent fetching
1463 // from local sources. this is really silly, and
1464 // should be fixed cleanly as soon as possible
1465 if(!FileExists(CurrentPackagesFile
) ||
1466 Desc
.URI
.substr(0,strlen("file:/")) == "file:/")
1468 // we don't have a pkg file or we don't want to queue
1469 Failed("No index file, local or canceld by user", NULL
);
1474 std::clog
<< "pkgAcqDiffIndex::pkgAcqDiffIndex(): "
1475 << CurrentPackagesFile
<< std::endl
;
1481 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
1482 // ---------------------------------------------------------------------
1483 /* The only header we use is the last-modified header. */
1484 string
pkgAcqDiffIndex::Custom600Headers() const
1486 string
const Final
= GetFinalFilename();
1489 std::clog
<< "Custom600Header-IMS: " << Final
<< std::endl
;
1492 if (stat(Final
.c_str(),&Buf
) != 0)
1493 return "\nIndex-File: true";
1495 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1498 void pkgAcqDiffIndex::QueueOnIMSHit() const /*{{{*/
1500 // list cleanup needs to know that this file as well as the already
1501 // present index is ours, so we create an empty diff to save it for us
1502 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
);
1505 bool pkgAcqDiffIndex::ParseDiffIndex(string
const &IndexDiffFile
) /*{{{*/
1507 // failing here is fine: our caller will take care of trying to
1508 // get the complete file if patching fails
1510 std::clog
<< "pkgAcqDiffIndex::ParseIndexDiff() " << IndexDiffFile
1513 FileFd
Fd(IndexDiffFile
,FileFd::ReadOnly
);
1515 if (_error
->PendingError() == true)
1519 if(unlikely(TF
.Step(Tags
) == false))
1522 HashStringList ServerHashes
;
1523 unsigned long long ServerSize
= 0;
1525 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
1527 std::string tagname
= *type
;
1528 tagname
.append("-Current");
1529 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1530 if (tmp
.empty() == true)
1534 unsigned long long size
;
1535 std::stringstream
ss(tmp
);
1537 if (unlikely(hash
.empty() == true))
1539 if (unlikely(ServerSize
!= 0 && ServerSize
!= size
))
1541 ServerHashes
.push_back(HashString(*type
, hash
));
1545 if (ServerHashes
.usable() == false)
1548 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": Did not find a good hashsum in the index" << std::endl
;
1552 HashStringList
const TargetFileHashes
= GetExpectedHashesFor(Target
->MetaKey
);
1553 if (TargetFileHashes
.usable() == false || ServerHashes
!= TargetFileHashes
)
1557 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": Index has different hashes than parser, probably older, so fail pdiffing" << std::endl
;
1558 printHashSumComparision(CurrentPackagesFile
, ServerHashes
, TargetFileHashes
);
1563 if (ServerHashes
.VerifyFile(CurrentPackagesFile
) == true)
1565 // we have the same sha1 as the server so we are done here
1567 std::clog
<< "pkgAcqDiffIndex: Package file " << CurrentPackagesFile
<< " is up-to-date" << std::endl
;
1572 FileFd
fd(CurrentPackagesFile
, FileFd::ReadOnly
);
1573 Hashes LocalHashesCalc
;
1574 LocalHashesCalc
.AddFD(fd
);
1575 HashStringList
const LocalHashes
= LocalHashesCalc
.GetHashStringList();
1578 std::clog
<< "Server-Current: " << ServerHashes
.find(NULL
)->toStr() << " and we start at "
1579 << fd
.Name() << " " << fd
.FileSize() << " " << LocalHashes
.find(NULL
)->toStr() << std::endl
;
1581 // parse all of (provided) history
1582 vector
<DiffInfo
> available_patches
;
1583 bool firstAcceptedHashes
= true;
1584 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
1586 if (LocalHashes
.find(*type
) == NULL
)
1589 std::string tagname
= *type
;
1590 tagname
.append("-History");
1591 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1592 if (tmp
.empty() == true)
1595 string hash
, filename
;
1596 unsigned long long size
;
1597 std::stringstream
ss(tmp
);
1599 while (ss
>> hash
>> size
>> filename
)
1601 if (unlikely(hash
.empty() == true || filename
.empty() == true))
1604 // see if we have a record for this file already
1605 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
1606 for (; cur
!= available_patches
.end(); ++cur
)
1608 if (cur
->file
!= filename
|| unlikely(cur
->result_size
!= size
))
1610 cur
->result_hashes
.push_back(HashString(*type
, hash
));
1613 if (cur
!= available_patches
.end())
1615 if (firstAcceptedHashes
== true)
1618 next
.file
= filename
;
1619 next
.result_hashes
.push_back(HashString(*type
, hash
));
1620 next
.result_size
= size
;
1621 next
.patch_size
= 0;
1622 available_patches
.push_back(next
);
1627 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
1628 << " wasn't in the list for the first parsed hash! (history)" << std::endl
;
1632 firstAcceptedHashes
= false;
1635 if (unlikely(available_patches
.empty() == true))
1638 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": "
1639 << "Couldn't find any patches for the patch series." << std::endl
;
1643 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
1645 if (LocalHashes
.find(*type
) == NULL
)
1648 std::string tagname
= *type
;
1649 tagname
.append("-Patches");
1650 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1651 if (tmp
.empty() == true)
1654 string hash
, filename
;
1655 unsigned long long size
;
1656 std::stringstream
ss(tmp
);
1658 while (ss
>> hash
>> size
>> filename
)
1660 if (unlikely(hash
.empty() == true || filename
.empty() == true))
1663 // see if we have a record for this file already
1664 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
1665 for (; cur
!= available_patches
.end(); ++cur
)
1667 if (cur
->file
!= filename
)
1669 if (unlikely(cur
->patch_size
!= 0 && cur
->patch_size
!= size
))
1671 cur
->patch_hashes
.push_back(HashString(*type
, hash
));
1672 cur
->patch_size
= size
;
1675 if (cur
!= available_patches
.end())
1678 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
1679 << " wasn't in the list for the first parsed hash! (patches)" << std::endl
;
1684 bool foundStart
= false;
1685 for (std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
1686 cur
!= available_patches
.end(); ++cur
)
1688 if (LocalHashes
!= cur
->result_hashes
)
1691 available_patches
.erase(available_patches
.begin(), cur
);
1696 if (foundStart
== false || unlikely(available_patches
.empty() == true))
1699 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": "
1700 << "Couldn't find the start of the patch series." << std::endl
;
1704 // patching with too many files is rather slow compared to a fast download
1705 unsigned long const fileLimit
= _config
->FindI("Acquire::PDiffs::FileLimit", 0);
1706 if (fileLimit
!= 0 && fileLimit
< available_patches
.size())
1709 std::clog
<< "Need " << available_patches
.size() << " diffs (Limit is " << fileLimit
1710 << ") so fallback to complete download" << std::endl
;
1714 // calculate the size of all patches we have to get
1715 // note that all sizes are uncompressed, while we download compressed files
1716 unsigned long long patchesSize
= 0;
1717 for (std::vector
<DiffInfo
>::const_iterator cur
= available_patches
.begin();
1718 cur
!= available_patches
.end(); ++cur
)
1719 patchesSize
+= cur
->patch_size
;
1720 unsigned long long const sizeLimit
= ServerSize
* _config
->FindI("Acquire::PDiffs::SizeLimit", 100);
1721 if (sizeLimit
> 0 && (sizeLimit
/100) < patchesSize
)
1724 std::clog
<< "Need " << patchesSize
<< " bytes (Limit is " << sizeLimit
/100
1725 << ") so fallback to complete download" << std::endl
;
1729 // we have something, queue the diffs
1730 string::size_type
const last_space
= Description
.rfind(" ");
1731 if(last_space
!= string::npos
)
1732 Description
.erase(last_space
, Description
.size()-last_space
);
1734 /* decide if we should download patches one by one or in one go:
1735 The first is good if the server merges patches, but many don't so client
1736 based merging can be attempt in which case the second is better.
1737 "bad things" will happen if patches are merged on the server,
1738 but client side merging is attempt as well */
1739 bool pdiff_merge
= _config
->FindB("Acquire::PDiffs::Merge", true);
1740 if (pdiff_merge
== true)
1742 // reprepro adds this flag if it has merged patches on the server
1743 std::string
const precedence
= Tags
.FindS("X-Patch-Precedence");
1744 pdiff_merge
= (precedence
!= "merged");
1747 if (pdiff_merge
== false)
1748 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
, available_patches
);
1751 std::vector
<pkgAcqIndexMergeDiffs
*> *diffs
= new std::vector
<pkgAcqIndexMergeDiffs
*>(available_patches
.size());
1752 for(size_t i
= 0; i
< available_patches
.size(); ++i
)
1753 (*diffs
)[i
] = new pkgAcqIndexMergeDiffs(Owner
, TransactionManager
,
1755 available_patches
[i
],
1765 void pkgAcqDiffIndex::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
1767 Item::Failed(Message
,Cnf
);
1771 std::clog
<< "pkgAcqDiffIndex failed: " << Desc
.URI
<< " with " << Message
<< std::endl
1772 << "Falling back to normal index file acquire" << std::endl
;
1774 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
1777 void pkgAcqDiffIndex::Done(string
const &Message
,HashStringList
const &Hashes
, /*{{{*/
1778 pkgAcquire::MethodConfig
const * const Cnf
)
1781 std::clog
<< "pkgAcqDiffIndex::Done(): " << Desc
.URI
<< std::endl
;
1783 Item::Done(Message
, Hashes
, Cnf
);
1785 string
const FinalFile
= GetFinalFilename();
1786 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false))
1787 DestFile
= FinalFile
;
1789 if(ParseDiffIndex(DestFile
) == false)
1791 Failed("Message: Couldn't parse pdiff index", Cnf
);
1792 // queue for final move - this should happen even if we fail
1793 // while parsing (e.g. on sizelimit) and download the complete file.
1794 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
1798 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
1808 // AcqIndexDiffs::AcqIndexDiffs - Constructor /*{{{*/
1809 // ---------------------------------------------------------------------
1810 /* The package diff is added to the queue. one object is constructed
1811 * for each diff and the index
1813 pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire
* const Owner
,
1814 pkgAcqMetaBase
* const TransactionManager
,
1815 IndexTarget
const * const Target
,
1816 vector
<DiffInfo
> const &diffs
)
1817 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
),
1818 available_patches(diffs
)
1820 DestFile
= GetPartialFileNameFromURI(Target
->URI
);
1822 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
1825 Description
= Target
->Description
;
1826 Desc
.ShortDesc
= Target
->ShortDesc
;
1828 if(available_patches
.empty() == true)
1830 // we are done (yeah!), check hashes against the final file
1831 DestFile
= GetFinalFileNameFromURI(Target
->URI
);
1836 // patching needs to be bootstrapped with the 'old' version
1837 std::string
const PartialFile
= GetPartialFileNameFromURI(Target
->URI
);
1838 if (RealFileExists(PartialFile
) == false)
1840 if (symlink(GetFinalFilename().c_str(), PartialFile
.c_str()) != 0)
1842 Failed("Link creation of " + PartialFile
+ " to " + GetFinalFilename() + " failed", NULL
);
1847 // get the next diff
1848 State
= StateFetchDiff
;
1853 void pkgAcqIndexDiffs::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
1855 Item::Failed(Message
,Cnf
);
1859 std::clog
<< "pkgAcqIndexDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
1860 << "Falling back to normal index file acquire" << std::endl
;
1861 DestFile
= GetPartialFileNameFromURI(Target
->URI
);
1862 RenameOnError(PDiffError
);
1863 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
1867 // Finish - helper that cleans the item out of the fetcher queue /*{{{*/
1868 void pkgAcqIndexDiffs::Finish(bool allDone
)
1871 std::clog
<< "pkgAcqIndexDiffs::Finish(): "
1873 << Desc
.URI
<< std::endl
;
1875 // we restore the original name, this is required, otherwise
1876 // the file will be cleaned
1879 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
1881 // this is for the "real" finish
1886 std::clog
<< "\n\nallDone: " << DestFile
<< "\n" << std::endl
;
1891 std::clog
<< "Finishing: " << Desc
.URI
<< std::endl
;
1898 bool pkgAcqIndexDiffs::QueueNextDiff() /*{{{*/
1900 // calc sha1 of the just patched file
1901 std::string
const FinalFile
= GetPartialFileNameFromURI(Target
->URI
);
1903 if(!FileExists(FinalFile
))
1905 Failed("Message: No FinalFile " + FinalFile
+ " available", NULL
);
1909 FileFd
fd(FinalFile
, FileFd::ReadOnly
);
1910 Hashes LocalHashesCalc
;
1911 LocalHashesCalc
.AddFD(fd
);
1912 HashStringList
const LocalHashes
= LocalHashesCalc
.GetHashStringList();
1915 std::clog
<< "QueueNextDiff: " << FinalFile
<< " (" << LocalHashes
.find(NULL
)->toStr() << ")" << std::endl
;
1917 HashStringList
const TargetFileHashes
= GetExpectedHashesFor(Target
->MetaKey
);
1918 if (unlikely(LocalHashes
.usable() == false || TargetFileHashes
.usable() == false))
1920 Failed("Local/Expected hashes are not usable", NULL
);
1925 // final file reached before all patches are applied
1926 if(LocalHashes
== TargetFileHashes
)
1932 // remove all patches until the next matching patch is found
1933 // this requires the Index file to be ordered
1934 for(vector
<DiffInfo
>::iterator I
= available_patches
.begin();
1935 available_patches
.empty() == false &&
1936 I
!= available_patches
.end() &&
1937 I
->result_hashes
!= LocalHashes
;
1940 available_patches
.erase(I
);
1943 // error checking and falling back if no patch was found
1944 if(available_patches
.empty() == true)
1946 Failed("No patches left to reach target", NULL
);
1950 // queue the right diff
1951 Desc
.URI
= Target
->URI
+ ".diff/" + available_patches
[0].file
+ ".gz";
1952 Desc
.Description
= Description
+ " " + available_patches
[0].file
+ string(".pdiff");
1953 DestFile
= GetPartialFileNameFromURI(Target
->URI
+ ".diff/" + available_patches
[0].file
);
1956 std::clog
<< "pkgAcqIndexDiffs::QueueNextDiff(): " << Desc
.URI
<< std::endl
;
1963 void pkgAcqIndexDiffs::Done(string
const &Message
, HashStringList
const &Hashes
, /*{{{*/
1964 pkgAcquire::MethodConfig
const * const Cnf
)
1967 std::clog
<< "pkgAcqIndexDiffs::Done(): " << Desc
.URI
<< std::endl
;
1969 Item::Done(Message
, Hashes
, Cnf
);
1971 // FIXME: verify this download too before feeding it to rred
1972 std::string
const FinalFile
= GetPartialFileNameFromURI(Target
->URI
);
1974 // success in downloading a diff, enter ApplyDiff state
1975 if(State
== StateFetchDiff
)
1977 FileFd
fd(DestFile
, FileFd::ReadOnly
, FileFd::Gzip
);
1978 class Hashes LocalHashesCalc
;
1979 LocalHashesCalc
.AddFD(fd
);
1980 HashStringList
const LocalHashes
= LocalHashesCalc
.GetHashStringList();
1982 if (fd
.Size() != available_patches
[0].patch_size
||
1983 available_patches
[0].patch_hashes
!= LocalHashes
)
1985 // patchfiles are dated, so bad indicates a bad download, so kill it
1986 unlink(DestFile
.c_str());
1987 Failed("Patch has Size/Hashsum mismatch", NULL
);
1991 // rred excepts the patch as $FinalFile.ed
1992 Rename(DestFile
,FinalFile
+".ed");
1995 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
1997 State
= StateApplyDiff
;
1999 Desc
.URI
= "rred:" + FinalFile
;
2001 SetActiveSubprocess("rred");
2006 // success in download/apply a diff, queue next (if needed)
2007 if(State
== StateApplyDiff
)
2009 // remove the just applied patch
2010 available_patches
.erase(available_patches
.begin());
2011 unlink((FinalFile
+ ".ed").c_str());
2016 std::clog
<< "Moving patched file in place: " << std::endl
2017 << DestFile
<< " -> " << FinalFile
<< std::endl
;
2019 Rename(DestFile
,FinalFile
);
2020 chmod(FinalFile
.c_str(),0644);
2022 // see if there is more to download
2023 if(available_patches
.empty() == false) {
2024 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
,
2029 DestFile
= FinalFile
;
2030 return Finish(true);
2035 // AcqIndexMergeDiffs::AcqIndexMergeDiffs - Constructor /*{{{*/
2036 pkgAcqIndexMergeDiffs::pkgAcqIndexMergeDiffs(pkgAcquire
* const Owner
,
2037 pkgAcqMetaBase
* const TransactionManager
,
2038 IndexTarget
const * const Target
,
2039 DiffInfo
const &patch
,
2040 std::vector
<pkgAcqIndexMergeDiffs
*> const * const allPatches
)
2041 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
),
2042 patch(patch
), allPatches(allPatches
), State(StateFetchDiff
)
2044 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
2047 Description
= Target
->Description
;
2048 Desc
.ShortDesc
= Target
->ShortDesc
;
2050 Desc
.URI
= Target
->URI
+ ".diff/" + patch
.file
+ ".gz";
2051 Desc
.Description
= Description
+ " " + patch
.file
+ string(".pdiff");
2053 DestFile
= GetPartialFileNameFromURI(Target
->URI
+ ".diff/" + patch
.file
);
2056 std::clog
<< "pkgAcqIndexMergeDiffs: " << Desc
.URI
<< std::endl
;
2061 void pkgAcqIndexMergeDiffs::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
2064 std::clog
<< "pkgAcqIndexMergeDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
;
2066 Item::Failed(Message
,Cnf
);
2069 // check if we are the first to fail, otherwise we are done here
2070 State
= StateDoneDiff
;
2071 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2072 I
!= allPatches
->end(); ++I
)
2073 if ((*I
)->State
== StateErrorDiff
)
2076 // first failure means we should fallback
2077 State
= StateErrorDiff
;
2079 std::clog
<< "Falling back to normal index file acquire" << std::endl
;
2080 DestFile
= GetPartialFileNameFromURI(Target
->URI
);
2081 RenameOnError(PDiffError
);
2082 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
2085 void pkgAcqIndexMergeDiffs::Done(string
const &Message
, HashStringList
const &Hashes
, /*{{{*/
2086 pkgAcquire::MethodConfig
const * const Cnf
)
2089 std::clog
<< "pkgAcqIndexMergeDiffs::Done(): " << Desc
.URI
<< std::endl
;
2091 Item::Done(Message
, Hashes
, Cnf
);
2093 // FIXME: verify download before feeding it to rred
2094 string
const FinalFile
= GetPartialFileNameFromURI(Target
->URI
);
2096 if (State
== StateFetchDiff
)
2098 FileFd
fd(DestFile
, FileFd::ReadOnly
, FileFd::Gzip
);
2099 class Hashes LocalHashesCalc
;
2100 LocalHashesCalc
.AddFD(fd
);
2101 HashStringList
const LocalHashes
= LocalHashesCalc
.GetHashStringList();
2103 if (fd
.Size() != patch
.patch_size
|| patch
.patch_hashes
!= LocalHashes
)
2105 // patchfiles are dated, so bad indicates a bad download, so kill it
2106 unlink(DestFile
.c_str());
2107 Failed("Patch has Size/Hashsum mismatch", NULL
);
2111 // rred expects the patch as $FinalFile.ed.$patchname.gz
2112 Rename(DestFile
, FinalFile
+ ".ed." + patch
.file
+ ".gz");
2114 // check if this is the last completed diff
2115 State
= StateDoneDiff
;
2116 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2117 I
!= allPatches
->end(); ++I
)
2118 if ((*I
)->State
!= StateDoneDiff
)
2121 std::clog
<< "Not the last done diff in the batch: " << Desc
.URI
<< std::endl
;
2125 // this is the last completed diff, so we are ready to apply now
2126 State
= StateApplyDiff
;
2128 // patching needs to be bootstrapped with the 'old' version
2129 if (symlink(GetFinalFilename().c_str(), FinalFile
.c_str()) != 0)
2131 Failed("Link creation of " + FinalFile
+ " to " + GetFinalFilename() + " failed", NULL
);
2136 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
2139 Desc
.URI
= "rred:" + FinalFile
;
2141 SetActiveSubprocess("rred");
2144 // success in download/apply all diffs, clean up
2145 else if (State
== StateApplyDiff
)
2147 // move the result into place
2148 std::string
const Final
= GetFinalFilename();
2150 std::clog
<< "Queue patched file in place: " << std::endl
2151 << DestFile
<< " -> " << Final
<< std::endl
;
2153 // queue for copy by the transaction manager
2154 TransactionManager
->TransactionStageCopy(this, DestFile
, Final
);
2156 // ensure the ed's are gone regardless of list-cleanup
2157 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2158 I
!= allPatches
->end(); ++I
)
2160 std::string
const PartialFile
= GetPartialFileNameFromURI(Target
->URI
);
2161 std::string patch
= PartialFile
+ ".ed." + (*I
)->patch
.file
+ ".gz";
2162 unlink(patch
.c_str());
2164 unlink(FinalFile
.c_str());
2169 std::clog
<< "allDone: " << DestFile
<< "\n" << std::endl
;
2174 // AcqIndex::AcqIndex - Constructor /*{{{*/
2175 pkgAcqIndex::pkgAcqIndex(pkgAcquire
* const Owner
,
2176 pkgAcqMetaBase
* const TransactionManager
,
2177 IndexTarget
const * const Target
)
2178 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
)
2180 // autoselect the compression method
2181 AutoSelectCompression();
2182 Init(Target
->URI
, Target
->Description
, Target
->ShortDesc
);
2184 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
2185 std::clog
<< "New pkgIndex with TransactionManager "
2186 << TransactionManager
<< std::endl
;
2189 // AcqIndex::AutoSelectCompression - Select compression /*{{{*/
2190 void pkgAcqIndex::AutoSelectCompression()
2192 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
2193 CompressionExtensions
= "";
2194 if (TransactionManager
->MetaIndexParser
!= NULL
&& TransactionManager
->MetaIndexParser
->Exists(Target
->MetaKey
))
2196 for (std::vector
<std::string
>::const_iterator t
= types
.begin();
2197 t
!= types
.end(); ++t
)
2199 std::string CompressedMetaKey
= string(Target
->MetaKey
).append(".").append(*t
);
2200 if (*t
== "uncompressed" ||
2201 TransactionManager
->MetaIndexParser
->Exists(CompressedMetaKey
) == true)
2202 CompressionExtensions
.append(*t
).append(" ");
2207 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
2208 CompressionExtensions
.append(*t
).append(" ");
2210 if (CompressionExtensions
.empty() == false)
2211 CompressionExtensions
.erase(CompressionExtensions
.end()-1);
2214 // AcqIndex::Init - defered Constructor /*{{{*/
2215 void pkgAcqIndex::Init(string
const &URI
, string
const &URIDesc
,
2216 string
const &ShortDesc
)
2218 Stage
= STAGE_DOWNLOAD
;
2220 DestFile
= GetPartialFileNameFromURI(URI
);
2222 size_t const nextExt
= CompressionExtensions
.find(' ');
2223 if (nextExt
== std::string::npos
)
2225 CurrentCompressionExtension
= CompressionExtensions
;
2226 CompressionExtensions
.clear();
2230 CurrentCompressionExtension
= CompressionExtensions
.substr(0, nextExt
);
2231 CompressionExtensions
= CompressionExtensions
.substr(nextExt
+1);
2234 if (CurrentCompressionExtension
== "uncompressed")
2238 else if (unlikely(CurrentCompressionExtension
.empty()))
2242 Desc
.URI
= URI
+ '.' + CurrentCompressionExtension
;
2243 DestFile
= DestFile
+ '.' + CurrentCompressionExtension
;
2246 if(TransactionManager
->MetaIndexParser
!= NULL
)
2247 InitByHashIfNeeded();
2249 Desc
.Description
= URIDesc
;
2251 Desc
.ShortDesc
= ShortDesc
;
2256 // AcqIndex::AdjustForByHash - modify URI for by-hash support /*{{{*/
2257 void pkgAcqIndex::InitByHashIfNeeded()
2260 // - (maybe?) add support for by-hash into the sources.list as flag
2261 // - make apt-ftparchive generate the hashes (and expire?)
2262 std::string HostKnob
= "APT::Acquire::" + ::URI(Desc
.URI
).Host
+ "::By-Hash";
2263 if(_config
->FindB("APT::Acquire::By-Hash", false) == true ||
2264 _config
->FindB(HostKnob
, false) == true ||
2265 TransactionManager
->MetaIndexParser
->GetSupportsAcquireByHash())
2267 HashStringList
const Hashes
= GetExpectedHashes();
2270 // FIXME: should we really use the best hash here? or a fixed one?
2271 HashString
const * const TargetHash
= Hashes
.find("");
2272 std::string
const ByHash
= "/by-hash/" + TargetHash
->HashType() + "/" + TargetHash
->HashValue();
2273 size_t const trailing_slash
= Desc
.URI
.find_last_of("/");
2274 Desc
.URI
= Desc
.URI
.replace(
2276 Desc
.URI
.substr(trailing_slash
+1).size()+1,
2280 "Fetching ByHash requested but can not find record for %s",
2281 GetMetaKey().c_str());
2286 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
2287 // ---------------------------------------------------------------------
2288 /* The only header we use is the last-modified header. */
2289 string
pkgAcqIndex::Custom600Headers() const
2291 string Final
= GetFinalFilename();
2293 string msg
= "\nIndex-File: true";
2295 if (stat(Final
.c_str(),&Buf
) == 0)
2296 msg
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
2298 if(Target
->IsOptional())
2299 msg
+= "\nFail-Ignore: true";
2304 // AcqIndex::Failed - getting the indexfile failed /*{{{*/
2305 void pkgAcqIndex::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)
2307 Item::Failed(Message
,Cnf
);
2309 // authorisation matches will not be fixed by other compression types
2310 if (Status
!= StatAuthError
)
2312 if (CompressionExtensions
.empty() == false)
2314 Init(Target
->URI
, Desc
.Description
, Desc
.ShortDesc
);
2320 if(Target
->IsOptional() && GetExpectedHashes().empty() && Stage
== STAGE_DOWNLOAD
)
2323 TransactionManager
->AbortTransaction();
2326 // AcqIndex::ReverifyAfterIMS - Reverify index after an ims-hit /*{{{*/
2327 void pkgAcqIndex::ReverifyAfterIMS()
2329 // update destfile to *not* include the compression extension when doing
2330 // a reverify (as its uncompressed on disk already)
2331 DestFile
= GetCompressedFileName(Target
->URI
, GetPartialFileNameFromURI(Target
->URI
), CurrentCompressionExtension
);
2333 // copy FinalFile into partial/ so that we check the hash again
2334 string FinalFile
= GetFinalFilename();
2335 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
2336 Desc
.URI
= "copy:" + FinalFile
;
2340 // AcqIndex::ValidateFile - Validate the content of the downloaded file /*{{{*/
2341 bool pkgAcqIndex::ValidateFile(const std::string
&FileName
)
2343 // FIXME: this can go away once we only ever download stuff that
2344 // has a valid hash and we never do GET based probing
2345 // FIXME2: this also leaks debian-isms into the code and should go therefore
2347 /* Always validate the index file for correctness (all indexes must
2348 * have a Package field) (LP: #346386) (Closes: #627642)
2350 FileFd
fd(FileName
, FileFd::ReadOnly
, FileFd::Extension
);
2351 // Only test for correctness if the content of the file is not empty
2356 pkgTagFile
tag(&fd
);
2358 // all our current indexes have a field 'Package' in each section
2359 if (_error
->PendingError() == true ||
2360 tag
.Step(sec
) == false ||
2361 sec
.Exists("Package") == false)
2367 // AcqIndex::Done - Finished a fetch /*{{{*/
2368 // ---------------------------------------------------------------------
2369 /* This goes through a number of states.. On the initial fetch the
2370 method could possibly return an alternate filename which points
2371 to the uncompressed version of the file. If this is so the file
2372 is copied into the partial directory. In all other cases the file
2373 is decompressed with a compressed uri. */
2374 void pkgAcqIndex::Done(string
const &Message
,
2375 HashStringList
const &Hashes
,
2376 pkgAcquire::MethodConfig
const * const Cfg
)
2378 Item::Done(Message
,Hashes
,Cfg
);
2382 case STAGE_DOWNLOAD
:
2383 StageDownloadDone(Message
, Hashes
, Cfg
);
2385 case STAGE_DECOMPRESS_AND_VERIFY
:
2386 StageDecompressDone(Message
, Hashes
, Cfg
);
2391 // AcqIndex::StageDownloadDone - Queue for decompress and verify /*{{{*/
2392 void pkgAcqIndex::StageDownloadDone(string
const &Message
, HashStringList
const &,
2393 pkgAcquire::MethodConfig
const * const)
2397 // Handle the unzipd case
2398 string FileName
= LookupTag(Message
,"Alt-Filename");
2399 if (FileName
.empty() == false)
2401 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
2403 DestFile
+= ".decomp";
2404 Desc
.URI
= "copy:" + FileName
;
2406 SetActiveSubprocess("copy");
2410 FileName
= LookupTag(Message
,"Filename");
2411 if (FileName
.empty() == true)
2414 ErrorText
= "Method gave a blank filename";
2417 // Methods like e.g. "file:" will give us a (compressed) FileName that is
2418 // not the "DestFile" we set, in this case we uncompress from the local file
2419 if (FileName
!= DestFile
)
2422 EraseFileName
= FileName
;
2424 // we need to verify the file against the current Release file again
2425 // on if-modfied-since hit to avoid a stale attack against us
2426 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
2428 // The files timestamp matches, reverify by copy into partial/
2434 // If we have compressed indexes enabled, queue for hash verification
2435 if (_config
->FindB("Acquire::GzipIndexes",false))
2437 DestFile
= GetPartialFileNameFromURI(Target
->URI
+ '.' + CurrentCompressionExtension
);
2439 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
2440 Desc
.URI
= "copy:" + FileName
;
2442 SetActiveSubprocess("copy");
2446 // get the binary name for your used compression type
2448 if(CurrentCompressionExtension
== "uncompressed")
2449 decompProg
= "copy";
2451 decompProg
= _config
->Find(string("Acquire::CompressionTypes::").append(CurrentCompressionExtension
),"");
2452 if(decompProg
.empty() == true)
2454 _error
->Error("Unsupported extension: %s", CurrentCompressionExtension
.c_str());
2458 // queue uri for the next stage
2459 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
2460 DestFile
+= ".decomp";
2461 Desc
.URI
= decompProg
+ ":" + FileName
;
2463 SetActiveSubprocess(decompProg
);
2466 // AcqIndex::StageDecompressDone - Final verification /*{{{*/
2467 void pkgAcqIndex::StageDecompressDone(string
const &Message
,
2468 HashStringList
const &,
2469 pkgAcquire::MethodConfig
const * const Cfg
)
2471 if(!ValidateFile(DestFile
))
2473 RenameOnError(InvalidFormat
);
2474 Failed(Message
, Cfg
);
2478 // Done, queue for rename on transaction finished
2479 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
2486 // AcqArchive::AcqArchive - Constructor /*{{{*/
2487 // ---------------------------------------------------------------------
2488 /* This just sets up the initial fetch environment and queues the first
2490 pkgAcqArchive::pkgAcqArchive(pkgAcquire
* const Owner
,pkgSourceList
* const Sources
,
2491 pkgRecords
* const Recs
,pkgCache::VerIterator
const &Version
,
2492 string
&StoreFilename
) :
2493 Item(Owner
), LocalSource(false), Version(Version
), Sources(Sources
), Recs(Recs
),
2494 StoreFilename(StoreFilename
), Vf(Version
.FileList()),
2497 Retries
= _config
->FindI("Acquire::Retries",0);
2499 if (Version
.Arch() == 0)
2501 _error
->Error(_("I wasn't able to locate a file for the %s package. "
2502 "This might mean you need to manually fix this package. "
2503 "(due to missing arch)"),
2504 Version
.ParentPkg().FullName().c_str());
2508 /* We need to find a filename to determine the extension. We make the
2509 assumption here that all the available sources for this version share
2510 the same extension.. */
2511 // Skip not source sources, they do not have file fields.
2512 for (; Vf
.end() == false; ++Vf
)
2514 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
2519 // Does not really matter here.. we are going to fail out below
2520 if (Vf
.end() != true)
2522 // If this fails to get a file name we will bomb out below.
2523 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2524 if (_error
->PendingError() == true)
2527 // Generate the final file name as: package_version_arch.foo
2528 StoreFilename
= QuoteString(Version
.ParentPkg().Name(),"_:") + '_' +
2529 QuoteString(Version
.VerStr(),"_:") + '_' +
2530 QuoteString(Version
.Arch(),"_:.") +
2531 "." + flExtension(Parse
.FileName());
2534 // check if we have one trusted source for the package. if so, switch
2535 // to "TrustedOnly" mode - but only if not in AllowUnauthenticated mode
2536 bool const allowUnauth
= _config
->FindB("APT::Get::AllowUnauthenticated", false);
2537 bool const debugAuth
= _config
->FindB("Debug::pkgAcquire::Auth", false);
2538 bool seenUntrusted
= false;
2539 for (pkgCache::VerFileIterator i
= Version
.FileList(); i
.end() == false; ++i
)
2541 pkgIndexFile
*Index
;
2542 if (Sources
->FindIndex(i
.File(),Index
) == false)
2545 if (debugAuth
== true)
2546 std::cerr
<< "Checking index: " << Index
->Describe()
2547 << "(Trusted=" << Index
->IsTrusted() << ")" << std::endl
;
2549 if (Index
->IsTrusted() == true)
2552 if (allowUnauth
== false)
2556 seenUntrusted
= true;
2559 // "allow-unauthenticated" restores apts old fetching behaviour
2560 // that means that e.g. unauthenticated file:// uris are higher
2561 // priority than authenticated http:// uris
2562 if (allowUnauth
== true && seenUntrusted
== true)
2566 if (QueueNext() == false && _error
->PendingError() == false)
2567 _error
->Error(_("Can't find a source to download version '%s' of '%s'"),
2568 Version
.VerStr(), Version
.ParentPkg().FullName(false).c_str());
2571 // AcqArchive::QueueNext - Queue the next file source /*{{{*/
2572 // ---------------------------------------------------------------------
2573 /* This queues the next available file version for download. It checks if
2574 the archive is already available in the cache and stashs the MD5 for
2576 bool pkgAcqArchive::QueueNext()
2578 for (; Vf
.end() == false; ++Vf
)
2580 pkgCache::PkgFileIterator
const PkgF
= Vf
.File();
2581 // Ignore not source sources
2582 if ((PkgF
->Flags
& pkgCache::Flag::NotSource
) != 0)
2585 // Try to cross match against the source list
2586 pkgIndexFile
*Index
;
2587 if (Sources
->FindIndex(PkgF
, Index
) == false)
2589 LocalSource
= (PkgF
->Flags
& pkgCache::Flag::LocalSource
) == pkgCache::Flag::LocalSource
;
2591 // only try to get a trusted package from another source if that source
2593 if(Trusted
&& !Index
->IsTrusted())
2596 // Grab the text package record
2597 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2598 if (_error
->PendingError() == true)
2601 string PkgFile
= Parse
.FileName();
2602 ExpectedHashes
= Parse
.Hashes();
2604 if (PkgFile
.empty() == true)
2605 return _error
->Error(_("The package index files are corrupted. No Filename: "
2606 "field for package %s."),
2607 Version
.ParentPkg().Name());
2609 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
2610 Desc
.Description
= Index
->ArchiveInfo(Version
);
2612 Desc
.ShortDesc
= Version
.ParentPkg().FullName(true);
2614 // See if we already have the file. (Legacy filenames)
2615 FileSize
= Version
->Size
;
2616 string FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile
);
2618 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2620 // Make sure the size matches
2621 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2626 StoreFilename
= DestFile
= FinalFile
;
2630 /* Hmm, we have a file and its size does not match, this means it is
2631 an old style mismatched arch */
2632 unlink(FinalFile
.c_str());
2635 // Check it again using the new style output filenames
2636 FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
2637 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2639 // Make sure the size matches
2640 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2645 StoreFilename
= DestFile
= FinalFile
;
2649 /* Hmm, we have a file and its size does not match, this shouldn't
2651 unlink(FinalFile
.c_str());
2654 DestFile
= _config
->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename
);
2656 // Check the destination file
2657 if (stat(DestFile
.c_str(),&Buf
) == 0)
2659 // Hmm, the partial file is too big, erase it
2660 if ((unsigned long long)Buf
.st_size
> Version
->Size
)
2661 unlink(DestFile
.c_str());
2663 PartialSize
= Buf
.st_size
;
2666 // Disables download of archives - useful if no real installation follows,
2667 // e.g. if we are just interested in proposed installation order
2668 if (_config
->FindB("Debug::pkgAcqArchive::NoQueue", false) == true)
2673 StoreFilename
= DestFile
= FinalFile
;
2687 // AcqArchive::Done - Finished fetching /*{{{*/
2688 // ---------------------------------------------------------------------
2690 void pkgAcqArchive::Done(string
const &Message
, HashStringList
const &Hashes
,
2691 pkgAcquire::MethodConfig
const * const Cfg
)
2693 Item::Done(Message
, Hashes
, Cfg
);
2695 // Grab the output filename
2696 string FileName
= LookupTag(Message
,"Filename");
2697 if (FileName
.empty() == true)
2700 ErrorText
= "Method gave a blank filename";
2704 // Reference filename
2705 if (FileName
!= DestFile
)
2707 StoreFilename
= DestFile
= FileName
;
2713 // Done, move it into position
2714 string
const FinalFile
= GetFinalFilename();
2715 Rename(DestFile
,FinalFile
);
2716 StoreFilename
= DestFile
= FinalFile
;
2720 // AcqArchive::Failed - Failure handler /*{{{*/
2721 // ---------------------------------------------------------------------
2722 /* Here we try other sources */
2723 void pkgAcqArchive::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)
2725 Item::Failed(Message
,Cnf
);
2727 /* We don't really want to retry on failed media swaps, this prevents
2728 that. An interesting observation is that permanent failures are not
2730 if (Cnf
->Removable
== true &&
2731 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2733 // Vf = Version.FileList();
2734 while (Vf
.end() == false) ++Vf
;
2735 StoreFilename
= string();
2740 if (QueueNext() == false)
2742 // This is the retry counter
2744 Cnf
->LocalOnly
== false &&
2745 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2748 Vf
= Version
.FileList();
2749 if (QueueNext() == true)
2753 StoreFilename
= string();
2758 APT_PURE
bool pkgAcqArchive::IsTrusted() const /*{{{*/
2763 void pkgAcqArchive::Finished() /*{{{*/
2765 if (Status
== pkgAcquire::Item::StatDone
&&
2768 StoreFilename
= string();
2771 std::string
pkgAcqArchive::DescURI() const /*{{{*/
2776 std::string
pkgAcqArchive::ShortDesc() const /*{{{*/
2778 return Desc
.ShortDesc
;
2782 // AcqFile::pkgAcqFile - Constructor /*{{{*/
2783 pkgAcqFile::pkgAcqFile(pkgAcquire
* const Owner
,string
const &URI
, HashStringList
const &Hashes
,
2784 unsigned long long const Size
,string
const &Dsc
,string
const &ShortDesc
,
2785 const string
&DestDir
, const string
&DestFilename
,
2786 bool const IsIndexFile
) :
2787 Item(Owner
), IsIndexFile(IsIndexFile
), ExpectedHashes(Hashes
)
2789 Retries
= _config
->FindI("Acquire::Retries",0);
2791 if(!DestFilename
.empty())
2792 DestFile
= DestFilename
;
2793 else if(!DestDir
.empty())
2794 DestFile
= DestDir
+ "/" + flNotDir(URI
);
2796 DestFile
= flNotDir(URI
);
2800 Desc
.Description
= Dsc
;
2803 // Set the short description to the archive component
2804 Desc
.ShortDesc
= ShortDesc
;
2806 // Get the transfer sizes
2809 if (stat(DestFile
.c_str(),&Buf
) == 0)
2811 // Hmm, the partial file is too big, erase it
2812 if ((Size
> 0) && (unsigned long long)Buf
.st_size
> Size
)
2813 unlink(DestFile
.c_str());
2815 PartialSize
= Buf
.st_size
;
2821 // AcqFile::Done - Item downloaded OK /*{{{*/
2822 void pkgAcqFile::Done(string
const &Message
,HashStringList
const &CalcHashes
,
2823 pkgAcquire::MethodConfig
const * const Cnf
)
2825 Item::Done(Message
,CalcHashes
,Cnf
);
2827 string FileName
= LookupTag(Message
,"Filename");
2828 if (FileName
.empty() == true)
2831 ErrorText
= "Method gave a blank filename";
2837 // The files timestamp matches
2838 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
2841 // We have to copy it into place
2842 if (FileName
!= DestFile
)
2845 if (_config
->FindB("Acquire::Source-Symlinks",true) == false ||
2846 Cnf
->Removable
== true)
2848 Desc
.URI
= "copy:" + FileName
;
2853 // Erase the file if it is a symlink so we can overwrite it
2855 if (lstat(DestFile
.c_str(),&St
) == 0)
2857 if (S_ISLNK(St
.st_mode
) != 0)
2858 unlink(DestFile
.c_str());
2862 if (symlink(FileName
.c_str(),DestFile
.c_str()) != 0)
2864 _error
->PushToStack();
2865 _error
->Errno("pkgAcqFile::Done", "Symlinking file %s failed", DestFile
.c_str());
2866 std::stringstream msg
;
2867 _error
->DumpErrors(msg
);
2868 _error
->RevertToStack();
2869 ErrorText
= msg
.str();
2876 // AcqFile::Failed - Failure handler /*{{{*/
2877 // ---------------------------------------------------------------------
2878 /* Here we try other sources */
2879 void pkgAcqFile::Failed(string
const &Message
, pkgAcquire::MethodConfig
const * const Cnf
)
2881 Item::Failed(Message
,Cnf
);
2883 // This is the retry counter
2885 Cnf
->LocalOnly
== false &&
2886 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2896 string
pkgAcqFile::Custom600Headers() const /*{{{*/
2899 return "\nIndex-File: true";