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 auto const &posix
= std::locale("C.UTF-8");
2004 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
2006 std::string tagname
= *type
;
2007 tagname
.append("-Current");
2008 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
2009 if (tmp
.empty() == true)
2013 unsigned long long size
;
2014 std::stringstream
ss(tmp
);
2017 if (unlikely(hash
.empty() == true))
2019 if (unlikely(ServerSize
!= 0 && ServerSize
!= size
))
2021 ServerHashes
.push_back(HashString(*type
, hash
));
2025 if (ServerHashes
.usable() == false)
2028 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": Did not find a good hashsum in the index" << std::endl
;
2032 std::string
const CurrentPackagesFile
= GetFinalFileNameFromURI(Target
.URI
);
2033 HashStringList
const TargetFileHashes
= GetExpectedHashesFor(Target
.MetaKey
);
2034 if (TargetFileHashes
.usable() == false || ServerHashes
!= TargetFileHashes
)
2038 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": Index has different hashes than parser, probably older, so fail pdiffing" << std::endl
;
2039 printHashSumComparison(CurrentPackagesFile
, ServerHashes
, TargetFileHashes
);
2044 HashStringList LocalHashes
;
2045 // try avoiding calculating the hash here as this is costly
2046 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
2047 LocalHashes
= GetExpectedHashesFromFor(TransactionManager
->LastMetaIndexParser
, Target
.MetaKey
);
2048 if (LocalHashes
.usable() == false)
2050 FileFd
fd(CurrentPackagesFile
, FileFd::ReadOnly
, FileFd::Auto
);
2051 Hashes
LocalHashesCalc(ServerHashes
);
2052 LocalHashesCalc
.AddFD(fd
);
2053 LocalHashes
= LocalHashesCalc
.GetHashStringList();
2056 if (ServerHashes
== LocalHashes
)
2058 // we have the same sha1 as the server so we are done here
2060 std::clog
<< "pkgAcqDiffIndex: Package file " << CurrentPackagesFile
<< " is up-to-date" << std::endl
;
2066 std::clog
<< "Server-Current: " << ServerHashes
.find(NULL
)->toStr() << " and we start at "
2067 << CurrentPackagesFile
<< " " << LocalHashes
.FileSize() << " " << LocalHashes
.find(NULL
)->toStr() << std::endl
;
2069 // historically, older hashes have more info than newer ones, so start
2070 // collecting with older ones first to avoid implementing complicated
2071 // information merging techniques… a failure is after all always
2072 // recoverable with a complete file and hashes aren't changed that often.
2073 std::vector
<char const *> types
;
2074 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
2075 types
.push_back(*type
);
2077 // parse all of (provided) history
2078 vector
<DiffInfo
> available_patches
;
2079 bool firstAcceptedHashes
= true;
2080 for (auto type
= types
.crbegin(); type
!= types
.crend(); ++type
)
2082 if (LocalHashes
.find(*type
) == NULL
)
2085 std::string tagname
= *type
;
2086 tagname
.append("-History");
2087 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
2088 if (tmp
.empty() == true)
2091 string hash
, filename
;
2092 unsigned long long size
;
2093 std::stringstream
ss(tmp
);
2096 while (ss
>> hash
>> size
>> filename
)
2098 if (unlikely(hash
.empty() == true || filename
.empty() == true))
2101 // see if we have a record for this file already
2102 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
2103 for (; cur
!= available_patches
.end(); ++cur
)
2105 if (cur
->file
!= filename
)
2107 cur
->result_hashes
.push_back(HashString(*type
, hash
));
2110 if (cur
!= available_patches
.end())
2112 if (firstAcceptedHashes
== true)
2115 next
.file
= filename
;
2116 next
.result_hashes
.push_back(HashString(*type
, hash
));
2117 next
.result_hashes
.FileSize(size
);
2118 available_patches
.push_back(next
);
2123 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
2124 << " wasn't in the list for the first parsed hash! (history)" << std::endl
;
2128 firstAcceptedHashes
= false;
2131 if (unlikely(available_patches
.empty() == true))
2134 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": "
2135 << "Couldn't find any patches for the patch series." << std::endl
;
2139 for (auto type
= types
.crbegin(); type
!= types
.crend(); ++type
)
2141 if (LocalHashes
.find(*type
) == NULL
)
2144 std::string tagname
= *type
;
2145 tagname
.append("-Patches");
2146 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
2147 if (tmp
.empty() == true)
2150 string hash
, filename
;
2151 unsigned long long size
;
2152 std::stringstream
ss(tmp
);
2155 while (ss
>> hash
>> size
>> filename
)
2157 if (unlikely(hash
.empty() == true || filename
.empty() == true))
2160 // see if we have a record for this file already
2161 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
2162 for (; cur
!= available_patches
.end(); ++cur
)
2164 if (cur
->file
!= filename
)
2166 if (cur
->patch_hashes
.empty())
2167 cur
->patch_hashes
.FileSize(size
);
2168 cur
->patch_hashes
.push_back(HashString(*type
, hash
));
2171 if (cur
!= available_patches
.end())
2174 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
2175 << " wasn't in the list for the first parsed hash! (patches)" << std::endl
;
2180 for (auto type
= types
.crbegin(); type
!= types
.crend(); ++type
)
2182 std::string tagname
= *type
;
2183 tagname
.append("-Download");
2184 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
2185 if (tmp
.empty() == true)
2188 string hash
, filename
;
2189 unsigned long long size
;
2190 std::stringstream
ss(tmp
);
2193 // FIXME: all of pdiff supports only .gz compressed patches
2194 while (ss
>> hash
>> size
>> filename
)
2196 if (unlikely(hash
.empty() == true || filename
.empty() == true))
2198 if (unlikely(APT::String::Endswith(filename
, ".gz") == false))
2200 filename
.erase(filename
.length() - 3);
2202 // see if we have a record for this file already
2203 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
2204 for (; cur
!= available_patches
.end(); ++cur
)
2206 if (cur
->file
!= filename
)
2208 if (cur
->download_hashes
.empty())
2209 cur
->download_hashes
.FileSize(size
);
2210 cur
->download_hashes
.push_back(HashString(*type
, hash
));
2213 if (cur
!= available_patches
.end())
2216 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
2217 << " wasn't in the list for the first parsed hash! (download)" << std::endl
;
2223 bool foundStart
= false;
2224 for (std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
2225 cur
!= available_patches
.end(); ++cur
)
2227 if (LocalHashes
!= cur
->result_hashes
)
2230 available_patches
.erase(available_patches
.begin(), cur
);
2235 if (foundStart
== false || unlikely(available_patches
.empty() == true))
2238 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": "
2239 << "Couldn't find the start of the patch series." << std::endl
;
2243 for (auto const &patch
: available_patches
)
2244 if (patch
.result_hashes
.usable() == false ||
2245 patch
.patch_hashes
.usable() == false ||
2246 patch
.download_hashes
.usable() == false)
2249 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": provides no usable hashes for " << patch
.file
2250 << " so fallback to complete download" << std::endl
;
2254 // patching with too many files is rather slow compared to a fast download
2255 unsigned long const fileLimit
= _config
->FindI("Acquire::PDiffs::FileLimit", 0);
2256 if (fileLimit
!= 0 && fileLimit
< available_patches
.size())
2259 std::clog
<< "Need " << available_patches
.size() << " diffs (Limit is " << fileLimit
2260 << ") so fallback to complete download" << std::endl
;
2264 // calculate the size of all patches we have to get
2265 unsigned short const sizeLimitPercent
= _config
->FindI("Acquire::PDiffs::SizeLimit", 100);
2266 if (sizeLimitPercent
> 0)
2268 unsigned long long downloadSize
= std::accumulate(available_patches
.begin(),
2269 available_patches
.end(), 0llu, [](unsigned long long const T
, DiffInfo
const &I
) {
2270 return T
+ I
.download_hashes
.FileSize();
2272 if (downloadSize
!= 0)
2274 unsigned long long downloadSizeIdx
= 0;
2275 auto const types
= VectorizeString(Target
.Option(IndexTarget::COMPRESSIONTYPES
), ' ');
2276 for (auto const &t
: types
)
2278 std::string MetaKey
= Target
.MetaKey
;
2279 if (t
!= "uncompressed")
2281 HashStringList
const hsl
= GetExpectedHashesFor(MetaKey
);
2282 if (unlikely(hsl
.usable() == false))
2284 downloadSizeIdx
= hsl
.FileSize();
2287 unsigned long long const sizeLimit
= downloadSizeIdx
* sizeLimitPercent
;
2288 if ((sizeLimit
/100) < downloadSize
)
2291 std::clog
<< "Need " << downloadSize
<< " compressed bytes (Limit is " << (sizeLimit
/100) << ", "
2292 << "original is " << downloadSizeIdx
<< ") so fallback to complete download" << std::endl
;
2298 // we have something, queue the diffs
2299 string::size_type
const last_space
= Description
.rfind(" ");
2300 if(last_space
!= string::npos
)
2301 Description
.erase(last_space
, Description
.size()-last_space
);
2303 /* decide if we should download patches one by one or in one go:
2304 The first is good if the server merges patches, but many don't so client
2305 based merging can be attempt in which case the second is better.
2306 "bad things" will happen if patches are merged on the server,
2307 but client side merging is attempt as well */
2308 bool pdiff_merge
= _config
->FindB("Acquire::PDiffs::Merge", true);
2309 if (pdiff_merge
== true)
2311 // reprepro adds this flag if it has merged patches on the server
2312 std::string
const precedence
= Tags
.FindS("X-Patch-Precedence");
2313 pdiff_merge
= (precedence
!= "merged");
2318 std::string
const Final
= GetExistingFilename(CurrentPackagesFile
);
2319 if (unlikely(Final
.empty())) // because we wouldn't be called in such a case
2321 std::string
const PartialFile
= GetPartialFileNameFromURI(Target
.URI
);
2322 if (FileExists(PartialFile
) && RemoveFile("Bootstrap-linking", PartialFile
) == false)
2325 std::clog
<< "Bootstrap-linking for patching " << CurrentPackagesFile
2326 << " by removing stale " << PartialFile
<< " failed!" << std::endl
;
2329 for (auto const &ext
: APT::Configuration::getCompressorExtensions())
2331 std::string
const Partial
= PartialFile
+ ext
;
2332 if (FileExists(Partial
) && RemoveFile("Bootstrap-linking", Partial
) == false)
2335 std::clog
<< "Bootstrap-linking for patching " << CurrentPackagesFile
2336 << " by removing stale " << Partial
<< " failed!" << std::endl
;
2340 std::string
const Ext
= Final
.substr(CurrentPackagesFile
.length());
2341 std::string
const Partial
= PartialFile
+ Ext
;
2342 if (symlink(Final
.c_str(), Partial
.c_str()) != 0)
2345 std::clog
<< "Bootstrap-linking for patching " << CurrentPackagesFile
2346 << " by linking " << Final
<< " to " << Partial
<< " failed!" << std::endl
;
2351 if (pdiff_merge
== false)
2352 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
, available_patches
);
2355 diffs
= new std::vector
<pkgAcqIndexMergeDiffs
*>(available_patches
.size());
2356 for(size_t i
= 0; i
< available_patches
.size(); ++i
)
2357 (*diffs
)[i
] = new pkgAcqIndexMergeDiffs(Owner
, TransactionManager
,
2359 available_patches
[i
],
2369 void pkgAcqDiffIndex::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
2371 pkgAcqBaseIndex::Failed(Message
,Cnf
);
2373 ExpectedAdditionalItems
= 0;
2376 std::clog
<< "pkgAcqDiffIndex failed: " << Desc
.URI
<< " with " << Message
<< std::endl
2377 << "Falling back to normal index file acquire" << std::endl
;
2379 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
2382 void pkgAcqDiffIndex::Done(string
const &Message
,HashStringList
const &Hashes
, /*{{{*/
2383 pkgAcquire::MethodConfig
const * const Cnf
)
2386 std::clog
<< "pkgAcqDiffIndex::Done(): " << Desc
.URI
<< std::endl
;
2388 Item::Done(Message
, Hashes
, Cnf
);
2390 string
const FinalFile
= GetFinalFilename();
2391 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false))
2392 DestFile
= FinalFile
;
2394 if(ParseDiffIndex(DestFile
) == false)
2396 Failed("Message: Couldn't parse pdiff index", Cnf
);
2397 // queue for final move - this should happen even if we fail
2398 // while parsing (e.g. on sizelimit) and download the complete file.
2399 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
2403 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
2412 pkgAcqDiffIndex::~pkgAcqDiffIndex()
2418 // AcqIndexDiffs::AcqIndexDiffs - Constructor /*{{{*/
2419 // ---------------------------------------------------------------------
2420 /* The package diff is added to the queue. one object is constructed
2421 * for each diff and the index
2423 pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire
* const Owner
,
2424 pkgAcqMetaClearSig
* const TransactionManager
,
2425 IndexTarget
const &Target
,
2426 vector
<DiffInfo
> const &diffs
)
2427 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
),
2428 available_patches(diffs
)
2430 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
2432 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
2435 Description
= Target
.Description
;
2436 Desc
.ShortDesc
= Target
.ShortDesc
;
2438 if(available_patches
.empty() == true)
2440 // we are done (yeah!), check hashes against the final file
2441 DestFile
= GetKeepCompressedFileName(GetFinalFileNameFromURI(Target
.URI
), Target
);
2446 State
= StateFetchDiff
;
2451 void pkgAcqIndexDiffs::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
2453 pkgAcqBaseIndex::Failed(Message
,Cnf
);
2456 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
2458 std::clog
<< "pkgAcqIndexDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
2459 << "Falling back to normal index file acquire " << std::endl
;
2460 RenameOnError(PDiffError
);
2461 std::string
const patchname
= GetDiffsPatchFileName(DestFile
);
2462 if (RealFileExists(patchname
))
2463 Rename(patchname
, patchname
+ ".FAILED");
2464 std::string
const UnpatchedFile
= GetExistingFilename(GetPartialFileNameFromURI(Target
.URI
));
2465 if (UnpatchedFile
.empty() == false && FileExists(UnpatchedFile
))
2466 Rename(UnpatchedFile
, UnpatchedFile
+ ".FAILED");
2467 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
2471 // Finish - helper that cleans the item out of the fetcher queue /*{{{*/
2472 void pkgAcqIndexDiffs::Finish(bool allDone
)
2475 std::clog
<< "pkgAcqIndexDiffs::Finish(): "
2477 << Desc
.URI
<< std::endl
;
2479 // we restore the original name, this is required, otherwise
2480 // the file will be cleaned
2483 std::string
const Final
= GetKeepCompressedFileName(GetFinalFilename(), Target
);
2484 TransactionManager
->TransactionStageCopy(this, DestFile
, Final
);
2486 // this is for the "real" finish
2491 std::clog
<< "\n\nallDone: " << DestFile
<< "\n" << std::endl
;
2498 std::clog
<< "Finishing: " << Desc
.URI
<< std::endl
;
2505 bool pkgAcqIndexDiffs::QueueNextDiff() /*{{{*/
2507 // calc sha1 of the just patched file
2508 std::string
const PartialFile
= GetExistingFilename(GetPartialFileNameFromURI(Target
.URI
));
2509 if(unlikely(PartialFile
.empty()))
2511 Failed("Message: The file " + GetPartialFileNameFromURI(Target
.URI
) + " isn't available", NULL
);
2515 FileFd
fd(PartialFile
, FileFd::ReadOnly
, FileFd::Extension
);
2516 Hashes LocalHashesCalc
;
2517 LocalHashesCalc
.AddFD(fd
);
2518 HashStringList
const LocalHashes
= LocalHashesCalc
.GetHashStringList();
2521 std::clog
<< "QueueNextDiff: " << PartialFile
<< " (" << LocalHashes
.find(NULL
)->toStr() << ")" << std::endl
;
2523 HashStringList
const TargetFileHashes
= GetExpectedHashesFor(Target
.MetaKey
);
2524 if (unlikely(LocalHashes
.usable() == false || TargetFileHashes
.usable() == false))
2526 Failed("Local/Expected hashes are not usable for " + PartialFile
, NULL
);
2530 // final file reached before all patches are applied
2531 if(LocalHashes
== TargetFileHashes
)
2537 // remove all patches until the next matching patch is found
2538 // this requires the Index file to be ordered
2539 available_patches
.erase(available_patches
.begin(),
2540 std::find_if(available_patches
.begin(), available_patches
.end(), [&](DiffInfo
const &I
) {
2541 return I
.result_hashes
== LocalHashes
;
2544 // error checking and falling back if no patch was found
2545 if(available_patches
.empty() == true)
2547 Failed("No patches left to reach target for " + PartialFile
, NULL
);
2551 // queue the right diff
2552 Desc
.URI
= Target
.URI
+ ".diff/" + available_patches
[0].file
+ ".gz";
2553 Desc
.Description
= Description
+ " " + available_patches
[0].file
+ string(".pdiff");
2554 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
+ ".diff/" + available_patches
[0].file
), Target
);
2557 std::clog
<< "pkgAcqIndexDiffs::QueueNextDiff(): " << Desc
.URI
<< std::endl
;
2564 void pkgAcqIndexDiffs::Done(string
const &Message
, HashStringList
const &Hashes
, /*{{{*/
2565 pkgAcquire::MethodConfig
const * const Cnf
)
2568 std::clog
<< "pkgAcqIndexDiffs::Done(): " << Desc
.URI
<< std::endl
;
2570 Item::Done(Message
, Hashes
, Cnf
);
2572 std::string
const UncompressedUnpatchedFile
= GetPartialFileNameFromURI(Target
.URI
);
2573 std::string
const UnpatchedFile
= GetExistingFilename(UncompressedUnpatchedFile
);
2574 std::string
const PatchFile
= GetDiffsPatchFileName(UnpatchedFile
);
2575 std::string
const PatchedFile
= GetKeepCompressedFileName(UncompressedUnpatchedFile
, Target
);
2579 // success in downloading a diff, enter ApplyDiff state
2580 case StateFetchDiff
:
2581 Rename(DestFile
, PatchFile
);
2582 DestFile
= GetKeepCompressedFileName(UncompressedUnpatchedFile
+ "-patched", Target
);
2584 std::clog
<< "Sending to rred method: " << UnpatchedFile
<< std::endl
;
2585 State
= StateApplyDiff
;
2587 Desc
.URI
= "rred:" + UnpatchedFile
;
2589 SetActiveSubprocess("rred");
2591 // success in download/apply a diff, queue next (if needed)
2592 case StateApplyDiff
:
2593 // remove the just applied patch and base file
2594 available_patches
.erase(available_patches
.begin());
2595 RemoveFile("pkgAcqIndexDiffs::Done", PatchFile
);
2596 RemoveFile("pkgAcqIndexDiffs::Done", UnpatchedFile
);
2598 std::clog
<< "Moving patched file in place: " << std::endl
2599 << DestFile
<< " -> " << PatchedFile
<< std::endl
;
2600 Rename(DestFile
, PatchedFile
);
2602 // see if there is more to download
2603 if(available_patches
.empty() == false)
2605 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
, available_patches
);
2608 DestFile
= PatchedFile
;
2615 std::string
pkgAcqIndexDiffs::Custom600Headers() const /*{{{*/
2617 if(State
!= StateApplyDiff
)
2618 return pkgAcqBaseIndex::Custom600Headers();
2619 std::ostringstream patchhashes
;
2620 HashStringList
const ExpectedHashes
= available_patches
[0].patch_hashes
;
2621 for (HashStringList::const_iterator hs
= ExpectedHashes
.begin(); hs
!= ExpectedHashes
.end(); ++hs
)
2622 patchhashes
<< "\nPatch-0-" << hs
->HashType() << "-Hash: " << hs
->HashValue();
2623 patchhashes
<< pkgAcqBaseIndex::Custom600Headers();
2624 return patchhashes
.str();
2627 pkgAcqIndexDiffs::~pkgAcqIndexDiffs() {}
2629 // AcqIndexMergeDiffs::AcqIndexMergeDiffs - Constructor /*{{{*/
2630 pkgAcqIndexMergeDiffs::pkgAcqIndexMergeDiffs(pkgAcquire
* const Owner
,
2631 pkgAcqMetaClearSig
* const TransactionManager
,
2632 IndexTarget
const &Target
,
2633 DiffInfo
const &patch
,
2634 std::vector
<pkgAcqIndexMergeDiffs
*> const * const allPatches
)
2635 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
),
2636 patch(patch
), allPatches(allPatches
), State(StateFetchDiff
)
2638 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
2641 Description
= Target
.Description
;
2642 Desc
.ShortDesc
= Target
.ShortDesc
;
2643 Desc
.URI
= Target
.URI
+ ".diff/" + patch
.file
+ ".gz";
2644 Desc
.Description
= Description
+ " " + patch
.file
+ ".pdiff";
2645 DestFile
= GetPartialFileNameFromURI(Desc
.URI
);
2648 std::clog
<< "pkgAcqIndexMergeDiffs: " << Desc
.URI
<< std::endl
;
2653 void pkgAcqIndexMergeDiffs::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
2656 std::clog
<< "pkgAcqIndexMergeDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
;
2658 pkgAcqBaseIndex::Failed(Message
,Cnf
);
2661 // check if we are the first to fail, otherwise we are done here
2662 State
= StateDoneDiff
;
2663 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2664 I
!= allPatches
->end(); ++I
)
2665 if ((*I
)->State
== StateErrorDiff
)
2667 State
= StateErrorDiff
;
2671 // first failure means we should fallback
2672 State
= StateErrorDiff
;
2674 std::clog
<< "Falling back to normal index file acquire" << std::endl
;
2675 RenameOnError(PDiffError
);
2676 if (RealFileExists(DestFile
))
2677 Rename(DestFile
, DestFile
+ ".FAILED");
2678 std::string
const UnpatchedFile
= GetExistingFilename(GetPartialFileNameFromURI(Target
.URI
));
2679 if (UnpatchedFile
.empty() == false && FileExists(UnpatchedFile
))
2680 Rename(UnpatchedFile
, UnpatchedFile
+ ".FAILED");
2682 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
2685 void pkgAcqIndexMergeDiffs::Done(string
const &Message
, HashStringList
const &Hashes
, /*{{{*/
2686 pkgAcquire::MethodConfig
const * const Cnf
)
2689 std::clog
<< "pkgAcqIndexMergeDiffs::Done(): " << Desc
.URI
<< std::endl
;
2691 Item::Done(Message
, Hashes
, Cnf
);
2693 if (std::any_of(allPatches
->begin(), allPatches
->end(),
2694 [](pkgAcqIndexMergeDiffs
const * const P
) { return P
->State
== StateErrorDiff
; }))
2697 std::clog
<< "Another patch failed already, no point in processing this one." << std::endl
;
2698 State
= StateErrorDiff
;
2702 std::string
const UncompressedUnpatchedFile
= GetPartialFileNameFromURI(Target
.URI
);
2703 std::string
const UnpatchedFile
= GetExistingFilename(UncompressedUnpatchedFile
);
2704 if (UnpatchedFile
.empty())
2706 _error
->Fatal("Unpatched file %s doesn't exist (anymore)!", UncompressedUnpatchedFile
.c_str());
2707 State
= StateErrorDiff
;
2710 std::string
const PatchFile
= GetMergeDiffsPatchFileName(UnpatchedFile
, patch
.file
);
2711 std::string
const PatchedFile
= GetKeepCompressedFileName(UncompressedUnpatchedFile
, Target
);
2715 case StateFetchDiff
:
2716 Rename(DestFile
, PatchFile
);
2718 // check if this is the last completed diff
2719 State
= StateDoneDiff
;
2720 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2721 I
!= allPatches
->end(); ++I
)
2722 if ((*I
)->State
!= StateDoneDiff
)
2725 std::clog
<< "Not the last done diff in the batch: " << Desc
.URI
<< std::endl
;
2728 // this is the last completed diff, so we are ready to apply now
2729 DestFile
= GetKeepCompressedFileName(UncompressedUnpatchedFile
+ "-patched", Target
);
2731 std::clog
<< "Sending to rred method: " << UnpatchedFile
<< std::endl
;
2732 State
= StateApplyDiff
;
2734 Desc
.URI
= "rred:" + UnpatchedFile
;
2736 SetActiveSubprocess("rred");
2738 case StateApplyDiff
:
2739 // success in download & apply all diffs, finialize and clean up
2741 std::clog
<< "Queue patched file in place: " << std::endl
2742 << DestFile
<< " -> " << PatchedFile
<< std::endl
;
2744 // queue for copy by the transaction manager
2745 TransactionManager
->TransactionStageCopy(this, DestFile
, GetKeepCompressedFileName(GetFinalFilename(), Target
));
2747 // ensure the ed's are gone regardless of list-cleanup
2748 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2749 I
!= allPatches
->end(); ++I
)
2750 RemoveFile("pkgAcqIndexMergeDiffs::Done", GetMergeDiffsPatchFileName(UnpatchedFile
, (*I
)->patch
.file
));
2751 RemoveFile("pkgAcqIndexMergeDiffs::Done", UnpatchedFile
);
2756 std::clog
<< "allDone: " << DestFile
<< "\n" << std::endl
;
2758 case StateDoneDiff
: _error
->Fatal("Done called for %s which is in an invalid Done state", PatchFile
.c_str()); break;
2759 case StateErrorDiff
: _error
->Fatal("Done called for %s which is in an invalid Error state", PatchFile
.c_str()); break;
2763 std::string
pkgAcqIndexMergeDiffs::Custom600Headers() const /*{{{*/
2765 if(State
!= StateApplyDiff
)
2766 return pkgAcqBaseIndex::Custom600Headers();
2767 std::ostringstream patchhashes
;
2768 unsigned int seen_patches
= 0;
2769 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2770 I
!= allPatches
->end(); ++I
)
2772 HashStringList
const ExpectedHashes
= (*I
)->patch
.patch_hashes
;
2773 for (HashStringList::const_iterator hs
= ExpectedHashes
.begin(); hs
!= ExpectedHashes
.end(); ++hs
)
2774 patchhashes
<< "\nPatch-" << seen_patches
<< "-" << hs
->HashType() << "-Hash: " << hs
->HashValue();
2777 patchhashes
<< pkgAcqBaseIndex::Custom600Headers();
2778 return patchhashes
.str();
2781 pkgAcqIndexMergeDiffs::~pkgAcqIndexMergeDiffs() {}
2783 // AcqIndex::AcqIndex - Constructor /*{{{*/
2784 pkgAcqIndex::pkgAcqIndex(pkgAcquire
* const Owner
,
2785 pkgAcqMetaClearSig
* const TransactionManager
,
2786 IndexTarget
const &Target
)
2787 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
), Stage(STAGE_DOWNLOAD
),
2788 CompressionExtensions(Target
.Option(IndexTarget::COMPRESSIONTYPES
))
2790 Init(Target
.URI
, Target
.Description
, Target
.ShortDesc
);
2792 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
2793 std::clog
<< "New pkgIndex with TransactionManager "
2794 << TransactionManager
<< std::endl
;
2797 // AcqIndex::Init - defered Constructor /*{{{*/
2798 static void NextCompressionExtension(std::string
&CurrentCompressionExtension
, std::string
&CompressionExtensions
, bool const preview
)
2800 size_t const nextExt
= CompressionExtensions
.find(' ');
2801 if (nextExt
== std::string::npos
)
2803 CurrentCompressionExtension
= CompressionExtensions
;
2804 if (preview
== false)
2805 CompressionExtensions
.clear();
2809 CurrentCompressionExtension
= CompressionExtensions
.substr(0, nextExt
);
2810 if (preview
== false)
2811 CompressionExtensions
= CompressionExtensions
.substr(nextExt
+1);
2814 void pkgAcqIndex::Init(string
const &URI
, string
const &URIDesc
,
2815 string
const &ShortDesc
)
2817 Stage
= STAGE_DOWNLOAD
;
2819 DestFile
= GetPartialFileNameFromURI(URI
);
2820 NextCompressionExtension(CurrentCompressionExtension
, CompressionExtensions
, false);
2822 // store file size of the download to ensure the fetcher gives
2823 // accurate progress reporting
2824 FileSize
= GetExpectedHashes().FileSize();
2826 if (CurrentCompressionExtension
== "uncompressed")
2830 else if (CurrentCompressionExtension
== "by-hash")
2832 NextCompressionExtension(CurrentCompressionExtension
, CompressionExtensions
, true);
2833 if(unlikely(CurrentCompressionExtension
.empty()))
2835 if (CurrentCompressionExtension
!= "uncompressed")
2837 Desc
.URI
= URI
+ '.' + CurrentCompressionExtension
;
2838 DestFile
= DestFile
+ '.' + CurrentCompressionExtension
;
2841 HashStringList
const Hashes
= GetExpectedHashes();
2842 HashString
const * const TargetHash
= Hashes
.find(NULL
);
2843 if (unlikely(TargetHash
== nullptr))
2845 std::string
const ByHash
= "/by-hash/" + TargetHash
->HashType() + "/" + TargetHash
->HashValue();
2846 size_t const trailing_slash
= Desc
.URI
.find_last_of("/");
2847 if (unlikely(trailing_slash
== std::string::npos
))
2849 Desc
.URI
= Desc
.URI
.replace(
2851 Desc
.URI
.substr(trailing_slash
+1).size()+1,
2854 else if (unlikely(CurrentCompressionExtension
.empty()))
2858 Desc
.URI
= URI
+ '.' + CurrentCompressionExtension
;
2859 DestFile
= DestFile
+ '.' + CurrentCompressionExtension
;
2863 Desc
.Description
= URIDesc
;
2865 Desc
.ShortDesc
= ShortDesc
;
2870 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
2871 // ---------------------------------------------------------------------
2872 /* The only header we use is the last-modified header. */
2873 string
pkgAcqIndex::Custom600Headers() const
2876 string msg
= "\nIndex-File: true";
2878 if (TransactionManager
->LastMetaIndexParser
== NULL
)
2880 std::string
const Final
= GetFinalFilename();
2883 if (stat(Final
.c_str(),&Buf
) == 0)
2884 msg
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
2887 if(Target
.IsOptional
)
2888 msg
+= "\nFail-Ignore: true";
2893 // AcqIndex::Failed - getting the indexfile failed /*{{{*/
2894 void pkgAcqIndex::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)
2896 pkgAcqBaseIndex::Failed(Message
,Cnf
);
2898 // authorisation matches will not be fixed by other compression types
2899 if (Status
!= StatAuthError
)
2901 if (CompressionExtensions
.empty() == false)
2903 Init(Target
.URI
, Desc
.Description
, Desc
.ShortDesc
);
2909 if(Target
.IsOptional
&& GetExpectedHashes().empty() && Stage
== STAGE_DOWNLOAD
)
2912 TransactionManager
->AbortTransaction();
2915 // AcqIndex::Done - Finished a fetch /*{{{*/
2916 // ---------------------------------------------------------------------
2917 /* This goes through a number of states.. On the initial fetch the
2918 method could possibly return an alternate filename which points
2919 to the uncompressed version of the file. If this is so the file
2920 is copied into the partial directory. In all other cases the file
2921 is decompressed with a compressed uri. */
2922 void pkgAcqIndex::Done(string
const &Message
,
2923 HashStringList
const &Hashes
,
2924 pkgAcquire::MethodConfig
const * const Cfg
)
2926 Item::Done(Message
,Hashes
,Cfg
);
2930 case STAGE_DOWNLOAD
:
2931 StageDownloadDone(Message
);
2933 case STAGE_DECOMPRESS_AND_VERIFY
:
2934 StageDecompressDone();
2939 // AcqIndex::StageDownloadDone - Queue for decompress and verify /*{{{*/
2940 void pkgAcqIndex::StageDownloadDone(string
const &Message
)
2945 std::string
const AltFilename
= LookupTag(Message
,"Alt-Filename");
2946 std::string Filename
= LookupTag(Message
,"Filename");
2948 // we need to verify the file against the current Release file again
2949 // on if-modfied-since hit to avoid a stale attack against us
2950 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
2952 // copy FinalFile into partial/ so that we check the hash again
2953 string
const FinalFile
= GetExistingFilename(GetFinalFileNameFromURI(Target
.URI
));
2954 if (symlink(FinalFile
.c_str(), DestFile
.c_str()) != 0)
2955 _error
->WarningE("pkgAcqIndex::StageDownloadDone", "Symlinking final file %s back to %s failed", FinalFile
.c_str(), DestFile
.c_str());
2958 EraseFileName
= DestFile
;
2959 Filename
= DestFile
;
2961 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
2962 Desc
.URI
= "store:" + Filename
;
2964 SetActiveSubprocess(::URI(Desc
.URI
).Access
);
2967 // methods like file:// give us an alternative (uncompressed) file
2968 else if (Target
.KeepCompressed
== false && AltFilename
.empty() == false)
2970 Filename
= AltFilename
;
2971 EraseFileName
.clear();
2973 // Methods like e.g. "file:" will give us a (compressed) FileName that is
2974 // not the "DestFile" we set, in this case we uncompress from the local file
2975 else if (Filename
!= DestFile
&& RealFileExists(DestFile
) == false)
2977 // symlinking ensures that the filename can be used for compression detection
2978 // that is e.g. needed for by-hash which has no extension over file
2979 if (symlink(Filename
.c_str(),DestFile
.c_str()) != 0)
2980 _error
->WarningE("pkgAcqIndex::StageDownloadDone", "Symlinking file %s to %s failed", Filename
.c_str(), DestFile
.c_str());
2983 EraseFileName
= DestFile
;
2984 Filename
= DestFile
;
2988 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
2989 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
2990 if (Filename
!= DestFile
&& flExtension(Filename
) == flExtension(DestFile
))
2991 Desc
.URI
= "copy:" + Filename
;
2993 Desc
.URI
= "store:" + Filename
;
2994 if (DestFile
== Filename
)
2996 if (CurrentCompressionExtension
== "uncompressed")
2997 return StageDecompressDone();
2998 DestFile
= "/dev/null";
3001 if (EraseFileName
.empty() && Filename
!= AltFilename
)
3002 EraseFileName
= Filename
;
3004 // queue uri for the next stage
3006 SetActiveSubprocess(::URI(Desc
.URI
).Access
);
3009 // AcqIndex::StageDecompressDone - Final verification /*{{{*/
3010 void pkgAcqIndex::StageDecompressDone()
3012 if (DestFile
== "/dev/null")
3013 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
3015 // Done, queue for rename on transaction finished
3016 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
3019 pkgAcqIndex::~pkgAcqIndex() {}
3022 // AcqArchive::AcqArchive - Constructor /*{{{*/
3023 // ---------------------------------------------------------------------
3024 /* This just sets up the initial fetch environment and queues the first
3026 pkgAcqArchive::pkgAcqArchive(pkgAcquire
* const Owner
,pkgSourceList
* const Sources
,
3027 pkgRecords
* const Recs
,pkgCache::VerIterator
const &Version
,
3028 string
&StoreFilename
) :
3029 Item(Owner
), d(NULL
), LocalSource(false), Version(Version
), Sources(Sources
), Recs(Recs
),
3030 StoreFilename(StoreFilename
), Vf(Version
.FileList()),
3033 Retries
= _config
->FindI("Acquire::Retries",0);
3035 if (Version
.Arch() == 0)
3037 _error
->Error(_("I wasn't able to locate a file for the %s package. "
3038 "This might mean you need to manually fix this package. "
3039 "(due to missing arch)"),
3040 Version
.ParentPkg().FullName().c_str());
3044 /* We need to find a filename to determine the extension. We make the
3045 assumption here that all the available sources for this version share
3046 the same extension.. */
3047 // Skip not source sources, they do not have file fields.
3048 for (; Vf
.end() == false; ++Vf
)
3050 if (Vf
.File().Flagged(pkgCache::Flag::NotSource
))
3055 // Does not really matter here.. we are going to fail out below
3056 if (Vf
.end() != true)
3058 // If this fails to get a file name we will bomb out below.
3059 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
3060 if (_error
->PendingError() == true)
3063 // Generate the final file name as: package_version_arch.foo
3064 StoreFilename
= QuoteString(Version
.ParentPkg().Name(),"_:") + '_' +
3065 QuoteString(Version
.VerStr(),"_:") + '_' +
3066 QuoteString(Version
.Arch(),"_:.") +
3067 "." + flExtension(Parse
.FileName());
3070 // check if we have one trusted source for the package. if so, switch
3071 // to "TrustedOnly" mode - but only if not in AllowUnauthenticated mode
3072 bool const allowUnauth
= _config
->FindB("APT::Get::AllowUnauthenticated", false);
3073 bool const debugAuth
= _config
->FindB("Debug::pkgAcquire::Auth", false);
3074 bool seenUntrusted
= false;
3075 for (pkgCache::VerFileIterator i
= Version
.FileList(); i
.end() == false; ++i
)
3077 pkgIndexFile
*Index
;
3078 if (Sources
->FindIndex(i
.File(),Index
) == false)
3081 if (debugAuth
== true)
3082 std::cerr
<< "Checking index: " << Index
->Describe()
3083 << "(Trusted=" << Index
->IsTrusted() << ")" << std::endl
;
3085 if (Index
->IsTrusted() == true)
3088 if (allowUnauth
== false)
3092 seenUntrusted
= true;
3095 // "allow-unauthenticated" restores apts old fetching behaviour
3096 // that means that e.g. unauthenticated file:// uris are higher
3097 // priority than authenticated http:// uris
3098 if (allowUnauth
== true && seenUntrusted
== true)
3102 if (QueueNext() == false && _error
->PendingError() == false)
3103 _error
->Error(_("Can't find a source to download version '%s' of '%s'"),
3104 Version
.VerStr(), Version
.ParentPkg().FullName(false).c_str());
3107 // AcqArchive::QueueNext - Queue the next file source /*{{{*/
3108 // ---------------------------------------------------------------------
3109 /* This queues the next available file version for download. It checks if
3110 the archive is already available in the cache and stashs the MD5 for
3112 bool pkgAcqArchive::QueueNext()
3114 for (; Vf
.end() == false; ++Vf
)
3116 pkgCache::PkgFileIterator
const PkgF
= Vf
.File();
3117 // Ignore not source sources
3118 if (PkgF
.Flagged(pkgCache::Flag::NotSource
))
3121 // Try to cross match against the source list
3122 pkgIndexFile
*Index
;
3123 if (Sources
->FindIndex(PkgF
, Index
) == false)
3125 LocalSource
= PkgF
.Flagged(pkgCache::Flag::LocalSource
);
3127 // only try to get a trusted package from another source if that source
3129 if(Trusted
&& !Index
->IsTrusted())
3132 // Grab the text package record
3133 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
3134 if (_error
->PendingError() == true)
3137 string PkgFile
= Parse
.FileName();
3138 ExpectedHashes
= Parse
.Hashes();
3140 if (PkgFile
.empty() == true)
3141 return _error
->Error(_("The package index files are corrupted. No Filename: "
3142 "field for package %s."),
3143 Version
.ParentPkg().Name());
3145 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
3146 Desc
.Description
= Index
->ArchiveInfo(Version
);
3148 Desc
.ShortDesc
= Version
.ParentPkg().FullName(true);
3150 // See if we already have the file. (Legacy filenames)
3151 FileSize
= Version
->Size
;
3152 string FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile
);
3154 if (stat(FinalFile
.c_str(),&Buf
) == 0)
3156 // Make sure the size matches
3157 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
3162 StoreFilename
= DestFile
= FinalFile
;
3166 /* Hmm, we have a file and its size does not match, this means it is
3167 an old style mismatched arch */
3168 RemoveFile("pkgAcqArchive::QueueNext", FinalFile
);
3171 // Check it again using the new style output filenames
3172 FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
3173 if (stat(FinalFile
.c_str(),&Buf
) == 0)
3175 // Make sure the size matches
3176 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
3181 StoreFilename
= DestFile
= FinalFile
;
3185 /* Hmm, we have a file and its size does not match, this shouldn't
3187 RemoveFile("pkgAcqArchive::QueueNext", FinalFile
);
3190 DestFile
= _config
->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename
);
3192 // Check the destination file
3193 if (stat(DestFile
.c_str(),&Buf
) == 0)
3195 // Hmm, the partial file is too big, erase it
3196 if ((unsigned long long)Buf
.st_size
> Version
->Size
)
3197 RemoveFile("pkgAcqArchive::QueueNext", DestFile
);
3199 PartialSize
= Buf
.st_size
;
3202 // Disables download of archives - useful if no real installation follows,
3203 // e.g. if we are just interested in proposed installation order
3204 if (_config
->FindB("Debug::pkgAcqArchive::NoQueue", false) == true)
3209 StoreFilename
= DestFile
= FinalFile
;
3223 // AcqArchive::Done - Finished fetching /*{{{*/
3224 // ---------------------------------------------------------------------
3226 void pkgAcqArchive::Done(string
const &Message
, HashStringList
const &Hashes
,
3227 pkgAcquire::MethodConfig
const * const Cfg
)
3229 Item::Done(Message
, Hashes
, Cfg
);
3231 // Grab the output filename
3232 std::string
const FileName
= LookupTag(Message
,"Filename");
3233 if (DestFile
!= FileName
&& RealFileExists(DestFile
) == false)
3235 StoreFilename
= DestFile
= FileName
;
3241 // Done, move it into position
3242 string
const FinalFile
= GetFinalFilename();
3243 Rename(DestFile
,FinalFile
);
3244 StoreFilename
= DestFile
= FinalFile
;
3248 // AcqArchive::Failed - Failure handler /*{{{*/
3249 // ---------------------------------------------------------------------
3250 /* Here we try other sources */
3251 void pkgAcqArchive::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)
3253 Item::Failed(Message
,Cnf
);
3255 /* We don't really want to retry on failed media swaps, this prevents
3256 that. An interesting observation is that permanent failures are not
3258 if (Cnf
->Removable
== true &&
3259 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
3261 // Vf = Version.FileList();
3262 while (Vf
.end() == false) ++Vf
;
3263 StoreFilename
= string();
3268 if (QueueNext() == false)
3270 // This is the retry counter
3272 Cnf
->LocalOnly
== false &&
3273 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
3276 Vf
= Version
.FileList();
3277 if (QueueNext() == true)
3281 StoreFilename
= string();
3286 APT_PURE
bool pkgAcqArchive::IsTrusted() const /*{{{*/
3291 void pkgAcqArchive::Finished() /*{{{*/
3293 if (Status
== pkgAcquire::Item::StatDone
&&
3296 StoreFilename
= string();
3299 std::string
pkgAcqArchive::DescURI() const /*{{{*/
3304 std::string
pkgAcqArchive::ShortDesc() const /*{{{*/
3306 return Desc
.ShortDesc
;
3309 pkgAcqArchive::~pkgAcqArchive() {}
3311 // AcqChangelog::pkgAcqChangelog - Constructors /*{{{*/
3312 class pkgAcqChangelog::Private
3315 std::string FinalFile
;
3317 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire
* const Owner
, pkgCache::VerIterator
const &Ver
,
3318 std::string
const &DestDir
, std::string
const &DestFilename
) :
3319 pkgAcquire::Item(Owner
), d(new pkgAcqChangelog::Private()), SrcName(Ver
.SourcePkgName()), SrcVersion(Ver
.SourceVerStr())
3321 Desc
.URI
= URI(Ver
);
3322 Init(DestDir
, DestFilename
);
3324 // some parameters are char* here as they come likely from char* interfaces – which can also return NULL
3325 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire
* const Owner
, pkgCache::RlsFileIterator
const &RlsFile
,
3326 char const * const Component
, char const * const SrcName
, char const * const SrcVersion
,
3327 const string
&DestDir
, const string
&DestFilename
) :
3328 pkgAcquire::Item(Owner
), d(new pkgAcqChangelog::Private()), SrcName(SrcName
), SrcVersion(SrcVersion
)
3330 Desc
.URI
= URI(RlsFile
, Component
, SrcName
, SrcVersion
);
3331 Init(DestDir
, DestFilename
);
3333 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire
* const Owner
,
3334 std::string
const &URI
, char const * const SrcName
, char const * const SrcVersion
,
3335 const string
&DestDir
, const string
&DestFilename
) :
3336 pkgAcquire::Item(Owner
), d(new pkgAcqChangelog::Private()), SrcName(SrcName
), SrcVersion(SrcVersion
)
3339 Init(DestDir
, DestFilename
);
3341 void pkgAcqChangelog::Init(std::string
const &DestDir
, std::string
const &DestFilename
)
3343 if (Desc
.URI
.empty())
3346 // TRANSLATOR: %s=%s is sourcename=sourceversion, e.g. apt=1.1
3347 strprintf(ErrorText
, _("Changelog unavailable for %s=%s"), SrcName
.c_str(), SrcVersion
.c_str());
3348 // Let the error message print something sensible rather than "Failed to fetch /"
3349 if (DestFilename
.empty())
3350 DestFile
= SrcName
+ ".changelog";
3352 DestFile
= DestFilename
;
3353 Desc
.URI
= "changelog:/" + DestFile
;
3357 std::string DestFileName
;
3358 if (DestFilename
.empty())
3359 DestFileName
= flCombine(DestFile
, SrcName
+ ".changelog");
3361 DestFileName
= flCombine(DestFile
, DestFilename
);
3363 std::string
const SandboxUser
= _config
->Find("APT::Sandbox::User");
3364 std::string
const systemTemp
= GetTempDir(SandboxUser
);
3366 snprintf(tmpname
, sizeof(tmpname
), "%s/apt-changelog-XXXXXX", systemTemp
.c_str());
3367 if (NULL
== mkdtemp(tmpname
))
3369 _error
->Errno("mkdtemp", "mkdtemp failed in changelog acquire of %s %s", SrcName
.c_str(), SrcVersion
.c_str());
3373 TemporaryDirectory
= tmpname
;
3375 ChangeOwnerAndPermissionOfFile("Item::QueueURI", TemporaryDirectory
.c_str(),
3376 SandboxUser
.c_str(), "root", 0700);
3378 DestFile
= flCombine(TemporaryDirectory
, DestFileName
);
3379 if (DestDir
.empty() == false)
3381 d
->FinalFile
= flCombine(DestDir
, DestFileName
);
3382 if (RealFileExists(d
->FinalFile
))
3384 FileFd file1
, file2
;
3385 if (file1
.Open(DestFile
, FileFd::WriteOnly
| FileFd::Create
| FileFd::Exclusive
) &&
3386 file2
.Open(d
->FinalFile
, FileFd::ReadOnly
) && CopyFile(file2
, file1
))
3388 struct timeval times
[2];
3389 times
[0].tv_sec
= times
[1].tv_sec
= file2
.ModificationTime();
3390 times
[0].tv_usec
= times
[1].tv_usec
= 0;
3391 utimes(DestFile
.c_str(), times
);
3396 Desc
.ShortDesc
= "Changelog";
3397 strprintf(Desc
.Description
, "%s %s %s Changelog", URI::SiteOnly(Desc
.URI
).c_str(), SrcName
.c_str(), SrcVersion
.c_str());
3402 std::string
pkgAcqChangelog::URI(pkgCache::VerIterator
const &Ver
) /*{{{*/
3404 std::string
const confOnline
= "Acquire::Changelogs::AlwaysOnline";
3405 bool AlwaysOnline
= _config
->FindB(confOnline
, false);
3406 if (AlwaysOnline
== false)
3407 for (pkgCache::VerFileIterator VF
= Ver
.FileList(); VF
.end() == false; ++VF
)
3409 pkgCache::PkgFileIterator
const PF
= VF
.File();
3410 if (PF
.Flagged(pkgCache::Flag::NotSource
) || PF
->Release
== 0)
3412 pkgCache::RlsFileIterator
const RF
= PF
.ReleaseFile();
3413 if (RF
->Origin
!= 0 && _config
->FindB(confOnline
+ "::Origin::" + RF
.Origin(), false))
3415 AlwaysOnline
= true;
3419 if (AlwaysOnline
== false)
3421 pkgCache::PkgIterator
const Pkg
= Ver
.ParentPkg();
3422 if (Pkg
->CurrentVer
!= 0 && Pkg
.CurrentVer() == Ver
)
3424 std::string
const basename
= std::string("/usr/share/doc/") + Pkg
.Name() + "/changelog";
3425 std::string
const debianname
= basename
+ ".Debian";
3426 if (FileExists(debianname
))
3427 return "copy://" + debianname
;
3428 else if (FileExists(debianname
+ ".gz"))
3429 return "gzip://" + debianname
+ ".gz";
3430 else if (FileExists(basename
))
3431 return "copy://" + basename
;
3432 else if (FileExists(basename
+ ".gz"))
3433 return "gzip://" + basename
+ ".gz";
3437 char const * const SrcName
= Ver
.SourcePkgName();
3438 char const * const SrcVersion
= Ver
.SourceVerStr();
3439 // find the first source for this version which promises a changelog
3440 for (pkgCache::VerFileIterator VF
= Ver
.FileList(); VF
.end() == false; ++VF
)
3442 pkgCache::PkgFileIterator
const PF
= VF
.File();
3443 if (PF
.Flagged(pkgCache::Flag::NotSource
) || PF
->Release
== 0)
3445 pkgCache::RlsFileIterator
const RF
= PF
.ReleaseFile();
3446 std::string
const uri
= URI(RF
, PF
.Component(), SrcName
, SrcVersion
);
3453 std::string
pkgAcqChangelog::URITemplate(pkgCache::RlsFileIterator
const &Rls
)
3455 if (Rls
.end() == true || (Rls
->Label
== 0 && Rls
->Origin
== 0))
3457 std::string
const serverConfig
= "Acquire::Changelogs::URI";
3459 #define APT_EMPTY_SERVER \
3460 if (server.empty() == false) \
3462 if (server != "no") \
3466 #define APT_CHECK_SERVER(X, Y) \
3469 std::string const specialServerConfig = serverConfig + "::" + Y + #X + "::" + Rls.X(); \
3470 server = _config->Find(specialServerConfig); \
3473 // this way e.g. Debian-Security can fallback to Debian
3474 APT_CHECK_SERVER(Label
, "Override::")
3475 APT_CHECK_SERVER(Origin
, "Override::")
3477 if (RealFileExists(Rls
.FileName()))
3479 _error
->PushToStack();
3481 /* This can be costly. A caller wanting to get millions of URIs might
3482 want to do this on its own once and use Override settings.
3483 We don't do this here as Origin/Label are not as unique as they
3484 should be so this could produce request order-dependent anomalies */
3485 if (OpenMaybeClearSignedFile(Rls
.FileName(), rf
) == true)
3487 pkgTagFile
TagFile(&rf
, rf
.Size());
3488 pkgTagSection Section
;
3489 if (TagFile
.Step(Section
) == true)
3490 server
= Section
.FindS("Changelogs");
3492 _error
->RevertToStack();
3496 APT_CHECK_SERVER(Label
, "")
3497 APT_CHECK_SERVER(Origin
, "")
3498 #undef APT_CHECK_SERVER
3499 #undef APT_EMPTY_SERVER
3502 std::string
pkgAcqChangelog::URI(pkgCache::RlsFileIterator
const &Rls
,
3503 char const * const Component
, char const * const SrcName
,
3504 char const * const SrcVersion
)
3506 return URI(URITemplate(Rls
), Component
, SrcName
, SrcVersion
);
3508 std::string
pkgAcqChangelog::URI(std::string
const &Template
,
3509 char const * const Component
, char const * const SrcName
,
3510 char const * const SrcVersion
)
3512 if (Template
.find("@CHANGEPATH@") == std::string::npos
)
3515 // the path is: COMPONENT/SRC/SRCNAME/SRCNAME_SRCVER, e.g. main/a/apt/1.1 or contrib/liba/libapt/2.0
3516 std::string Src
= SrcName
;
3517 std::string path
= APT::String::Startswith(SrcName
, "lib") ? Src
.substr(0, 4) : Src
.substr(0,1);
3518 path
.append("/").append(Src
).append("/");
3519 path
.append(Src
).append("_").append(StripEpoch(SrcVersion
));
3520 // we omit component for releases without one (= flat-style repositories)
3521 if (Component
!= NULL
&& strlen(Component
) != 0)
3522 path
= std::string(Component
) + "/" + path
;
3524 return SubstVar(Template
, "@CHANGEPATH@", path
);
3527 // AcqChangelog::Failed - Failure handler /*{{{*/
3528 void pkgAcqChangelog::Failed(string
const &Message
, pkgAcquire::MethodConfig
const * const Cnf
)
3530 Item::Failed(Message
,Cnf
);
3532 std::string errText
;
3533 // TRANSLATOR: %s=%s is sourcename=sourceversion, e.g. apt=1.1
3534 strprintf(errText
, _("Changelog unavailable for %s=%s"), SrcName
.c_str(), SrcVersion
.c_str());
3536 // Error is probably something techy like 404 Not Found
3537 if (ErrorText
.empty())
3538 ErrorText
= errText
;
3540 ErrorText
= errText
+ " (" + ErrorText
+ ")";
3543 // AcqChangelog::Done - Item downloaded OK /*{{{*/
3544 void pkgAcqChangelog::Done(string
const &Message
,HashStringList
const &CalcHashes
,
3545 pkgAcquire::MethodConfig
const * const Cnf
)
3547 Item::Done(Message
,CalcHashes
,Cnf
);
3548 if (d
->FinalFile
.empty() == false)
3550 if (RemoveFile("pkgAcqChangelog::Done", d
->FinalFile
) == false ||
3551 Rename(DestFile
, d
->FinalFile
) == false)
3558 pkgAcqChangelog::~pkgAcqChangelog() /*{{{*/
3560 if (TemporaryDirectory
.empty() == false)
3562 RemoveFile("~pkgAcqChangelog", DestFile
);
3563 rmdir(TemporaryDirectory
.c_str());
3569 // AcqFile::pkgAcqFile - Constructor /*{{{*/
3570 pkgAcqFile::pkgAcqFile(pkgAcquire
* const Owner
,string
const &URI
, HashStringList
const &Hashes
,
3571 unsigned long long const Size
,string
const &Dsc
,string
const &ShortDesc
,
3572 const string
&DestDir
, const string
&DestFilename
,
3573 bool const IsIndexFile
) :
3574 Item(Owner
), d(NULL
), IsIndexFile(IsIndexFile
), ExpectedHashes(Hashes
)
3576 Retries
= _config
->FindI("Acquire::Retries",0);
3578 if(!DestFilename
.empty())
3579 DestFile
= DestFilename
;
3580 else if(!DestDir
.empty())
3581 DestFile
= DestDir
+ "/" + flNotDir(URI
);
3583 DestFile
= flNotDir(URI
);
3587 Desc
.Description
= Dsc
;
3590 // Set the short description to the archive component
3591 Desc
.ShortDesc
= ShortDesc
;
3593 // Get the transfer sizes
3596 if (stat(DestFile
.c_str(),&Buf
) == 0)
3598 // Hmm, the partial file is too big, erase it
3599 if ((Size
> 0) && (unsigned long long)Buf
.st_size
> Size
)
3600 RemoveFile("pkgAcqFile", DestFile
);
3602 PartialSize
= Buf
.st_size
;
3608 // AcqFile::Done - Item downloaded OK /*{{{*/
3609 void pkgAcqFile::Done(string
const &Message
,HashStringList
const &CalcHashes
,
3610 pkgAcquire::MethodConfig
const * const Cnf
)
3612 Item::Done(Message
,CalcHashes
,Cnf
);
3614 std::string
const FileName
= LookupTag(Message
,"Filename");
3617 // The files timestamp matches
3618 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
3621 // We have to copy it into place
3622 if (RealFileExists(DestFile
.c_str()) == false)
3625 if (_config
->FindB("Acquire::Source-Symlinks",true) == false ||
3626 Cnf
->Removable
== true)
3628 Desc
.URI
= "copy:" + FileName
;
3633 // Erase the file if it is a symlink so we can overwrite it
3635 if (lstat(DestFile
.c_str(),&St
) == 0)
3637 if (S_ISLNK(St
.st_mode
) != 0)
3638 RemoveFile("pkgAcqFile::Done", DestFile
);
3642 if (symlink(FileName
.c_str(),DestFile
.c_str()) != 0)
3644 _error
->PushToStack();
3645 _error
->Errno("pkgAcqFile::Done", "Symlinking file %s failed", DestFile
.c_str());
3646 std::stringstream msg
;
3647 _error
->DumpErrors(msg
, GlobalError::DEBUG
, false);
3648 _error
->RevertToStack();
3649 ErrorText
= msg
.str();
3656 // AcqFile::Failed - Failure handler /*{{{*/
3657 // ---------------------------------------------------------------------
3658 /* Here we try other sources */
3659 void pkgAcqFile::Failed(string
const &Message
, pkgAcquire::MethodConfig
const * const Cnf
)
3661 Item::Failed(Message
,Cnf
);
3663 // This is the retry counter
3665 Cnf
->LocalOnly
== false &&
3666 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
3676 string
pkgAcqFile::Custom600Headers() const /*{{{*/
3679 return "\nIndex-File: true";
3683 pkgAcqFile::~pkgAcqFile() {}