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/metaindex.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>
34 #include <apt-pkg/gpgv.h>
54 static void printHashSumComparision(std::string
const &URI
, HashStringList
const &Expected
, HashStringList
const &Actual
) /*{{{*/
56 if (_config
->FindB("Debug::Acquire::HashSumMismatch", false) == false)
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
;
66 static std::string
GetPartialFileName(std::string
const &file
) /*{{{*/
68 std::string DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
73 static std::string
GetPartialFileNameFromURI(std::string
const &uri
) /*{{{*/
75 return GetPartialFileName(URItoFileName(uri
));
78 static std::string
GetFinalFileNameFromURI(std::string
const &uri
) /*{{{*/
80 return _config
->FindDir("Dir::State::lists") + URItoFileName(uri
);
83 static std::string
GetCompressedFileName(std::string
const &URI
, std::string
const &Name
, std::string
const &Ext
) /*{{{*/
85 if (Ext
.empty() || Ext
== "uncompressed")
88 // do not reverify cdrom sources as apt-cdrom may rewrite the Packages
89 // file when its doing the indexcopy
90 if (URI
.substr(0,6) == "cdrom:")
93 // adjust DestFile if its compressed on disk
94 if (_config
->FindB("Acquire::GzipIndexes",false) == true)
95 return Name
+ '.' + Ext
;
99 static std::string
GetMergeDiffsPatchFileName(std::string
const &Final
, std::string
const &Patch
)/*{{{*/
101 // rred expects the patch as $FinalFile.ed.$patchname.gz
102 return Final
+ ".ed." + Patch
+ ".gz";
105 static std::string
GetDiffsPatchFileName(std::string
const &Final
) /*{{{*/
107 // rred expects the patch as $FinalFile.ed
108 return Final
+ ".ed";
112 static bool AllowInsecureRepositories(metaIndex
const * const MetaIndexParser
, pkgAcqMetaClearSig
* const TransactionManager
, pkgAcquire::Item
* const I
) /*{{{*/
114 if(MetaIndexParser
->GetTrusted() == metaIndex::TRI_YES
|| _config
->FindB("Acquire::AllowInsecureRepositories") == true)
117 _error
->Error(_("Use --allow-insecure-repositories to force the update"));
118 TransactionManager
->AbortTransaction();
119 I
->Status
= pkgAcquire::Item::StatError
;
123 static HashStringList
GetExpectedHashesFromFor(metaIndex
* const Parser
, std::string
const &MetaKey
)/*{{{*/
126 return HashStringList();
127 metaIndex::checkSum
* const R
= Parser
->Lookup(MetaKey
);
129 return HashStringList();
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. */
140 APT_CONST
bool pkgAcqTransactionItem::HashesRequired() const
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 */
147 return TransactionManager
->MetaIndexParser
!= NULL
&&
148 TransactionManager
->MetaIndexParser
->GetLoadedSuccessfully() != metaIndex::TRI_UNSET
;
150 HashStringList
pkgAcqTransactionItem::GetExpectedHashes() const
152 return GetExpectedHashesFor(GetMetaKey());
155 APT_CONST
bool pkgAcqMetaBase::HashesRequired() const
157 // Release and co have no hashes 'by design'.
160 HashStringList
pkgAcqMetaBase::GetExpectedHashes() const
162 return HashStringList();
165 APT_CONST
bool pkgAcqIndexDiffs::HashesRequired() const
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;
175 HashStringList
pkgAcqIndexDiffs::GetExpectedHashes() const
177 if (State
== StateFetchDiff
)
178 return available_patches
[0].download_hashes
;
179 return HashStringList();
182 APT_CONST
bool pkgAcqIndexMergeDiffs::HashesRequired() const
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 */
187 if (State
== StateFetchDiff
)
188 return patch
.download_hashes
.empty() == false;
189 return State
== StateApplyDiff
;
191 HashStringList
pkgAcqIndexMergeDiffs::GetExpectedHashes() const
193 if (State
== StateFetchDiff
)
194 return patch
.download_hashes
;
195 else if (State
== StateApplyDiff
)
196 return GetExpectedHashesFor(Target
.MetaKey
);
197 return HashStringList();
200 APT_CONST
bool pkgAcqArchive::HashesRequired() const
202 return LocalSource
== false;
204 HashStringList
pkgAcqArchive::GetExpectedHashes() const
206 // figured out while parsing the records
207 return ExpectedHashes
;
210 APT_CONST
bool pkgAcqFile::HashesRequired() const
212 // supplied as parameter at creation time, so the caller decides
213 return ExpectedHashes
.usable();
215 HashStringList
pkgAcqFile::GetExpectedHashes() const
217 return ExpectedHashes
;
220 // Acquire::Item::QueueURI and specialisations from child classes /*{{{*/
221 bool pkgAcquire::Item::QueueURI(pkgAcquire::ItemDesc
&Item
)
223 Owner
->Enqueue(Item
);
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) */
230 bool pkgAcqTransactionItem::QueueURI(pkgAcquire::ItemDesc
&Item
)
232 std::string
const FinalFile
= GetFinalFilename();
233 if (TransactionManager
!= NULL
&& TransactionManager
->IMSHit
== true &&
234 FileExists(FinalFile
) == true)
236 PartialFile
= DestFile
= FinalFile
;
240 return pkgAcquire::Item::QueueURI(Item
);
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 */
245 bool pkgAcqMetaBase::QueueURI(pkgAcquire::ItemDesc
&Item
)
247 return pkgAcquire::Item::QueueURI(Item
);
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 */
251 bool pkgAcqDiffIndex::QueueURI(pkgAcquire::ItemDesc
&Item
)
253 if (pkgAcqTransactionItem::QueueURI(Item
) == true)
259 // Acquire::Item::GetFinalFilename and specialisations for child classes /*{{{*/
260 std::string
pkgAcquire::Item::GetFinalFilename() const
262 return GetFinalFileNameFromURI(Desc
.URI
);
264 std::string
pkgAcqDiffIndex::GetFinalFilename() const
266 // the logic we inherent from pkgAcqBaseIndex isn't what we need here
267 return pkgAcquire::Item::GetFinalFilename();
269 std::string
pkgAcqIndex::GetFinalFilename() const
271 std::string
const FinalFile
= GetFinalFileNameFromURI(Target
.URI
);
272 return GetCompressedFileName(Target
.URI
, FinalFile
, CurrentCompressionExtension
);
274 std::string
pkgAcqMetaSig::GetFinalFilename() const
276 return GetFinalFileNameFromURI(Target
.URI
);
278 std::string
pkgAcqBaseIndex::GetFinalFilename() const
280 return GetFinalFileNameFromURI(Target
.URI
);
282 std::string
pkgAcqMetaBase::GetFinalFilename() const
284 return GetFinalFileNameFromURI(Target
.URI
);
286 std::string
pkgAcqArchive::GetFinalFilename() const
288 return _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
291 // pkgAcqTransactionItem::GetMetaKey and specialisations for child classes /*{{{*/
292 std::string
pkgAcqTransactionItem::GetMetaKey() const
294 return Target
.MetaKey
;
296 std::string
pkgAcqIndex::GetMetaKey() const
298 if (Stage
== STAGE_DECOMPRESS_AND_VERIFY
|| CurrentCompressionExtension
== "uncompressed")
299 return Target
.MetaKey
;
300 return Target
.MetaKey
+ "." + CurrentCompressionExtension
;
302 std::string
pkgAcqDiffIndex::GetMetaKey() const
304 return Target
.MetaKey
+ ".diff/Index";
307 //pkgAcqTransactionItem::TransactionState and specialisations for child classes /*{{{*/
308 bool pkgAcqTransactionItem::TransactionState(TransactionStates
const state
)
310 bool const Debug
= _config
->FindB("Debug::Acquire::Transaction", false);
313 case TransactionAbort
:
315 std::clog
<< " Cancel: " << DestFile
<< std::endl
;
316 if (Status
== pkgAcquire::Item::StatIdle
)
318 Status
= pkgAcquire::Item::StatDone
;
322 case TransactionCommit
:
323 if(PartialFile
!= "")
326 std::clog
<< "mv " << PartialFile
<< " -> "<< DestFile
<< " # " << DescURI() << std::endl
;
328 Rename(PartialFile
, DestFile
);
331 std::clog
<< "rm " << DestFile
<< " # " << DescURI() << std::endl
;
332 unlink(DestFile
.c_str());
338 bool pkgAcqMetaBase::TransactionState(TransactionStates
const state
)
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
);
345 bool pkgAcqIndex::TransactionState(TransactionStates
const state
)
347 if (pkgAcqTransactionItem::TransactionState(state
) == false)
352 case TransactionAbort
:
353 if (Stage
== STAGE_DECOMPRESS_AND_VERIFY
)
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());
361 case TransactionCommit
:
362 if (EraseFileName
.empty() == false)
363 unlink(EraseFileName
.c_str());
368 bool pkgAcqDiffIndex::TransactionState(TransactionStates
const state
)
370 if (pkgAcqTransactionItem::TransactionState(state
) == false)
375 case TransactionCommit
:
377 case TransactionAbort
:
378 std::string
const Partial
= GetPartialFileNameFromURI(Target
.URI
);
379 unlink(Partial
.c_str());
387 class 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. */
392 IndexTarget
const Target
;
394 virtual std::string
DescURI() const {return Target
.URI
;};
395 virtual HashStringList
GetExpectedHashes() const {return HashStringList();};
397 NoActionItem(pkgAcquire
* const Owner
, IndexTarget
const &Target
) :
398 pkgAcquire::Item(Owner
), Target(Target
)
401 DestFile
= GetFinalFileNameFromURI(Target
.URI
);
406 // Acquire::Item::Item - Constructor /*{{{*/
407 APT_IGNORE_DEPRECATED_PUSH
408 pkgAcquire::Item::Item(pkgAcquire
* const owner
) :
409 FileSize(0), PartialSize(0), Mode(0), ID(0), Complete(false), Local(false),
410 QueueCounter(0), ExpectedAdditionalItems(0), Owner(owner
), d(NULL
)
415 APT_IGNORE_DEPRECATED_POP
417 // Acquire::Item::~Item - Destructor /*{{{*/
418 pkgAcquire::Item::~Item()
423 std::string
pkgAcquire::Item::Custom600Headers() const /*{{{*/
425 return std::string();
428 std::string
pkgAcquire::Item::ShortDesc() const /*{{{*/
433 APT_CONST
void pkgAcquire::Item::Finished() /*{{{*/
437 APT_PURE pkgAcquire
* pkgAcquire::Item::GetOwner() const /*{{{*/
442 APT_CONST
pkgAcquire::ItemDesc
&pkgAcquire::Item::GetItemDesc() /*{{{*/
447 APT_CONST
bool pkgAcquire::Item::IsTrusted() const /*{{{*/
452 // Acquire::Item::Failed - Item failed to download /*{{{*/
453 // ---------------------------------------------------------------------
454 /* We return to an idle state if there are still other queues that could
456 void pkgAcquire::Item::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)
458 if(ErrorText
.empty())
459 ErrorText
= LookupTag(Message
,"Message");
460 UsedMirror
= LookupTag(Message
,"UsedMirror");
461 if (QueueCounter
<= 1)
463 /* This indicates that the file is not available right now but might
464 be sometime later. If we do a retry cycle then this should be
466 if (Cnf
!= NULL
&& Cnf
->LocalOnly
== true &&
467 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
483 case StatTransientNetworkError
:
490 string
const FailReason
= LookupTag(Message
, "FailReason");
491 if (FailReason
== "MaximumSizeExceeded")
492 RenameOnError(MaximumSizeExceeded
);
493 else if (Status
== StatAuthError
)
494 RenameOnError(HashSumMismatch
);
496 // report mirror failure back to LP if we actually use a mirror
497 if (FailReason
.empty() == false)
498 ReportMirrorFailure(FailReason
);
500 ReportMirrorFailure(ErrorText
);
502 if (QueueCounter
> 1)
506 // Acquire::Item::Start - Item has begun to download /*{{{*/
507 // ---------------------------------------------------------------------
508 /* Stash status and the file size. Note that setting Complete means
509 sub-phases of the acquire process such as decompresion are operating */
510 void pkgAcquire::Item::Start(string
const &/*Message*/, unsigned long long const Size
)
512 Status
= StatFetching
;
514 if (FileSize
== 0 && Complete
== false)
518 // Acquire::Item::Done - Item downloaded OK /*{{{*/
519 void pkgAcquire::Item::Done(string
const &Message
, HashStringList
const &Hashes
,
520 pkgAcquire::MethodConfig
const * const /*Cnf*/)
522 // We just downloaded something..
523 UsedMirror
= LookupTag(Message
,"UsedMirror");
526 unsigned long long const downloadedSize
= Hashes
.FileSize();
527 if (downloadedSize
!= 0)
529 FileSize
= downloadedSize
;
533 ErrorText
= string();
534 Owner
->Dequeue(this);
537 // Acquire::Item::Rename - Rename a file /*{{{*/
538 // ---------------------------------------------------------------------
539 /* This helper function is used by a lot of item methods as their final
541 bool pkgAcquire::Item::Rename(string
const &From
,string
const &To
)
543 if (From
== To
|| rename(From
.c_str(),To
.c_str()) == 0)
547 strprintf(S
, _("rename failed, %s (%s -> %s)."), strerror(errno
),
548 From
.c_str(),To
.c_str());
550 if (ErrorText
.empty())
553 ErrorText
= ErrorText
+ ": " + S
;
557 void pkgAcquire::Item::Dequeue() /*{{{*/
559 Owner
->Dequeue(this);
562 bool pkgAcquire::Item::RenameOnError(pkgAcquire::Item::RenameOnErrorState
const error
)/*{{{*/
564 if (RealFileExists(DestFile
))
565 Rename(DestFile
, DestFile
+ ".FAILED");
570 case HashSumMismatch
:
571 errtext
= _("Hash Sum mismatch");
572 Status
= StatAuthError
;
573 ReportMirrorFailure("HashChecksumFailure");
576 errtext
= _("Size mismatch");
577 Status
= StatAuthError
;
578 ReportMirrorFailure("SizeFailure");
581 errtext
= _("Invalid file format");
583 // do not report as usually its not the mirrors fault, but Portal/Proxy
586 errtext
= _("Signature error");
590 errtext
= _("Does not start with a cleartext signature");
593 case MaximumSizeExceeded
:
594 // the method is expected to report a good error for this
598 // no handling here, done by callers
601 if (ErrorText
.empty())
606 void pkgAcquire::Item::SetActiveSubprocess(const std::string
&subprocess
)/*{{{*/
608 ActiveSubprocess
= subprocess
;
609 APT_IGNORE_DEPRECATED(Mode
= ActiveSubprocess
.c_str();)
612 // Acquire::Item::ReportMirrorFailure /*{{{*/
613 void pkgAcquire::Item::ReportMirrorFailure(string
const &FailCode
)
615 // we only act if a mirror was used at all
616 if(UsedMirror
.empty())
619 std::cerr
<< "\nReportMirrorFailure: "
621 << " Uri: " << DescURI()
623 << FailCode
<< std::endl
;
625 string report
= _config
->Find("Methods::Mirror::ProblemReporting",
626 "/usr/lib/apt/apt-report-mirror-failure");
627 if(!FileExists(report
))
630 std::vector
<char const*> Args
;
631 Args
.push_back(report
.c_str());
632 Args
.push_back(UsedMirror
.c_str());
633 Args
.push_back(DescURI().c_str());
634 Args
.push_back(FailCode
.c_str());
635 Args
.push_back(NULL
);
637 pid_t pid
= ExecFork();
640 _error
->Error("ReportMirrorFailure Fork failed");
645 execvp(Args
[0], (char**)Args
.data());
646 std::cerr
<< "Could not exec " << Args
[0] << std::endl
;
649 if(!ExecWait(pid
, "report-mirror-failure"))
651 _error
->Warning("Couldn't report problem to '%s'",
652 _config
->Find("Methods::Mirror::ProblemReporting").c_str());
656 std::string
pkgAcquire::Item::HashSum() const /*{{{*/
658 HashStringList
const hashes
= GetExpectedHashes();
659 HashString
const * const hs
= hashes
.find(NULL
);
660 return hs
!= NULL
? hs
->toStr() : "";
664 pkgAcqTransactionItem::pkgAcqTransactionItem(pkgAcquire
* const Owner
, /*{{{*/
665 pkgAcqMetaClearSig
* const transactionManager
, IndexTarget
const &target
) :
666 pkgAcquire::Item(Owner
), d(NULL
), Target(target
), TransactionManager(transactionManager
)
668 if (TransactionManager
!= this)
669 TransactionManager
->Add(this);
672 pkgAcqTransactionItem::~pkgAcqTransactionItem() /*{{{*/
676 HashStringList
pkgAcqTransactionItem::GetExpectedHashesFor(std::string
const &MetaKey
) const /*{{{*/
678 return GetExpectedHashesFromFor(TransactionManager
->MetaIndexParser
, MetaKey
);
682 // AcqMetaBase - Constructor /*{{{*/
683 pkgAcqMetaBase::pkgAcqMetaBase(pkgAcquire
* const Owner
,
684 pkgAcqMetaClearSig
* const TransactionManager
,
685 std::vector
<IndexTarget
> const &IndexTargets
,
686 IndexTarget
const &DataTarget
)
687 : pkgAcqTransactionItem(Owner
, TransactionManager
, DataTarget
), d(NULL
),
688 IndexTargets(IndexTargets
),
689 AuthPass(false), IMSHit(false)
693 // AcqMetaBase::Add - Add a item to the current Transaction /*{{{*/
694 void pkgAcqMetaBase::Add(pkgAcqTransactionItem
* const I
)
696 Transaction
.push_back(I
);
699 // AcqMetaBase::AbortTransaction - Abort the current Transaction /*{{{*/
700 void pkgAcqMetaBase::AbortTransaction()
702 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
703 std::clog
<< "AbortTransaction: " << TransactionManager
<< std::endl
;
705 // ensure the toplevel is in error state too
706 for (std::vector
<pkgAcqTransactionItem
*>::iterator I
= Transaction
.begin();
707 I
!= Transaction
.end(); ++I
)
709 (*I
)->TransactionState(TransactionAbort
);
714 // AcqMetaBase::TransactionHasError - Check for errors in Transaction /*{{{*/
715 APT_PURE
bool pkgAcqMetaBase::TransactionHasError() const
717 for (std::vector
<pkgAcqTransactionItem
*>::const_iterator I
= Transaction
.begin();
718 I
!= Transaction
.end(); ++I
)
720 switch((*I
)->Status
) {
721 case StatDone
: break;
722 case StatIdle
: break;
723 case StatAuthError
: return true;
724 case StatError
: return true;
725 case StatTransientNetworkError
: return true;
726 case StatFetching
: break;
732 // AcqMetaBase::CommitTransaction - Commit a transaction /*{{{*/
733 void pkgAcqMetaBase::CommitTransaction()
735 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
736 std::clog
<< "CommitTransaction: " << this << std::endl
;
738 // move new files into place *and* remove files that are not
739 // part of the transaction but are still on disk
740 for (std::vector
<pkgAcqTransactionItem
*>::iterator I
= Transaction
.begin();
741 I
!= Transaction
.end(); ++I
)
743 (*I
)->TransactionState(TransactionCommit
);
748 // AcqMetaBase::TransactionStageCopy - Stage a file for copying /*{{{*/
749 void pkgAcqMetaBase::TransactionStageCopy(pkgAcqTransactionItem
* const I
,
750 const std::string
&From
,
751 const std::string
&To
)
753 I
->PartialFile
= From
;
757 // AcqMetaBase::TransactionStageRemoval - Stage a file for removal /*{{{*/
758 void pkgAcqMetaBase::TransactionStageRemoval(pkgAcqTransactionItem
* const I
,
759 const std::string
&FinalFile
)
762 I
->DestFile
= FinalFile
;
765 // AcqMetaBase::GenerateAuthWarning - Check gpg authentication error /*{{{*/
766 bool pkgAcqMetaBase::CheckStopAuthentication(pkgAcquire::Item
* const I
, const std::string
&Message
)
768 // FIXME: this entire function can do now that we disallow going to
769 // a unauthenticated state and can cleanly rollback
771 string
const Final
= I
->GetFinalFilename();
772 if(FileExists(Final
))
774 I
->Status
= StatTransientNetworkError
;
775 _error
->Warning(_("An error occurred during the signature "
776 "verification. The repository is not updated "
777 "and the previous index files will be used. "
778 "GPG error: %s: %s\n"),
779 Desc
.Description
.c_str(),
780 LookupTag(Message
,"Message").c_str());
781 RunScripts("APT::Update::Auth-Failure");
783 } else if (LookupTag(Message
,"Message").find("NODATA") != string::npos
) {
784 /* Invalid signature file, reject (LP: #346386) (Closes: #627642) */
785 _error
->Error(_("GPG error: %s: %s"),
786 Desc
.Description
.c_str(),
787 LookupTag(Message
,"Message").c_str());
788 I
->Status
= StatError
;
791 _error
->Warning(_("GPG error: %s: %s"),
792 Desc
.Description
.c_str(),
793 LookupTag(Message
,"Message").c_str());
795 // gpgv method failed
796 ReportMirrorFailure("GPGFailure");
800 // AcqMetaBase::Custom600Headers - Get header for AcqMetaBase /*{{{*/
801 // ---------------------------------------------------------------------
802 string
pkgAcqMetaBase::Custom600Headers() const
804 std::string Header
= "\nIndex-File: true";
805 std::string MaximumSize
;
806 strprintf(MaximumSize
, "\nMaximum-Size: %i",
807 _config
->FindI("Acquire::MaxReleaseFileSize", 10*1000*1000));
808 Header
+= MaximumSize
;
810 string
const FinalFile
= GetFinalFilename();
813 if (stat(FinalFile
.c_str(),&Buf
) == 0)
814 Header
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
819 // AcqMetaBase::QueueForSignatureVerify /*{{{*/
820 void pkgAcqMetaBase::QueueForSignatureVerify(pkgAcqTransactionItem
* const I
, std::string
const &File
, std::string
const &Signature
)
823 I
->Desc
.URI
= "gpgv:" + Signature
;
826 I
->SetActiveSubprocess("gpgv");
829 // AcqMetaBase::CheckDownloadDone /*{{{*/
830 bool pkgAcqMetaBase::CheckDownloadDone(pkgAcqTransactionItem
* const I
, const std::string
&Message
, HashStringList
const &Hashes
) const
832 // We have just finished downloading a Release file (it is not
835 string
const FileName
= LookupTag(Message
,"Filename");
836 if (FileName
.empty() == true)
838 I
->Status
= StatError
;
839 I
->ErrorText
= "Method gave a blank filename";
843 if (FileName
!= I
->DestFile
&& RealFileExists(I
->DestFile
) == false)
846 I
->Desc
.URI
= "copy:" + FileName
;
847 I
->QueueURI(I
->Desc
);
851 // make sure to verify against the right file on I-M-S hit
852 bool IMSHit
= StringToBool(LookupTag(Message
,"IMS-Hit"), false);
853 if (IMSHit
== false && Hashes
.usable())
855 // detect IMS-Hits servers haven't detected by Hash comparison
856 std::string
const FinalFile
= I
->GetFinalFilename();
857 if (RealFileExists(FinalFile
) && Hashes
.VerifyFile(FinalFile
) == true)
860 unlink(I
->DestFile
.c_str());
866 // for simplicity, the transaction manager is always InRelease
867 // even if it doesn't exist.
868 if (TransactionManager
!= NULL
)
869 TransactionManager
->IMSHit
= true;
870 I
->PartialFile
= I
->DestFile
= I
->GetFinalFilename();
873 // set Item to complete as the remaining work is all local (verify etc)
879 bool pkgAcqMetaBase::CheckAuthDone(string
const &Message
) /*{{{*/
881 // At this point, the gpgv method has succeeded, so there is a
882 // valid signature from a key in the trusted keyring. We
883 // perform additional verification of its contents, and use them
884 // to verify the indexes we are about to download
886 if (TransactionManager
->IMSHit
== false)
888 // open the last (In)Release if we have it
889 std::string
const FinalFile
= GetFinalFilename();
890 std::string FinalRelease
;
891 std::string FinalInRelease
;
892 if (APT::String::Endswith(FinalFile
, "InRelease"))
894 FinalInRelease
= FinalFile
;
895 FinalRelease
= FinalFile
.substr(0, FinalFile
.length() - strlen("InRelease")) + "Release";
899 FinalInRelease
= FinalFile
.substr(0, FinalFile
.length() - strlen("Release")) + "InRelease";
900 FinalRelease
= FinalFile
;
902 if (RealFileExists(FinalInRelease
) || RealFileExists(FinalRelease
))
904 TransactionManager
->LastMetaIndexParser
= TransactionManager
->MetaIndexParser
->UnloadedClone();
905 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
907 _error
->PushToStack();
908 if (RealFileExists(FinalInRelease
))
909 TransactionManager
->LastMetaIndexParser
->Load(FinalInRelease
, NULL
);
911 TransactionManager
->LastMetaIndexParser
->Load(FinalRelease
, NULL
);
912 // its unlikely to happen, but if what we have is bad ignore it
913 if (_error
->PendingError())
915 delete TransactionManager
->LastMetaIndexParser
;
916 TransactionManager
->LastMetaIndexParser
= NULL
;
918 _error
->RevertToStack();
923 if (TransactionManager
->MetaIndexParser
->Load(DestFile
, &ErrorText
) == false)
925 Status
= StatAuthError
;
929 if (!VerifyVendor(Message
))
931 Status
= StatAuthError
;
935 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
936 std::cerr
<< "Signature verification succeeded: "
937 << DestFile
<< std::endl
;
939 // Download further indexes with verification
945 void pkgAcqMetaBase::QueueIndexes(bool const verify
) /*{{{*/
947 // at this point the real Items are loaded in the fetcher
948 ExpectedAdditionalItems
= 0;
950 for (std::vector
<IndexTarget
>::const_iterator Target
= IndexTargets
.begin();
951 Target
!= IndexTargets
.end();
954 bool trypdiff
= _config
->FindB("Acquire::PDiffs", true);
957 if (TransactionManager
->MetaIndexParser
->Exists(Target
->MetaKey
) == false)
959 // optional targets that we do not have in the Release file are skipped
960 if (Target
->IsOptional
)
963 Status
= StatAuthError
;
964 strprintf(ErrorText
, _("Unable to find expected entry '%s' in Release file (Wrong sources.list entry or malformed file)"), Target
->MetaKey
.c_str());
968 if (RealFileExists(GetFinalFileNameFromURI(Target
->URI
)))
970 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
972 HashStringList
const newFile
= GetExpectedHashesFromFor(TransactionManager
->MetaIndexParser
, Target
->MetaKey
);
973 HashStringList
const oldFile
= GetExpectedHashesFromFor(TransactionManager
->LastMetaIndexParser
, Target
->MetaKey
);
974 if (newFile
== oldFile
)
976 // we have the file already, no point in trying to acquire it again
977 new NoActionItem(Owner
, *Target
);
983 trypdiff
= false; // no file to patch
985 // check if we have patches available
986 trypdiff
&= TransactionManager
->MetaIndexParser
->Exists(Target
->MetaKey
+ ".diff/Index");
988 // if we have no file to patch, no point in trying
989 trypdiff
&= RealFileExists(GetFinalFileNameFromURI(Target
->URI
));
991 // no point in patching from local sources
994 std::string
const proto
= Target
->URI
.substr(0, strlen("file:/"));
995 if (proto
== "file:/" || proto
== "copy:/" || proto
== "cdrom:")
999 // Queue the Index file (Packages, Sources, Translation-$foo, …)
1001 new pkgAcqDiffIndex(Owner
, TransactionManager
, *Target
);
1003 new pkgAcqIndex(Owner
, TransactionManager
, *Target
);
1007 bool pkgAcqMetaBase::VerifyVendor(string
const &Message
) /*{{{*/
1009 string::size_type pos
;
1011 // check for missing sigs (that where not fatal because otherwise we had
1014 string msg
= _("There is no public key available for the "
1015 "following key IDs:\n");
1016 pos
= Message
.find("NO_PUBKEY ");
1017 if (pos
!= std::string::npos
)
1019 string::size_type start
= pos
+strlen("NO_PUBKEY ");
1020 string Fingerprint
= Message
.substr(start
, Message
.find("\n")-start
);
1021 missingkeys
+= (Fingerprint
);
1023 if(!missingkeys
.empty())
1024 _error
->Warning("%s", (msg
+ missingkeys
).c_str());
1026 string Transformed
= TransactionManager
->MetaIndexParser
->GetExpectedDist();
1028 if (Transformed
== "../project/experimental")
1030 Transformed
= "experimental";
1033 pos
= Transformed
.rfind('/');
1034 if (pos
!= string::npos
)
1036 Transformed
= Transformed
.substr(0, pos
);
1039 if (Transformed
== ".")
1044 if (_config
->FindB("Acquire::Check-Valid-Until", true) == true &&
1045 TransactionManager
->MetaIndexParser
->GetValidUntil() > 0) {
1046 time_t const invalid_since
= time(NULL
) - TransactionManager
->MetaIndexParser
->GetValidUntil();
1047 if (invalid_since
> 0)
1051 // TRANSLATOR: The first %s is the URL of the bad Release file, the second is
1052 // the time since then the file is invalid - formatted in the same way as in
1053 // the download progress display (e.g. 7d 3h 42min 1s)
1054 _("Release file for %s is expired (invalid since %s). "
1055 "Updates for this repository will not be applied."),
1056 Target
.URI
.c_str(), TimeToStr(invalid_since
).c_str());
1057 if (ErrorText
.empty())
1059 return _error
->Error("%s", errmsg
.c_str());
1063 /* Did we get a file older than what we have? This is a last minute IMS hit and doubles
1064 as a prevention of downgrading us to older (still valid) files */
1065 if (TransactionManager
->IMSHit
== false && TransactionManager
->LastMetaIndexParser
!= NULL
&&
1066 TransactionManager
->LastMetaIndexParser
->GetDate() > TransactionManager
->MetaIndexParser
->GetDate())
1068 TransactionManager
->IMSHit
= true;
1069 unlink(DestFile
.c_str());
1070 PartialFile
= DestFile
= GetFinalFilename();
1071 // load the 'old' file in the 'new' one instead of flipping pointers as
1072 // the new one isn't owned by us, while the old one is so cleanup would be confused.
1073 TransactionManager
->MetaIndexParser
->swapLoad(TransactionManager
->LastMetaIndexParser
);
1074 delete TransactionManager
->LastMetaIndexParser
;
1075 TransactionManager
->LastMetaIndexParser
= NULL
;
1078 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1080 std::cerr
<< "Got Codename: " << TransactionManager
->MetaIndexParser
->GetCodename() << std::endl
;
1081 std::cerr
<< "Expecting Dist: " << TransactionManager
->MetaIndexParser
->GetExpectedDist() << std::endl
;
1082 std::cerr
<< "Transformed Dist: " << Transformed
<< std::endl
;
1085 if (TransactionManager
->MetaIndexParser
->CheckDist(Transformed
) == false)
1087 // This might become fatal one day
1088 // Status = StatAuthError;
1089 // ErrorText = "Conflicting distribution; expected "
1090 // + MetaIndexParser->GetExpectedDist() + " but got "
1091 // + MetaIndexParser->GetCodename();
1093 if (!Transformed
.empty())
1095 _error
->Warning(_("Conflicting distribution: %s (expected %s but got %s)"),
1096 Desc
.Description
.c_str(),
1097 Transformed
.c_str(),
1098 TransactionManager
->MetaIndexParser
->GetCodename().c_str());
1105 pkgAcqMetaBase::~pkgAcqMetaBase()
1109 pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire
* const Owner
, /*{{{*/
1110 IndexTarget
const &ClearsignedTarget
,
1111 IndexTarget
const &DetachedDataTarget
, IndexTarget
const &DetachedSigTarget
,
1112 std::vector
<IndexTarget
> const &IndexTargets
,
1113 metaIndex
* const MetaIndexParser
) :
1114 pkgAcqMetaIndex(Owner
, this, ClearsignedTarget
, DetachedSigTarget
, IndexTargets
),
1115 d(NULL
), ClearsignedTarget(ClearsignedTarget
),
1116 DetachedDataTarget(DetachedDataTarget
),
1117 MetaIndexParser(MetaIndexParser
), LastMetaIndexParser(NULL
)
1119 // index targets + (worst case:) Release/Release.gpg
1120 ExpectedAdditionalItems
= IndexTargets
.size() + 2;
1121 TransactionManager
->Add(this);
1124 pkgAcqMetaClearSig::~pkgAcqMetaClearSig() /*{{{*/
1126 if (LastMetaIndexParser
!= NULL
)
1127 delete LastMetaIndexParser
;
1130 // pkgAcqMetaClearSig::Custom600Headers - Insert custom request headers /*{{{*/
1131 string
pkgAcqMetaClearSig::Custom600Headers() const
1133 string Header
= pkgAcqMetaBase::Custom600Headers();
1134 Header
+= "\nFail-Ignore: true";
1138 // pkgAcqMetaClearSig::Done - We got a file /*{{{*/
1139 void pkgAcqMetaClearSig::Done(std::string
const &Message
,
1140 HashStringList
const &Hashes
,
1141 pkgAcquire::MethodConfig
const * const Cnf
)
1143 Item::Done(Message
, Hashes
, Cnf
);
1145 // if we expect a ClearTextSignature (InRelease), ensure that
1146 // this is what we get and if not fail to queue a
1147 // Release/Release.gpg, see #346386
1148 if (FileExists(DestFile
) && !StartsWithGPGClearTextSignature(DestFile
))
1150 pkgAcquire::Item::Failed(Message
, Cnf
);
1151 RenameOnError(NotClearsigned
);
1152 TransactionManager
->AbortTransaction();
1156 if(AuthPass
== false)
1158 if(CheckDownloadDone(this, Message
, Hashes
) == true)
1159 QueueForSignatureVerify(this, DestFile
, DestFile
);
1162 else if(CheckAuthDone(Message
) == true)
1164 if (TransactionManager
->IMSHit
== false)
1165 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
1166 else if (RealFileExists(GetFinalFilename()) == false)
1168 // We got an InRelease file IMSHit, but we haven't one, which means
1169 // we had a valid Release/Release.gpg combo stepping in, which we have
1170 // to 'acquire' now to ensure list cleanup isn't removing them
1171 new NoActionItem(Owner
, DetachedDataTarget
);
1172 new NoActionItem(Owner
, DetachedSigTarget
);
1177 void pkgAcqMetaClearSig::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
) /*{{{*/
1179 Item::Failed(Message
, Cnf
);
1181 // we failed, we will not get additional items from this method
1182 ExpectedAdditionalItems
= 0;
1184 if (AuthPass
== false)
1186 // Queue the 'old' InRelease file for removal if we try Release.gpg
1187 // as otherwise the file will stay around and gives a false-auth
1188 // impression (CVE-2012-0214)
1189 TransactionManager
->TransactionStageRemoval(this, GetFinalFilename());
1192 new pkgAcqMetaIndex(Owner
, TransactionManager
, DetachedDataTarget
, DetachedSigTarget
, IndexTargets
);
1196 if(CheckStopAuthentication(this, Message
))
1199 _error
->Warning(_("The data from '%s' is not signed. Packages "
1200 "from that repository can not be authenticated."),
1201 ClearsignedTarget
.Description
.c_str());
1203 // No Release file was present, or verification failed, so fall
1204 // back to queueing Packages files without verification
1205 // only allow going further if the users explicitely wants it
1206 if(AllowInsecureRepositories(TransactionManager
->MetaIndexParser
, TransactionManager
, this) == true)
1210 /* InRelease files become Release files, otherwise
1211 * they would be considered as trusted later on */
1212 string
const FinalRelease
= GetFinalFileNameFromURI(DetachedDataTarget
.URI
);
1213 string
const PartialRelease
= GetPartialFileNameFromURI(DetachedDataTarget
.URI
);
1214 string
const FinalReleasegpg
= GetFinalFileNameFromURI(DetachedSigTarget
.URI
);
1215 string
const FinalInRelease
= GetFinalFilename();
1216 Rename(DestFile
, PartialRelease
);
1217 TransactionManager
->TransactionStageCopy(this, PartialRelease
, FinalRelease
);
1219 if (RealFileExists(FinalReleasegpg
) || RealFileExists(FinalInRelease
))
1221 // open the last Release if we have it
1222 if (TransactionManager
->IMSHit
== false)
1224 TransactionManager
->LastMetaIndexParser
= TransactionManager
->MetaIndexParser
->UnloadedClone();
1225 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1227 _error
->PushToStack();
1228 if (RealFileExists(FinalInRelease
))
1229 TransactionManager
->LastMetaIndexParser
->Load(FinalInRelease
, NULL
);
1231 TransactionManager
->LastMetaIndexParser
->Load(FinalRelease
, NULL
);
1232 // its unlikely to happen, but if what we have is bad ignore it
1233 if (_error
->PendingError())
1235 delete TransactionManager
->LastMetaIndexParser
;
1236 TransactionManager
->LastMetaIndexParser
= NULL
;
1238 _error
->RevertToStack();
1243 // we parse the indexes here because at this point the user wanted
1244 // a repository that may potentially harm him
1245 if (TransactionManager
->MetaIndexParser
->Load(PartialRelease
, &ErrorText
) == false || VerifyVendor(Message
) == false)
1246 /* expired Release files are still a problem you need extra force for */;
1254 pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire
* const Owner
, /*{{{*/
1255 pkgAcqMetaClearSig
* const TransactionManager
,
1256 IndexTarget
const &DataTarget
,
1257 IndexTarget
const &DetachedSigTarget
,
1258 vector
<IndexTarget
> const &IndexTargets
) :
1259 pkgAcqMetaBase(Owner
, TransactionManager
, IndexTargets
, DataTarget
), d(NULL
),
1260 DetachedSigTarget(DetachedSigTarget
)
1262 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1263 std::clog
<< "New pkgAcqMetaIndex with TransactionManager "
1264 << this->TransactionManager
<< std::endl
;
1266 DestFile
= GetPartialFileNameFromURI(DataTarget
.URI
);
1269 Desc
.Description
= DataTarget
.Description
;
1271 Desc
.ShortDesc
= DataTarget
.ShortDesc
;
1272 Desc
.URI
= DataTarget
.URI
;
1274 // we expect more item
1275 ExpectedAdditionalItems
= IndexTargets
.size();
1279 void pkgAcqMetaIndex::Done(string
const &Message
, /*{{{*/
1280 HashStringList
const &Hashes
,
1281 pkgAcquire::MethodConfig
const * const Cfg
)
1283 Item::Done(Message
,Hashes
,Cfg
);
1285 if(CheckDownloadDone(this, Message
, Hashes
))
1287 // we have a Release file, now download the Signature, all further
1288 // verify/queue for additional downloads will be done in the
1289 // pkgAcqMetaSig::Done() code
1290 new pkgAcqMetaSig(Owner
, TransactionManager
, DetachedSigTarget
, this);
1294 // pkgAcqMetaIndex::Failed - no Release file present /*{{{*/
1295 void pkgAcqMetaIndex::Failed(string
const &Message
,
1296 pkgAcquire::MethodConfig
const * const Cnf
)
1298 pkgAcquire::Item::Failed(Message
, Cnf
);
1301 _error
->Warning(_("The repository '%s' does not have a Release file. "
1302 "This is deprecated, please contact the owner of the "
1303 "repository."), Target
.Description
.c_str());
1305 // No Release file was present so fall
1306 // back to queueing Packages files without verification
1307 // only allow going further if the users explicitely wants it
1308 if(AllowInsecureRepositories(TransactionManager
->MetaIndexParser
, TransactionManager
, this) == true)
1310 // ensure old Release files are removed
1311 TransactionManager
->TransactionStageRemoval(this, GetFinalFilename());
1313 // queue without any kind of hashsum support
1314 QueueIndexes(false);
1318 void pkgAcqMetaIndex::Finished() /*{{{*/
1320 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1321 std::clog
<< "Finished: " << DestFile
<<std::endl
;
1322 if(TransactionManager
!= NULL
&&
1323 TransactionManager
->TransactionHasError() == false)
1324 TransactionManager
->CommitTransaction();
1327 std::string
pkgAcqMetaIndex::DescURI() const /*{{{*/
1332 pkgAcqMetaIndex::~pkgAcqMetaIndex() {}
1334 // AcqMetaSig::AcqMetaSig - Constructor /*{{{*/
1335 pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire
* const Owner
,
1336 pkgAcqMetaClearSig
* const TransactionManager
,
1337 IndexTarget
const &Target
,
1338 pkgAcqMetaIndex
* const MetaIndex
) :
1339 pkgAcqTransactionItem(Owner
, TransactionManager
, Target
), d(NULL
), MetaIndex(MetaIndex
)
1341 DestFile
= GetPartialFileNameFromURI(Target
.URI
);
1343 // remove any partial downloaded sig-file in partial/.
1344 // it may confuse proxies and is too small to warrant a
1345 // partial download anyway
1346 unlink(DestFile
.c_str());
1348 // set the TransactionManager
1349 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1350 std::clog
<< "New pkgAcqMetaSig with TransactionManager "
1351 << TransactionManager
<< std::endl
;
1354 Desc
.Description
= Target
.Description
;
1356 Desc
.ShortDesc
= Target
.ShortDesc
;
1357 Desc
.URI
= Target
.URI
;
1359 // If we got a hit for Release, we will get one for Release.gpg too (or obscure errors),
1360 // so we skip the download step and go instantly to verification
1361 if (TransactionManager
->IMSHit
== true && RealFileExists(GetFinalFilename()))
1365 PartialFile
= DestFile
= GetFinalFilename();
1366 MetaIndexFileSignature
= DestFile
;
1367 MetaIndex
->QueueForSignatureVerify(this, MetaIndex
->DestFile
, DestFile
);
1373 pkgAcqMetaSig::~pkgAcqMetaSig() /*{{{*/
1377 // AcqMetaSig::Done - The signature was downloaded/verified /*{{{*/
1378 void pkgAcqMetaSig::Done(string
const &Message
, HashStringList
const &Hashes
,
1379 pkgAcquire::MethodConfig
const * const Cfg
)
1381 if (MetaIndexFileSignature
.empty() == false)
1383 DestFile
= MetaIndexFileSignature
;
1384 MetaIndexFileSignature
.clear();
1386 Item::Done(Message
, Hashes
, Cfg
);
1388 if(MetaIndex
->AuthPass
== false)
1390 if(MetaIndex
->CheckDownloadDone(this, Message
, Hashes
) == true)
1392 // destfile will be modified to point to MetaIndexFile for the
1393 // gpgv method, so we need to save it here
1394 MetaIndexFileSignature
= DestFile
;
1395 MetaIndex
->QueueForSignatureVerify(this, MetaIndex
->DestFile
, DestFile
);
1399 else if(MetaIndex
->CheckAuthDone(Message
) == true)
1401 if (TransactionManager
->IMSHit
== false)
1403 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
1404 TransactionManager
->TransactionStageCopy(MetaIndex
, MetaIndex
->DestFile
, MetaIndex
->GetFinalFilename());
1409 void pkgAcqMetaSig::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
1411 Item::Failed(Message
,Cnf
);
1413 // check if we need to fail at this point
1414 if (MetaIndex
->AuthPass
== true && MetaIndex
->CheckStopAuthentication(this, Message
))
1417 string
const FinalRelease
= MetaIndex
->GetFinalFilename();
1418 string
const FinalReleasegpg
= GetFinalFilename();
1419 string
const FinalInRelease
= TransactionManager
->GetFinalFilename();
1421 if (RealFileExists(FinalReleasegpg
) || RealFileExists(FinalInRelease
))
1423 std::string downgrade_msg
;
1424 strprintf(downgrade_msg
, _("The repository '%s' is no longer signed."),
1425 MetaIndex
->Target
.Description
.c_str());
1426 if(_config
->FindB("Acquire::AllowDowngradeToInsecureRepositories"))
1428 // meh, the users wants to take risks (we still mark the packages
1429 // from this repository as unauthenticated)
1430 _error
->Warning("%s", downgrade_msg
.c_str());
1431 _error
->Warning(_("This is normally not allowed, but the option "
1432 "Acquire::AllowDowngradeToInsecureRepositories was "
1433 "given to override it."));
1436 _error
->Error("%s", downgrade_msg
.c_str());
1437 if (TransactionManager
->IMSHit
== false)
1438 Rename(MetaIndex
->DestFile
, MetaIndex
->DestFile
+ ".FAILED");
1439 Item::Failed("Message: " + downgrade_msg
, Cnf
);
1440 TransactionManager
->AbortTransaction();
1445 _error
->Warning(_("The data from '%s' is not signed. Packages "
1446 "from that repository can not be authenticated."),
1447 MetaIndex
->Target
.Description
.c_str());
1449 // ensures that a Release.gpg file in the lists/ is removed by the transaction
1450 TransactionManager
->TransactionStageRemoval(this, DestFile
);
1452 // only allow going further if the users explicitely wants it
1453 if(AllowInsecureRepositories(TransactionManager
->MetaIndexParser
, TransactionManager
, this) == true)
1455 if (RealFileExists(FinalReleasegpg
) || RealFileExists(FinalInRelease
))
1457 // open the last Release if we have it
1458 if (TransactionManager
->IMSHit
== false)
1460 TransactionManager
->LastMetaIndexParser
= TransactionManager
->MetaIndexParser
->UnloadedClone();
1461 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1463 _error
->PushToStack();
1464 if (RealFileExists(FinalInRelease
))
1465 TransactionManager
->LastMetaIndexParser
->Load(FinalInRelease
, NULL
);
1467 TransactionManager
->LastMetaIndexParser
->Load(FinalRelease
, NULL
);
1468 // its unlikely to happen, but if what we have is bad ignore it
1469 if (_error
->PendingError())
1471 delete TransactionManager
->LastMetaIndexParser
;
1472 TransactionManager
->LastMetaIndexParser
= NULL
;
1474 _error
->RevertToStack();
1479 // we parse the indexes here because at this point the user wanted
1480 // a repository that may potentially harm him
1481 if (TransactionManager
->MetaIndexParser
->Load(MetaIndex
->DestFile
, &ErrorText
) == false || MetaIndex
->VerifyVendor(Message
) == false)
1482 /* expired Release files are still a problem you need extra force for */;
1484 MetaIndex
->QueueIndexes(true);
1486 TransactionManager
->TransactionStageCopy(MetaIndex
, MetaIndex
->DestFile
, MetaIndex
->GetFinalFilename());
1489 // FIXME: this is used often (e.g. in pkgAcqIndexTrans) so refactor
1490 if (Cnf
->LocalOnly
== true ||
1491 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1500 // AcqBaseIndex - Constructor /*{{{*/
1501 pkgAcqBaseIndex::pkgAcqBaseIndex(pkgAcquire
* const Owner
,
1502 pkgAcqMetaClearSig
* const TransactionManager
,
1503 IndexTarget
const &Target
)
1504 : pkgAcqTransactionItem(Owner
, TransactionManager
, Target
), d(NULL
)
1508 pkgAcqBaseIndex::~pkgAcqBaseIndex() {}
1510 // AcqDiffIndex::AcqDiffIndex - Constructor /*{{{*/
1511 // ---------------------------------------------------------------------
1512 /* Get the DiffIndex file first and see if there are patches available
1513 * If so, create a pkgAcqIndexDiffs fetcher that will get and apply the
1514 * patches. If anything goes wrong in that process, it will fall back to
1515 * the original packages file
1517 pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire
* const Owner
,
1518 pkgAcqMetaClearSig
* const TransactionManager
,
1519 IndexTarget
const &Target
)
1520 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
), diffs(NULL
)
1522 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
1525 Desc
.Description
= Target
.Description
+ ".diff/Index";
1526 Desc
.ShortDesc
= Target
.ShortDesc
;
1527 Desc
.URI
= Target
.URI
+ ".diff/Index";
1529 DestFile
= GetPartialFileNameFromURI(Desc
.URI
);
1532 std::clog
<< "pkgAcqDiffIndex: " << Desc
.URI
<< std::endl
;
1537 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
1538 // ---------------------------------------------------------------------
1539 /* The only header we use is the last-modified header. */
1540 string
pkgAcqDiffIndex::Custom600Headers() const
1542 string
const Final
= GetFinalFilename();
1545 std::clog
<< "Custom600Header-IMS: " << Final
<< std::endl
;
1548 if (stat(Final
.c_str(),&Buf
) != 0)
1549 return "\nIndex-File: true";
1551 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1554 void pkgAcqDiffIndex::QueueOnIMSHit() const /*{{{*/
1556 // list cleanup needs to know that this file as well as the already
1557 // present index is ours, so we create an empty diff to save it for us
1558 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
);
1561 bool pkgAcqDiffIndex::ParseDiffIndex(string
const &IndexDiffFile
) /*{{{*/
1563 // failing here is fine: our caller will take care of trying to
1564 // get the complete file if patching fails
1566 std::clog
<< "pkgAcqDiffIndex::ParseIndexDiff() " << IndexDiffFile
1569 FileFd
Fd(IndexDiffFile
,FileFd::ReadOnly
);
1571 if (_error
->PendingError() == true)
1575 if(unlikely(TF
.Step(Tags
) == false))
1578 HashStringList ServerHashes
;
1579 unsigned long long ServerSize
= 0;
1581 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
1583 std::string tagname
= *type
;
1584 tagname
.append("-Current");
1585 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1586 if (tmp
.empty() == true)
1590 unsigned long long size
;
1591 std::stringstream
ss(tmp
);
1593 if (unlikely(hash
.empty() == true))
1595 if (unlikely(ServerSize
!= 0 && ServerSize
!= size
))
1597 ServerHashes
.push_back(HashString(*type
, hash
));
1601 if (ServerHashes
.usable() == false)
1604 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": Did not find a good hashsum in the index" << std::endl
;
1608 std::string
const CurrentPackagesFile
= GetFinalFileNameFromURI(Target
.URI
);
1609 HashStringList
const TargetFileHashes
= GetExpectedHashesFor(Target
.MetaKey
);
1610 if (TargetFileHashes
.usable() == false || ServerHashes
!= TargetFileHashes
)
1614 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": Index has different hashes than parser, probably older, so fail pdiffing" << std::endl
;
1615 printHashSumComparision(CurrentPackagesFile
, ServerHashes
, TargetFileHashes
);
1620 HashStringList LocalHashes
;
1621 // try avoiding calculating the hash here as this is costly
1622 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1623 LocalHashes
= GetExpectedHashesFromFor(TransactionManager
->LastMetaIndexParser
, Target
.MetaKey
);
1624 if (LocalHashes
.usable() == false)
1626 FileFd
fd(CurrentPackagesFile
, FileFd::ReadOnly
);
1627 Hashes
LocalHashesCalc(ServerHashes
);
1628 LocalHashesCalc
.AddFD(fd
);
1629 LocalHashes
= LocalHashesCalc
.GetHashStringList();
1632 if (ServerHashes
== LocalHashes
)
1634 // we have the same sha1 as the server so we are done here
1636 std::clog
<< "pkgAcqDiffIndex: Package file " << CurrentPackagesFile
<< " is up-to-date" << std::endl
;
1642 std::clog
<< "Server-Current: " << ServerHashes
.find(NULL
)->toStr() << " and we start at "
1643 << CurrentPackagesFile
<< " " << LocalHashes
.FileSize() << " " << LocalHashes
.find(NULL
)->toStr() << std::endl
;
1645 // parse all of (provided) history
1646 vector
<DiffInfo
> available_patches
;
1647 bool firstAcceptedHashes
= true;
1648 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
1650 if (LocalHashes
.find(*type
) == NULL
)
1653 std::string tagname
= *type
;
1654 tagname
.append("-History");
1655 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1656 if (tmp
.empty() == true)
1659 string hash
, filename
;
1660 unsigned long long size
;
1661 std::stringstream
ss(tmp
);
1663 while (ss
>> hash
>> size
>> filename
)
1665 if (unlikely(hash
.empty() == true || filename
.empty() == true))
1668 // see if we have a record for this file already
1669 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
1670 for (; cur
!= available_patches
.end(); ++cur
)
1672 if (cur
->file
!= filename
)
1674 cur
->result_hashes
.push_back(HashString(*type
, hash
));
1677 if (cur
!= available_patches
.end())
1679 if (firstAcceptedHashes
== true)
1682 next
.file
= filename
;
1683 next
.result_hashes
.push_back(HashString(*type
, hash
));
1684 next
.result_hashes
.FileSize(size
);
1685 available_patches
.push_back(next
);
1690 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
1691 << " wasn't in the list for the first parsed hash! (history)" << std::endl
;
1695 firstAcceptedHashes
= false;
1698 if (unlikely(available_patches
.empty() == true))
1701 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": "
1702 << "Couldn't find any patches for the patch series." << std::endl
;
1706 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
1708 if (LocalHashes
.find(*type
) == NULL
)
1711 std::string tagname
= *type
;
1712 tagname
.append("-Patches");
1713 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1714 if (tmp
.empty() == true)
1717 string hash
, filename
;
1718 unsigned long long size
;
1719 std::stringstream
ss(tmp
);
1721 while (ss
>> hash
>> size
>> filename
)
1723 if (unlikely(hash
.empty() == true || filename
.empty() == true))
1726 // see if we have a record for this file already
1727 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
1728 for (; cur
!= available_patches
.end(); ++cur
)
1730 if (cur
->file
!= filename
)
1732 if (cur
->patch_hashes
.empty())
1733 cur
->patch_hashes
.FileSize(size
);
1734 cur
->patch_hashes
.push_back(HashString(*type
, hash
));
1737 if (cur
!= available_patches
.end())
1740 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
1741 << " wasn't in the list for the first parsed hash! (patches)" << std::endl
;
1746 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
1748 std::string tagname
= *type
;
1749 tagname
.append("-Download");
1750 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1751 if (tmp
.empty() == true)
1754 string hash
, filename
;
1755 unsigned long long size
;
1756 std::stringstream
ss(tmp
);
1758 // FIXME: all of pdiff supports only .gz compressed patches
1759 while (ss
>> hash
>> size
>> filename
)
1761 if (unlikely(hash
.empty() == true || filename
.empty() == true))
1763 if (unlikely(APT::String::Endswith(filename
, ".gz") == false))
1765 filename
.erase(filename
.length() - 3);
1767 // see if we have a record for this file already
1768 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
1769 for (; cur
!= available_patches
.end(); ++cur
)
1771 if (cur
->file
!= filename
)
1773 if (cur
->download_hashes
.empty())
1774 cur
->download_hashes
.FileSize(size
);
1775 cur
->download_hashes
.push_back(HashString(*type
, hash
));
1778 if (cur
!= available_patches
.end())
1781 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
1782 << " wasn't in the list for the first parsed hash! (download)" << std::endl
;
1788 bool foundStart
= false;
1789 for (std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
1790 cur
!= available_patches
.end(); ++cur
)
1792 if (LocalHashes
!= cur
->result_hashes
)
1795 available_patches
.erase(available_patches
.begin(), cur
);
1800 if (foundStart
== false || unlikely(available_patches
.empty() == true))
1803 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": "
1804 << "Couldn't find the start of the patch series." << std::endl
;
1808 // patching with too many files is rather slow compared to a fast download
1809 unsigned long const fileLimit
= _config
->FindI("Acquire::PDiffs::FileLimit", 0);
1810 if (fileLimit
!= 0 && fileLimit
< available_patches
.size())
1813 std::clog
<< "Need " << available_patches
.size() << " diffs (Limit is " << fileLimit
1814 << ") so fallback to complete download" << std::endl
;
1818 // calculate the size of all patches we have to get
1819 // note that all sizes are uncompressed, while we download compressed files
1820 unsigned long long patchesSize
= 0;
1821 for (std::vector
<DiffInfo
>::const_iterator cur
= available_patches
.begin();
1822 cur
!= available_patches
.end(); ++cur
)
1823 patchesSize
+= cur
->patch_hashes
.FileSize();
1824 unsigned long long const sizeLimit
= ServerSize
* _config
->FindI("Acquire::PDiffs::SizeLimit", 100);
1825 if (sizeLimit
> 0 && (sizeLimit
/100) < patchesSize
)
1828 std::clog
<< "Need " << patchesSize
<< " bytes (Limit is " << sizeLimit
/100
1829 << ") so fallback to complete download" << std::endl
;
1833 // we have something, queue the diffs
1834 string::size_type
const last_space
= Description
.rfind(" ");
1835 if(last_space
!= string::npos
)
1836 Description
.erase(last_space
, Description
.size()-last_space
);
1838 /* decide if we should download patches one by one or in one go:
1839 The first is good if the server merges patches, but many don't so client
1840 based merging can be attempt in which case the second is better.
1841 "bad things" will happen if patches are merged on the server,
1842 but client side merging is attempt as well */
1843 bool pdiff_merge
= _config
->FindB("Acquire::PDiffs::Merge", true);
1844 if (pdiff_merge
== true)
1846 // reprepro adds this flag if it has merged patches on the server
1847 std::string
const precedence
= Tags
.FindS("X-Patch-Precedence");
1848 pdiff_merge
= (precedence
!= "merged");
1851 if (pdiff_merge
== false)
1852 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
, available_patches
);
1855 diffs
= new std::vector
<pkgAcqIndexMergeDiffs
*>(available_patches
.size());
1856 for(size_t i
= 0; i
< available_patches
.size(); ++i
)
1857 (*diffs
)[i
] = new pkgAcqIndexMergeDiffs(Owner
, TransactionManager
,
1859 available_patches
[i
],
1869 void pkgAcqDiffIndex::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
1871 Item::Failed(Message
,Cnf
);
1875 std::clog
<< "pkgAcqDiffIndex failed: " << Desc
.URI
<< " with " << Message
<< std::endl
1876 << "Falling back to normal index file acquire" << std::endl
;
1878 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
1881 void pkgAcqDiffIndex::Done(string
const &Message
,HashStringList
const &Hashes
, /*{{{*/
1882 pkgAcquire::MethodConfig
const * const Cnf
)
1885 std::clog
<< "pkgAcqDiffIndex::Done(): " << Desc
.URI
<< std::endl
;
1887 Item::Done(Message
, Hashes
, Cnf
);
1889 string
const FinalFile
= GetFinalFilename();
1890 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false))
1891 DestFile
= FinalFile
;
1893 if(ParseDiffIndex(DestFile
) == false)
1895 Failed("Message: Couldn't parse pdiff index", Cnf
);
1896 // queue for final move - this should happen even if we fail
1897 // while parsing (e.g. on sizelimit) and download the complete file.
1898 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
1902 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
1911 pkgAcqDiffIndex::~pkgAcqDiffIndex()
1917 // AcqIndexDiffs::AcqIndexDiffs - Constructor /*{{{*/
1918 // ---------------------------------------------------------------------
1919 /* The package diff is added to the queue. one object is constructed
1920 * for each diff and the index
1922 pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire
* const Owner
,
1923 pkgAcqMetaClearSig
* const TransactionManager
,
1924 IndexTarget
const &Target
,
1925 vector
<DiffInfo
> const &diffs
)
1926 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
),
1927 available_patches(diffs
)
1929 DestFile
= GetPartialFileNameFromURI(Target
.URI
);
1931 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
1934 Description
= Target
.Description
;
1935 Desc
.ShortDesc
= Target
.ShortDesc
;
1937 if(available_patches
.empty() == true)
1939 // we are done (yeah!), check hashes against the final file
1940 DestFile
= GetFinalFileNameFromURI(Target
.URI
);
1945 // patching needs to be bootstrapped with the 'old' version
1946 std::string
const PartialFile
= GetPartialFileNameFromURI(Target
.URI
);
1947 if (RealFileExists(PartialFile
) == false)
1949 if (symlink(GetFinalFilename().c_str(), PartialFile
.c_str()) != 0)
1951 Failed("Link creation of " + PartialFile
+ " to " + GetFinalFilename() + " failed", NULL
);
1956 // get the next diff
1957 State
= StateFetchDiff
;
1962 void pkgAcqIndexDiffs::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
1964 Item::Failed(Message
,Cnf
);
1968 std::clog
<< "pkgAcqIndexDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
1969 << "Falling back to normal index file acquire" << std::endl
;
1970 DestFile
= GetPartialFileNameFromURI(Target
.URI
);
1971 RenameOnError(PDiffError
);
1972 std::string
const patchname
= GetDiffsPatchFileName(DestFile
);
1973 if (RealFileExists(patchname
))
1974 rename(patchname
.c_str(), std::string(patchname
+ ".FAILED").c_str());
1975 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
1979 // Finish - helper that cleans the item out of the fetcher queue /*{{{*/
1980 void pkgAcqIndexDiffs::Finish(bool allDone
)
1983 std::clog
<< "pkgAcqIndexDiffs::Finish(): "
1985 << Desc
.URI
<< std::endl
;
1987 // we restore the original name, this is required, otherwise
1988 // the file will be cleaned
1991 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
1993 // this is for the "real" finish
1998 std::clog
<< "\n\nallDone: " << DestFile
<< "\n" << std::endl
;
2003 std::clog
<< "Finishing: " << Desc
.URI
<< std::endl
;
2010 bool pkgAcqIndexDiffs::QueueNextDiff() /*{{{*/
2012 // calc sha1 of the just patched file
2013 std::string
const FinalFile
= GetPartialFileNameFromURI(Target
.URI
);
2015 if(!FileExists(FinalFile
))
2017 Failed("Message: No FinalFile " + FinalFile
+ " available", NULL
);
2021 FileFd
fd(FinalFile
, FileFd::ReadOnly
);
2022 Hashes LocalHashesCalc
;
2023 LocalHashesCalc
.AddFD(fd
);
2024 HashStringList
const LocalHashes
= LocalHashesCalc
.GetHashStringList();
2027 std::clog
<< "QueueNextDiff: " << FinalFile
<< " (" << LocalHashes
.find(NULL
)->toStr() << ")" << std::endl
;
2029 HashStringList
const TargetFileHashes
= GetExpectedHashesFor(Target
.MetaKey
);
2030 if (unlikely(LocalHashes
.usable() == false || TargetFileHashes
.usable() == false))
2032 Failed("Local/Expected hashes are not usable", NULL
);
2037 // final file reached before all patches are applied
2038 if(LocalHashes
== TargetFileHashes
)
2044 // remove all patches until the next matching patch is found
2045 // this requires the Index file to be ordered
2046 for(vector
<DiffInfo
>::iterator I
= available_patches
.begin();
2047 available_patches
.empty() == false &&
2048 I
!= available_patches
.end() &&
2049 I
->result_hashes
!= LocalHashes
;
2052 available_patches
.erase(I
);
2055 // error checking and falling back if no patch was found
2056 if(available_patches
.empty() == true)
2058 Failed("No patches left to reach target", NULL
);
2062 // queue the right diff
2063 Desc
.URI
= Target
.URI
+ ".diff/" + available_patches
[0].file
+ ".gz";
2064 Desc
.Description
= Description
+ " " + available_patches
[0].file
+ string(".pdiff");
2065 DestFile
= GetPartialFileNameFromURI(Target
.URI
+ ".diff/" + available_patches
[0].file
);
2068 std::clog
<< "pkgAcqIndexDiffs::QueueNextDiff(): " << Desc
.URI
<< std::endl
;
2075 void pkgAcqIndexDiffs::Done(string
const &Message
, HashStringList
const &Hashes
, /*{{{*/
2076 pkgAcquire::MethodConfig
const * const Cnf
)
2079 std::clog
<< "pkgAcqIndexDiffs::Done(): " << Desc
.URI
<< std::endl
;
2081 Item::Done(Message
, Hashes
, Cnf
);
2083 std::string
const FinalFile
= GetPartialFileNameFromURI(Target
.URI
);
2084 std::string
const PatchFile
= GetDiffsPatchFileName(FinalFile
);
2086 // success in downloading a diff, enter ApplyDiff state
2087 if(State
== StateFetchDiff
)
2089 Rename(DestFile
, PatchFile
);
2092 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
2094 State
= StateApplyDiff
;
2096 Desc
.URI
= "rred:" + FinalFile
;
2098 SetActiveSubprocess("rred");
2102 // success in download/apply a diff, queue next (if needed)
2103 if(State
== StateApplyDiff
)
2105 // remove the just applied patch
2106 available_patches
.erase(available_patches
.begin());
2107 unlink(PatchFile
.c_str());
2112 std::clog
<< "Moving patched file in place: " << std::endl
2113 << DestFile
<< " -> " << FinalFile
<< std::endl
;
2115 Rename(DestFile
,FinalFile
);
2116 chmod(FinalFile
.c_str(),0644);
2118 // see if there is more to download
2119 if(available_patches
.empty() == false) {
2120 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
,
2125 DestFile
= FinalFile
;
2126 return Finish(true);
2130 std::string
pkgAcqIndexDiffs::Custom600Headers() const /*{{{*/
2132 if(State
!= StateApplyDiff
)
2133 return pkgAcqBaseIndex::Custom600Headers();
2134 std::ostringstream patchhashes
;
2135 HashStringList
const ExpectedHashes
= available_patches
[0].patch_hashes
;
2136 for (HashStringList::const_iterator hs
= ExpectedHashes
.begin(); hs
!= ExpectedHashes
.end(); ++hs
)
2137 patchhashes
<< "\nPatch-0-" << hs
->HashType() << "-Hash: " << hs
->HashValue();
2138 patchhashes
<< pkgAcqBaseIndex::Custom600Headers();
2139 return patchhashes
.str();
2142 pkgAcqIndexDiffs::~pkgAcqIndexDiffs() {}
2144 // AcqIndexMergeDiffs::AcqIndexMergeDiffs - Constructor /*{{{*/
2145 pkgAcqIndexMergeDiffs::pkgAcqIndexMergeDiffs(pkgAcquire
* const Owner
,
2146 pkgAcqMetaClearSig
* const TransactionManager
,
2147 IndexTarget
const &Target
,
2148 DiffInfo
const &patch
,
2149 std::vector
<pkgAcqIndexMergeDiffs
*> const * const allPatches
)
2150 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
),
2151 patch(patch
), allPatches(allPatches
), State(StateFetchDiff
)
2153 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
2156 Description
= Target
.Description
;
2157 Desc
.ShortDesc
= Target
.ShortDesc
;
2159 Desc
.URI
= Target
.URI
+ ".diff/" + patch
.file
+ ".gz";
2160 Desc
.Description
= Description
+ " " + patch
.file
+ string(".pdiff");
2162 DestFile
= GetPartialFileNameFromURI(Target
.URI
+ ".diff/" + patch
.file
);
2165 std::clog
<< "pkgAcqIndexMergeDiffs: " << Desc
.URI
<< std::endl
;
2170 void pkgAcqIndexMergeDiffs::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
2173 std::clog
<< "pkgAcqIndexMergeDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
;
2175 Item::Failed(Message
,Cnf
);
2178 // check if we are the first to fail, otherwise we are done here
2179 State
= StateDoneDiff
;
2180 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2181 I
!= allPatches
->end(); ++I
)
2182 if ((*I
)->State
== StateErrorDiff
)
2185 // first failure means we should fallback
2186 State
= StateErrorDiff
;
2188 std::clog
<< "Falling back to normal index file acquire" << std::endl
;
2189 DestFile
= GetPartialFileNameFromURI(Target
.URI
);
2190 RenameOnError(PDiffError
);
2191 std::string
const patchname
= GetMergeDiffsPatchFileName(DestFile
, patch
.file
);
2192 if (RealFileExists(patchname
))
2193 rename(patchname
.c_str(), std::string(patchname
+ ".FAILED").c_str());
2194 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
2197 void pkgAcqIndexMergeDiffs::Done(string
const &Message
, HashStringList
const &Hashes
, /*{{{*/
2198 pkgAcquire::MethodConfig
const * const Cnf
)
2201 std::clog
<< "pkgAcqIndexMergeDiffs::Done(): " << Desc
.URI
<< std::endl
;
2203 Item::Done(Message
, Hashes
, Cnf
);
2205 string
const FinalFile
= GetPartialFileNameFromURI(Target
.URI
);
2206 if (State
== StateFetchDiff
)
2208 Rename(DestFile
, GetMergeDiffsPatchFileName(FinalFile
, patch
.file
));
2210 // check if this is the last completed diff
2211 State
= StateDoneDiff
;
2212 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2213 I
!= allPatches
->end(); ++I
)
2214 if ((*I
)->State
!= StateDoneDiff
)
2217 std::clog
<< "Not the last done diff in the batch: " << Desc
.URI
<< std::endl
;
2221 // this is the last completed diff, so we are ready to apply now
2222 State
= StateApplyDiff
;
2224 // patching needs to be bootstrapped with the 'old' version
2225 if (symlink(GetFinalFilename().c_str(), FinalFile
.c_str()) != 0)
2227 Failed("Link creation of " + FinalFile
+ " to " + GetFinalFilename() + " failed", NULL
);
2232 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
2235 Desc
.URI
= "rred:" + FinalFile
;
2237 SetActiveSubprocess("rred");
2240 // success in download/apply all diffs, clean up
2241 else if (State
== StateApplyDiff
)
2243 // move the result into place
2244 std::string
const Final
= GetFinalFilename();
2246 std::clog
<< "Queue patched file in place: " << std::endl
2247 << DestFile
<< " -> " << Final
<< std::endl
;
2249 // queue for copy by the transaction manager
2250 TransactionManager
->TransactionStageCopy(this, DestFile
, Final
);
2252 // ensure the ed's are gone regardless of list-cleanup
2253 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2254 I
!= allPatches
->end(); ++I
)
2256 std::string
const PartialFile
= GetPartialFileNameFromURI(Target
.URI
);
2257 std::string
const patch
= GetMergeDiffsPatchFileName(PartialFile
, (*I
)->patch
.file
);
2258 unlink(patch
.c_str());
2260 unlink(FinalFile
.c_str());
2265 std::clog
<< "allDone: " << DestFile
<< "\n" << std::endl
;
2269 std::string
pkgAcqIndexMergeDiffs::Custom600Headers() const /*{{{*/
2271 if(State
!= StateApplyDiff
)
2272 return pkgAcqBaseIndex::Custom600Headers();
2273 std::ostringstream patchhashes
;
2274 unsigned int seen_patches
= 0;
2275 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2276 I
!= allPatches
->end(); ++I
)
2278 HashStringList
const ExpectedHashes
= (*I
)->patch
.patch_hashes
;
2279 for (HashStringList::const_iterator hs
= ExpectedHashes
.begin(); hs
!= ExpectedHashes
.end(); ++hs
)
2280 patchhashes
<< "\nPatch-" << seen_patches
<< "-" << hs
->HashType() << "-Hash: " << hs
->HashValue();
2283 patchhashes
<< pkgAcqBaseIndex::Custom600Headers();
2284 return patchhashes
.str();
2287 pkgAcqIndexMergeDiffs::~pkgAcqIndexMergeDiffs() {}
2289 // AcqIndex::AcqIndex - Constructor /*{{{*/
2290 pkgAcqIndex::pkgAcqIndex(pkgAcquire
* const Owner
,
2291 pkgAcqMetaClearSig
* const TransactionManager
,
2292 IndexTarget
const &Target
)
2293 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
), Stage(STAGE_DOWNLOAD
)
2295 // autoselect the compression method
2296 AutoSelectCompression();
2297 Init(Target
.URI
, Target
.Description
, Target
.ShortDesc
);
2299 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
2300 std::clog
<< "New pkgIndex with TransactionManager "
2301 << TransactionManager
<< std::endl
;
2304 // AcqIndex::AutoSelectCompression - Select compression /*{{{*/
2305 void pkgAcqIndex::AutoSelectCompression()
2307 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
2308 CompressionExtensions
= "";
2309 if (TransactionManager
->MetaIndexParser
!= NULL
&& TransactionManager
->MetaIndexParser
->Exists(Target
.MetaKey
))
2311 for (std::vector
<std::string
>::const_iterator t
= types
.begin();
2312 t
!= types
.end(); ++t
)
2314 std::string CompressedMetaKey
= string(Target
.MetaKey
).append(".").append(*t
);
2315 if (*t
== "uncompressed" ||
2316 TransactionManager
->MetaIndexParser
->Exists(CompressedMetaKey
) == true)
2317 CompressionExtensions
.append(*t
).append(" ");
2322 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
2323 CompressionExtensions
.append(*t
).append(" ");
2325 if (CompressionExtensions
.empty() == false)
2326 CompressionExtensions
.erase(CompressionExtensions
.end()-1);
2329 // AcqIndex::Init - defered Constructor /*{{{*/
2330 void pkgAcqIndex::Init(string
const &URI
, string
const &URIDesc
,
2331 string
const &ShortDesc
)
2333 Stage
= STAGE_DOWNLOAD
;
2335 DestFile
= GetPartialFileNameFromURI(URI
);
2337 size_t const nextExt
= CompressionExtensions
.find(' ');
2338 if (nextExt
== std::string::npos
)
2340 CurrentCompressionExtension
= CompressionExtensions
;
2341 CompressionExtensions
.clear();
2345 CurrentCompressionExtension
= CompressionExtensions
.substr(0, nextExt
);
2346 CompressionExtensions
= CompressionExtensions
.substr(nextExt
+1);
2349 if (CurrentCompressionExtension
== "uncompressed")
2353 else if (unlikely(CurrentCompressionExtension
.empty()))
2357 Desc
.URI
= URI
+ '.' + CurrentCompressionExtension
;
2358 DestFile
= DestFile
+ '.' + CurrentCompressionExtension
;
2361 if(TransactionManager
->MetaIndexParser
!= NULL
)
2362 InitByHashIfNeeded();
2364 Desc
.Description
= URIDesc
;
2366 Desc
.ShortDesc
= ShortDesc
;
2371 // AcqIndex::AdjustForByHash - modify URI for by-hash support /*{{{*/
2372 void pkgAcqIndex::InitByHashIfNeeded()
2375 // - (maybe?) add support for by-hash into the sources.list as flag
2376 // - make apt-ftparchive generate the hashes (and expire?)
2377 std::string HostKnob
= "APT::Acquire::" + ::URI(Desc
.URI
).Host
+ "::By-Hash";
2378 if(_config
->FindB("APT::Acquire::By-Hash", false) == true ||
2379 _config
->FindB(HostKnob
, false) == true ||
2380 TransactionManager
->MetaIndexParser
->GetSupportsAcquireByHash())
2382 HashStringList
const Hashes
= GetExpectedHashes();
2385 // FIXME: should we really use the best hash here? or a fixed one?
2386 HashString
const * const TargetHash
= Hashes
.find("");
2387 std::string
const ByHash
= "/by-hash/" + TargetHash
->HashType() + "/" + TargetHash
->HashValue();
2388 size_t const trailing_slash
= Desc
.URI
.find_last_of("/");
2389 Desc
.URI
= Desc
.URI
.replace(
2391 Desc
.URI
.substr(trailing_slash
+1).size()+1,
2395 "Fetching ByHash requested but can not find record for %s",
2396 GetMetaKey().c_str());
2401 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
2402 // ---------------------------------------------------------------------
2403 /* The only header we use is the last-modified header. */
2404 string
pkgAcqIndex::Custom600Headers() const
2406 string Final
= GetFinalFilename();
2408 string msg
= "\nIndex-File: true";
2410 if (stat(Final
.c_str(),&Buf
) == 0)
2411 msg
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
2413 if(Target
.IsOptional
)
2414 msg
+= "\nFail-Ignore: true";
2419 // AcqIndex::Failed - getting the indexfile failed /*{{{*/
2420 void pkgAcqIndex::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)
2422 Item::Failed(Message
,Cnf
);
2424 // authorisation matches will not be fixed by other compression types
2425 if (Status
!= StatAuthError
)
2427 if (CompressionExtensions
.empty() == false)
2429 Init(Target
.URI
, Desc
.Description
, Desc
.ShortDesc
);
2435 if(Target
.IsOptional
&& GetExpectedHashes().empty() && Stage
== STAGE_DOWNLOAD
)
2438 TransactionManager
->AbortTransaction();
2441 // AcqIndex::ReverifyAfterIMS - Reverify index after an ims-hit /*{{{*/
2442 void pkgAcqIndex::ReverifyAfterIMS()
2444 // update destfile to *not* include the compression extension when doing
2445 // a reverify (as its uncompressed on disk already)
2446 DestFile
= GetCompressedFileName(Target
.URI
, GetPartialFileNameFromURI(Target
.URI
), CurrentCompressionExtension
);
2448 // copy FinalFile into partial/ so that we check the hash again
2449 string FinalFile
= GetFinalFilename();
2450 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
2451 Desc
.URI
= "copy:" + FinalFile
;
2455 // AcqIndex::Done - Finished a fetch /*{{{*/
2456 // ---------------------------------------------------------------------
2457 /* This goes through a number of states.. On the initial fetch the
2458 method could possibly return an alternate filename which points
2459 to the uncompressed version of the file. If this is so the file
2460 is copied into the partial directory. In all other cases the file
2461 is decompressed with a compressed uri. */
2462 void pkgAcqIndex::Done(string
const &Message
,
2463 HashStringList
const &Hashes
,
2464 pkgAcquire::MethodConfig
const * const Cfg
)
2466 Item::Done(Message
,Hashes
,Cfg
);
2470 case STAGE_DOWNLOAD
:
2471 StageDownloadDone(Message
, Hashes
, Cfg
);
2473 case STAGE_DECOMPRESS_AND_VERIFY
:
2474 StageDecompressDone(Message
, Hashes
, Cfg
);
2479 // AcqIndex::StageDownloadDone - Queue for decompress and verify /*{{{*/
2480 void pkgAcqIndex::StageDownloadDone(string
const &Message
, HashStringList
const &,
2481 pkgAcquire::MethodConfig
const * const)
2485 // Handle the unzipd case
2486 string FileName
= LookupTag(Message
,"Alt-Filename");
2487 if (FileName
.empty() == false)
2489 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
2491 DestFile
+= ".decomp";
2492 Desc
.URI
= "copy:" + FileName
;
2494 SetActiveSubprocess("copy");
2498 FileName
= LookupTag(Message
,"Filename");
2499 if (FileName
.empty() == true)
2502 ErrorText
= "Method gave a blank filename";
2505 // Methods like e.g. "file:" will give us a (compressed) FileName that is
2506 // not the "DestFile" we set, in this case we uncompress from the local file
2507 if (FileName
!= DestFile
&& RealFileExists(DestFile
) == false)
2510 EraseFileName
= FileName
;
2512 // we need to verify the file against the current Release file again
2513 // on if-modfied-since hit to avoid a stale attack against us
2514 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
2516 // The files timestamp matches, reverify by copy into partial/
2522 // If we have compressed indexes enabled, queue for hash verification
2523 if (_config
->FindB("Acquire::GzipIndexes",false))
2525 DestFile
= GetPartialFileNameFromURI(Target
.URI
+ '.' + CurrentCompressionExtension
);
2527 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
2528 Desc
.URI
= "copy:" + FileName
;
2530 SetActiveSubprocess("copy");
2534 // get the binary name for your used compression type
2536 if(CurrentCompressionExtension
== "uncompressed")
2537 decompProg
= "copy";
2539 decompProg
= _config
->Find(string("Acquire::CompressionTypes::").append(CurrentCompressionExtension
),"");
2540 if(decompProg
.empty() == true)
2542 _error
->Error("Unsupported extension: %s", CurrentCompressionExtension
.c_str());
2546 // queue uri for the next stage
2547 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
2548 DestFile
+= ".decomp";
2549 Desc
.URI
= decompProg
+ ":" + FileName
;
2551 SetActiveSubprocess(decompProg
);
2554 // AcqIndex::StageDecompressDone - Final verification /*{{{*/
2555 void pkgAcqIndex::StageDecompressDone(string
const &,
2556 HashStringList
const &,
2557 pkgAcquire::MethodConfig
const * const)
2559 // Done, queue for rename on transaction finished
2560 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
2564 pkgAcqIndex::~pkgAcqIndex() {}
2567 // AcqArchive::AcqArchive - Constructor /*{{{*/
2568 // ---------------------------------------------------------------------
2569 /* This just sets up the initial fetch environment and queues the first
2571 pkgAcqArchive::pkgAcqArchive(pkgAcquire
* const Owner
,pkgSourceList
* const Sources
,
2572 pkgRecords
* const Recs
,pkgCache::VerIterator
const &Version
,
2573 string
&StoreFilename
) :
2574 Item(Owner
), d(NULL
), LocalSource(false), Version(Version
), Sources(Sources
), Recs(Recs
),
2575 StoreFilename(StoreFilename
), Vf(Version
.FileList()),
2578 Retries
= _config
->FindI("Acquire::Retries",0);
2580 if (Version
.Arch() == 0)
2582 _error
->Error(_("I wasn't able to locate a file for the %s package. "
2583 "This might mean you need to manually fix this package. "
2584 "(due to missing arch)"),
2585 Version
.ParentPkg().FullName().c_str());
2589 /* We need to find a filename to determine the extension. We make the
2590 assumption here that all the available sources for this version share
2591 the same extension.. */
2592 // Skip not source sources, they do not have file fields.
2593 for (; Vf
.end() == false; ++Vf
)
2595 if (Vf
.File().Flagged(pkgCache::Flag::NotSource
))
2600 // Does not really matter here.. we are going to fail out below
2601 if (Vf
.end() != true)
2603 // If this fails to get a file name we will bomb out below.
2604 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2605 if (_error
->PendingError() == true)
2608 // Generate the final file name as: package_version_arch.foo
2609 StoreFilename
= QuoteString(Version
.ParentPkg().Name(),"_:") + '_' +
2610 QuoteString(Version
.VerStr(),"_:") + '_' +
2611 QuoteString(Version
.Arch(),"_:.") +
2612 "." + flExtension(Parse
.FileName());
2615 // check if we have one trusted source for the package. if so, switch
2616 // to "TrustedOnly" mode - but only if not in AllowUnauthenticated mode
2617 bool const allowUnauth
= _config
->FindB("APT::Get::AllowUnauthenticated", false);
2618 bool const debugAuth
= _config
->FindB("Debug::pkgAcquire::Auth", false);
2619 bool seenUntrusted
= false;
2620 for (pkgCache::VerFileIterator i
= Version
.FileList(); i
.end() == false; ++i
)
2622 pkgIndexFile
*Index
;
2623 if (Sources
->FindIndex(i
.File(),Index
) == false)
2626 if (debugAuth
== true)
2627 std::cerr
<< "Checking index: " << Index
->Describe()
2628 << "(Trusted=" << Index
->IsTrusted() << ")" << std::endl
;
2630 if (Index
->IsTrusted() == true)
2633 if (allowUnauth
== false)
2637 seenUntrusted
= true;
2640 // "allow-unauthenticated" restores apts old fetching behaviour
2641 // that means that e.g. unauthenticated file:// uris are higher
2642 // priority than authenticated http:// uris
2643 if (allowUnauth
== true && seenUntrusted
== true)
2647 if (QueueNext() == false && _error
->PendingError() == false)
2648 _error
->Error(_("Can't find a source to download version '%s' of '%s'"),
2649 Version
.VerStr(), Version
.ParentPkg().FullName(false).c_str());
2652 // AcqArchive::QueueNext - Queue the next file source /*{{{*/
2653 // ---------------------------------------------------------------------
2654 /* This queues the next available file version for download. It checks if
2655 the archive is already available in the cache and stashs the MD5 for
2657 bool pkgAcqArchive::QueueNext()
2659 for (; Vf
.end() == false; ++Vf
)
2661 pkgCache::PkgFileIterator
const PkgF
= Vf
.File();
2662 // Ignore not source sources
2663 if (PkgF
.Flagged(pkgCache::Flag::NotSource
))
2666 // Try to cross match against the source list
2667 pkgIndexFile
*Index
;
2668 if (Sources
->FindIndex(PkgF
, Index
) == false)
2670 LocalSource
= PkgF
.Flagged(pkgCache::Flag::LocalSource
);
2672 // only try to get a trusted package from another source if that source
2674 if(Trusted
&& !Index
->IsTrusted())
2677 // Grab the text package record
2678 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2679 if (_error
->PendingError() == true)
2682 string PkgFile
= Parse
.FileName();
2683 ExpectedHashes
= Parse
.Hashes();
2685 if (PkgFile
.empty() == true)
2686 return _error
->Error(_("The package index files are corrupted. No Filename: "
2687 "field for package %s."),
2688 Version
.ParentPkg().Name());
2690 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
2691 Desc
.Description
= Index
->ArchiveInfo(Version
);
2693 Desc
.ShortDesc
= Version
.ParentPkg().FullName(true);
2695 // See if we already have the file. (Legacy filenames)
2696 FileSize
= Version
->Size
;
2697 string FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile
);
2699 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2701 // Make sure the size matches
2702 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2707 StoreFilename
= DestFile
= FinalFile
;
2711 /* Hmm, we have a file and its size does not match, this means it is
2712 an old style mismatched arch */
2713 unlink(FinalFile
.c_str());
2716 // Check it again using the new style output filenames
2717 FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
2718 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2720 // Make sure the size matches
2721 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2726 StoreFilename
= DestFile
= FinalFile
;
2730 /* Hmm, we have a file and its size does not match, this shouldn't
2732 unlink(FinalFile
.c_str());
2735 DestFile
= _config
->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename
);
2737 // Check the destination file
2738 if (stat(DestFile
.c_str(),&Buf
) == 0)
2740 // Hmm, the partial file is too big, erase it
2741 if ((unsigned long long)Buf
.st_size
> Version
->Size
)
2742 unlink(DestFile
.c_str());
2744 PartialSize
= Buf
.st_size
;
2747 // Disables download of archives - useful if no real installation follows,
2748 // e.g. if we are just interested in proposed installation order
2749 if (_config
->FindB("Debug::pkgAcqArchive::NoQueue", false) == true)
2754 StoreFilename
= DestFile
= FinalFile
;
2768 // AcqArchive::Done - Finished fetching /*{{{*/
2769 // ---------------------------------------------------------------------
2771 void pkgAcqArchive::Done(string
const &Message
, HashStringList
const &Hashes
,
2772 pkgAcquire::MethodConfig
const * const Cfg
)
2774 Item::Done(Message
, Hashes
, Cfg
);
2776 // Grab the output filename
2777 string FileName
= LookupTag(Message
,"Filename");
2778 if (FileName
.empty() == true)
2781 ErrorText
= "Method gave a blank filename";
2785 // Reference filename
2786 if (DestFile
!= FileName
&& RealFileExists(DestFile
) == false)
2788 StoreFilename
= DestFile
= FileName
;
2794 // Done, move it into position
2795 string
const FinalFile
= GetFinalFilename();
2796 Rename(DestFile
,FinalFile
);
2797 StoreFilename
= DestFile
= FinalFile
;
2801 // AcqArchive::Failed - Failure handler /*{{{*/
2802 // ---------------------------------------------------------------------
2803 /* Here we try other sources */
2804 void pkgAcqArchive::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)
2806 Item::Failed(Message
,Cnf
);
2808 /* We don't really want to retry on failed media swaps, this prevents
2809 that. An interesting observation is that permanent failures are not
2811 if (Cnf
->Removable
== true &&
2812 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2814 // Vf = Version.FileList();
2815 while (Vf
.end() == false) ++Vf
;
2816 StoreFilename
= string();
2821 if (QueueNext() == false)
2823 // This is the retry counter
2825 Cnf
->LocalOnly
== false &&
2826 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2829 Vf
= Version
.FileList();
2830 if (QueueNext() == true)
2834 StoreFilename
= string();
2839 APT_PURE
bool pkgAcqArchive::IsTrusted() const /*{{{*/
2844 void pkgAcqArchive::Finished() /*{{{*/
2846 if (Status
== pkgAcquire::Item::StatDone
&&
2849 StoreFilename
= string();
2852 std::string
pkgAcqArchive::DescURI() const /*{{{*/
2857 std::string
pkgAcqArchive::ShortDesc() const /*{{{*/
2859 return Desc
.ShortDesc
;
2862 pkgAcqArchive::~pkgAcqArchive() {}
2864 // AcqChangelog::pkgAcqChangelog - Constructors /*{{{*/
2865 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire
* const Owner
, pkgCache::VerIterator
const &Ver
,
2866 std::string
const &DestDir
, std::string
const &DestFilename
) :
2867 pkgAcquire::Item(Owner
), d(NULL
), SrcName(Ver
.SourcePkgName()), SrcVersion(Ver
.SourceVerStr())
2869 Desc
.URI
= URI(Ver
);
2870 Init(DestDir
, DestFilename
);
2872 // some parameters are char* here as they come likely from char* interfaces – which can also return NULL
2873 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire
* const Owner
, pkgCache::RlsFileIterator
const &RlsFile
,
2874 char const * const Component
, char const * const SrcName
, char const * const SrcVersion
,
2875 const string
&DestDir
, const string
&DestFilename
) :
2876 pkgAcquire::Item(Owner
), d(NULL
), SrcName(SrcName
), SrcVersion(SrcVersion
)
2878 Desc
.URI
= URI(RlsFile
, Component
, SrcName
, SrcVersion
);
2879 Init(DestDir
, DestFilename
);
2881 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire
* const Owner
,
2882 std::string
const &URI
, char const * const SrcName
, char const * const SrcVersion
,
2883 const string
&DestDir
, const string
&DestFilename
) :
2884 pkgAcquire::Item(Owner
), d(NULL
), SrcName(SrcName
), SrcVersion(SrcVersion
)
2887 Init(DestDir
, DestFilename
);
2889 void pkgAcqChangelog::Init(std::string
const &DestDir
, std::string
const &DestFilename
)
2891 if (Desc
.URI
.empty())
2894 // TRANSLATOR: %s=%s is sourcename=sourceversion, e.g. apt=1.1
2895 strprintf(ErrorText
, _("Changelog unavailable for %s=%s"), SrcName
.c_str(), SrcVersion
.c_str());
2896 // Let the error message print something sensible rather than "Failed to fetch /"
2897 if (DestFilename
.empty())
2898 DestFile
= SrcName
+ ".changelog";
2900 DestFile
= DestFilename
;
2901 Desc
.URI
= "changelog:/" + DestFile
;
2905 if (DestDir
.empty())
2907 std::string
const systemTemp
= GetTempDir();
2909 snprintf(tmpname
, sizeof(tmpname
), "%s/apt-changelog-XXXXXX", systemTemp
.c_str());
2910 if (NULL
== mkdtemp(tmpname
))
2912 _error
->Errno("mkdtemp", "mkdtemp failed in changelog acquire of %s %s", SrcName
.c_str(), SrcVersion
.c_str());
2916 DestFile
= TemporaryDirectory
= tmpname
;
2921 if (DestFilename
.empty())
2922 DestFile
= flCombine(DestFile
, SrcName
+ ".changelog");
2924 DestFile
= flCombine(DestFile
, DestFilename
);
2926 Desc
.ShortDesc
= "Changelog";
2927 strprintf(Desc
.Description
, "%s %s %s Changelog", URI::SiteOnly(Desc
.URI
).c_str(), SrcName
.c_str(), SrcVersion
.c_str());
2932 std::string
pkgAcqChangelog::URI(pkgCache::VerIterator
const &Ver
) /*{{{*/
2934 char const * const SrcName
= Ver
.SourcePkgName();
2935 char const * const SrcVersion
= Ver
.SourceVerStr();
2936 pkgCache::PkgFileIterator PkgFile
;
2937 // find the first source for this version which promises a changelog
2938 for (pkgCache::VerFileIterator VF
= Ver
.FileList(); VF
.end() == false; ++VF
)
2940 pkgCache::PkgFileIterator
const PF
= VF
.File();
2941 if (PF
.Flagged(pkgCache::Flag::NotSource
) || PF
->Release
== 0)
2944 pkgCache::RlsFileIterator
const RF
= PF
.ReleaseFile();
2945 std::string
const uri
= URI(RF
, PF
.Component(), SrcName
, SrcVersion
);
2952 std::string
pkgAcqChangelog::URITemplate(pkgCache::RlsFileIterator
const &Rls
)
2954 if (Rls
.end() == true || (Rls
->Label
== 0 && Rls
->Origin
== 0))
2956 std::string
const serverConfig
= "Acquire::Changelogs::URI";
2958 #define APT_EMPTY_SERVER \
2959 if (server.empty() == false) \
2961 if (server != "no") \
2965 #define APT_CHECK_SERVER(X, Y) \
2968 std::string const specialServerConfig = serverConfig + "::" + Y + #X + "::" + Rls.X(); \
2969 server = _config->Find(specialServerConfig); \
2972 // this way e.g. Debian-Security can fallback to Debian
2973 APT_CHECK_SERVER(Label
, "Override::")
2974 APT_CHECK_SERVER(Origin
, "Override::")
2976 if (RealFileExists(Rls
.FileName()))
2978 _error
->PushToStack();
2980 /* This can be costly. A caller wanting to get millions of URIs might
2981 want to do this on its own once and use Override settings.
2982 We don't do this here as Origin/Label are not as unique as they
2983 should be so this could produce request order-dependent anomalies */
2984 if (OpenMaybeClearSignedFile(Rls
.FileName(), rf
) == true)
2986 pkgTagFile
TagFile(&rf
, rf
.Size());
2987 pkgTagSection Section
;
2988 if (TagFile
.Step(Section
) == true)
2989 server
= Section
.FindS("Changelogs");
2991 _error
->RevertToStack();
2995 APT_CHECK_SERVER(Label
, "")
2996 APT_CHECK_SERVER(Origin
, "")
2997 #undef APT_CHECK_SERVER
2998 #undef APT_EMPTY_SERVER
3001 std::string
pkgAcqChangelog::URI(pkgCache::RlsFileIterator
const &Rls
,
3002 char const * const Component
, char const * const SrcName
,
3003 char const * const SrcVersion
)
3005 return URI(URITemplate(Rls
), Component
, SrcName
, SrcVersion
);
3007 std::string
pkgAcqChangelog::URI(std::string
const &Template
,
3008 char const * const Component
, char const * const SrcName
,
3009 char const * const SrcVersion
)
3011 if (Template
.find("CHANGEPATH") == std::string::npos
)
3014 // the path is: COMPONENT/SRC/SRCNAME/SRCNAME_SRCVER, e.g. main/a/apt/1.1 or contrib/liba/libapt/2.0
3015 std::string Src
= SrcName
;
3016 std::string path
= APT::String::Startswith(SrcName
, "lib") ? Src
.substr(0, 4) : Src
.substr(0,1);
3017 path
.append("/").append(Src
).append("/");
3018 path
.append(Src
).append("_").append(StripEpoch(SrcVersion
));
3019 // we omit component for releases without one (= flat-style repositories)
3020 if (Component
!= NULL
&& strlen(Component
) != 0)
3021 path
= std::string(Component
) + "/" + path
;
3023 return SubstVar(Template
, "CHANGEPATH", path
);
3026 // AcqChangelog::Failed - Failure handler /*{{{*/
3027 void pkgAcqChangelog::Failed(string
const &Message
, pkgAcquire::MethodConfig
const * const Cnf
)
3029 Item::Failed(Message
,Cnf
);
3031 std::string errText
;
3032 // TRANSLATOR: %s=%s is sourcename=sourceversion, e.g. apt=1.1
3033 strprintf(errText
, _("Changelog unavailable for %s=%s"), SrcName
.c_str(), SrcVersion
.c_str());
3035 // Error is probably something techy like 404 Not Found
3036 if (ErrorText
.empty())
3037 ErrorText
= errText
;
3039 ErrorText
= errText
+ " (" + ErrorText
+ ")";
3043 // AcqChangelog::Done - Item downloaded OK /*{{{*/
3044 void pkgAcqChangelog::Done(string
const &Message
,HashStringList
const &CalcHashes
,
3045 pkgAcquire::MethodConfig
const * const Cnf
)
3047 Item::Done(Message
,CalcHashes
,Cnf
);
3052 pkgAcqChangelog::~pkgAcqChangelog() /*{{{*/
3054 if (TemporaryDirectory
.empty() == false)
3056 unlink(DestFile
.c_str());
3057 rmdir(TemporaryDirectory
.c_str());
3062 // AcqFile::pkgAcqFile - Constructor /*{{{*/
3063 pkgAcqFile::pkgAcqFile(pkgAcquire
* const Owner
,string
const &URI
, HashStringList
const &Hashes
,
3064 unsigned long long const Size
,string
const &Dsc
,string
const &ShortDesc
,
3065 const string
&DestDir
, const string
&DestFilename
,
3066 bool const IsIndexFile
) :
3067 Item(Owner
), d(NULL
), IsIndexFile(IsIndexFile
), ExpectedHashes(Hashes
)
3069 Retries
= _config
->FindI("Acquire::Retries",0);
3071 if(!DestFilename
.empty())
3072 DestFile
= DestFilename
;
3073 else if(!DestDir
.empty())
3074 DestFile
= DestDir
+ "/" + flNotDir(URI
);
3076 DestFile
= flNotDir(URI
);
3080 Desc
.Description
= Dsc
;
3083 // Set the short description to the archive component
3084 Desc
.ShortDesc
= ShortDesc
;
3086 // Get the transfer sizes
3089 if (stat(DestFile
.c_str(),&Buf
) == 0)
3091 // Hmm, the partial file is too big, erase it
3092 if ((Size
> 0) && (unsigned long long)Buf
.st_size
> Size
)
3093 unlink(DestFile
.c_str());
3095 PartialSize
= Buf
.st_size
;
3101 // AcqFile::Done - Item downloaded OK /*{{{*/
3102 void pkgAcqFile::Done(string
const &Message
,HashStringList
const &CalcHashes
,
3103 pkgAcquire::MethodConfig
const * const Cnf
)
3105 Item::Done(Message
,CalcHashes
,Cnf
);
3107 string FileName
= LookupTag(Message
,"Filename");
3108 if (FileName
.empty() == true)
3111 ErrorText
= "Method gave a blank filename";
3117 // The files timestamp matches
3118 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
3121 // We have to copy it into place
3122 if (RealFileExists(DestFile
.c_str()) == false)
3125 if (_config
->FindB("Acquire::Source-Symlinks",true) == false ||
3126 Cnf
->Removable
== true)
3128 Desc
.URI
= "copy:" + FileName
;
3133 // Erase the file if it is a symlink so we can overwrite it
3135 if (lstat(DestFile
.c_str(),&St
) == 0)
3137 if (S_ISLNK(St
.st_mode
) != 0)
3138 unlink(DestFile
.c_str());
3142 if (symlink(FileName
.c_str(),DestFile
.c_str()) != 0)
3144 _error
->PushToStack();
3145 _error
->Errno("pkgAcqFile::Done", "Symlinking file %s failed", DestFile
.c_str());
3146 std::stringstream msg
;
3147 _error
->DumpErrors(msg
);
3148 _error
->RevertToStack();
3149 ErrorText
= msg
.str();
3156 // AcqFile::Failed - Failure handler /*{{{*/
3157 // ---------------------------------------------------------------------
3158 /* Here we try other sources */
3159 void pkgAcqFile::Failed(string
const &Message
, pkgAcquire::MethodConfig
const * const Cnf
)
3161 Item::Failed(Message
,Cnf
);
3163 // This is the retry counter
3165 Cnf
->LocalOnly
== false &&
3166 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
3176 string
pkgAcqFile::Custom600Headers() const /*{{{*/
3179 return "\nIndex-File: true";
3183 pkgAcqFile::~pkgAcqFile() {}