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/tagfile.h>
26 #include <apt-pkg/metaindex.h>
27 #include <apt-pkg/acquire.h>
28 #include <apt-pkg/hashes.h>
29 #include <apt-pkg/indexfile.h>
30 #include <apt-pkg/pkgcache.h>
31 #include <apt-pkg/cacheiterators.h>
32 #include <apt-pkg/pkgrecords.h>
33 #include <apt-pkg/gpgv.h>
55 static void printHashSumComparison(std::string
const &URI
, HashStringList
const &Expected
, HashStringList
const &Actual
) /*{{{*/
57 if (_config
->FindB("Debug::Acquire::HashSumMismatch", false) == false)
59 std::cerr
<< std::endl
<< URI
<< ":" << std::endl
<< " Expected Hash: " << std::endl
;
60 for (HashStringList::const_iterator hs
= Expected
.begin(); hs
!= Expected
.end(); ++hs
)
61 std::cerr
<< "\t- " << hs
->toStr() << std::endl
;
62 std::cerr
<< " Actual Hash: " << std::endl
;
63 for (HashStringList::const_iterator hs
= Actual
.begin(); hs
!= Actual
.end(); ++hs
)
64 std::cerr
<< "\t- " << hs
->toStr() << std::endl
;
67 static std::string
GetPartialFileName(std::string
const &file
) /*{{{*/
69 std::string DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
74 static std::string
GetPartialFileNameFromURI(std::string
const &uri
) /*{{{*/
76 return GetPartialFileName(URItoFileName(uri
));
79 static std::string
GetFinalFileNameFromURI(std::string
const &uri
) /*{{{*/
81 return _config
->FindDir("Dir::State::lists") + URItoFileName(uri
);
84 static std::string
GetKeepCompressedFileName(std::string file
, IndexTarget
const &Target
)/*{{{*/
86 if (Target
.KeepCompressed
== false)
89 std::string
const KeepCompressedAs
= Target
.Option(IndexTarget::KEEPCOMPRESSEDAS
);
90 if (KeepCompressedAs
.empty() == false)
92 std::string
const ext
= KeepCompressedAs
.substr(0, KeepCompressedAs
.find(' '));
93 if (ext
!= "uncompressed")
94 file
.append(".").append(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";
111 static std::string
GetExistingFilename(std::string
const &File
) /*{{{*/
113 if (RealFileExists(File
))
115 for (auto const &type
: APT::Configuration::getCompressorExtensions())
117 std::string
const Final
= File
+ type
;
118 if (RealFileExists(Final
))
124 static std::string
GetDiffIndexFileName(std::string
const &Name
) /*{{{*/
126 return Name
+ ".diff/Index";
129 static std::string
GetDiffIndexURI(IndexTarget
const &Target
) /*{{{*/
131 return Target
.URI
+ ".diff/Index";
135 static void ReportMirrorFailureToCentral(pkgAcquire::Item
const &I
, std::string
const &FailCode
, std::string
const &Details
)/*{{{*/
137 // we only act if a mirror was used at all
138 if(I
.UsedMirror
.empty())
141 std::cerr
<< "\nReportMirrorFailure: "
143 << " Uri: " << DescURI()
145 << FailCode
<< std::endl
;
147 string
const report
= _config
->Find("Methods::Mirror::ProblemReporting",
148 "/usr/lib/apt/apt-report-mirror-failure");
149 if(!FileExists(report
))
152 std::vector
<char const*> const Args
= {
154 I
.UsedMirror
.c_str(),
161 pid_t pid
= ExecFork();
164 _error
->Error("ReportMirrorFailure Fork failed");
169 execvp(Args
[0], (char**)Args
.data());
170 std::cerr
<< "Could not exec " << Args
[0] << std::endl
;
173 if(!ExecWait(pid
, "report-mirror-failure"))
174 _error
->Warning("Couldn't report problem to '%s'", report
.c_str());
178 static APT_NONNULL(2) bool MessageInsecureRepository(bool const isError
, char const * const msg
, std::string
const &repo
)/*{{{*/
181 strprintf(m
, msg
, repo
.c_str());
184 _error
->Error("%s", m
.c_str());
185 _error
->Notice("%s", _("Updating from such a repository can't be done securely, and is therefore disabled by default."));
189 _error
->Warning("%s", m
.c_str());
190 _error
->Notice("%s", _("Data from such a repository can't be authenticated and is therefore potentially dangerous to use."));
192 _error
->Notice("%s", _("See apt-secure(8) manpage for repository creation and user configuration details."));
196 // AllowInsecureRepositories /*{{{*/
197 enum class InsecureType
{ UNSIGNED
, WEAK
, NORELEASE
};
198 static bool TargetIsAllowedToBe(IndexTarget
const &Target
, InsecureType
const type
)
200 if (_config
->FindB("Acquire::AllowInsecureRepositories"))
203 if (Target
.OptionBool(IndexTarget::ALLOW_INSECURE
))
208 case InsecureType::UNSIGNED
: break;
209 case InsecureType::NORELEASE
: break;
210 case InsecureType::WEAK
:
211 if (_config
->FindB("Acquire::AllowWeakRepositories"))
213 if (Target
.OptionBool(IndexTarget::ALLOW_WEAK
))
219 static bool APT_NONNULL(3, 4, 5) AllowInsecureRepositories(InsecureType
const msg
, std::string
const &repo
,
220 metaIndex
const * const MetaIndexParser
, pkgAcqMetaClearSig
* const TransactionManager
, pkgAcquire::Item
* const I
)
222 // we skip weak downgrades as its unlikely that a repository gets really weaker –
223 // its more realistic that apt got pickier in a newer version
224 if (msg
!= InsecureType::WEAK
)
226 std::string
const FinalInRelease
= TransactionManager
->GetFinalFilename();
227 std::string
const FinalReleasegpg
= FinalInRelease
.substr(0, FinalInRelease
.length() - strlen("InRelease")) + "Release.gpg";
228 if (RealFileExists(FinalReleasegpg
) || RealFileExists(FinalInRelease
))
230 char const * msgstr
= nullptr;
233 case InsecureType::UNSIGNED
: msgstr
= _("The repository '%s' is no longer signed."); break;
234 case InsecureType::NORELEASE
: msgstr
= _("The repository '%s' does no longer have a Release file."); break;
235 case InsecureType::WEAK
: /* unreachable */ break;
237 if (_config
->FindB("Acquire::AllowDowngradeToInsecureRepositories") ||
238 TransactionManager
->Target
.OptionBool(IndexTarget::ALLOW_DOWNGRADE_TO_INSECURE
))
240 // meh, the users wants to take risks (we still mark the packages
241 // from this repository as unauthenticated)
242 _error
->Warning(msgstr
, repo
.c_str());
243 _error
->Warning(_("This is normally not allowed, but the option "
244 "Acquire::AllowDowngradeToInsecureRepositories was "
245 "given to override it."));
247 MessageInsecureRepository(true, msgstr
, repo
);
248 TransactionManager
->AbortTransaction();
249 I
->Status
= pkgAcquire::Item::StatError
;
255 if(MetaIndexParser
->GetTrusted() == metaIndex::TRI_YES
)
258 char const * msgstr
= nullptr;
261 case InsecureType::UNSIGNED
: msgstr
= _("The repository '%s' is not signed."); break;
262 case InsecureType::NORELEASE
: msgstr
= _("The repository '%s' does not have a Release file."); break;
263 case InsecureType::WEAK
: msgstr
= _("The repository '%s' provides only weak security information."); break;
266 if (TargetIsAllowedToBe(TransactionManager
->Target
, msg
) == true)
268 MessageInsecureRepository(false, msgstr
, repo
);
272 MessageInsecureRepository(true, msgstr
, repo
);
273 TransactionManager
->AbortTransaction();
274 I
->Status
= pkgAcquire::Item::StatError
;
278 static HashStringList
GetExpectedHashesFromFor(metaIndex
* const Parser
, std::string
const &MetaKey
)/*{{{*/
281 return HashStringList();
282 metaIndex::checkSum
* const R
= Parser
->Lookup(MetaKey
);
284 return HashStringList();
289 // all ::HashesRequired and ::GetExpectedHashes implementations /*{{{*/
290 /* ::GetExpectedHashes is abstract and has to be implemented by all subclasses.
291 It is best to implement it as broadly as possible, while ::HashesRequired defaults
292 to true and should be as restrictive as possible for false cases. Note that if
293 a hash is returned by ::GetExpectedHashes it must match. Only if it doesn't
294 ::HashesRequired is called to evaluate if its okay to have no hashes. */
295 APT_CONST
bool pkgAcqTransactionItem::HashesRequired() const
297 /* signed repositories obviously have a parser and good hashes.
298 unsigned repositories, too, as even if we can't trust them for security,
299 we can at least trust them for integrity of the download itself.
300 Only repositories without a Release file can (obviously) not have
301 hashes – and they are very uncommon and strongly discouraged */
302 if (TransactionManager
->MetaIndexParser
->GetLoadedSuccessfully() != metaIndex::TRI_YES
)
304 if (TargetIsAllowedToBe(Target
, InsecureType::WEAK
))
306 /* If we allow weak hashes, we check that we have some (weak) and then
307 declare hashes not needed. That will tip us in the right direction
308 as if hashes exist, they will be used, even if not required */
309 auto const hsl
= GetExpectedHashes();
312 if (hsl
.empty() == false)
317 HashStringList
pkgAcqTransactionItem::GetExpectedHashes() const
319 return GetExpectedHashesFor(GetMetaKey());
322 APT_CONST
bool pkgAcqMetaBase::HashesRequired() const
324 // Release and co have no hashes 'by design'.
327 HashStringList
pkgAcqMetaBase::GetExpectedHashes() const
329 return HashStringList();
332 APT_CONST
bool pkgAcqIndexDiffs::HashesRequired() const
334 /* We can't check hashes of rred result as we don't know what the
335 hash of the file will be. We just know the hash of the patch(es),
336 the hash of the file they will apply on and the hash of the resulting
338 if (State
== StateFetchDiff
)
342 HashStringList
pkgAcqIndexDiffs::GetExpectedHashes() const
344 if (State
== StateFetchDiff
)
345 return available_patches
[0].download_hashes
;
346 return HashStringList();
349 APT_CONST
bool pkgAcqIndexMergeDiffs::HashesRequired() const
351 /* @see #pkgAcqIndexDiffs::HashesRequired, with the difference that
352 we can check the rred result after all patches are applied as
353 we know the expected result rather than potentially apply more patches */
354 if (State
== StateFetchDiff
)
356 return State
== StateApplyDiff
;
358 HashStringList
pkgAcqIndexMergeDiffs::GetExpectedHashes() const
360 if (State
== StateFetchDiff
)
361 return patch
.download_hashes
;
362 else if (State
== StateApplyDiff
)
363 return GetExpectedHashesFor(Target
.MetaKey
);
364 return HashStringList();
367 APT_CONST
bool pkgAcqArchive::HashesRequired() const
369 return LocalSource
== false;
371 HashStringList
pkgAcqArchive::GetExpectedHashes() const
373 // figured out while parsing the records
374 return ExpectedHashes
;
377 APT_CONST
bool pkgAcqFile::HashesRequired() const
379 // supplied as parameter at creation time, so the caller decides
380 return ExpectedHashes
.usable();
382 HashStringList
pkgAcqFile::GetExpectedHashes() const
384 return ExpectedHashes
;
387 // Acquire::Item::QueueURI and specialisations from child classes /*{{{*/
388 bool pkgAcquire::Item::QueueURI(pkgAcquire::ItemDesc
&Item
)
390 Owner
->Enqueue(Item
);
393 /* The idea here is that an item isn't queued if it exists on disk and the
394 transition manager was a hit as this means that the files it contains
395 the checksums for can't be updated either (or they are and we are asking
396 for a hashsum mismatch to happen which helps nobody) */
397 bool pkgAcqTransactionItem::QueueURI(pkgAcquire::ItemDesc
&Item
)
399 if (TransactionManager
->State
!= TransactionStarted
)
401 if (_config
->FindB("Debug::Acquire::Transaction", false))
402 std::clog
<< "Skip " << Target
.URI
<< " as transaction was already dealt with!" << std::endl
;
405 std::string
const FinalFile
= GetFinalFilename();
406 if (TransactionManager
->IMSHit
== true && FileExists(FinalFile
) == true)
408 PartialFile
= DestFile
= FinalFile
;
412 // If we got the InRelease file via a mirror, pick all indexes directly from this mirror, too
413 if (TransactionManager
->BaseURI
.empty() == false &&
414 URI::SiteOnly(Item
.URI
) != URI::SiteOnly(TransactionManager
->BaseURI
))
416 // this ensures we rewrite only once and only the first step
417 auto const OldBaseURI
= Target
.Option(IndexTarget::BASE_URI
);
418 if (OldBaseURI
.empty() == false && APT::String::Startswith(Item
.URI
, OldBaseURI
))
420 auto const ExtraPath
= Item
.URI
.substr(OldBaseURI
.length());
421 Item
.URI
= flCombine(TransactionManager
->BaseURI
, ExtraPath
);
422 UsedMirror
= TransactionManager
->UsedMirror
;
423 if (Item
.Description
.find(" ") != string::npos
)
424 Item
.Description
.replace(0, Item
.Description
.find(" "), UsedMirror
);
427 return pkgAcquire::Item::QueueURI(Item
);
429 /* The transition manager InRelease itself (or its older sisters-in-law
430 Release & Release.gpg) is always queued as this allows us to rerun gpgv
431 on it to verify that we aren't stalled with old files */
432 bool pkgAcqMetaBase::QueueURI(pkgAcquire::ItemDesc
&Item
)
434 return pkgAcquire::Item::QueueURI(Item
);
436 /* the Diff/Index needs to queue also the up-to-date complete index file
437 to ensure that the list cleaner isn't eating it */
438 bool pkgAcqDiffIndex::QueueURI(pkgAcquire::ItemDesc
&Item
)
440 if (pkgAcqTransactionItem::QueueURI(Item
) == true)
446 // Acquire::Item::GetFinalFilename and specialisations for child classes /*{{{*/
447 std::string
pkgAcquire::Item::GetFinalFilename() const
449 // Beware: Desc.URI is modified by redirections
450 return GetFinalFileNameFromURI(Desc
.URI
);
452 std::string
pkgAcqDiffIndex::GetFinalFilename() const
454 return GetFinalFileNameFromURI(GetDiffIndexURI(Target
));
456 std::string
pkgAcqIndex::GetFinalFilename() const
458 std::string
const FinalFile
= GetFinalFileNameFromURI(Target
.URI
);
459 return GetKeepCompressedFileName(FinalFile
, Target
);
461 std::string
pkgAcqMetaSig::GetFinalFilename() const
463 return GetFinalFileNameFromURI(Target
.URI
);
465 std::string
pkgAcqBaseIndex::GetFinalFilename() const
467 return GetFinalFileNameFromURI(Target
.URI
);
469 std::string
pkgAcqMetaBase::GetFinalFilename() const
471 return GetFinalFileNameFromURI(Target
.URI
);
473 std::string
pkgAcqArchive::GetFinalFilename() const
475 return _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
478 // pkgAcqTransactionItem::GetMetaKey and specialisations for child classes /*{{{*/
479 std::string
pkgAcqTransactionItem::GetMetaKey() const
481 return Target
.MetaKey
;
483 std::string
pkgAcqIndex::GetMetaKey() const
485 if (Stage
== STAGE_DECOMPRESS_AND_VERIFY
|| CurrentCompressionExtension
== "uncompressed")
486 return Target
.MetaKey
;
487 return Target
.MetaKey
+ "." + CurrentCompressionExtension
;
489 std::string
pkgAcqDiffIndex::GetMetaKey() const
491 return GetDiffIndexFileName(Target
.MetaKey
);
494 //pkgAcqTransactionItem::TransactionState and specialisations for child classes /*{{{*/
495 bool pkgAcqTransactionItem::TransactionState(TransactionStates
const state
)
497 bool const Debug
= _config
->FindB("Debug::Acquire::Transaction", false);
500 case TransactionStarted
: _error
->Fatal("Item %s changed to invalid transaction start state!", Target
.URI
.c_str()); break;
501 case TransactionAbort
:
503 std::clog
<< " Cancel: " << DestFile
<< std::endl
;
504 if (Status
== pkgAcquire::Item::StatIdle
)
506 Status
= pkgAcquire::Item::StatDone
;
510 case TransactionCommit
:
511 if(PartialFile
.empty() == false)
513 bool sameFile
= (PartialFile
== DestFile
);
514 // we use symlinks on IMS-Hit to avoid copies
515 if (RealFileExists(DestFile
))
518 if (lstat(PartialFile
.c_str(), &Buf
) != -1)
520 if (S_ISLNK(Buf
.st_mode
) && Buf
.st_size
> 0)
522 char partial
[Buf
.st_size
+ 1];
523 ssize_t
const sp
= readlink(PartialFile
.c_str(), partial
, Buf
.st_size
);
525 _error
->Errno("pkgAcqTransactionItem::TransactionState-sp", _("Failed to readlink %s"), PartialFile
.c_str());
529 sameFile
= (DestFile
== partial
);
534 _error
->Errno("pkgAcqTransactionItem::TransactionState-stat", _("Failed to stat %s"), PartialFile
.c_str());
536 if (sameFile
== false)
538 // ensure that even without lists-cleanup all compressions are nuked
539 std::string FinalFile
= GetFinalFileNameFromURI(Target
.URI
);
540 if (FileExists(FinalFile
))
543 std::clog
<< "rm " << FinalFile
<< " # " << DescURI() << std::endl
;
544 if (RemoveFile("TransactionStates-Cleanup", FinalFile
) == false)
547 for (auto const &ext
: APT::Configuration::getCompressorExtensions())
549 auto const Final
= FinalFile
+ ext
;
550 if (FileExists(Final
))
553 std::clog
<< "rm " << Final
<< " # " << DescURI() << std::endl
;
554 if (RemoveFile("TransactionStates-Cleanup", Final
) == false)
559 std::clog
<< "mv " << PartialFile
<< " -> "<< DestFile
<< " # " << DescURI() << std::endl
;
560 if (Rename(PartialFile
, DestFile
) == false)
563 else if(Debug
== true)
564 std::clog
<< "keep " << PartialFile
<< " # " << DescURI() << std::endl
;
568 std::clog
<< "rm " << DestFile
<< " # " << DescURI() << std::endl
;
569 if (RemoveFile("TransItem::TransactionCommit", DestFile
) == false)
576 bool pkgAcqMetaBase::TransactionState(TransactionStates
const state
)
578 // Do not remove InRelease on IMSHit of Release.gpg [yes, this is very edgecasey]
579 if (TransactionManager
->IMSHit
== false)
580 return pkgAcqTransactionItem::TransactionState(state
);
583 bool pkgAcqIndex::TransactionState(TransactionStates
const state
)
585 if (pkgAcqTransactionItem::TransactionState(state
) == false)
590 case TransactionStarted
: _error
->Fatal("AcqIndex %s changed to invalid transaction start state!", Target
.URI
.c_str()); break;
591 case TransactionAbort
:
592 if (Stage
== STAGE_DECOMPRESS_AND_VERIFY
)
594 // keep the compressed file, but drop the decompressed
595 EraseFileName
.clear();
596 if (PartialFile
.empty() == false && flExtension(PartialFile
) != CurrentCompressionExtension
)
597 RemoveFile("TransactionAbort", PartialFile
);
600 case TransactionCommit
:
601 if (EraseFileName
.empty() == false)
602 RemoveFile("AcqIndex::TransactionCommit", EraseFileName
);
607 bool pkgAcqDiffIndex::TransactionState(TransactionStates
const state
)
609 if (pkgAcqTransactionItem::TransactionState(state
) == false)
614 case TransactionStarted
: _error
->Fatal("Item %s changed to invalid transaction start state!", Target
.URI
.c_str()); break;
615 case TransactionCommit
:
617 case TransactionAbort
:
618 std::string
const Partial
= GetPartialFileNameFromURI(Target
.URI
);
619 RemoveFile("TransactionAbort", Partial
);
627 class APT_HIDDEN NoActionItem
: public pkgAcquire::Item
/*{{{*/
628 /* The sole purpose of this class is having an item which does nothing to
629 reach its done state to prevent cleanup deleting the mentioned file.
630 Handy in cases in which we know we have the file already, like IMS-Hits. */
632 IndexTarget
const Target
;
634 virtual std::string
DescURI() const APT_OVERRIDE
{return Target
.URI
;};
635 virtual HashStringList
GetExpectedHashes() const APT_OVERRIDE
{return HashStringList();};
637 NoActionItem(pkgAcquire
* const Owner
, IndexTarget
const &Target
) :
638 pkgAcquire::Item(Owner
), Target(Target
)
641 DestFile
= GetFinalFileNameFromURI(Target
.URI
);
643 NoActionItem(pkgAcquire
* const Owner
, IndexTarget
const &Target
, std::string
const &FinalFile
) :
644 pkgAcquire::Item(Owner
), Target(Target
)
647 DestFile
= FinalFile
;
651 class APT_HIDDEN CleanupItem
: public pkgAcqTransactionItem
/*{{{*/
652 /* This class ensures that a file which was configured but isn't downloaded
653 for various reasons isn't kept in an old version in the lists directory.
654 In a way its the reverse of NoActionItem as it helps with removing files
655 even if the lists-cleanup is deactivated. */
658 virtual std::string
DescURI() const APT_OVERRIDE
{return Target
.URI
;};
659 virtual HashStringList
GetExpectedHashes() const APT_OVERRIDE
{return HashStringList();};
661 CleanupItem(pkgAcquire
* const Owner
, pkgAcqMetaClearSig
* const TransactionManager
, IndexTarget
const &Target
) :
662 pkgAcqTransactionItem(Owner
, TransactionManager
, Target
)
665 DestFile
= GetFinalFileNameFromURI(Target
.URI
);
667 bool TransactionState(TransactionStates
const state
) APT_OVERRIDE
671 case TransactionStarted
:
673 case TransactionAbort
:
675 case TransactionCommit
:
676 if (_config
->FindB("Debug::Acquire::Transaction", false) == true)
677 std::clog
<< "rm " << DestFile
<< " # " << DescURI() << std::endl
;
678 if (RemoveFile("TransItem::TransactionCommit", DestFile
) == false)
687 // Acquire::Item::Item - Constructor /*{{{*/
688 APT_IGNORE_DEPRECATED_PUSH
689 pkgAcquire::Item::Item(pkgAcquire
* const owner
) :
690 FileSize(0), PartialSize(0), Mode(0), ID(0), Complete(false), Local(false),
691 QueueCounter(0), ExpectedAdditionalItems(0), Owner(owner
), d(NULL
)
696 APT_IGNORE_DEPRECATED_POP
698 // Acquire::Item::~Item - Destructor /*{{{*/
699 pkgAcquire::Item::~Item()
704 std::string
pkgAcquire::Item::Custom600Headers() const /*{{{*/
706 return std::string();
709 std::string
pkgAcquire::Item::ShortDesc() const /*{{{*/
714 APT_CONST
void pkgAcquire::Item::Finished() /*{{{*/
718 APT_PURE pkgAcquire
* pkgAcquire::Item::GetOwner() const /*{{{*/
723 APT_CONST
pkgAcquire::ItemDesc
&pkgAcquire::Item::GetItemDesc() /*{{{*/
728 APT_CONST
bool pkgAcquire::Item::IsTrusted() const /*{{{*/
733 // Acquire::Item::Failed - Item failed to download /*{{{*/
734 // ---------------------------------------------------------------------
735 /* We return to an idle state if there are still other queues that could
737 void pkgAcquire::Item::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)
739 if (QueueCounter
<= 1)
741 /* This indicates that the file is not available right now but might
742 be sometime later. If we do a retry cycle then this should be
744 if (Cnf
!= NULL
&& Cnf
->LocalOnly
== true &&
745 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
761 case StatTransientNetworkError
:
768 string
const FailReason
= LookupTag(Message
, "FailReason");
769 enum { MAXIMUM_SIZE_EXCEEDED
, HASHSUM_MISMATCH
, WEAK_HASHSUMS
, OTHER
} failreason
= OTHER
;
770 if ( FailReason
== "MaximumSizeExceeded")
771 failreason
= MAXIMUM_SIZE_EXCEEDED
;
772 else if ( FailReason
== "WeakHashSums")
773 failreason
= WEAK_HASHSUMS
;
774 else if (Status
== StatAuthError
)
775 failreason
= HASHSUM_MISMATCH
;
777 if(ErrorText
.empty())
779 if (Status
== StatAuthError
)
781 std::ostringstream out
;
784 case HASHSUM_MISMATCH
:
785 out
<< _("Hash Sum mismatch") << std::endl
;
788 out
<< _("Insufficient information available to perform this download securely") << std::endl
;
790 case MAXIMUM_SIZE_EXCEEDED
:
792 out
<< LookupTag(Message
, "Message") << std::endl
;
795 auto const ExpectedHashes
= GetExpectedHashes();
796 if (ExpectedHashes
.empty() == false)
798 out
<< "Hashes of expected file:" << std::endl
;
799 for (auto const &hs
: ExpectedHashes
)
801 out
<< " - " << hs
.toStr();
802 if (hs
.usable() == false)
807 if (failreason
== HASHSUM_MISMATCH
)
809 out
<< "Hashes of received file:" << std::endl
;
810 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
812 std::string
const tagname
= std::string(*type
) + "-Hash";
813 std::string
const hashsum
= LookupTag(Message
, tagname
.c_str());
814 if (hashsum
.empty() == false)
816 auto const hs
= HashString(*type
, hashsum
);
817 out
<< " - " << hs
.toStr();
818 if (hs
.usable() == false)
823 out
<< "Last modification reported: " << LookupTag(Message
, "Last-Modified", "<none>") << std::endl
;
825 ErrorText
= out
.str();
828 ErrorText
= LookupTag(Message
,"Message");
833 case MAXIMUM_SIZE_EXCEEDED
: RenameOnError(MaximumSizeExceeded
); break;
834 case HASHSUM_MISMATCH
: RenameOnError(HashSumMismatch
); break;
835 case WEAK_HASHSUMS
: break;
839 if (FailReason
.empty() == false)
840 ReportMirrorFailureToCentral(*this, FailReason
, ErrorText
);
842 ReportMirrorFailureToCentral(*this, ErrorText
, ErrorText
);
844 if (QueueCounter
> 1)
848 // Acquire::Item::Start - Item has begun to download /*{{{*/
849 // ---------------------------------------------------------------------
850 /* Stash status and the file size. Note that setting Complete means
851 sub-phases of the acquire process such as decompresion are operating */
852 void pkgAcquire::Item::Start(string
const &/*Message*/, unsigned long long const Size
)
854 Status
= StatFetching
;
856 if (FileSize
== 0 && Complete
== false)
860 // Acquire::Item::VerifyDone - check if Item was downloaded OK /*{{{*/
861 /* Note that hash-verification is 'hardcoded' in acquire-worker and has
862 * already passed if this method is called. */
863 bool pkgAcquire::Item::VerifyDone(std::string
const &Message
,
864 pkgAcquire::MethodConfig
const * const /*Cnf*/)
866 std::string
const FileName
= LookupTag(Message
,"Filename");
867 if (FileName
.empty() == true)
870 ErrorText
= "Method gave a blank filename";
877 // Acquire::Item::Done - Item downloaded OK /*{{{*/
878 void pkgAcquire::Item::Done(string
const &/*Message*/, HashStringList
const &Hashes
,
879 pkgAcquire::MethodConfig
const * const /*Cnf*/)
881 // We just downloaded something..
884 unsigned long long const downloadedSize
= Hashes
.FileSize();
885 if (downloadedSize
!= 0)
887 FileSize
= downloadedSize
;
891 ErrorText
= string();
892 Owner
->Dequeue(this);
895 // Acquire::Item::Rename - Rename a file /*{{{*/
896 // ---------------------------------------------------------------------
897 /* This helper function is used by a lot of item methods as their final
899 bool pkgAcquire::Item::Rename(string
const &From
,string
const &To
)
901 if (From
== To
|| rename(From
.c_str(),To
.c_str()) == 0)
905 strprintf(S
, _("rename failed, %s (%s -> %s)."), strerror(errno
),
906 From
.c_str(),To
.c_str());
908 if (ErrorText
.empty())
911 ErrorText
= ErrorText
+ ": " + S
;
915 void pkgAcquire::Item::Dequeue() /*{{{*/
917 Owner
->Dequeue(this);
920 bool pkgAcquire::Item::RenameOnError(pkgAcquire::Item::RenameOnErrorState
const error
)/*{{{*/
922 if (RealFileExists(DestFile
))
923 Rename(DestFile
, DestFile
+ ".FAILED");
928 case HashSumMismatch
:
929 errtext
= _("Hash Sum mismatch");
932 errtext
= _("Size mismatch");
933 Status
= StatAuthError
;
936 errtext
= _("Invalid file format");
938 // do not report as usually its not the mirrors fault, but Portal/Proxy
941 errtext
= _("Signature error");
945 strprintf(errtext
, _("Clearsigned file isn't valid, got '%s' (does the network require authentication?)"), "NOSPLIT");
946 Status
= StatAuthError
;
948 case MaximumSizeExceeded
:
949 // the method is expected to report a good error for this
952 // no handling here, done by callers
955 if (ErrorText
.empty())
960 void pkgAcquire::Item::SetActiveSubprocess(const std::string
&subprocess
)/*{{{*/
962 ActiveSubprocess
= subprocess
;
963 APT_IGNORE_DEPRECATED(Mode
= ActiveSubprocess
.c_str();)
966 // Acquire::Item::ReportMirrorFailure /*{{{*/
967 void pkgAcquire::Item::ReportMirrorFailure(std::string
const &FailCode
)
969 ReportMirrorFailureToCentral(*this, FailCode
, FailCode
);
972 std::string
pkgAcquire::Item::HashSum() const /*{{{*/
974 HashStringList
const hashes
= GetExpectedHashes();
975 HashString
const * const hs
= hashes
.find(NULL
);
976 return hs
!= NULL
? hs
->toStr() : "";
980 pkgAcqTransactionItem::pkgAcqTransactionItem(pkgAcquire
* const Owner
, /*{{{*/
981 pkgAcqMetaClearSig
* const transactionManager
, IndexTarget
const &target
) :
982 pkgAcquire::Item(Owner
), d(NULL
), Target(target
), TransactionManager(transactionManager
)
984 if (TransactionManager
!= this)
985 TransactionManager
->Add(this);
988 pkgAcqTransactionItem::~pkgAcqTransactionItem() /*{{{*/
992 HashStringList
pkgAcqTransactionItem::GetExpectedHashesFor(std::string
const &MetaKey
) const /*{{{*/
994 return GetExpectedHashesFromFor(TransactionManager
->MetaIndexParser
, MetaKey
);
998 static void LoadLastMetaIndexParser(pkgAcqMetaClearSig
* const TransactionManager
, std::string
const &FinalRelease
, std::string
const &FinalInRelease
)/*{{{*/
1000 if (TransactionManager
->IMSHit
== true)
1002 if (RealFileExists(FinalInRelease
) || RealFileExists(FinalRelease
))
1004 TransactionManager
->LastMetaIndexParser
= TransactionManager
->MetaIndexParser
->UnloadedClone();
1005 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1007 _error
->PushToStack();
1008 if (RealFileExists(FinalInRelease
))
1009 TransactionManager
->LastMetaIndexParser
->Load(FinalInRelease
, NULL
);
1011 TransactionManager
->LastMetaIndexParser
->Load(FinalRelease
, NULL
);
1012 // its unlikely to happen, but if what we have is bad ignore it
1013 if (_error
->PendingError())
1015 delete TransactionManager
->LastMetaIndexParser
;
1016 TransactionManager
->LastMetaIndexParser
= NULL
;
1018 _error
->RevertToStack();
1024 // AcqMetaBase - Constructor /*{{{*/
1025 pkgAcqMetaBase::pkgAcqMetaBase(pkgAcquire
* const Owner
,
1026 pkgAcqMetaClearSig
* const TransactionManager
,
1027 IndexTarget
const &DataTarget
)
1028 : pkgAcqTransactionItem(Owner
, TransactionManager
, DataTarget
), d(NULL
),
1029 AuthPass(false), IMSHit(false), State(TransactionStarted
)
1033 // AcqMetaBase::Add - Add a item to the current Transaction /*{{{*/
1034 void pkgAcqMetaBase::Add(pkgAcqTransactionItem
* const I
)
1036 Transaction
.push_back(I
);
1039 // AcqMetaBase::AbortTransaction - Abort the current Transaction /*{{{*/
1040 void pkgAcqMetaBase::AbortTransaction()
1042 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1043 std::clog
<< "AbortTransaction: " << TransactionManager
<< std::endl
;
1045 switch (TransactionManager
->State
)
1047 case TransactionStarted
: break;
1048 case TransactionAbort
: _error
->Fatal("Transaction %s was already aborted and is aborted again", TransactionManager
->Target
.URI
.c_str()); return;
1049 case TransactionCommit
: _error
->Fatal("Transaction %s was already aborted and is now committed", TransactionManager
->Target
.URI
.c_str()); return;
1051 TransactionManager
->State
= TransactionAbort
;
1053 // ensure the toplevel is in error state too
1054 for (std::vector
<pkgAcqTransactionItem
*>::iterator I
= Transaction
.begin();
1055 I
!= Transaction
.end(); ++I
)
1057 if ((*I
)->Status
!= pkgAcquire::Item::StatFetching
)
1059 (*I
)->TransactionState(TransactionAbort
);
1061 Transaction
.clear();
1064 // AcqMetaBase::TransactionHasError - Check for errors in Transaction /*{{{*/
1065 APT_PURE
bool pkgAcqMetaBase::TransactionHasError() const
1067 for (std::vector
<pkgAcqTransactionItem
*>::const_iterator I
= Transaction
.begin();
1068 I
!= Transaction
.end(); ++I
)
1070 switch((*I
)->Status
) {
1071 case StatDone
: break;
1072 case StatIdle
: break;
1073 case StatAuthError
: return true;
1074 case StatError
: return true;
1075 case StatTransientNetworkError
: return true;
1076 case StatFetching
: break;
1082 // AcqMetaBase::CommitTransaction - Commit a transaction /*{{{*/
1083 void pkgAcqMetaBase::CommitTransaction()
1085 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1086 std::clog
<< "CommitTransaction: " << this << std::endl
;
1088 switch (TransactionManager
->State
)
1090 case TransactionStarted
: break;
1091 case TransactionAbort
: _error
->Fatal("Transaction %s was already committed and is now aborted", TransactionManager
->Target
.URI
.c_str()); return;
1092 case TransactionCommit
: _error
->Fatal("Transaction %s was already committed and is again committed", TransactionManager
->Target
.URI
.c_str()); return;
1094 TransactionManager
->State
= TransactionCommit
;
1096 // move new files into place *and* remove files that are not
1097 // part of the transaction but are still on disk
1098 for (std::vector
<pkgAcqTransactionItem
*>::iterator I
= Transaction
.begin();
1099 I
!= Transaction
.end(); ++I
)
1101 (*I
)->TransactionState(TransactionCommit
);
1103 Transaction
.clear();
1106 // AcqMetaBase::TransactionStageCopy - Stage a file for copying /*{{{*/
1107 void pkgAcqMetaBase::TransactionStageCopy(pkgAcqTransactionItem
* const I
,
1108 const std::string
&From
,
1109 const std::string
&To
)
1111 I
->PartialFile
= From
;
1115 // AcqMetaBase::TransactionStageRemoval - Stage a file for removal /*{{{*/
1116 void pkgAcqMetaBase::TransactionStageRemoval(pkgAcqTransactionItem
* const I
,
1117 const std::string
&FinalFile
)
1119 I
->PartialFile
= "";
1120 I
->DestFile
= FinalFile
;
1123 // AcqMetaBase::GenerateAuthWarning - Check gpg authentication error /*{{{*/
1124 /* This method is called from ::Failed handlers. If it returns true,
1125 no fallback to other files or modi is performed */
1126 bool pkgAcqMetaBase::CheckStopAuthentication(pkgAcquire::Item
* const I
, const std::string
&Message
)
1128 string
const Final
= I
->GetFinalFilename();
1129 std::string
const GPGError
= LookupTag(Message
, "Message");
1130 if (FileExists(Final
))
1132 I
->Status
= StatTransientNetworkError
;
1133 _error
->Warning(_("An error occurred during the signature verification. "
1134 "The repository is not updated and the previous index files will be used. "
1135 "GPG error: %s: %s"),
1136 Desc
.Description
.c_str(),
1138 RunScripts("APT::Update::Auth-Failure");
1140 } else if (LookupTag(Message
,"Message").find("NODATA") != string::npos
) {
1141 /* Invalid signature file, reject (LP: #346386) (Closes: #627642) */
1142 _error
->Error(_("GPG error: %s: %s"),
1143 Desc
.Description
.c_str(),
1145 I
->Status
= StatAuthError
;
1148 _error
->Warning(_("GPG error: %s: %s"),
1149 Desc
.Description
.c_str(),
1152 // gpgv method failed
1153 ReportMirrorFailureToCentral(*this, "GPGFailure", GPGError
);
1157 // AcqMetaBase::Custom600Headers - Get header for AcqMetaBase /*{{{*/
1158 // ---------------------------------------------------------------------
1159 string
pkgAcqMetaBase::Custom600Headers() const
1161 std::string Header
= "\nIndex-File: true";
1162 std::string MaximumSize
;
1163 strprintf(MaximumSize
, "\nMaximum-Size: %i",
1164 _config
->FindI("Acquire::MaxReleaseFileSize", 10*1000*1000));
1165 Header
+= MaximumSize
;
1167 string
const FinalFile
= GetFinalFilename();
1169 if (stat(FinalFile
.c_str(),&Buf
) == 0)
1170 Header
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1175 // AcqMetaBase::QueueForSignatureVerify /*{{{*/
1176 void pkgAcqMetaBase::QueueForSignatureVerify(pkgAcqTransactionItem
* const I
, std::string
const &File
, std::string
const &Signature
)
1179 I
->Desc
.URI
= "gpgv:" + Signature
;
1182 I
->SetActiveSubprocess("gpgv");
1185 // AcqMetaBase::CheckDownloadDone /*{{{*/
1186 bool pkgAcqMetaBase::CheckDownloadDone(pkgAcqTransactionItem
* const I
, const std::string
&Message
, HashStringList
const &Hashes
) const
1188 // We have just finished downloading a Release file (it is not
1191 // Save the final base URI we got this Release file from
1192 if (I
->UsedMirror
.empty() == false && _config
->FindB("Acquire::SameMirrorForAllIndexes", true))
1194 if (APT::String::Endswith(I
->Desc
.URI
, "InRelease"))
1195 TransactionManager
->BaseURI
= I
->Desc
.URI
.substr(0, I
->Desc
.URI
.length() - strlen("InRelease"));
1196 else if (APT::String::Endswith(I
->Desc
.URI
, "Release"))
1197 TransactionManager
->BaseURI
= I
->Desc
.URI
.substr(0, I
->Desc
.URI
.length() - strlen("Release"));
1200 std::string
const FileName
= LookupTag(Message
,"Filename");
1201 if (FileName
!= I
->DestFile
&& RealFileExists(I
->DestFile
) == false)
1204 I
->Desc
.URI
= "copy:" + FileName
;
1205 I
->QueueURI(I
->Desc
);
1209 // make sure to verify against the right file on I-M-S hit
1210 bool IMSHit
= StringToBool(LookupTag(Message
,"IMS-Hit"), false);
1211 if (IMSHit
== false && Hashes
.usable())
1213 // detect IMS-Hits servers haven't detected by Hash comparison
1214 std::string
const FinalFile
= I
->GetFinalFilename();
1215 if (RealFileExists(FinalFile
) && Hashes
.VerifyFile(FinalFile
) == true)
1218 RemoveFile("CheckDownloadDone", I
->DestFile
);
1224 // for simplicity, the transaction manager is always InRelease
1225 // even if it doesn't exist.
1226 TransactionManager
->IMSHit
= true;
1227 I
->PartialFile
= I
->DestFile
= I
->GetFinalFilename();
1230 // set Item to complete as the remaining work is all local (verify etc)
1236 bool pkgAcqMetaBase::CheckAuthDone(string
const &Message
) /*{{{*/
1238 // At this point, the gpgv method has succeeded, so there is a
1239 // valid signature from a key in the trusted keyring. We
1240 // perform additional verification of its contents, and use them
1241 // to verify the indexes we are about to download
1242 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1243 std::cerr
<< "Signature verification succeeded: " << DestFile
<< std::endl
;
1245 if (TransactionManager
->IMSHit
== false)
1247 // open the last (In)Release if we have it
1248 std::string
const FinalFile
= GetFinalFilename();
1249 std::string FinalRelease
;
1250 std::string FinalInRelease
;
1251 if (APT::String::Endswith(FinalFile
, "InRelease"))
1253 FinalInRelease
= FinalFile
;
1254 FinalRelease
= FinalFile
.substr(0, FinalFile
.length() - strlen("InRelease")) + "Release";
1258 FinalInRelease
= FinalFile
.substr(0, FinalFile
.length() - strlen("Release")) + "InRelease";
1259 FinalRelease
= FinalFile
;
1261 LoadLastMetaIndexParser(TransactionManager
, FinalRelease
, FinalInRelease
);
1264 bool const GoodAuth
= TransactionManager
->MetaIndexParser
->Load(DestFile
, &ErrorText
);
1265 if (GoodAuth
== false && AllowInsecureRepositories(InsecureType::WEAK
, Target
.Description
, TransactionManager
->MetaIndexParser
, TransactionManager
, this) == false)
1267 Status
= StatAuthError
;
1271 if (!VerifyVendor(Message
))
1273 Status
= StatAuthError
;
1277 // Download further indexes with verification
1278 TransactionManager
->QueueIndexes(GoodAuth
);
1283 void pkgAcqMetaClearSig::QueueIndexes(bool const verify
) /*{{{*/
1285 // at this point the real Items are loaded in the fetcher
1286 ExpectedAdditionalItems
= 0;
1288 std::set
<std::string
> targetsSeen
;
1289 bool const hasReleaseFile
= TransactionManager
->MetaIndexParser
!= NULL
;
1290 bool const metaBaseSupportsByHash
= hasReleaseFile
&& TransactionManager
->MetaIndexParser
->GetSupportsAcquireByHash();
1291 bool hasHashes
= true;
1292 auto IndexTargets
= TransactionManager
->MetaIndexParser
->GetIndexTargets();
1293 if (hasReleaseFile
&& verify
== false)
1294 hasHashes
= std::any_of(IndexTargets
.begin(), IndexTargets
.end(),
1295 [&](IndexTarget
const &Target
) { return TransactionManager
->MetaIndexParser
->Exists(Target
.MetaKey
); });
1296 for (auto&& Target
: IndexTargets
)
1298 // if we have seen a target which is created-by a target this one here is declared a
1299 // fallback to, we skip acquiring the fallback (but we make sure we clean up)
1300 if (targetsSeen
.find(Target
.Option(IndexTarget::FALLBACK_OF
)) != targetsSeen
.end())
1302 targetsSeen
.emplace(Target
.Option(IndexTarget::CREATED_BY
));
1303 new CleanupItem(Owner
, TransactionManager
, Target
);
1306 // all is an implementation detail. Users shouldn't use this as arch
1307 // We need this support trickery here as e.g. Debian has binary-all files already,
1308 // but arch:all packages are still in the arch:any files, so we would waste precious
1309 // download time, bandwidth and diskspace for nothing, BUT Debian doesn't feature all
1310 // in the set of supported architectures, so we can filter based on this property rather
1311 // than invent an entirely new flag we would need to carry for all of eternity.
1312 if (hasReleaseFile
&& Target
.Option(IndexTarget::ARCHITECTURE
) == "all")
1314 if (TransactionManager
->MetaIndexParser
->IsArchitectureSupported("all") == false ||
1315 TransactionManager
->MetaIndexParser
->IsArchitectureAllSupportedFor(Target
) == false)
1317 new CleanupItem(Owner
, TransactionManager
, Target
);
1322 bool trypdiff
= Target
.OptionBool(IndexTarget::PDIFFS
);
1323 if (hasReleaseFile
== true)
1325 if (TransactionManager
->MetaIndexParser
->Exists(Target
.MetaKey
) == false)
1327 // optional targets that we do not have in the Release file are skipped
1328 if (hasHashes
== true && Target
.IsOptional
)
1330 new CleanupItem(Owner
, TransactionManager
, Target
);
1334 std::string
const &arch
= Target
.Option(IndexTarget::ARCHITECTURE
);
1335 if (arch
.empty() == false)
1337 if (TransactionManager
->MetaIndexParser
->IsArchitectureSupported(arch
) == false)
1339 new CleanupItem(Owner
, TransactionManager
, Target
);
1340 _error
->Notice(_("Skipping acquire of configured file '%s' as repository '%s' doesn't support architecture '%s'"),
1341 Target
.MetaKey
.c_str(), TransactionManager
->Target
.Description
.c_str(), arch
.c_str());
1344 // if the architecture is officially supported but currently no packages for it available,
1345 // ignore silently as this is pretty much the same as just shipping an empty file.
1346 // if we don't know which architectures are supported, we do NOT ignore it to notify user about this
1347 if (hasHashes
== true && TransactionManager
->MetaIndexParser
->IsArchitectureSupported("*undefined*") == false)
1349 new CleanupItem(Owner
, TransactionManager
, Target
);
1354 if (hasHashes
== true)
1356 Status
= StatAuthError
;
1357 strprintf(ErrorText
, _("Unable to find expected entry '%s' in Release file (Wrong sources.list entry or malformed file)"), Target
.MetaKey
.c_str());
1362 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
1368 auto const hashes
= GetExpectedHashesFor(Target
.MetaKey
);
1369 if (hashes
.empty() == false)
1371 if (hashes
.usable() == false && TargetIsAllowedToBe(TransactionManager
->Target
, InsecureType::WEAK
) == false)
1373 new CleanupItem(Owner
, TransactionManager
, Target
);
1374 _error
->Warning(_("Skipping acquire of configured file '%s' as repository '%s' provides only weak security information for it"),
1375 Target
.MetaKey
.c_str(), TransactionManager
->Target
.Description
.c_str());
1378 // empty files are skipped as acquiring the very small compressed files is a waste of time
1379 else if (hashes
.FileSize() == 0)
1381 new CleanupItem(Owner
, TransactionManager
, Target
);
1382 targetsSeen
.emplace(Target
.Option(IndexTarget::CREATED_BY
));
1388 // autoselect the compression method
1389 std::vector
<std::string
> types
= VectorizeString(Target
.Option(IndexTarget::COMPRESSIONTYPES
), ' ');
1390 types
.erase(std::remove_if(types
.begin(), types
.end(), [&](std::string
const &t
) {
1391 if (t
== "uncompressed")
1392 return TransactionManager
->MetaIndexParser
->Exists(Target
.MetaKey
) == false;
1393 std::string
const MetaKey
= Target
.MetaKey
+ "." + t
;
1394 return TransactionManager
->MetaIndexParser
->Exists(MetaKey
) == false;
1396 if (types
.empty() == false)
1398 std::ostringstream os
;
1399 // add the special compressiontype byhash first if supported
1400 std::string
const useByHashConf
= Target
.Option(IndexTarget::BY_HASH
);
1401 bool useByHash
= false;
1402 if(useByHashConf
== "force")
1405 useByHash
= StringToBool(useByHashConf
) == true && metaBaseSupportsByHash
;
1406 if (useByHash
== true)
1408 std::copy(types
.begin(), types
.end()-1, std::ostream_iterator
<std::string
>(os
, " "));
1409 os
<< *types
.rbegin();
1410 Target
.Options
["COMPRESSIONTYPES"] = os
.str();
1413 Target
.Options
["COMPRESSIONTYPES"].clear();
1415 std::string filename
= GetExistingFilename(GetFinalFileNameFromURI(Target
.URI
));
1416 if (filename
.empty() == false)
1418 // if the Release file is a hit and we have an index it must be the current one
1419 if (TransactionManager
->IMSHit
== true)
1421 else if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1423 // see if the file changed since the last Release file
1424 // we use the uncompressed files as we might compress differently compared to the server,
1425 // so the hashes might not match, even if they contain the same data.
1426 HashStringList
const newFile
= GetExpectedHashesFromFor(TransactionManager
->MetaIndexParser
, Target
.MetaKey
);
1427 HashStringList
const oldFile
= GetExpectedHashesFromFor(TransactionManager
->LastMetaIndexParser
, Target
.MetaKey
);
1428 if (newFile
!= oldFile
)
1435 trypdiff
= false; // no file to patch
1437 if (filename
.empty() == false)
1439 new NoActionItem(Owner
, Target
, filename
);
1440 std::string
const idxfilename
= GetFinalFileNameFromURI(GetDiffIndexURI(Target
));
1441 if (FileExists(idxfilename
))
1442 new NoActionItem(Owner
, Target
, idxfilename
);
1443 targetsSeen
.emplace(Target
.Option(IndexTarget::CREATED_BY
));
1447 // check if we have patches available
1448 trypdiff
&= TransactionManager
->MetaIndexParser
->Exists(GetDiffIndexFileName(Target
.MetaKey
));
1452 // if we have no file to patch, no point in trying
1453 trypdiff
&= (GetExistingFilename(GetFinalFileNameFromURI(Target
.URI
)).empty() == false);
1456 // no point in patching from local sources
1459 std::string
const proto
= Target
.URI
.substr(0, strlen("file:/"));
1460 if (proto
== "file:/" || proto
== "copy:/" || proto
== "cdrom:")
1464 // Queue the Index file (Packages, Sources, Translation-$foo, …)
1465 targetsSeen
.emplace(Target
.Option(IndexTarget::CREATED_BY
));
1467 new pkgAcqDiffIndex(Owner
, TransactionManager
, Target
);
1469 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
1473 bool pkgAcqMetaBase::VerifyVendor(string
const &) /*{{{*/
1475 string Transformed
= TransactionManager
->MetaIndexParser
->GetExpectedDist();
1477 if (Transformed
== "../project/experimental")
1479 Transformed
= "experimental";
1482 auto pos
= Transformed
.rfind('/');
1483 if (pos
!= string::npos
)
1485 Transformed
= Transformed
.substr(0, pos
);
1488 if (Transformed
== ".")
1493 if (TransactionManager
->MetaIndexParser
->GetValidUntil() > 0)
1495 time_t const invalid_since
= time(NULL
) - TransactionManager
->MetaIndexParser
->GetValidUntil();
1496 if (invalid_since
> 0)
1500 // TRANSLATOR: The first %s is the URL of the bad Release file, the second is
1501 // the time since then the file is invalid - formatted in the same way as in
1502 // the download progress display (e.g. 7d 3h 42min 1s)
1503 _("Release file for %s is expired (invalid since %s). "
1504 "Updates for this repository will not be applied."),
1505 Target
.URI
.c_str(), TimeToStr(invalid_since
).c_str());
1506 if (ErrorText
.empty())
1508 return _error
->Error("%s", errmsg
.c_str());
1512 /* Did we get a file older than what we have? This is a last minute IMS hit and doubles
1513 as a prevention of downgrading us to older (still valid) files */
1514 if (TransactionManager
->IMSHit
== false && TransactionManager
->LastMetaIndexParser
!= NULL
&&
1515 TransactionManager
->LastMetaIndexParser
->GetDate() > TransactionManager
->MetaIndexParser
->GetDate())
1517 TransactionManager
->IMSHit
= true;
1518 RemoveFile("VerifyVendor", DestFile
);
1519 PartialFile
= DestFile
= GetFinalFilename();
1520 // load the 'old' file in the 'new' one instead of flipping pointers as
1521 // the new one isn't owned by us, while the old one is so cleanup would be confused.
1522 TransactionManager
->MetaIndexParser
->swapLoad(TransactionManager
->LastMetaIndexParser
);
1523 delete TransactionManager
->LastMetaIndexParser
;
1524 TransactionManager
->LastMetaIndexParser
= NULL
;
1527 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1529 std::cerr
<< "Got Codename: " << TransactionManager
->MetaIndexParser
->GetCodename() << std::endl
;
1530 std::cerr
<< "Expecting Dist: " << TransactionManager
->MetaIndexParser
->GetExpectedDist() << std::endl
;
1531 std::cerr
<< "Transformed Dist: " << Transformed
<< std::endl
;
1534 if (TransactionManager
->MetaIndexParser
->CheckDist(Transformed
) == false)
1536 // This might become fatal one day
1537 // Status = StatAuthError;
1538 // ErrorText = "Conflicting distribution; expected "
1539 // + MetaIndexParser->GetExpectedDist() + " but got "
1540 // + MetaIndexParser->GetCodename();
1542 if (!Transformed
.empty())
1544 _error
->Warning(_("Conflicting distribution: %s (expected %s but got %s)"),
1545 Desc
.Description
.c_str(),
1546 Transformed
.c_str(),
1547 TransactionManager
->MetaIndexParser
->GetCodename().c_str());
1554 pkgAcqMetaBase::~pkgAcqMetaBase()
1558 pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire
* const Owner
, /*{{{*/
1559 IndexTarget
const &ClearsignedTarget
,
1560 IndexTarget
const &DetachedDataTarget
, IndexTarget
const &DetachedSigTarget
,
1561 metaIndex
* const MetaIndexParser
) :
1562 pkgAcqMetaIndex(Owner
, this, ClearsignedTarget
, DetachedSigTarget
),
1563 d(NULL
), DetachedDataTarget(DetachedDataTarget
),
1564 MetaIndexParser(MetaIndexParser
), LastMetaIndexParser(NULL
)
1566 // index targets + (worst case:) Release/Release.gpg
1567 ExpectedAdditionalItems
= std::numeric_limits
<decltype(ExpectedAdditionalItems
)>::max();
1568 TransactionManager
->Add(this);
1571 pkgAcqMetaClearSig::~pkgAcqMetaClearSig() /*{{{*/
1573 if (LastMetaIndexParser
!= NULL
)
1574 delete LastMetaIndexParser
;
1577 // pkgAcqMetaClearSig::Custom600Headers - Insert custom request headers /*{{{*/
1578 string
pkgAcqMetaClearSig::Custom600Headers() const
1580 string Header
= pkgAcqMetaBase::Custom600Headers();
1581 Header
+= "\nFail-Ignore: true";
1582 std::string
const key
= TransactionManager
->MetaIndexParser
->GetSignedBy();
1583 if (key
.empty() == false)
1584 Header
+= "\nSigned-By: " + key
;
1589 void pkgAcqMetaClearSig::Finished() /*{{{*/
1591 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1592 std::clog
<< "Finished: " << DestFile
<<std::endl
;
1593 if(TransactionManager
->State
== TransactionStarted
&&
1594 TransactionManager
->TransactionHasError() == false)
1595 TransactionManager
->CommitTransaction();
1598 bool pkgAcqMetaClearSig::VerifyDone(std::string
const &Message
, /*{{{*/
1599 pkgAcquire::MethodConfig
const * const Cnf
)
1601 Item::VerifyDone(Message
, Cnf
);
1603 if (FileExists(DestFile
) && !StartsWithGPGClearTextSignature(DestFile
))
1604 return RenameOnError(NotClearsigned
);
1609 // pkgAcqMetaClearSig::Done - We got a file /*{{{*/
1610 void pkgAcqMetaClearSig::Done(std::string
const &Message
,
1611 HashStringList
const &Hashes
,
1612 pkgAcquire::MethodConfig
const * const Cnf
)
1614 Item::Done(Message
, Hashes
, Cnf
);
1616 if(AuthPass
== false)
1618 if(CheckDownloadDone(this, Message
, Hashes
) == true)
1619 QueueForSignatureVerify(this, DestFile
, DestFile
);
1622 else if(CheckAuthDone(Message
) == true)
1624 if (TransactionManager
->IMSHit
== false)
1625 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
1626 else if (RealFileExists(GetFinalFilename()) == false)
1628 // We got an InRelease file IMSHit, but we haven't one, which means
1629 // we had a valid Release/Release.gpg combo stepping in, which we have
1630 // to 'acquire' now to ensure list cleanup isn't removing them
1631 new NoActionItem(Owner
, DetachedDataTarget
);
1632 new NoActionItem(Owner
, DetachedSigTarget
);
1635 else if (Status
!= StatAuthError
)
1637 string
const FinalFile
= GetFinalFileNameFromURI(DetachedDataTarget
.URI
);
1638 string
const OldFile
= GetFinalFilename();
1639 if (TransactionManager
->IMSHit
== false)
1640 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
1641 else if (RealFileExists(OldFile
) == false)
1642 new NoActionItem(Owner
, DetachedDataTarget
);
1644 TransactionManager
->TransactionStageCopy(this, OldFile
, FinalFile
);
1648 void pkgAcqMetaClearSig::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
) /*{{{*/
1650 Item::Failed(Message
, Cnf
);
1652 if (AuthPass
== false)
1654 if (Status
== StatAuthError
|| Status
== StatTransientNetworkError
)
1656 // if we expected a ClearTextSignature (InRelease) but got a network
1657 // error or got a file, but it wasn't valid, we end up here (see VerifyDone).
1658 // As these is usually called by web-portals we do not try Release/Release.gpg
1659 // as this is gonna fail anyway and instead abort our try (LP#346386)
1660 TransactionManager
->AbortTransaction();
1664 // Queue the 'old' InRelease file for removal if we try Release.gpg
1665 // as otherwise the file will stay around and gives a false-auth
1666 // impression (CVE-2012-0214)
1667 TransactionManager
->TransactionStageRemoval(this, GetFinalFilename());
1670 new pkgAcqMetaIndex(Owner
, TransactionManager
, DetachedDataTarget
, DetachedSigTarget
);
1674 if(CheckStopAuthentication(this, Message
))
1677 if(AllowInsecureRepositories(InsecureType::UNSIGNED
, Target
.Description
, TransactionManager
->MetaIndexParser
, TransactionManager
, this) == true)
1681 /* InRelease files become Release files, otherwise
1682 * they would be considered as trusted later on */
1683 string
const FinalRelease
= GetFinalFileNameFromURI(DetachedDataTarget
.URI
);
1684 string
const PartialRelease
= GetPartialFileNameFromURI(DetachedDataTarget
.URI
);
1685 string
const FinalReleasegpg
= GetFinalFileNameFromURI(DetachedSigTarget
.URI
);
1686 string
const FinalInRelease
= GetFinalFilename();
1687 Rename(DestFile
, PartialRelease
);
1688 TransactionManager
->TransactionStageCopy(this, PartialRelease
, FinalRelease
);
1689 LoadLastMetaIndexParser(TransactionManager
, FinalRelease
, FinalInRelease
);
1691 // we parse the indexes here because at this point the user wanted
1692 // a repository that may potentially harm him
1693 if (TransactionManager
->MetaIndexParser
->Load(PartialRelease
, &ErrorText
) == false || VerifyVendor(Message
) == false)
1694 /* expired Release files are still a problem you need extra force for */;
1696 TransactionManager
->QueueIndexes(true);
1702 pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire
* const Owner
, /*{{{*/
1703 pkgAcqMetaClearSig
* const TransactionManager
,
1704 IndexTarget
const &DataTarget
,
1705 IndexTarget
const &DetachedSigTarget
) :
1706 pkgAcqMetaBase(Owner
, TransactionManager
, DataTarget
), d(NULL
),
1707 DetachedSigTarget(DetachedSigTarget
)
1709 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1710 std::clog
<< "New pkgAcqMetaIndex with TransactionManager "
1711 << this->TransactionManager
<< std::endl
;
1713 DestFile
= GetPartialFileNameFromURI(DataTarget
.URI
);
1716 Desc
.Description
= DataTarget
.Description
;
1718 Desc
.ShortDesc
= DataTarget
.ShortDesc
;
1719 Desc
.URI
= DataTarget
.URI
;
1723 void pkgAcqMetaIndex::Done(string
const &Message
, /*{{{*/
1724 HashStringList
const &Hashes
,
1725 pkgAcquire::MethodConfig
const * const Cfg
)
1727 Item::Done(Message
,Hashes
,Cfg
);
1729 if(CheckDownloadDone(this, Message
, Hashes
))
1731 // we have a Release file, now download the Signature, all further
1732 // verify/queue for additional downloads will be done in the
1733 // pkgAcqMetaSig::Done() code
1734 new pkgAcqMetaSig(Owner
, TransactionManager
, DetachedSigTarget
, this);
1738 // pkgAcqMetaIndex::Failed - no Release file present /*{{{*/
1739 void pkgAcqMetaIndex::Failed(string
const &Message
,
1740 pkgAcquire::MethodConfig
const * const Cnf
)
1742 pkgAcquire::Item::Failed(Message
, Cnf
);
1745 // No Release file was present so fall
1746 // back to queueing Packages files without verification
1747 // only allow going further if the user explicitly wants it
1748 if(AllowInsecureRepositories(InsecureType::NORELEASE
, Target
.Description
, TransactionManager
->MetaIndexParser
, TransactionManager
, this) == true)
1750 // ensure old Release files are removed
1751 TransactionManager
->TransactionStageRemoval(this, GetFinalFilename());
1753 // queue without any kind of hashsum support
1754 TransactionManager
->QueueIndexes(false);
1758 std::string
pkgAcqMetaIndex::DescURI() const /*{{{*/
1763 pkgAcqMetaIndex::~pkgAcqMetaIndex() {}
1765 // AcqMetaSig::AcqMetaSig - Constructor /*{{{*/
1766 pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire
* const Owner
,
1767 pkgAcqMetaClearSig
* const TransactionManager
,
1768 IndexTarget
const &Target
,
1769 pkgAcqMetaIndex
* const MetaIndex
) :
1770 pkgAcqTransactionItem(Owner
, TransactionManager
, Target
), d(NULL
), MetaIndex(MetaIndex
)
1772 DestFile
= GetPartialFileNameFromURI(Target
.URI
);
1774 // remove any partial downloaded sig-file in partial/.
1775 // it may confuse proxies and is too small to warrant a
1776 // partial download anyway
1777 RemoveFile("pkgAcqMetaSig", DestFile
);
1779 // set the TransactionManager
1780 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1781 std::clog
<< "New pkgAcqMetaSig with TransactionManager "
1782 << TransactionManager
<< std::endl
;
1785 Desc
.Description
= Target
.Description
;
1787 Desc
.ShortDesc
= Target
.ShortDesc
;
1788 Desc
.URI
= Target
.URI
;
1790 // If we got a hit for Release, we will get one for Release.gpg too (or obscure errors),
1791 // so we skip the download step and go instantly to verification
1792 if (TransactionManager
->IMSHit
== true && RealFileExists(GetFinalFilename()))
1796 PartialFile
= DestFile
= GetFinalFilename();
1797 MetaIndexFileSignature
= DestFile
;
1798 MetaIndex
->QueueForSignatureVerify(this, MetaIndex
->DestFile
, DestFile
);
1804 pkgAcqMetaSig::~pkgAcqMetaSig() /*{{{*/
1808 // pkgAcqMetaSig::Custom600Headers - Insert custom request headers /*{{{*/
1809 std::string
pkgAcqMetaSig::Custom600Headers() const
1811 std::string Header
= pkgAcqTransactionItem::Custom600Headers();
1812 std::string
const key
= TransactionManager
->MetaIndexParser
->GetSignedBy();
1813 if (key
.empty() == false)
1814 Header
+= "\nSigned-By: " + key
;
1818 // AcqMetaSig::Done - The signature was downloaded/verified /*{{{*/
1819 void pkgAcqMetaSig::Done(string
const &Message
, HashStringList
const &Hashes
,
1820 pkgAcquire::MethodConfig
const * const Cfg
)
1822 if (MetaIndexFileSignature
.empty() == false)
1824 DestFile
= MetaIndexFileSignature
;
1825 MetaIndexFileSignature
.clear();
1827 Item::Done(Message
, Hashes
, Cfg
);
1829 if(MetaIndex
->AuthPass
== false)
1831 if(MetaIndex
->CheckDownloadDone(this, Message
, Hashes
) == true)
1833 // destfile will be modified to point to MetaIndexFile for the
1834 // gpgv method, so we need to save it here
1835 MetaIndexFileSignature
= DestFile
;
1836 MetaIndex
->QueueForSignatureVerify(this, MetaIndex
->DestFile
, DestFile
);
1840 else if(MetaIndex
->CheckAuthDone(Message
) == true)
1842 if (TransactionManager
->IMSHit
== false)
1844 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
1845 TransactionManager
->TransactionStageCopy(MetaIndex
, MetaIndex
->DestFile
, MetaIndex
->GetFinalFilename());
1848 else if (MetaIndex
->Status
!= StatAuthError
)
1850 std::string
const FinalFile
= MetaIndex
->GetFinalFilename();
1851 if (TransactionManager
->IMSHit
== false)
1852 TransactionManager
->TransactionStageCopy(MetaIndex
, MetaIndex
->DestFile
, FinalFile
);
1854 TransactionManager
->TransactionStageCopy(MetaIndex
, FinalFile
, FinalFile
);
1858 void pkgAcqMetaSig::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
1860 Item::Failed(Message
,Cnf
);
1862 // check if we need to fail at this point
1863 if (MetaIndex
->AuthPass
== true && MetaIndex
->CheckStopAuthentication(this, Message
))
1866 // ensures that a Release.gpg file in the lists/ is removed by the transaction
1867 TransactionManager
->TransactionStageRemoval(this, DestFile
);
1869 // only allow going further if the user explicitly wants it
1870 if (AllowInsecureRepositories(InsecureType::UNSIGNED
, MetaIndex
->Target
.Description
, TransactionManager
->MetaIndexParser
, TransactionManager
, this) == true)
1872 string
const FinalRelease
= MetaIndex
->GetFinalFilename();
1873 string
const FinalInRelease
= TransactionManager
->GetFinalFilename();
1874 LoadLastMetaIndexParser(TransactionManager
, FinalRelease
, FinalInRelease
);
1876 // we parse the indexes here because at this point the user wanted
1877 // a repository that may potentially harm him
1878 bool const GoodLoad
= TransactionManager
->MetaIndexParser
->Load(MetaIndex
->DestFile
, &ErrorText
);
1879 if (MetaIndex
->VerifyVendor(Message
) == false)
1880 /* expired Release files are still a problem you need extra force for */;
1882 TransactionManager
->QueueIndexes(GoodLoad
);
1884 TransactionManager
->TransactionStageCopy(MetaIndex
, MetaIndex
->DestFile
, FinalRelease
);
1886 else if (TransactionManager
->IMSHit
== false)
1887 Rename(MetaIndex
->DestFile
, MetaIndex
->DestFile
+ ".FAILED");
1889 // FIXME: this is used often (e.g. in pkgAcqIndexTrans) so refactor
1890 if (Cnf
->LocalOnly
== true ||
1891 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1900 // AcqBaseIndex - Constructor /*{{{*/
1901 pkgAcqBaseIndex::pkgAcqBaseIndex(pkgAcquire
* const Owner
,
1902 pkgAcqMetaClearSig
* const TransactionManager
,
1903 IndexTarget
const &Target
)
1904 : pkgAcqTransactionItem(Owner
, TransactionManager
, Target
), d(NULL
)
1908 void pkgAcqBaseIndex::Failed(std::string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
1910 pkgAcquire::Item::Failed(Message
, Cnf
);
1911 if (Status
!= StatAuthError
)
1914 ErrorText
.append("Release file created at: ");
1915 auto const timespec
= TransactionManager
->MetaIndexParser
->GetDate();
1917 ErrorText
.append("<unknown>");
1919 ErrorText
.append(TimeRFC1123(timespec
));
1920 ErrorText
.append("\n");
1923 pkgAcqBaseIndex::~pkgAcqBaseIndex() {}
1925 // AcqDiffIndex::AcqDiffIndex - Constructor /*{{{*/
1926 // ---------------------------------------------------------------------
1927 /* Get the DiffIndex file first and see if there are patches available
1928 * If so, create a pkgAcqIndexDiffs fetcher that will get and apply the
1929 * patches. If anything goes wrong in that process, it will fall back to
1930 * the original packages file
1932 pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire
* const Owner
,
1933 pkgAcqMetaClearSig
* const TransactionManager
,
1934 IndexTarget
const &Target
)
1935 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
), diffs(NULL
)
1937 // FIXME: Magic number as an upper bound on pdiffs we will reasonably acquire
1938 ExpectedAdditionalItems
= 40;
1940 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
1943 Desc
.Description
= GetDiffIndexFileName(Target
.Description
);
1944 Desc
.ShortDesc
= Target
.ShortDesc
;
1945 Desc
.URI
= GetDiffIndexURI(Target
);
1947 DestFile
= GetPartialFileNameFromURI(Desc
.URI
);
1950 std::clog
<< "pkgAcqDiffIndex: " << Desc
.URI
<< std::endl
;
1955 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
1956 // ---------------------------------------------------------------------
1957 /* The only header we use is the last-modified header. */
1958 string
pkgAcqDiffIndex::Custom600Headers() const
1960 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1961 return "\nIndex-File: true";
1963 string
const Final
= GetFinalFilename();
1966 std::clog
<< "Custom600Header-IMS: " << Final
<< std::endl
;
1969 if (stat(Final
.c_str(),&Buf
) != 0)
1970 return "\nIndex-File: true";
1972 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1975 void pkgAcqDiffIndex::QueueOnIMSHit() const /*{{{*/
1977 // list cleanup needs to know that this file as well as the already
1978 // present index is ours, so we create an empty diff to save it for us
1979 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
);
1982 bool pkgAcqDiffIndex::ParseDiffIndex(string
const &IndexDiffFile
) /*{{{*/
1984 ExpectedAdditionalItems
= 0;
1985 // failing here is fine: our caller will take care of trying to
1986 // get the complete file if patching fails
1988 std::clog
<< "pkgAcqDiffIndex::ParseIndexDiff() " << IndexDiffFile
1991 FileFd
Fd(IndexDiffFile
,FileFd::ReadOnly
);
1993 if (Fd
.IsOpen() == false || Fd
.Failed())
1997 if(unlikely(TF
.Step(Tags
) == false))
2000 HashStringList ServerHashes
;
2001 unsigned long long ServerSize
= 0;
2003 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
2005 std::string tagname
= *type
;
2006 tagname
.append("-Current");
2007 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
2008 if (tmp
.empty() == true)
2012 unsigned long long size
;
2013 std::stringstream
ss(tmp
);
2015 if (unlikely(hash
.empty() == true))
2017 if (unlikely(ServerSize
!= 0 && ServerSize
!= size
))
2019 ServerHashes
.push_back(HashString(*type
, hash
));
2023 if (ServerHashes
.usable() == false)
2026 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": Did not find a good hashsum in the index" << std::endl
;
2030 std::string
const CurrentPackagesFile
= GetFinalFileNameFromURI(Target
.URI
);
2031 HashStringList
const TargetFileHashes
= GetExpectedHashesFor(Target
.MetaKey
);
2032 if (TargetFileHashes
.usable() == false || ServerHashes
!= TargetFileHashes
)
2036 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": Index has different hashes than parser, probably older, so fail pdiffing" << std::endl
;
2037 printHashSumComparison(CurrentPackagesFile
, ServerHashes
, TargetFileHashes
);
2042 HashStringList LocalHashes
;
2043 // try avoiding calculating the hash here as this is costly
2044 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
2045 LocalHashes
= GetExpectedHashesFromFor(TransactionManager
->LastMetaIndexParser
, Target
.MetaKey
);
2046 if (LocalHashes
.usable() == false)
2048 FileFd
fd(CurrentPackagesFile
, FileFd::ReadOnly
, FileFd::Auto
);
2049 Hashes
LocalHashesCalc(ServerHashes
);
2050 LocalHashesCalc
.AddFD(fd
);
2051 LocalHashes
= LocalHashesCalc
.GetHashStringList();
2054 if (ServerHashes
== LocalHashes
)
2056 // we have the same sha1 as the server so we are done here
2058 std::clog
<< "pkgAcqDiffIndex: Package file " << CurrentPackagesFile
<< " is up-to-date" << std::endl
;
2064 std::clog
<< "Server-Current: " << ServerHashes
.find(NULL
)->toStr() << " and we start at "
2065 << CurrentPackagesFile
<< " " << LocalHashes
.FileSize() << " " << LocalHashes
.find(NULL
)->toStr() << std::endl
;
2067 // historically, older hashes have more info than newer ones, so start
2068 // collecting with older ones first to avoid implementing complicated
2069 // information merging techniques… a failure is after all always
2070 // recoverable with a complete file and hashes aren't changed that often.
2071 std::vector
<char const *> types
;
2072 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
2073 types
.push_back(*type
);
2075 // parse all of (provided) history
2076 vector
<DiffInfo
> available_patches
;
2077 bool firstAcceptedHashes
= true;
2078 for (auto type
= types
.crbegin(); type
!= types
.crend(); ++type
)
2080 if (LocalHashes
.find(*type
) == NULL
)
2083 std::string tagname
= *type
;
2084 tagname
.append("-History");
2085 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
2086 if (tmp
.empty() == true)
2089 string hash
, filename
;
2090 unsigned long long size
;
2091 std::stringstream
ss(tmp
);
2093 while (ss
>> hash
>> size
>> filename
)
2095 if (unlikely(hash
.empty() == true || filename
.empty() == true))
2098 // see if we have a record for this file already
2099 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
2100 for (; cur
!= available_patches
.end(); ++cur
)
2102 if (cur
->file
!= filename
)
2104 cur
->result_hashes
.push_back(HashString(*type
, hash
));
2107 if (cur
!= available_patches
.end())
2109 if (firstAcceptedHashes
== true)
2112 next
.file
= filename
;
2113 next
.result_hashes
.push_back(HashString(*type
, hash
));
2114 next
.result_hashes
.FileSize(size
);
2115 available_patches
.push_back(next
);
2120 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
2121 << " wasn't in the list for the first parsed hash! (history)" << std::endl
;
2125 firstAcceptedHashes
= false;
2128 if (unlikely(available_patches
.empty() == true))
2131 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": "
2132 << "Couldn't find any patches for the patch series." << std::endl
;
2136 for (auto type
= types
.crbegin(); type
!= types
.crend(); ++type
)
2138 if (LocalHashes
.find(*type
) == NULL
)
2141 std::string tagname
= *type
;
2142 tagname
.append("-Patches");
2143 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
2144 if (tmp
.empty() == true)
2147 string hash
, filename
;
2148 unsigned long long size
;
2149 std::stringstream
ss(tmp
);
2151 while (ss
>> hash
>> size
>> filename
)
2153 if (unlikely(hash
.empty() == true || filename
.empty() == true))
2156 // see if we have a record for this file already
2157 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
2158 for (; cur
!= available_patches
.end(); ++cur
)
2160 if (cur
->file
!= filename
)
2162 if (cur
->patch_hashes
.empty())
2163 cur
->patch_hashes
.FileSize(size
);
2164 cur
->patch_hashes
.push_back(HashString(*type
, hash
));
2167 if (cur
!= available_patches
.end())
2170 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
2171 << " wasn't in the list for the first parsed hash! (patches)" << std::endl
;
2176 for (auto type
= types
.crbegin(); type
!= types
.crend(); ++type
)
2178 std::string tagname
= *type
;
2179 tagname
.append("-Download");
2180 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
2181 if (tmp
.empty() == true)
2184 string hash
, filename
;
2185 unsigned long long size
;
2186 std::stringstream
ss(tmp
);
2188 // FIXME: all of pdiff supports only .gz compressed patches
2189 while (ss
>> hash
>> size
>> filename
)
2191 if (unlikely(hash
.empty() == true || filename
.empty() == true))
2193 if (unlikely(APT::String::Endswith(filename
, ".gz") == false))
2195 filename
.erase(filename
.length() - 3);
2197 // see if we have a record for this file already
2198 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
2199 for (; cur
!= available_patches
.end(); ++cur
)
2201 if (cur
->file
!= filename
)
2203 if (cur
->download_hashes
.empty())
2204 cur
->download_hashes
.FileSize(size
);
2205 cur
->download_hashes
.push_back(HashString(*type
, hash
));
2208 if (cur
!= available_patches
.end())
2211 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
2212 << " wasn't in the list for the first parsed hash! (download)" << std::endl
;
2218 bool foundStart
= false;
2219 for (std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
2220 cur
!= available_patches
.end(); ++cur
)
2222 if (LocalHashes
!= cur
->result_hashes
)
2225 available_patches
.erase(available_patches
.begin(), cur
);
2230 if (foundStart
== false || unlikely(available_patches
.empty() == true))
2233 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": "
2234 << "Couldn't find the start of the patch series." << std::endl
;
2238 for (auto const &patch
: available_patches
)
2239 if (patch
.result_hashes
.usable() == false ||
2240 patch
.patch_hashes
.usable() == false ||
2241 patch
.download_hashes
.usable() == false)
2244 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": provides no usable hashes for " << patch
.file
2245 << " so fallback to complete download" << std::endl
;
2249 // patching with too many files is rather slow compared to a fast download
2250 unsigned long const fileLimit
= _config
->FindI("Acquire::PDiffs::FileLimit", 0);
2251 if (fileLimit
!= 0 && fileLimit
< available_patches
.size())
2254 std::clog
<< "Need " << available_patches
.size() << " diffs (Limit is " << fileLimit
2255 << ") so fallback to complete download" << std::endl
;
2259 // calculate the size of all patches we have to get
2260 unsigned short const sizeLimitPercent
= _config
->FindI("Acquire::PDiffs::SizeLimit", 100);
2261 if (sizeLimitPercent
> 0)
2263 unsigned long long downloadSize
= std::accumulate(available_patches
.begin(),
2264 available_patches
.end(), 0llu, [](unsigned long long const T
, DiffInfo
const &I
) {
2265 return T
+ I
.download_hashes
.FileSize();
2267 if (downloadSize
!= 0)
2269 unsigned long long downloadSizeIdx
= 0;
2270 auto const types
= VectorizeString(Target
.Option(IndexTarget::COMPRESSIONTYPES
), ' ');
2271 for (auto const &t
: types
)
2273 std::string MetaKey
= Target
.MetaKey
;
2274 if (t
!= "uncompressed")
2276 HashStringList
const hsl
= GetExpectedHashesFor(MetaKey
);
2277 if (unlikely(hsl
.usable() == false))
2279 downloadSizeIdx
= hsl
.FileSize();
2282 unsigned long long const sizeLimit
= downloadSizeIdx
* sizeLimitPercent
;
2283 if ((sizeLimit
/100) < downloadSize
)
2286 std::clog
<< "Need " << downloadSize
<< " compressed bytes (Limit is " << (sizeLimit
/100) << ", "
2287 << "original is " << downloadSizeIdx
<< ") so fallback to complete download" << std::endl
;
2293 // we have something, queue the diffs
2294 string::size_type
const last_space
= Description
.rfind(" ");
2295 if(last_space
!= string::npos
)
2296 Description
.erase(last_space
, Description
.size()-last_space
);
2298 /* decide if we should download patches one by one or in one go:
2299 The first is good if the server merges patches, but many don't so client
2300 based merging can be attempt in which case the second is better.
2301 "bad things" will happen if patches are merged on the server,
2302 but client side merging is attempt as well */
2303 bool pdiff_merge
= _config
->FindB("Acquire::PDiffs::Merge", true);
2304 if (pdiff_merge
== true)
2306 // reprepro adds this flag if it has merged patches on the server
2307 std::string
const precedence
= Tags
.FindS("X-Patch-Precedence");
2308 pdiff_merge
= (precedence
!= "merged");
2313 std::string
const Final
= GetExistingFilename(CurrentPackagesFile
);
2314 if (unlikely(Final
.empty())) // because we wouldn't be called in such a case
2316 std::string
const PartialFile
= GetPartialFileNameFromURI(Target
.URI
);
2317 if (FileExists(PartialFile
) && RemoveFile("Bootstrap-linking", PartialFile
) == false)
2320 std::clog
<< "Bootstrap-linking for patching " << CurrentPackagesFile
2321 << " by removing stale " << PartialFile
<< " failed!" << std::endl
;
2324 for (auto const &ext
: APT::Configuration::getCompressorExtensions())
2326 std::string
const Partial
= PartialFile
+ ext
;
2327 if (FileExists(Partial
) && RemoveFile("Bootstrap-linking", Partial
) == false)
2330 std::clog
<< "Bootstrap-linking for patching " << CurrentPackagesFile
2331 << " by removing stale " << Partial
<< " failed!" << std::endl
;
2335 std::string
const Ext
= Final
.substr(CurrentPackagesFile
.length());
2336 std::string
const Partial
= PartialFile
+ Ext
;
2337 if (symlink(Final
.c_str(), Partial
.c_str()) != 0)
2340 std::clog
<< "Bootstrap-linking for patching " << CurrentPackagesFile
2341 << " by linking " << Final
<< " to " << Partial
<< " failed!" << std::endl
;
2346 if (pdiff_merge
== false)
2347 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
, available_patches
);
2350 diffs
= new std::vector
<pkgAcqIndexMergeDiffs
*>(available_patches
.size());
2351 for(size_t i
= 0; i
< available_patches
.size(); ++i
)
2352 (*diffs
)[i
] = new pkgAcqIndexMergeDiffs(Owner
, TransactionManager
,
2354 available_patches
[i
],
2364 void pkgAcqDiffIndex::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
2366 pkgAcqBaseIndex::Failed(Message
,Cnf
);
2368 ExpectedAdditionalItems
= 0;
2371 std::clog
<< "pkgAcqDiffIndex failed: " << Desc
.URI
<< " with " << Message
<< std::endl
2372 << "Falling back to normal index file acquire" << std::endl
;
2374 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
2377 void pkgAcqDiffIndex::Done(string
const &Message
,HashStringList
const &Hashes
, /*{{{*/
2378 pkgAcquire::MethodConfig
const * const Cnf
)
2381 std::clog
<< "pkgAcqDiffIndex::Done(): " << Desc
.URI
<< std::endl
;
2383 Item::Done(Message
, Hashes
, Cnf
);
2385 string
const FinalFile
= GetFinalFilename();
2386 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false))
2387 DestFile
= FinalFile
;
2389 if(ParseDiffIndex(DestFile
) == false)
2391 Failed("Message: Couldn't parse pdiff index", Cnf
);
2392 // queue for final move - this should happen even if we fail
2393 // while parsing (e.g. on sizelimit) and download the complete file.
2394 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
2398 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
2407 pkgAcqDiffIndex::~pkgAcqDiffIndex()
2413 // AcqIndexDiffs::AcqIndexDiffs - Constructor /*{{{*/
2414 // ---------------------------------------------------------------------
2415 /* The package diff is added to the queue. one object is constructed
2416 * for each diff and the index
2418 pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire
* const Owner
,
2419 pkgAcqMetaClearSig
* const TransactionManager
,
2420 IndexTarget
const &Target
,
2421 vector
<DiffInfo
> const &diffs
)
2422 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
),
2423 available_patches(diffs
)
2425 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
2427 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
2430 Description
= Target
.Description
;
2431 Desc
.ShortDesc
= Target
.ShortDesc
;
2433 if(available_patches
.empty() == true)
2435 // we are done (yeah!), check hashes against the final file
2436 DestFile
= GetKeepCompressedFileName(GetFinalFileNameFromURI(Target
.URI
), Target
);
2441 State
= StateFetchDiff
;
2446 void pkgAcqIndexDiffs::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
2448 pkgAcqBaseIndex::Failed(Message
,Cnf
);
2451 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
2453 std::clog
<< "pkgAcqIndexDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
2454 << "Falling back to normal index file acquire " << std::endl
;
2455 RenameOnError(PDiffError
);
2456 std::string
const patchname
= GetDiffsPatchFileName(DestFile
);
2457 if (RealFileExists(patchname
))
2458 Rename(patchname
, patchname
+ ".FAILED");
2459 std::string
const UnpatchedFile
= GetExistingFilename(GetPartialFileNameFromURI(Target
.URI
));
2460 if (UnpatchedFile
.empty() == false && FileExists(UnpatchedFile
))
2461 Rename(UnpatchedFile
, UnpatchedFile
+ ".FAILED");
2462 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
2466 // Finish - helper that cleans the item out of the fetcher queue /*{{{*/
2467 void pkgAcqIndexDiffs::Finish(bool allDone
)
2470 std::clog
<< "pkgAcqIndexDiffs::Finish(): "
2472 << Desc
.URI
<< std::endl
;
2474 // we restore the original name, this is required, otherwise
2475 // the file will be cleaned
2478 std::string
const Final
= GetKeepCompressedFileName(GetFinalFilename(), Target
);
2479 TransactionManager
->TransactionStageCopy(this, DestFile
, Final
);
2481 // this is for the "real" finish
2486 std::clog
<< "\n\nallDone: " << DestFile
<< "\n" << std::endl
;
2493 std::clog
<< "Finishing: " << Desc
.URI
<< std::endl
;
2500 bool pkgAcqIndexDiffs::QueueNextDiff() /*{{{*/
2502 // calc sha1 of the just patched file
2503 std::string
const PartialFile
= GetExistingFilename(GetPartialFileNameFromURI(Target
.URI
));
2504 if(unlikely(PartialFile
.empty()))
2506 Failed("Message: The file " + GetPartialFileNameFromURI(Target
.URI
) + " isn't available", NULL
);
2510 FileFd
fd(PartialFile
, FileFd::ReadOnly
, FileFd::Extension
);
2511 Hashes LocalHashesCalc
;
2512 LocalHashesCalc
.AddFD(fd
);
2513 HashStringList
const LocalHashes
= LocalHashesCalc
.GetHashStringList();
2516 std::clog
<< "QueueNextDiff: " << PartialFile
<< " (" << LocalHashes
.find(NULL
)->toStr() << ")" << std::endl
;
2518 HashStringList
const TargetFileHashes
= GetExpectedHashesFor(Target
.MetaKey
);
2519 if (unlikely(LocalHashes
.usable() == false || TargetFileHashes
.usable() == false))
2521 Failed("Local/Expected hashes are not usable for " + PartialFile
, NULL
);
2525 // final file reached before all patches are applied
2526 if(LocalHashes
== TargetFileHashes
)
2532 // remove all patches until the next matching patch is found
2533 // this requires the Index file to be ordered
2534 available_patches
.erase(available_patches
.begin(),
2535 std::find_if(available_patches
.begin(), available_patches
.end(), [&](DiffInfo
const &I
) {
2536 return I
.result_hashes
== LocalHashes
;
2539 // error checking and falling back if no patch was found
2540 if(available_patches
.empty() == true)
2542 Failed("No patches left to reach target for " + PartialFile
, NULL
);
2546 // queue the right diff
2547 Desc
.URI
= Target
.URI
+ ".diff/" + available_patches
[0].file
+ ".gz";
2548 Desc
.Description
= Description
+ " " + available_patches
[0].file
+ string(".pdiff");
2549 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
+ ".diff/" + available_patches
[0].file
), Target
);
2552 std::clog
<< "pkgAcqIndexDiffs::QueueNextDiff(): " << Desc
.URI
<< std::endl
;
2559 void pkgAcqIndexDiffs::Done(string
const &Message
, HashStringList
const &Hashes
, /*{{{*/
2560 pkgAcquire::MethodConfig
const * const Cnf
)
2563 std::clog
<< "pkgAcqIndexDiffs::Done(): " << Desc
.URI
<< std::endl
;
2565 Item::Done(Message
, Hashes
, Cnf
);
2567 std::string
const UncompressedUnpatchedFile
= GetPartialFileNameFromURI(Target
.URI
);
2568 std::string
const UnpatchedFile
= GetExistingFilename(UncompressedUnpatchedFile
);
2569 std::string
const PatchFile
= GetDiffsPatchFileName(UnpatchedFile
);
2570 std::string
const PatchedFile
= GetKeepCompressedFileName(UncompressedUnpatchedFile
, Target
);
2574 // success in downloading a diff, enter ApplyDiff state
2575 case StateFetchDiff
:
2576 Rename(DestFile
, PatchFile
);
2577 DestFile
= GetKeepCompressedFileName(UncompressedUnpatchedFile
+ "-patched", Target
);
2579 std::clog
<< "Sending to rred method: " << UnpatchedFile
<< std::endl
;
2580 State
= StateApplyDiff
;
2582 Desc
.URI
= "rred:" + UnpatchedFile
;
2584 SetActiveSubprocess("rred");
2586 // success in download/apply a diff, queue next (if needed)
2587 case StateApplyDiff
:
2588 // remove the just applied patch and base file
2589 available_patches
.erase(available_patches
.begin());
2590 RemoveFile("pkgAcqIndexDiffs::Done", PatchFile
);
2591 RemoveFile("pkgAcqIndexDiffs::Done", UnpatchedFile
);
2593 std::clog
<< "Moving patched file in place: " << std::endl
2594 << DestFile
<< " -> " << PatchedFile
<< std::endl
;
2595 Rename(DestFile
, PatchedFile
);
2597 // see if there is more to download
2598 if(available_patches
.empty() == false)
2600 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
, available_patches
);
2603 DestFile
= PatchedFile
;
2610 std::string
pkgAcqIndexDiffs::Custom600Headers() const /*{{{*/
2612 if(State
!= StateApplyDiff
)
2613 return pkgAcqBaseIndex::Custom600Headers();
2614 std::ostringstream patchhashes
;
2615 HashStringList
const ExpectedHashes
= available_patches
[0].patch_hashes
;
2616 for (HashStringList::const_iterator hs
= ExpectedHashes
.begin(); hs
!= ExpectedHashes
.end(); ++hs
)
2617 patchhashes
<< "\nPatch-0-" << hs
->HashType() << "-Hash: " << hs
->HashValue();
2618 patchhashes
<< pkgAcqBaseIndex::Custom600Headers();
2619 return patchhashes
.str();
2622 pkgAcqIndexDiffs::~pkgAcqIndexDiffs() {}
2624 // AcqIndexMergeDiffs::AcqIndexMergeDiffs - Constructor /*{{{*/
2625 pkgAcqIndexMergeDiffs::pkgAcqIndexMergeDiffs(pkgAcquire
* const Owner
,
2626 pkgAcqMetaClearSig
* const TransactionManager
,
2627 IndexTarget
const &Target
,
2628 DiffInfo
const &patch
,
2629 std::vector
<pkgAcqIndexMergeDiffs
*> const * const allPatches
)
2630 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
),
2631 patch(patch
), allPatches(allPatches
), State(StateFetchDiff
)
2633 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
2636 Description
= Target
.Description
;
2637 Desc
.ShortDesc
= Target
.ShortDesc
;
2638 Desc
.URI
= Target
.URI
+ ".diff/" + patch
.file
+ ".gz";
2639 Desc
.Description
= Description
+ " " + patch
.file
+ ".pdiff";
2640 DestFile
= GetPartialFileNameFromURI(Desc
.URI
);
2643 std::clog
<< "pkgAcqIndexMergeDiffs: " << Desc
.URI
<< std::endl
;
2648 void pkgAcqIndexMergeDiffs::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
2651 std::clog
<< "pkgAcqIndexMergeDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
;
2653 pkgAcqBaseIndex::Failed(Message
,Cnf
);
2656 // check if we are the first to fail, otherwise we are done here
2657 State
= StateDoneDiff
;
2658 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2659 I
!= allPatches
->end(); ++I
)
2660 if ((*I
)->State
== StateErrorDiff
)
2662 State
= StateErrorDiff
;
2666 // first failure means we should fallback
2667 State
= StateErrorDiff
;
2669 std::clog
<< "Falling back to normal index file acquire" << std::endl
;
2670 RenameOnError(PDiffError
);
2671 if (RealFileExists(DestFile
))
2672 Rename(DestFile
, DestFile
+ ".FAILED");
2673 std::string
const UnpatchedFile
= GetExistingFilename(GetPartialFileNameFromURI(Target
.URI
));
2674 if (UnpatchedFile
.empty() == false && FileExists(UnpatchedFile
))
2675 Rename(UnpatchedFile
, UnpatchedFile
+ ".FAILED");
2677 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
2680 void pkgAcqIndexMergeDiffs::Done(string
const &Message
, HashStringList
const &Hashes
, /*{{{*/
2681 pkgAcquire::MethodConfig
const * const Cnf
)
2684 std::clog
<< "pkgAcqIndexMergeDiffs::Done(): " << Desc
.URI
<< std::endl
;
2686 Item::Done(Message
, Hashes
, Cnf
);
2688 if (std::any_of(allPatches
->begin(), allPatches
->end(),
2689 [](pkgAcqIndexMergeDiffs
const * const P
) { return P
->State
== StateErrorDiff
; }))
2692 std::clog
<< "Another patch failed already, no point in processing this one." << std::endl
;
2693 State
= StateErrorDiff
;
2697 std::string
const UncompressedUnpatchedFile
= GetPartialFileNameFromURI(Target
.URI
);
2698 std::string
const UnpatchedFile
= GetExistingFilename(UncompressedUnpatchedFile
);
2699 if (UnpatchedFile
.empty())
2701 _error
->Fatal("Unpatched file %s doesn't exist (anymore)!", UncompressedUnpatchedFile
.c_str());
2702 State
= StateErrorDiff
;
2705 std::string
const PatchFile
= GetMergeDiffsPatchFileName(UnpatchedFile
, patch
.file
);
2706 std::string
const PatchedFile
= GetKeepCompressedFileName(UncompressedUnpatchedFile
, Target
);
2710 case StateFetchDiff
:
2711 Rename(DestFile
, PatchFile
);
2713 // check if this is the last completed diff
2714 State
= StateDoneDiff
;
2715 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2716 I
!= allPatches
->end(); ++I
)
2717 if ((*I
)->State
!= StateDoneDiff
)
2720 std::clog
<< "Not the last done diff in the batch: " << Desc
.URI
<< std::endl
;
2723 // this is the last completed diff, so we are ready to apply now
2724 DestFile
= GetKeepCompressedFileName(UncompressedUnpatchedFile
+ "-patched", Target
);
2726 std::clog
<< "Sending to rred method: " << UnpatchedFile
<< std::endl
;
2727 State
= StateApplyDiff
;
2729 Desc
.URI
= "rred:" + UnpatchedFile
;
2731 SetActiveSubprocess("rred");
2733 case StateApplyDiff
:
2734 // success in download & apply all diffs, finialize and clean up
2736 std::clog
<< "Queue patched file in place: " << std::endl
2737 << DestFile
<< " -> " << PatchedFile
<< std::endl
;
2739 // queue for copy by the transaction manager
2740 TransactionManager
->TransactionStageCopy(this, DestFile
, GetKeepCompressedFileName(GetFinalFilename(), Target
));
2742 // ensure the ed's are gone regardless of list-cleanup
2743 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2744 I
!= allPatches
->end(); ++I
)
2745 RemoveFile("pkgAcqIndexMergeDiffs::Done", GetMergeDiffsPatchFileName(UnpatchedFile
, (*I
)->patch
.file
));
2746 RemoveFile("pkgAcqIndexMergeDiffs::Done", UnpatchedFile
);
2751 std::clog
<< "allDone: " << DestFile
<< "\n" << std::endl
;
2753 case StateDoneDiff
: _error
->Fatal("Done called for %s which is in an invalid Done state", PatchFile
.c_str()); break;
2754 case StateErrorDiff
: _error
->Fatal("Done called for %s which is in an invalid Error state", PatchFile
.c_str()); break;
2758 std::string
pkgAcqIndexMergeDiffs::Custom600Headers() const /*{{{*/
2760 if(State
!= StateApplyDiff
)
2761 return pkgAcqBaseIndex::Custom600Headers();
2762 std::ostringstream patchhashes
;
2763 unsigned int seen_patches
= 0;
2764 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2765 I
!= allPatches
->end(); ++I
)
2767 HashStringList
const ExpectedHashes
= (*I
)->patch
.patch_hashes
;
2768 for (HashStringList::const_iterator hs
= ExpectedHashes
.begin(); hs
!= ExpectedHashes
.end(); ++hs
)
2769 patchhashes
<< "\nPatch-" << seen_patches
<< "-" << hs
->HashType() << "-Hash: " << hs
->HashValue();
2772 patchhashes
<< pkgAcqBaseIndex::Custom600Headers();
2773 return patchhashes
.str();
2776 pkgAcqIndexMergeDiffs::~pkgAcqIndexMergeDiffs() {}
2778 // AcqIndex::AcqIndex - Constructor /*{{{*/
2779 pkgAcqIndex::pkgAcqIndex(pkgAcquire
* const Owner
,
2780 pkgAcqMetaClearSig
* const TransactionManager
,
2781 IndexTarget
const &Target
)
2782 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
), Stage(STAGE_DOWNLOAD
),
2783 CompressionExtensions(Target
.Option(IndexTarget::COMPRESSIONTYPES
))
2785 Init(Target
.URI
, Target
.Description
, Target
.ShortDesc
);
2787 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
2788 std::clog
<< "New pkgIndex with TransactionManager "
2789 << TransactionManager
<< std::endl
;
2792 // AcqIndex::Init - defered Constructor /*{{{*/
2793 static void NextCompressionExtension(std::string
&CurrentCompressionExtension
, std::string
&CompressionExtensions
, bool const preview
)
2795 size_t const nextExt
= CompressionExtensions
.find(' ');
2796 if (nextExt
== std::string::npos
)
2798 CurrentCompressionExtension
= CompressionExtensions
;
2799 if (preview
== false)
2800 CompressionExtensions
.clear();
2804 CurrentCompressionExtension
= CompressionExtensions
.substr(0, nextExt
);
2805 if (preview
== false)
2806 CompressionExtensions
= CompressionExtensions
.substr(nextExt
+1);
2809 void pkgAcqIndex::Init(string
const &URI
, string
const &URIDesc
,
2810 string
const &ShortDesc
)
2812 Stage
= STAGE_DOWNLOAD
;
2814 DestFile
= GetPartialFileNameFromURI(URI
);
2815 NextCompressionExtension(CurrentCompressionExtension
, CompressionExtensions
, false);
2817 // store file size of the download to ensure the fetcher gives
2818 // accurate progress reporting
2819 FileSize
= GetExpectedHashes().FileSize();
2821 if (CurrentCompressionExtension
== "uncompressed")
2825 else if (CurrentCompressionExtension
== "by-hash")
2827 NextCompressionExtension(CurrentCompressionExtension
, CompressionExtensions
, true);
2828 if(unlikely(CurrentCompressionExtension
.empty()))
2830 if (CurrentCompressionExtension
!= "uncompressed")
2832 Desc
.URI
= URI
+ '.' + CurrentCompressionExtension
;
2833 DestFile
= DestFile
+ '.' + CurrentCompressionExtension
;
2836 HashStringList
const Hashes
= GetExpectedHashes();
2837 HashString
const * const TargetHash
= Hashes
.find(NULL
);
2838 if (unlikely(TargetHash
== nullptr))
2840 std::string
const ByHash
= "/by-hash/" + TargetHash
->HashType() + "/" + TargetHash
->HashValue();
2841 size_t const trailing_slash
= Desc
.URI
.find_last_of("/");
2842 if (unlikely(trailing_slash
== std::string::npos
))
2844 Desc
.URI
= Desc
.URI
.replace(
2846 Desc
.URI
.substr(trailing_slash
+1).size()+1,
2849 else if (unlikely(CurrentCompressionExtension
.empty()))
2853 Desc
.URI
= URI
+ '.' + CurrentCompressionExtension
;
2854 DestFile
= DestFile
+ '.' + CurrentCompressionExtension
;
2858 Desc
.Description
= URIDesc
;
2860 Desc
.ShortDesc
= ShortDesc
;
2865 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
2866 // ---------------------------------------------------------------------
2867 /* The only header we use is the last-modified header. */
2868 string
pkgAcqIndex::Custom600Headers() const
2871 string msg
= "\nIndex-File: true";
2873 if (TransactionManager
->LastMetaIndexParser
== NULL
)
2875 std::string
const Final
= GetFinalFilename();
2878 if (stat(Final
.c_str(),&Buf
) == 0)
2879 msg
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
2882 if(Target
.IsOptional
)
2883 msg
+= "\nFail-Ignore: true";
2888 // AcqIndex::Failed - getting the indexfile failed /*{{{*/
2889 void pkgAcqIndex::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)
2891 pkgAcqBaseIndex::Failed(Message
,Cnf
);
2893 // authorisation matches will not be fixed by other compression types
2894 if (Status
!= StatAuthError
)
2896 if (CompressionExtensions
.empty() == false)
2898 Init(Target
.URI
, Desc
.Description
, Desc
.ShortDesc
);
2904 if(Target
.IsOptional
&& GetExpectedHashes().empty() && Stage
== STAGE_DOWNLOAD
)
2907 TransactionManager
->AbortTransaction();
2910 // AcqIndex::Done - Finished a fetch /*{{{*/
2911 // ---------------------------------------------------------------------
2912 /* This goes through a number of states.. On the initial fetch the
2913 method could possibly return an alternate filename which points
2914 to the uncompressed version of the file. If this is so the file
2915 is copied into the partial directory. In all other cases the file
2916 is decompressed with a compressed uri. */
2917 void pkgAcqIndex::Done(string
const &Message
,
2918 HashStringList
const &Hashes
,
2919 pkgAcquire::MethodConfig
const * const Cfg
)
2921 Item::Done(Message
,Hashes
,Cfg
);
2925 case STAGE_DOWNLOAD
:
2926 StageDownloadDone(Message
);
2928 case STAGE_DECOMPRESS_AND_VERIFY
:
2929 StageDecompressDone();
2934 // AcqIndex::StageDownloadDone - Queue for decompress and verify /*{{{*/
2935 void pkgAcqIndex::StageDownloadDone(string
const &Message
)
2940 std::string
const AltFilename
= LookupTag(Message
,"Alt-Filename");
2941 std::string Filename
= LookupTag(Message
,"Filename");
2943 // we need to verify the file against the current Release file again
2944 // on if-modfied-since hit to avoid a stale attack against us
2945 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
2947 // copy FinalFile into partial/ so that we check the hash again
2948 string
const FinalFile
= GetExistingFilename(GetFinalFileNameFromURI(Target
.URI
));
2949 if (symlink(FinalFile
.c_str(), DestFile
.c_str()) != 0)
2950 _error
->WarningE("pkgAcqIndex::StageDownloadDone", "Symlinking final file %s back to %s failed", FinalFile
.c_str(), DestFile
.c_str());
2953 EraseFileName
= DestFile
;
2954 Filename
= DestFile
;
2956 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
2957 Desc
.URI
= "store:" + Filename
;
2959 SetActiveSubprocess(::URI(Desc
.URI
).Access
);
2962 // methods like file:// give us an alternative (uncompressed) file
2963 else if (Target
.KeepCompressed
== false && AltFilename
.empty() == false)
2965 Filename
= AltFilename
;
2966 EraseFileName
.clear();
2968 // Methods like e.g. "file:" will give us a (compressed) FileName that is
2969 // not the "DestFile" we set, in this case we uncompress from the local file
2970 else if (Filename
!= DestFile
&& RealFileExists(DestFile
) == false)
2972 // symlinking ensures that the filename can be used for compression detection
2973 // that is e.g. needed for by-hash which has no extension over file
2974 if (symlink(Filename
.c_str(),DestFile
.c_str()) != 0)
2975 _error
->WarningE("pkgAcqIndex::StageDownloadDone", "Symlinking file %s to %s failed", Filename
.c_str(), DestFile
.c_str());
2978 EraseFileName
= DestFile
;
2979 Filename
= DestFile
;
2983 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
2984 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
2985 if (Filename
!= DestFile
&& flExtension(Filename
) == flExtension(DestFile
))
2986 Desc
.URI
= "copy:" + Filename
;
2988 Desc
.URI
= "store:" + Filename
;
2989 if (DestFile
== Filename
)
2991 if (CurrentCompressionExtension
== "uncompressed")
2992 return StageDecompressDone();
2993 DestFile
= "/dev/null";
2996 if (EraseFileName
.empty() && Filename
!= AltFilename
)
2997 EraseFileName
= Filename
;
2999 // queue uri for the next stage
3001 SetActiveSubprocess(::URI(Desc
.URI
).Access
);
3004 // AcqIndex::StageDecompressDone - Final verification /*{{{*/
3005 void pkgAcqIndex::StageDecompressDone()
3007 if (DestFile
== "/dev/null")
3008 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
3010 // Done, queue for rename on transaction finished
3011 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
3014 pkgAcqIndex::~pkgAcqIndex() {}
3017 // AcqArchive::AcqArchive - Constructor /*{{{*/
3018 // ---------------------------------------------------------------------
3019 /* This just sets up the initial fetch environment and queues the first
3021 pkgAcqArchive::pkgAcqArchive(pkgAcquire
* const Owner
,pkgSourceList
* const Sources
,
3022 pkgRecords
* const Recs
,pkgCache::VerIterator
const &Version
,
3023 string
&StoreFilename
) :
3024 Item(Owner
), d(NULL
), LocalSource(false), Version(Version
), Sources(Sources
), Recs(Recs
),
3025 StoreFilename(StoreFilename
), Vf(Version
.FileList()),
3028 Retries
= _config
->FindI("Acquire::Retries",0);
3030 if (Version
.Arch() == 0)
3032 _error
->Error(_("I wasn't able to locate a file for the %s package. "
3033 "This might mean you need to manually fix this package. "
3034 "(due to missing arch)"),
3035 Version
.ParentPkg().FullName().c_str());
3039 /* We need to find a filename to determine the extension. We make the
3040 assumption here that all the available sources for this version share
3041 the same extension.. */
3042 // Skip not source sources, they do not have file fields.
3043 for (; Vf
.end() == false; ++Vf
)
3045 if (Vf
.File().Flagged(pkgCache::Flag::NotSource
))
3050 // Does not really matter here.. we are going to fail out below
3051 if (Vf
.end() != true)
3053 // If this fails to get a file name we will bomb out below.
3054 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
3055 if (_error
->PendingError() == true)
3058 // Generate the final file name as: package_version_arch.foo
3059 StoreFilename
= QuoteString(Version
.ParentPkg().Name(),"_:") + '_' +
3060 QuoteString(Version
.VerStr(),"_:") + '_' +
3061 QuoteString(Version
.Arch(),"_:.") +
3062 "." + flExtension(Parse
.FileName());
3065 // check if we have one trusted source for the package. if so, switch
3066 // to "TrustedOnly" mode - but only if not in AllowUnauthenticated mode
3067 bool const allowUnauth
= _config
->FindB("APT::Get::AllowUnauthenticated", false);
3068 bool const debugAuth
= _config
->FindB("Debug::pkgAcquire::Auth", false);
3069 bool seenUntrusted
= false;
3070 for (pkgCache::VerFileIterator i
= Version
.FileList(); i
.end() == false; ++i
)
3072 pkgIndexFile
*Index
;
3073 if (Sources
->FindIndex(i
.File(),Index
) == false)
3076 if (debugAuth
== true)
3077 std::cerr
<< "Checking index: " << Index
->Describe()
3078 << "(Trusted=" << Index
->IsTrusted() << ")" << std::endl
;
3080 if (Index
->IsTrusted() == true)
3083 if (allowUnauth
== false)
3087 seenUntrusted
= true;
3090 // "allow-unauthenticated" restores apts old fetching behaviour
3091 // that means that e.g. unauthenticated file:// uris are higher
3092 // priority than authenticated http:// uris
3093 if (allowUnauth
== true && seenUntrusted
== true)
3097 if (QueueNext() == false && _error
->PendingError() == false)
3098 _error
->Error(_("Can't find a source to download version '%s' of '%s'"),
3099 Version
.VerStr(), Version
.ParentPkg().FullName(false).c_str());
3102 // AcqArchive::QueueNext - Queue the next file source /*{{{*/
3103 // ---------------------------------------------------------------------
3104 /* This queues the next available file version for download. It checks if
3105 the archive is already available in the cache and stashs the MD5 for
3107 bool pkgAcqArchive::QueueNext()
3109 for (; Vf
.end() == false; ++Vf
)
3111 pkgCache::PkgFileIterator
const PkgF
= Vf
.File();
3112 // Ignore not source sources
3113 if (PkgF
.Flagged(pkgCache::Flag::NotSource
))
3116 // Try to cross match against the source list
3117 pkgIndexFile
*Index
;
3118 if (Sources
->FindIndex(PkgF
, Index
) == false)
3120 LocalSource
= PkgF
.Flagged(pkgCache::Flag::LocalSource
);
3122 // only try to get a trusted package from another source if that source
3124 if(Trusted
&& !Index
->IsTrusted())
3127 // Grab the text package record
3128 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
3129 if (_error
->PendingError() == true)
3132 string PkgFile
= Parse
.FileName();
3133 ExpectedHashes
= Parse
.Hashes();
3135 if (PkgFile
.empty() == true)
3136 return _error
->Error(_("The package index files are corrupted. No Filename: "
3137 "field for package %s."),
3138 Version
.ParentPkg().Name());
3140 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
3141 Desc
.Description
= Index
->ArchiveInfo(Version
);
3143 Desc
.ShortDesc
= Version
.ParentPkg().FullName(true);
3145 // See if we already have the file. (Legacy filenames)
3146 FileSize
= Version
->Size
;
3147 string FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile
);
3149 if (stat(FinalFile
.c_str(),&Buf
) == 0)
3151 // Make sure the size matches
3152 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
3157 StoreFilename
= DestFile
= FinalFile
;
3161 /* Hmm, we have a file and its size does not match, this means it is
3162 an old style mismatched arch */
3163 RemoveFile("pkgAcqArchive::QueueNext", FinalFile
);
3166 // Check it again using the new style output filenames
3167 FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
3168 if (stat(FinalFile
.c_str(),&Buf
) == 0)
3170 // Make sure the size matches
3171 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
3176 StoreFilename
= DestFile
= FinalFile
;
3180 /* Hmm, we have a file and its size does not match, this shouldn't
3182 RemoveFile("pkgAcqArchive::QueueNext", FinalFile
);
3185 DestFile
= _config
->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename
);
3187 // Check the destination file
3188 if (stat(DestFile
.c_str(),&Buf
) == 0)
3190 // Hmm, the partial file is too big, erase it
3191 if ((unsigned long long)Buf
.st_size
> Version
->Size
)
3192 RemoveFile("pkgAcqArchive::QueueNext", DestFile
);
3194 PartialSize
= Buf
.st_size
;
3197 // Disables download of archives - useful if no real installation follows,
3198 // e.g. if we are just interested in proposed installation order
3199 if (_config
->FindB("Debug::pkgAcqArchive::NoQueue", false) == true)
3204 StoreFilename
= DestFile
= FinalFile
;
3218 // AcqArchive::Done - Finished fetching /*{{{*/
3219 // ---------------------------------------------------------------------
3221 void pkgAcqArchive::Done(string
const &Message
, HashStringList
const &Hashes
,
3222 pkgAcquire::MethodConfig
const * const Cfg
)
3224 Item::Done(Message
, Hashes
, Cfg
);
3226 // Grab the output filename
3227 std::string
const FileName
= LookupTag(Message
,"Filename");
3228 if (DestFile
!= FileName
&& RealFileExists(DestFile
) == false)
3230 StoreFilename
= DestFile
= FileName
;
3236 // Done, move it into position
3237 string
const FinalFile
= GetFinalFilename();
3238 Rename(DestFile
,FinalFile
);
3239 StoreFilename
= DestFile
= FinalFile
;
3243 // AcqArchive::Failed - Failure handler /*{{{*/
3244 // ---------------------------------------------------------------------
3245 /* Here we try other sources */
3246 void pkgAcqArchive::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)
3248 Item::Failed(Message
,Cnf
);
3250 /* We don't really want to retry on failed media swaps, this prevents
3251 that. An interesting observation is that permanent failures are not
3253 if (Cnf
->Removable
== true &&
3254 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
3256 // Vf = Version.FileList();
3257 while (Vf
.end() == false) ++Vf
;
3258 StoreFilename
= string();
3263 if (QueueNext() == false)
3265 // This is the retry counter
3267 Cnf
->LocalOnly
== false &&
3268 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
3271 Vf
= Version
.FileList();
3272 if (QueueNext() == true)
3276 StoreFilename
= string();
3281 APT_PURE
bool pkgAcqArchive::IsTrusted() const /*{{{*/
3286 void pkgAcqArchive::Finished() /*{{{*/
3288 if (Status
== pkgAcquire::Item::StatDone
&&
3291 StoreFilename
= string();
3294 std::string
pkgAcqArchive::DescURI() const /*{{{*/
3299 std::string
pkgAcqArchive::ShortDesc() const /*{{{*/
3301 return Desc
.ShortDesc
;
3304 pkgAcqArchive::~pkgAcqArchive() {}
3306 // AcqChangelog::pkgAcqChangelog - Constructors /*{{{*/
3307 class pkgAcqChangelog::Private
3310 std::string FinalFile
;
3312 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire
* const Owner
, pkgCache::VerIterator
const &Ver
,
3313 std::string
const &DestDir
, std::string
const &DestFilename
) :
3314 pkgAcquire::Item(Owner
), d(new pkgAcqChangelog::Private()), SrcName(Ver
.SourcePkgName()), SrcVersion(Ver
.SourceVerStr())
3316 Desc
.URI
= URI(Ver
);
3317 Init(DestDir
, DestFilename
);
3319 // some parameters are char* here as they come likely from char* interfaces – which can also return NULL
3320 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire
* const Owner
, pkgCache::RlsFileIterator
const &RlsFile
,
3321 char const * const Component
, char const * const SrcName
, char const * const SrcVersion
,
3322 const string
&DestDir
, const string
&DestFilename
) :
3323 pkgAcquire::Item(Owner
), d(new pkgAcqChangelog::Private()), SrcName(SrcName
), SrcVersion(SrcVersion
)
3325 Desc
.URI
= URI(RlsFile
, Component
, SrcName
, SrcVersion
);
3326 Init(DestDir
, DestFilename
);
3328 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire
* const Owner
,
3329 std::string
const &URI
, char const * const SrcName
, char const * const SrcVersion
,
3330 const string
&DestDir
, const string
&DestFilename
) :
3331 pkgAcquire::Item(Owner
), d(new pkgAcqChangelog::Private()), SrcName(SrcName
), SrcVersion(SrcVersion
)
3334 Init(DestDir
, DestFilename
);
3336 void pkgAcqChangelog::Init(std::string
const &DestDir
, std::string
const &DestFilename
)
3338 if (Desc
.URI
.empty())
3341 // TRANSLATOR: %s=%s is sourcename=sourceversion, e.g. apt=1.1
3342 strprintf(ErrorText
, _("Changelog unavailable for %s=%s"), SrcName
.c_str(), SrcVersion
.c_str());
3343 // Let the error message print something sensible rather than "Failed to fetch /"
3344 if (DestFilename
.empty())
3345 DestFile
= SrcName
+ ".changelog";
3347 DestFile
= DestFilename
;
3348 Desc
.URI
= "changelog:/" + DestFile
;
3352 std::string DestFileName
;
3353 if (DestFilename
.empty())
3354 DestFileName
= flCombine(DestFile
, SrcName
+ ".changelog");
3356 DestFileName
= flCombine(DestFile
, DestFilename
);
3358 std::string
const SandboxUser
= _config
->Find("APT::Sandbox::User");
3359 std::string
const systemTemp
= GetTempDir(SandboxUser
);
3361 snprintf(tmpname
, sizeof(tmpname
), "%s/apt-changelog-XXXXXX", systemTemp
.c_str());
3362 if (NULL
== mkdtemp(tmpname
))
3364 _error
->Errno("mkdtemp", "mkdtemp failed in changelog acquire of %s %s", SrcName
.c_str(), SrcVersion
.c_str());
3368 TemporaryDirectory
= tmpname
;
3370 ChangeOwnerAndPermissionOfFile("Item::QueueURI", TemporaryDirectory
.c_str(),
3371 SandboxUser
.c_str(), "root", 0700);
3373 DestFile
= flCombine(TemporaryDirectory
, DestFileName
);
3374 if (DestDir
.empty() == false)
3376 d
->FinalFile
= flCombine(DestDir
, DestFileName
);
3377 if (RealFileExists(d
->FinalFile
))
3379 FileFd file1
, file2
;
3380 if (file1
.Open(DestFile
, FileFd::WriteOnly
| FileFd::Create
| FileFd::Exclusive
) &&
3381 file2
.Open(d
->FinalFile
, FileFd::ReadOnly
) && CopyFile(file2
, file1
))
3383 struct timeval times
[2];
3384 times
[0].tv_sec
= times
[1].tv_sec
= file2
.ModificationTime();
3385 times
[0].tv_usec
= times
[1].tv_usec
= 0;
3386 utimes(DestFile
.c_str(), times
);
3391 Desc
.ShortDesc
= "Changelog";
3392 strprintf(Desc
.Description
, "%s %s %s Changelog", URI::SiteOnly(Desc
.URI
).c_str(), SrcName
.c_str(), SrcVersion
.c_str());
3397 std::string
pkgAcqChangelog::URI(pkgCache::VerIterator
const &Ver
) /*{{{*/
3399 std::string
const confOnline
= "Acquire::Changelogs::AlwaysOnline";
3400 bool AlwaysOnline
= _config
->FindB(confOnline
, false);
3401 if (AlwaysOnline
== false)
3402 for (pkgCache::VerFileIterator VF
= Ver
.FileList(); VF
.end() == false; ++VF
)
3404 pkgCache::PkgFileIterator
const PF
= VF
.File();
3405 if (PF
.Flagged(pkgCache::Flag::NotSource
) || PF
->Release
== 0)
3407 pkgCache::RlsFileIterator
const RF
= PF
.ReleaseFile();
3408 if (RF
->Origin
!= 0 && _config
->FindB(confOnline
+ "::Origin::" + RF
.Origin(), false))
3410 AlwaysOnline
= true;
3414 if (AlwaysOnline
== false)
3416 pkgCache::PkgIterator
const Pkg
= Ver
.ParentPkg();
3417 if (Pkg
->CurrentVer
!= 0 && Pkg
.CurrentVer() == Ver
)
3419 std::string
const basename
= std::string("/usr/share/doc/") + Pkg
.Name() + "/changelog";
3420 std::string
const debianname
= basename
+ ".Debian";
3421 if (FileExists(debianname
))
3422 return "copy://" + debianname
;
3423 else if (FileExists(debianname
+ ".gz"))
3424 return "gzip://" + debianname
+ ".gz";
3425 else if (FileExists(basename
))
3426 return "copy://" + basename
;
3427 else if (FileExists(basename
+ ".gz"))
3428 return "gzip://" + basename
+ ".gz";
3432 char const * const SrcName
= Ver
.SourcePkgName();
3433 char const * const SrcVersion
= Ver
.SourceVerStr();
3434 // find the first source for this version which promises a changelog
3435 for (pkgCache::VerFileIterator VF
= Ver
.FileList(); VF
.end() == false; ++VF
)
3437 pkgCache::PkgFileIterator
const PF
= VF
.File();
3438 if (PF
.Flagged(pkgCache::Flag::NotSource
) || PF
->Release
== 0)
3440 pkgCache::RlsFileIterator
const RF
= PF
.ReleaseFile();
3441 std::string
const uri
= URI(RF
, PF
.Component(), SrcName
, SrcVersion
);
3448 std::string
pkgAcqChangelog::URITemplate(pkgCache::RlsFileIterator
const &Rls
)
3450 if (Rls
.end() == true || (Rls
->Label
== 0 && Rls
->Origin
== 0))
3452 std::string
const serverConfig
= "Acquire::Changelogs::URI";
3454 #define APT_EMPTY_SERVER \
3455 if (server.empty() == false) \
3457 if (server != "no") \
3461 #define APT_CHECK_SERVER(X, Y) \
3464 std::string const specialServerConfig = serverConfig + "::" + Y + #X + "::" + Rls.X(); \
3465 server = _config->Find(specialServerConfig); \
3468 // this way e.g. Debian-Security can fallback to Debian
3469 APT_CHECK_SERVER(Label
, "Override::")
3470 APT_CHECK_SERVER(Origin
, "Override::")
3472 if (RealFileExists(Rls
.FileName()))
3474 _error
->PushToStack();
3476 /* This can be costly. A caller wanting to get millions of URIs might
3477 want to do this on its own once and use Override settings.
3478 We don't do this here as Origin/Label are not as unique as they
3479 should be so this could produce request order-dependent anomalies */
3480 if (OpenMaybeClearSignedFile(Rls
.FileName(), rf
) == true)
3482 pkgTagFile
TagFile(&rf
, rf
.Size());
3483 pkgTagSection Section
;
3484 if (TagFile
.Step(Section
) == true)
3485 server
= Section
.FindS("Changelogs");
3487 _error
->RevertToStack();
3491 APT_CHECK_SERVER(Label
, "")
3492 APT_CHECK_SERVER(Origin
, "")
3493 #undef APT_CHECK_SERVER
3494 #undef APT_EMPTY_SERVER
3497 std::string
pkgAcqChangelog::URI(pkgCache::RlsFileIterator
const &Rls
,
3498 char const * const Component
, char const * const SrcName
,
3499 char const * const SrcVersion
)
3501 return URI(URITemplate(Rls
), Component
, SrcName
, SrcVersion
);
3503 std::string
pkgAcqChangelog::URI(std::string
const &Template
,
3504 char const * const Component
, char const * const SrcName
,
3505 char const * const SrcVersion
)
3507 if (Template
.find("@CHANGEPATH@") == std::string::npos
)
3510 // the path is: COMPONENT/SRC/SRCNAME/SRCNAME_SRCVER, e.g. main/a/apt/1.1 or contrib/liba/libapt/2.0
3511 std::string Src
= SrcName
;
3512 std::string path
= APT::String::Startswith(SrcName
, "lib") ? Src
.substr(0, 4) : Src
.substr(0,1);
3513 path
.append("/").append(Src
).append("/");
3514 path
.append(Src
).append("_").append(StripEpoch(SrcVersion
));
3515 // we omit component for releases without one (= flat-style repositories)
3516 if (Component
!= NULL
&& strlen(Component
) != 0)
3517 path
= std::string(Component
) + "/" + path
;
3519 return SubstVar(Template
, "@CHANGEPATH@", path
);
3522 // AcqChangelog::Failed - Failure handler /*{{{*/
3523 void pkgAcqChangelog::Failed(string
const &Message
, pkgAcquire::MethodConfig
const * const Cnf
)
3525 Item::Failed(Message
,Cnf
);
3527 std::string errText
;
3528 // TRANSLATOR: %s=%s is sourcename=sourceversion, e.g. apt=1.1
3529 strprintf(errText
, _("Changelog unavailable for %s=%s"), SrcName
.c_str(), SrcVersion
.c_str());
3531 // Error is probably something techy like 404 Not Found
3532 if (ErrorText
.empty())
3533 ErrorText
= errText
;
3535 ErrorText
= errText
+ " (" + ErrorText
+ ")";
3538 // AcqChangelog::Done - Item downloaded OK /*{{{*/
3539 void pkgAcqChangelog::Done(string
const &Message
,HashStringList
const &CalcHashes
,
3540 pkgAcquire::MethodConfig
const * const Cnf
)
3542 Item::Done(Message
,CalcHashes
,Cnf
);
3543 if (d
->FinalFile
.empty() == false)
3545 if (RemoveFile("pkgAcqChangelog::Done", d
->FinalFile
) == false ||
3546 Rename(DestFile
, d
->FinalFile
) == false)
3553 pkgAcqChangelog::~pkgAcqChangelog() /*{{{*/
3555 if (TemporaryDirectory
.empty() == false)
3557 RemoveFile("~pkgAcqChangelog", DestFile
);
3558 rmdir(TemporaryDirectory
.c_str());
3564 // AcqFile::pkgAcqFile - Constructor /*{{{*/
3565 pkgAcqFile::pkgAcqFile(pkgAcquire
* const Owner
,string
const &URI
, HashStringList
const &Hashes
,
3566 unsigned long long const Size
,string
const &Dsc
,string
const &ShortDesc
,
3567 const string
&DestDir
, const string
&DestFilename
,
3568 bool const IsIndexFile
) :
3569 Item(Owner
), d(NULL
), IsIndexFile(IsIndexFile
), ExpectedHashes(Hashes
)
3571 Retries
= _config
->FindI("Acquire::Retries",0);
3573 if(!DestFilename
.empty())
3574 DestFile
= DestFilename
;
3575 else if(!DestDir
.empty())
3576 DestFile
= DestDir
+ "/" + flNotDir(URI
);
3578 DestFile
= flNotDir(URI
);
3582 Desc
.Description
= Dsc
;
3585 // Set the short description to the archive component
3586 Desc
.ShortDesc
= ShortDesc
;
3588 // Get the transfer sizes
3591 if (stat(DestFile
.c_str(),&Buf
) == 0)
3593 // Hmm, the partial file is too big, erase it
3594 if ((Size
> 0) && (unsigned long long)Buf
.st_size
> Size
)
3595 RemoveFile("pkgAcqFile", DestFile
);
3597 PartialSize
= Buf
.st_size
;
3603 // AcqFile::Done - Item downloaded OK /*{{{*/
3604 void pkgAcqFile::Done(string
const &Message
,HashStringList
const &CalcHashes
,
3605 pkgAcquire::MethodConfig
const * const Cnf
)
3607 Item::Done(Message
,CalcHashes
,Cnf
);
3609 std::string
const FileName
= LookupTag(Message
,"Filename");
3612 // The files timestamp matches
3613 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
3616 // We have to copy it into place
3617 if (RealFileExists(DestFile
.c_str()) == false)
3620 if (_config
->FindB("Acquire::Source-Symlinks",true) == false ||
3621 Cnf
->Removable
== true)
3623 Desc
.URI
= "copy:" + FileName
;
3628 // Erase the file if it is a symlink so we can overwrite it
3630 if (lstat(DestFile
.c_str(),&St
) == 0)
3632 if (S_ISLNK(St
.st_mode
) != 0)
3633 RemoveFile("pkgAcqFile::Done", DestFile
);
3637 if (symlink(FileName
.c_str(),DestFile
.c_str()) != 0)
3639 _error
->PushToStack();
3640 _error
->Errno("pkgAcqFile::Done", "Symlinking file %s failed", DestFile
.c_str());
3641 std::stringstream msg
;
3642 _error
->DumpErrors(msg
, GlobalError::DEBUG
, false);
3643 _error
->RevertToStack();
3644 ErrorText
= msg
.str();
3651 // AcqFile::Failed - Failure handler /*{{{*/
3652 // ---------------------------------------------------------------------
3653 /* Here we try other sources */
3654 void pkgAcqFile::Failed(string
const &Message
, pkgAcquire::MethodConfig
const * const Cnf
)
3656 Item::Failed(Message
,Cnf
);
3658 // This is the retry counter
3660 Cnf
->LocalOnly
== false &&
3661 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
3671 string
pkgAcqFile::Custom600Headers() const /*{{{*/
3674 return "\nIndex-File: true";
3678 pkgAcqFile::~pkgAcqFile() {}