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 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 APT_NONNULL(3, 4, 5) AllowInsecureRepositories(InsecureType msg
, std::string
const &repo
,
199 metaIndex
const * const MetaIndexParser
, pkgAcqMetaClearSig
* const TransactionManager
, pkgAcquire::Item
* const I
)
201 // we skip weak downgrades as its unlikely that a repository gets really weaker –
202 // its more realistic that apt got pickier in a newer version
203 if (msg
!= InsecureType::WEAK
)
205 std::string
const FinalInRelease
= TransactionManager
->GetFinalFilename();
206 std::string
const FinalReleasegpg
= FinalInRelease
.substr(0, FinalInRelease
.length() - strlen("InRelease")) + "Release.gpg";
207 if (RealFileExists(FinalReleasegpg
) || RealFileExists(FinalInRelease
))
209 char const * msgstr
= nullptr;
212 case InsecureType::UNSIGNED
: msgstr
= _("The repository '%s' is no longer signed."); break;
213 case InsecureType::NORELEASE
: msgstr
= _("The repository '%s' does no longer have a Release file."); break;
214 case InsecureType::WEAK
: /* unreachable */ break;
216 if (_config
->FindB("Acquire::AllowDowngradeToInsecureRepositories"))
218 // meh, the users wants to take risks (we still mark the packages
219 // from this repository as unauthenticated)
220 _error
->Warning(msgstr
, repo
.c_str());
221 _error
->Warning(_("This is normally not allowed, but the option "
222 "Acquire::AllowDowngradeToInsecureRepositories was "
223 "given to override it."));
225 MessageInsecureRepository(true, msgstr
, repo
);
226 TransactionManager
->AbortTransaction();
227 I
->Status
= pkgAcquire::Item::StatError
;
233 if(MetaIndexParser
->GetTrusted() == metaIndex::TRI_YES
)
236 char const * msgstr
= nullptr;
239 case InsecureType::UNSIGNED
: msgstr
= _("The repository '%s' is not signed."); break;
240 case InsecureType::NORELEASE
: msgstr
= _("The repository '%s' does not have a Release file."); break;
241 case InsecureType::WEAK
: msgstr
= _("The repository '%s' provides only weak security information."); break;
244 if (_config
->FindB("Acquire::AllowInsecureRepositories") == true)
246 MessageInsecureRepository(false, msgstr
, repo
);
250 MessageInsecureRepository(true, msgstr
, repo
);
251 TransactionManager
->AbortTransaction();
252 I
->Status
= pkgAcquire::Item::StatError
;
256 static HashStringList
GetExpectedHashesFromFor(metaIndex
* const Parser
, std::string
const &MetaKey
)/*{{{*/
259 return HashStringList();
260 metaIndex::checkSum
* const R
= Parser
->Lookup(MetaKey
);
262 return HashStringList();
267 // all ::HashesRequired and ::GetExpectedHashes implementations /*{{{*/
268 /* ::GetExpectedHashes is abstract and has to be implemented by all subclasses.
269 It is best to implement it as broadly as possible, while ::HashesRequired defaults
270 to true and should be as restrictive as possible for false cases. Note that if
271 a hash is returned by ::GetExpectedHashes it must match. Only if it doesn't
272 ::HashesRequired is called to evaluate if its okay to have no hashes. */
273 APT_CONST
bool pkgAcqTransactionItem::HashesRequired() const
275 /* signed repositories obviously have a parser and good hashes.
276 unsigned repositories, too, as even if we can't trust them for security,
277 we can at least trust them for integrity of the download itself.
278 Only repositories without a Release file can (obviously) not have
279 hashes – and they are very uncommon and strongly discouraged */
280 return TransactionManager
->MetaIndexParser
->GetLoadedSuccessfully() == metaIndex::TRI_YES
;
282 HashStringList
pkgAcqTransactionItem::GetExpectedHashes() const
284 return GetExpectedHashesFor(GetMetaKey());
287 APT_CONST
bool pkgAcqMetaBase::HashesRequired() const
289 // Release and co have no hashes 'by design'.
292 HashStringList
pkgAcqMetaBase::GetExpectedHashes() const
294 return HashStringList();
297 APT_CONST
bool pkgAcqIndexDiffs::HashesRequired() const
299 /* We can't check hashes of rred result as we don't know what the
300 hash of the file will be. We just know the hash of the patch(es),
301 the hash of the file they will apply on and the hash of the resulting
303 if (State
== StateFetchDiff
)
307 HashStringList
pkgAcqIndexDiffs::GetExpectedHashes() const
309 if (State
== StateFetchDiff
)
310 return available_patches
[0].download_hashes
;
311 return HashStringList();
314 APT_CONST
bool pkgAcqIndexMergeDiffs::HashesRequired() const
316 /* @see #pkgAcqIndexDiffs::HashesRequired, with the difference that
317 we can check the rred result after all patches are applied as
318 we know the expected result rather than potentially apply more patches */
319 if (State
== StateFetchDiff
)
321 return State
== StateApplyDiff
;
323 HashStringList
pkgAcqIndexMergeDiffs::GetExpectedHashes() const
325 if (State
== StateFetchDiff
)
326 return patch
.download_hashes
;
327 else if (State
== StateApplyDiff
)
328 return GetExpectedHashesFor(Target
.MetaKey
);
329 return HashStringList();
332 APT_CONST
bool pkgAcqArchive::HashesRequired() const
334 return LocalSource
== false;
336 HashStringList
pkgAcqArchive::GetExpectedHashes() const
338 // figured out while parsing the records
339 return ExpectedHashes
;
342 APT_CONST
bool pkgAcqFile::HashesRequired() const
344 // supplied as parameter at creation time, so the caller decides
345 return ExpectedHashes
.usable();
347 HashStringList
pkgAcqFile::GetExpectedHashes() const
349 return ExpectedHashes
;
352 // Acquire::Item::QueueURI and specialisations from child classes /*{{{*/
353 bool pkgAcquire::Item::QueueURI(pkgAcquire::ItemDesc
&Item
)
355 Owner
->Enqueue(Item
);
358 /* The idea here is that an item isn't queued if it exists on disk and the
359 transition manager was a hit as this means that the files it contains
360 the checksums for can't be updated either (or they are and we are asking
361 for a hashsum mismatch to happen which helps nobody) */
362 bool pkgAcqTransactionItem::QueueURI(pkgAcquire::ItemDesc
&Item
)
364 if (TransactionManager
->State
!= TransactionStarted
)
366 if (_config
->FindB("Debug::Acquire::Transaction", false))
367 std::clog
<< "Skip " << Target
.URI
<< " as transaction was already dealt with!" << std::endl
;
370 std::string
const FinalFile
= GetFinalFilename();
371 if (TransactionManager
->IMSHit
== true && FileExists(FinalFile
) == true)
373 PartialFile
= DestFile
= FinalFile
;
377 // If we got the InRelease file via a mirror, pick all indexes directly from this mirror, too
378 if (TransactionManager
->BaseURI
.empty() == false &&
379 URI::SiteOnly(Item
.URI
) != URI::SiteOnly(TransactionManager
->BaseURI
))
381 // this ensures we rewrite only once and only the first step
382 auto const OldBaseURI
= Target
.Option(IndexTarget::BASE_URI
);
383 if (OldBaseURI
.empty() == false && APT::String::Startswith(Item
.URI
, OldBaseURI
))
385 auto const ExtraPath
= Item
.URI
.substr(OldBaseURI
.length());
386 Item
.URI
= flCombine(TransactionManager
->BaseURI
, ExtraPath
);
387 UsedMirror
= TransactionManager
->UsedMirror
;
388 if (Item
.Description
.find(" ") != string::npos
)
389 Item
.Description
.replace(0, Item
.Description
.find(" "), UsedMirror
);
392 return pkgAcquire::Item::QueueURI(Item
);
394 /* The transition manager InRelease itself (or its older sisters-in-law
395 Release & Release.gpg) is always queued as this allows us to rerun gpgv
396 on it to verify that we aren't stalled with old files */
397 bool pkgAcqMetaBase::QueueURI(pkgAcquire::ItemDesc
&Item
)
399 return pkgAcquire::Item::QueueURI(Item
);
401 /* the Diff/Index needs to queue also the up-to-date complete index file
402 to ensure that the list cleaner isn't eating it */
403 bool pkgAcqDiffIndex::QueueURI(pkgAcquire::ItemDesc
&Item
)
405 if (pkgAcqTransactionItem::QueueURI(Item
) == true)
411 // Acquire::Item::GetFinalFilename and specialisations for child classes /*{{{*/
412 std::string
pkgAcquire::Item::GetFinalFilename() const
414 // Beware: Desc.URI is modified by redirections
415 return GetFinalFileNameFromURI(Desc
.URI
);
417 std::string
pkgAcqDiffIndex::GetFinalFilename() const
419 return GetFinalFileNameFromURI(GetDiffIndexURI(Target
));
421 std::string
pkgAcqIndex::GetFinalFilename() const
423 std::string
const FinalFile
= GetFinalFileNameFromURI(Target
.URI
);
424 return GetKeepCompressedFileName(FinalFile
, Target
);
426 std::string
pkgAcqMetaSig::GetFinalFilename() const
428 return GetFinalFileNameFromURI(Target
.URI
);
430 std::string
pkgAcqBaseIndex::GetFinalFilename() const
432 return GetFinalFileNameFromURI(Target
.URI
);
434 std::string
pkgAcqMetaBase::GetFinalFilename() const
436 return GetFinalFileNameFromURI(Target
.URI
);
438 std::string
pkgAcqArchive::GetFinalFilename() const
440 return _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
443 // pkgAcqTransactionItem::GetMetaKey and specialisations for child classes /*{{{*/
444 std::string
pkgAcqTransactionItem::GetMetaKey() const
446 return Target
.MetaKey
;
448 std::string
pkgAcqIndex::GetMetaKey() const
450 if (Stage
== STAGE_DECOMPRESS_AND_VERIFY
|| CurrentCompressionExtension
== "uncompressed")
451 return Target
.MetaKey
;
452 return Target
.MetaKey
+ "." + CurrentCompressionExtension
;
454 std::string
pkgAcqDiffIndex::GetMetaKey() const
456 return GetDiffIndexFileName(Target
.MetaKey
);
459 //pkgAcqTransactionItem::TransactionState and specialisations for child classes /*{{{*/
460 bool pkgAcqTransactionItem::TransactionState(TransactionStates
const state
)
462 bool const Debug
= _config
->FindB("Debug::Acquire::Transaction", false);
465 case TransactionStarted
: _error
->Fatal("Item %s changed to invalid transaction start state!", Target
.URI
.c_str()); break;
466 case TransactionAbort
:
468 std::clog
<< " Cancel: " << DestFile
<< std::endl
;
469 if (Status
== pkgAcquire::Item::StatIdle
)
471 Status
= pkgAcquire::Item::StatDone
;
475 case TransactionCommit
:
476 if(PartialFile
.empty() == false)
478 bool sameFile
= (PartialFile
== DestFile
);
479 // we use symlinks on IMS-Hit to avoid copies
480 if (RealFileExists(DestFile
))
483 if (lstat(PartialFile
.c_str(), &Buf
) != -1)
485 if (S_ISLNK(Buf
.st_mode
) && Buf
.st_size
> 0)
487 char partial
[Buf
.st_size
+ 1];
488 ssize_t
const sp
= readlink(PartialFile
.c_str(), partial
, Buf
.st_size
);
490 _error
->Errno("pkgAcqTransactionItem::TransactionState-sp", _("Failed to readlink %s"), PartialFile
.c_str());
494 sameFile
= (DestFile
== partial
);
499 _error
->Errno("pkgAcqTransactionItem::TransactionState-stat", _("Failed to stat %s"), PartialFile
.c_str());
501 if (sameFile
== false)
503 // ensure that even without lists-cleanup all compressions are nuked
504 std::string FinalFile
= GetFinalFileNameFromURI(Target
.URI
);
505 if (FileExists(FinalFile
))
508 std::clog
<< "rm " << FinalFile
<< " # " << DescURI() << std::endl
;
509 if (RemoveFile("TransactionStates-Cleanup", FinalFile
) == false)
512 for (auto const &ext
: APT::Configuration::getCompressorExtensions())
514 auto const Final
= FinalFile
+ ext
;
515 if (FileExists(Final
))
518 std::clog
<< "rm " << Final
<< " # " << DescURI() << std::endl
;
519 if (RemoveFile("TransactionStates-Cleanup", Final
) == false)
524 std::clog
<< "mv " << PartialFile
<< " -> "<< DestFile
<< " # " << DescURI() << std::endl
;
525 if (Rename(PartialFile
, DestFile
) == false)
528 else if(Debug
== true)
529 std::clog
<< "keep " << PartialFile
<< " # " << DescURI() << std::endl
;
533 std::clog
<< "rm " << DestFile
<< " # " << DescURI() << std::endl
;
534 if (RemoveFile("TransItem::TransactionCommit", DestFile
) == false)
541 bool pkgAcqMetaBase::TransactionState(TransactionStates
const state
)
543 // Do not remove InRelease on IMSHit of Release.gpg [yes, this is very edgecasey]
544 if (TransactionManager
->IMSHit
== false)
545 return pkgAcqTransactionItem::TransactionState(state
);
548 bool pkgAcqIndex::TransactionState(TransactionStates
const state
)
550 if (pkgAcqTransactionItem::TransactionState(state
) == false)
555 case TransactionStarted
: _error
->Fatal("AcqIndex %s changed to invalid transaction start state!", Target
.URI
.c_str()); break;
556 case TransactionAbort
:
557 if (Stage
== STAGE_DECOMPRESS_AND_VERIFY
)
559 // keep the compressed file, but drop the decompressed
560 EraseFileName
.clear();
561 if (PartialFile
.empty() == false && flExtension(PartialFile
) != CurrentCompressionExtension
)
562 RemoveFile("TransactionAbort", PartialFile
);
565 case TransactionCommit
:
566 if (EraseFileName
.empty() == false)
567 RemoveFile("AcqIndex::TransactionCommit", EraseFileName
);
572 bool pkgAcqDiffIndex::TransactionState(TransactionStates
const state
)
574 if (pkgAcqTransactionItem::TransactionState(state
) == false)
579 case TransactionStarted
: _error
->Fatal("Item %s changed to invalid transaction start state!", Target
.URI
.c_str()); break;
580 case TransactionCommit
:
582 case TransactionAbort
:
583 std::string
const Partial
= GetPartialFileNameFromURI(Target
.URI
);
584 RemoveFile("TransactionAbort", Partial
);
592 class APT_HIDDEN NoActionItem
: public pkgAcquire::Item
/*{{{*/
593 /* The sole purpose of this class is having an item which does nothing to
594 reach its done state to prevent cleanup deleting the mentioned file.
595 Handy in cases in which we know we have the file already, like IMS-Hits. */
597 IndexTarget
const Target
;
599 virtual std::string
DescURI() const APT_OVERRIDE
{return Target
.URI
;};
600 virtual HashStringList
GetExpectedHashes() const APT_OVERRIDE
{return HashStringList();};
602 NoActionItem(pkgAcquire
* const Owner
, IndexTarget
const &Target
) :
603 pkgAcquire::Item(Owner
), Target(Target
)
606 DestFile
= GetFinalFileNameFromURI(Target
.URI
);
608 NoActionItem(pkgAcquire
* const Owner
, IndexTarget
const &Target
, std::string
const &FinalFile
) :
609 pkgAcquire::Item(Owner
), Target(Target
)
612 DestFile
= FinalFile
;
616 class APT_HIDDEN CleanupItem
: public pkgAcqTransactionItem
/*{{{*/
617 /* This class ensures that a file which was configured but isn't downloaded
618 for various reasons isn't kept in an old version in the lists directory.
619 In a way its the reverse of NoActionItem as it helps with removing files
620 even if the lists-cleanup is deactivated. */
623 virtual std::string
DescURI() const APT_OVERRIDE
{return Target
.URI
;};
624 virtual HashStringList
GetExpectedHashes() const APT_OVERRIDE
{return HashStringList();};
626 CleanupItem(pkgAcquire
* const Owner
, pkgAcqMetaClearSig
* const TransactionManager
, IndexTarget
const &Target
) :
627 pkgAcqTransactionItem(Owner
, TransactionManager
, Target
)
630 DestFile
= GetFinalFileNameFromURI(Target
.URI
);
632 bool TransactionState(TransactionStates
const state
) APT_OVERRIDE
636 case TransactionStarted
:
638 case TransactionAbort
:
640 case TransactionCommit
:
641 if (_config
->FindB("Debug::Acquire::Transaction", false) == true)
642 std::clog
<< "rm " << DestFile
<< " # " << DescURI() << std::endl
;
643 if (RemoveFile("TransItem::TransactionCommit", DestFile
) == false)
652 // Acquire::Item::Item - Constructor /*{{{*/
653 APT_IGNORE_DEPRECATED_PUSH
654 pkgAcquire::Item::Item(pkgAcquire
* const owner
) :
655 FileSize(0), PartialSize(0), Mode(0), ID(0), Complete(false), Local(false),
656 QueueCounter(0), ExpectedAdditionalItems(0), Owner(owner
), d(NULL
)
661 APT_IGNORE_DEPRECATED_POP
663 // Acquire::Item::~Item - Destructor /*{{{*/
664 pkgAcquire::Item::~Item()
669 std::string
pkgAcquire::Item::Custom600Headers() const /*{{{*/
671 return std::string();
674 std::string
pkgAcquire::Item::ShortDesc() const /*{{{*/
679 APT_CONST
void pkgAcquire::Item::Finished() /*{{{*/
683 APT_PURE pkgAcquire
* pkgAcquire::Item::GetOwner() const /*{{{*/
688 APT_CONST
pkgAcquire::ItemDesc
&pkgAcquire::Item::GetItemDesc() /*{{{*/
693 APT_CONST
bool pkgAcquire::Item::IsTrusted() const /*{{{*/
698 // Acquire::Item::Failed - Item failed to download /*{{{*/
699 // ---------------------------------------------------------------------
700 /* We return to an idle state if there are still other queues that could
702 void pkgAcquire::Item::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)
704 if (QueueCounter
<= 1)
706 /* This indicates that the file is not available right now but might
707 be sometime later. If we do a retry cycle then this should be
709 if (Cnf
!= NULL
&& Cnf
->LocalOnly
== true &&
710 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
726 case StatTransientNetworkError
:
733 string
const FailReason
= LookupTag(Message
, "FailReason");
734 enum { MAXIMUM_SIZE_EXCEEDED
, HASHSUM_MISMATCH
, WEAK_HASHSUMS
, OTHER
} failreason
= OTHER
;
735 if ( FailReason
== "MaximumSizeExceeded")
736 failreason
= MAXIMUM_SIZE_EXCEEDED
;
737 else if ( FailReason
== "WeakHashSums")
738 failreason
= WEAK_HASHSUMS
;
739 else if (Status
== StatAuthError
)
740 failreason
= HASHSUM_MISMATCH
;
742 if(ErrorText
.empty())
744 if (Status
== StatAuthError
)
746 std::ostringstream out
;
749 case HASHSUM_MISMATCH
:
750 out
<< _("Hash Sum mismatch") << std::endl
;
753 out
<< _("Insufficient information available to perform this download securely") << std::endl
;
755 case MAXIMUM_SIZE_EXCEEDED
:
757 out
<< LookupTag(Message
, "Message") << std::endl
;
760 auto const ExpectedHashes
= GetExpectedHashes();
761 if (ExpectedHashes
.empty() == false)
763 out
<< "Hashes of expected file:" << std::endl
;
764 for (auto const &hs
: ExpectedHashes
)
766 out
<< " - " << hs
.toStr();
767 if (hs
.usable() == false)
772 if (failreason
== HASHSUM_MISMATCH
)
774 out
<< "Hashes of received file:" << std::endl
;
775 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
777 std::string
const tagname
= std::string(*type
) + "-Hash";
778 std::string
const hashsum
= LookupTag(Message
, tagname
.c_str());
779 if (hashsum
.empty() == false)
781 auto const hs
= HashString(*type
, hashsum
);
782 out
<< " - " << hs
.toStr();
783 if (hs
.usable() == false)
788 out
<< "Last modification reported: " << LookupTag(Message
, "Last-Modified", "<none>") << std::endl
;
790 ErrorText
= out
.str();
793 ErrorText
= LookupTag(Message
,"Message");
798 case MAXIMUM_SIZE_EXCEEDED
: RenameOnError(MaximumSizeExceeded
); break;
799 case HASHSUM_MISMATCH
: RenameOnError(HashSumMismatch
); break;
800 case WEAK_HASHSUMS
: break;
804 if (FailReason
.empty() == false)
805 ReportMirrorFailureToCentral(*this, FailReason
, ErrorText
);
807 ReportMirrorFailureToCentral(*this, ErrorText
, ErrorText
);
809 if (QueueCounter
> 1)
813 // Acquire::Item::Start - Item has begun to download /*{{{*/
814 // ---------------------------------------------------------------------
815 /* Stash status and the file size. Note that setting Complete means
816 sub-phases of the acquire process such as decompresion are operating */
817 void pkgAcquire::Item::Start(string
const &/*Message*/, unsigned long long const Size
)
819 Status
= StatFetching
;
821 if (FileSize
== 0 && Complete
== false)
825 // Acquire::Item::VerifyDone - check if Item was downloaded OK /*{{{*/
826 /* Note that hash-verification is 'hardcoded' in acquire-worker and has
827 * already passed if this method is called. */
828 bool pkgAcquire::Item::VerifyDone(std::string
const &Message
,
829 pkgAcquire::MethodConfig
const * const /*Cnf*/)
831 std::string
const FileName
= LookupTag(Message
,"Filename");
832 if (FileName
.empty() == true)
835 ErrorText
= "Method gave a blank filename";
842 // Acquire::Item::Done - Item downloaded OK /*{{{*/
843 void pkgAcquire::Item::Done(string
const &/*Message*/, HashStringList
const &Hashes
,
844 pkgAcquire::MethodConfig
const * const /*Cnf*/)
846 // We just downloaded something..
849 unsigned long long const downloadedSize
= Hashes
.FileSize();
850 if (downloadedSize
!= 0)
852 FileSize
= downloadedSize
;
856 ErrorText
= string();
857 Owner
->Dequeue(this);
860 // Acquire::Item::Rename - Rename a file /*{{{*/
861 // ---------------------------------------------------------------------
862 /* This helper function is used by a lot of item methods as their final
864 bool pkgAcquire::Item::Rename(string
const &From
,string
const &To
)
866 if (From
== To
|| rename(From
.c_str(),To
.c_str()) == 0)
870 strprintf(S
, _("rename failed, %s (%s -> %s)."), strerror(errno
),
871 From
.c_str(),To
.c_str());
873 if (ErrorText
.empty())
876 ErrorText
= ErrorText
+ ": " + S
;
880 void pkgAcquire::Item::Dequeue() /*{{{*/
882 Owner
->Dequeue(this);
885 bool pkgAcquire::Item::RenameOnError(pkgAcquire::Item::RenameOnErrorState
const error
)/*{{{*/
887 if (RealFileExists(DestFile
))
888 Rename(DestFile
, DestFile
+ ".FAILED");
893 case HashSumMismatch
:
894 errtext
= _("Hash Sum mismatch");
897 errtext
= _("Size mismatch");
898 Status
= StatAuthError
;
901 errtext
= _("Invalid file format");
903 // do not report as usually its not the mirrors fault, but Portal/Proxy
906 errtext
= _("Signature error");
910 strprintf(errtext
, _("Clearsigned file isn't valid, got '%s' (does the network require authentication?)"), "NOSPLIT");
911 Status
= StatAuthError
;
913 case MaximumSizeExceeded
:
914 // the method is expected to report a good error for this
917 // no handling here, done by callers
920 if (ErrorText
.empty())
925 void pkgAcquire::Item::SetActiveSubprocess(const std::string
&subprocess
)/*{{{*/
927 ActiveSubprocess
= subprocess
;
928 APT_IGNORE_DEPRECATED(Mode
= ActiveSubprocess
.c_str();)
931 // Acquire::Item::ReportMirrorFailure /*{{{*/
932 void pkgAcquire::Item::ReportMirrorFailure(std::string
const &FailCode
)
934 ReportMirrorFailureToCentral(*this, FailCode
, FailCode
);
937 std::string
pkgAcquire::Item::HashSum() const /*{{{*/
939 HashStringList
const hashes
= GetExpectedHashes();
940 HashString
const * const hs
= hashes
.find(NULL
);
941 return hs
!= NULL
? hs
->toStr() : "";
945 pkgAcqTransactionItem::pkgAcqTransactionItem(pkgAcquire
* const Owner
, /*{{{*/
946 pkgAcqMetaClearSig
* const transactionManager
, IndexTarget
const &target
) :
947 pkgAcquire::Item(Owner
), d(NULL
), Target(target
), TransactionManager(transactionManager
)
949 if (TransactionManager
!= this)
950 TransactionManager
->Add(this);
953 pkgAcqTransactionItem::~pkgAcqTransactionItem() /*{{{*/
957 HashStringList
pkgAcqTransactionItem::GetExpectedHashesFor(std::string
const &MetaKey
) const /*{{{*/
959 return GetExpectedHashesFromFor(TransactionManager
->MetaIndexParser
, MetaKey
);
963 static void LoadLastMetaIndexParser(pkgAcqMetaClearSig
* const TransactionManager
, std::string
const &FinalRelease
, std::string
const &FinalInRelease
)/*{{{*/
965 if (TransactionManager
->IMSHit
== true)
967 if (RealFileExists(FinalInRelease
) || RealFileExists(FinalRelease
))
969 TransactionManager
->LastMetaIndexParser
= TransactionManager
->MetaIndexParser
->UnloadedClone();
970 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
972 _error
->PushToStack();
973 if (RealFileExists(FinalInRelease
))
974 TransactionManager
->LastMetaIndexParser
->Load(FinalInRelease
, NULL
);
976 TransactionManager
->LastMetaIndexParser
->Load(FinalRelease
, NULL
);
977 // its unlikely to happen, but if what we have is bad ignore it
978 if (_error
->PendingError())
980 delete TransactionManager
->LastMetaIndexParser
;
981 TransactionManager
->LastMetaIndexParser
= NULL
;
983 _error
->RevertToStack();
989 // AcqMetaBase - Constructor /*{{{*/
990 pkgAcqMetaBase::pkgAcqMetaBase(pkgAcquire
* const Owner
,
991 pkgAcqMetaClearSig
* const TransactionManager
,
992 IndexTarget
const &DataTarget
)
993 : pkgAcqTransactionItem(Owner
, TransactionManager
, DataTarget
), d(NULL
),
994 AuthPass(false), IMSHit(false), State(TransactionStarted
)
998 // AcqMetaBase::Add - Add a item to the current Transaction /*{{{*/
999 void pkgAcqMetaBase::Add(pkgAcqTransactionItem
* const I
)
1001 Transaction
.push_back(I
);
1004 // AcqMetaBase::AbortTransaction - Abort the current Transaction /*{{{*/
1005 void pkgAcqMetaBase::AbortTransaction()
1007 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1008 std::clog
<< "AbortTransaction: " << TransactionManager
<< std::endl
;
1010 switch (TransactionManager
->State
)
1012 case TransactionStarted
: break;
1013 case TransactionAbort
: _error
->Fatal("Transaction %s was already aborted and is aborted again", TransactionManager
->Target
.URI
.c_str()); return;
1014 case TransactionCommit
: _error
->Fatal("Transaction %s was already aborted and is now committed", TransactionManager
->Target
.URI
.c_str()); return;
1016 TransactionManager
->State
= TransactionAbort
;
1018 // ensure the toplevel is in error state too
1019 for (std::vector
<pkgAcqTransactionItem
*>::iterator I
= Transaction
.begin();
1020 I
!= Transaction
.end(); ++I
)
1022 if ((*I
)->Status
!= pkgAcquire::Item::StatFetching
)
1024 (*I
)->TransactionState(TransactionAbort
);
1026 Transaction
.clear();
1029 // AcqMetaBase::TransactionHasError - Check for errors in Transaction /*{{{*/
1030 APT_PURE
bool pkgAcqMetaBase::TransactionHasError() const
1032 for (std::vector
<pkgAcqTransactionItem
*>::const_iterator I
= Transaction
.begin();
1033 I
!= Transaction
.end(); ++I
)
1035 switch((*I
)->Status
) {
1036 case StatDone
: break;
1037 case StatIdle
: break;
1038 case StatAuthError
: return true;
1039 case StatError
: return true;
1040 case StatTransientNetworkError
: return true;
1041 case StatFetching
: break;
1047 // AcqMetaBase::CommitTransaction - Commit a transaction /*{{{*/
1048 void pkgAcqMetaBase::CommitTransaction()
1050 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1051 std::clog
<< "CommitTransaction: " << this << std::endl
;
1053 switch (TransactionManager
->State
)
1055 case TransactionStarted
: break;
1056 case TransactionAbort
: _error
->Fatal("Transaction %s was already committed and is now aborted", TransactionManager
->Target
.URI
.c_str()); return;
1057 case TransactionCommit
: _error
->Fatal("Transaction %s was already committed and is again committed", TransactionManager
->Target
.URI
.c_str()); return;
1059 TransactionManager
->State
= TransactionCommit
;
1061 // move new files into place *and* remove files that are not
1062 // part of the transaction but are still on disk
1063 for (std::vector
<pkgAcqTransactionItem
*>::iterator I
= Transaction
.begin();
1064 I
!= Transaction
.end(); ++I
)
1066 (*I
)->TransactionState(TransactionCommit
);
1068 Transaction
.clear();
1071 // AcqMetaBase::TransactionStageCopy - Stage a file for copying /*{{{*/
1072 void pkgAcqMetaBase::TransactionStageCopy(pkgAcqTransactionItem
* const I
,
1073 const std::string
&From
,
1074 const std::string
&To
)
1076 I
->PartialFile
= From
;
1080 // AcqMetaBase::TransactionStageRemoval - Stage a file for removal /*{{{*/
1081 void pkgAcqMetaBase::TransactionStageRemoval(pkgAcqTransactionItem
* const I
,
1082 const std::string
&FinalFile
)
1084 I
->PartialFile
= "";
1085 I
->DestFile
= FinalFile
;
1088 // AcqMetaBase::GenerateAuthWarning - Check gpg authentication error /*{{{*/
1089 /* This method is called from ::Failed handlers. If it returns true,
1090 no fallback to other files or modi is performed */
1091 bool pkgAcqMetaBase::CheckStopAuthentication(pkgAcquire::Item
* const I
, const std::string
&Message
)
1093 string
const Final
= I
->GetFinalFilename();
1094 std::string
const GPGError
= LookupTag(Message
, "Message");
1095 if (FileExists(Final
))
1097 I
->Status
= StatTransientNetworkError
;
1098 _error
->Warning(_("An error occurred during the signature verification. "
1099 "The repository is not updated and the previous index files will be used. "
1100 "GPG error: %s: %s"),
1101 Desc
.Description
.c_str(),
1103 RunScripts("APT::Update::Auth-Failure");
1105 } else if (LookupTag(Message
,"Message").find("NODATA") != string::npos
) {
1106 /* Invalid signature file, reject (LP: #346386) (Closes: #627642) */
1107 _error
->Error(_("GPG error: %s: %s"),
1108 Desc
.Description
.c_str(),
1110 I
->Status
= StatAuthError
;
1113 _error
->Warning(_("GPG error: %s: %s"),
1114 Desc
.Description
.c_str(),
1117 // gpgv method failed
1118 ReportMirrorFailureToCentral(*this, "GPGFailure", GPGError
);
1122 // AcqMetaBase::Custom600Headers - Get header for AcqMetaBase /*{{{*/
1123 // ---------------------------------------------------------------------
1124 string
pkgAcqMetaBase::Custom600Headers() const
1126 std::string Header
= "\nIndex-File: true";
1127 std::string MaximumSize
;
1128 strprintf(MaximumSize
, "\nMaximum-Size: %i",
1129 _config
->FindI("Acquire::MaxReleaseFileSize", 10*1000*1000));
1130 Header
+= MaximumSize
;
1132 string
const FinalFile
= GetFinalFilename();
1134 if (stat(FinalFile
.c_str(),&Buf
) == 0)
1135 Header
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1140 // AcqMetaBase::QueueForSignatureVerify /*{{{*/
1141 void pkgAcqMetaBase::QueueForSignatureVerify(pkgAcqTransactionItem
* const I
, std::string
const &File
, std::string
const &Signature
)
1144 I
->Desc
.URI
= "gpgv:" + Signature
;
1147 I
->SetActiveSubprocess("gpgv");
1150 // AcqMetaBase::CheckDownloadDone /*{{{*/
1151 bool pkgAcqMetaBase::CheckDownloadDone(pkgAcqTransactionItem
* const I
, const std::string
&Message
, HashStringList
const &Hashes
) const
1153 // We have just finished downloading a Release file (it is not
1156 // Save the final base URI we got this Release file from
1157 if (I
->UsedMirror
.empty() == false && _config
->FindB("Acquire::SameMirrorForAllIndexes", true))
1159 if (APT::String::Endswith(I
->Desc
.URI
, "InRelease"))
1160 TransactionManager
->BaseURI
= I
->Desc
.URI
.substr(0, I
->Desc
.URI
.length() - strlen("InRelease"));
1161 else if (APT::String::Endswith(I
->Desc
.URI
, "Release"))
1162 TransactionManager
->BaseURI
= I
->Desc
.URI
.substr(0, I
->Desc
.URI
.length() - strlen("Release"));
1165 std::string
const FileName
= LookupTag(Message
,"Filename");
1166 if (FileName
!= I
->DestFile
&& RealFileExists(I
->DestFile
) == false)
1169 I
->Desc
.URI
= "copy:" + FileName
;
1170 I
->QueueURI(I
->Desc
);
1174 // make sure to verify against the right file on I-M-S hit
1175 bool IMSHit
= StringToBool(LookupTag(Message
,"IMS-Hit"), false);
1176 if (IMSHit
== false && Hashes
.usable())
1178 // detect IMS-Hits servers haven't detected by Hash comparison
1179 std::string
const FinalFile
= I
->GetFinalFilename();
1180 if (RealFileExists(FinalFile
) && Hashes
.VerifyFile(FinalFile
) == true)
1183 RemoveFile("CheckDownloadDone", I
->DestFile
);
1189 // for simplicity, the transaction manager is always InRelease
1190 // even if it doesn't exist.
1191 TransactionManager
->IMSHit
= true;
1192 I
->PartialFile
= I
->DestFile
= I
->GetFinalFilename();
1195 // set Item to complete as the remaining work is all local (verify etc)
1201 bool pkgAcqMetaBase::CheckAuthDone(string
const &Message
) /*{{{*/
1203 // At this point, the gpgv method has succeeded, so there is a
1204 // valid signature from a key in the trusted keyring. We
1205 // perform additional verification of its contents, and use them
1206 // to verify the indexes we are about to download
1207 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1208 std::cerr
<< "Signature verification succeeded: " << DestFile
<< std::endl
;
1210 if (TransactionManager
->IMSHit
== false)
1212 // open the last (In)Release if we have it
1213 std::string
const FinalFile
= GetFinalFilename();
1214 std::string FinalRelease
;
1215 std::string FinalInRelease
;
1216 if (APT::String::Endswith(FinalFile
, "InRelease"))
1218 FinalInRelease
= FinalFile
;
1219 FinalRelease
= FinalFile
.substr(0, FinalFile
.length() - strlen("InRelease")) + "Release";
1223 FinalInRelease
= FinalFile
.substr(0, FinalFile
.length() - strlen("Release")) + "InRelease";
1224 FinalRelease
= FinalFile
;
1226 LoadLastMetaIndexParser(TransactionManager
, FinalRelease
, FinalInRelease
);
1229 bool const GoodAuth
= TransactionManager
->MetaIndexParser
->Load(DestFile
, &ErrorText
);
1230 if (GoodAuth
== false && AllowInsecureRepositories(InsecureType::WEAK
, Target
.Description
, TransactionManager
->MetaIndexParser
, TransactionManager
, this) == false)
1232 Status
= StatAuthError
;
1236 if (!VerifyVendor(Message
))
1238 Status
= StatAuthError
;
1242 // Download further indexes with verification
1243 TransactionManager
->QueueIndexes(GoodAuth
);
1248 void pkgAcqMetaClearSig::QueueIndexes(bool const verify
) /*{{{*/
1250 // at this point the real Items are loaded in the fetcher
1251 ExpectedAdditionalItems
= 0;
1253 std::set
<std::string
> targetsSeen
;
1254 bool const hasReleaseFile
= TransactionManager
->MetaIndexParser
!= NULL
;
1255 bool const metaBaseSupportsByHash
= hasReleaseFile
&& TransactionManager
->MetaIndexParser
->GetSupportsAcquireByHash();
1256 bool hasHashes
= true;
1257 auto IndexTargets
= TransactionManager
->MetaIndexParser
->GetIndexTargets();
1258 if (hasReleaseFile
&& verify
== false)
1259 hasHashes
= std::any_of(IndexTargets
.begin(), IndexTargets
.end(),
1260 [&](IndexTarget
const &Target
) { return TransactionManager
->MetaIndexParser
->Exists(Target
.MetaKey
); });
1261 for (auto&& Target
: IndexTargets
)
1263 // if we have seen a target which is created-by a target this one here is declared a
1264 // fallback to, we skip acquiring the fallback (but we make sure we clean up)
1265 if (targetsSeen
.find(Target
.Option(IndexTarget::FALLBACK_OF
)) != targetsSeen
.end())
1267 targetsSeen
.emplace(Target
.Option(IndexTarget::CREATED_BY
));
1268 new CleanupItem(Owner
, TransactionManager
, Target
);
1271 // all is an implementation detail. Users shouldn't use this as arch
1272 // We need this support trickery here as e.g. Debian has binary-all files already,
1273 // but arch:all packages are still in the arch:any files, so we would waste precious
1274 // download time, bandwidth and diskspace for nothing, BUT Debian doesn't feature all
1275 // in the set of supported architectures, so we can filter based on this property rather
1276 // than invent an entirely new flag we would need to carry for all of eternity.
1277 if (hasReleaseFile
&& Target
.Option(IndexTarget::ARCHITECTURE
) == "all")
1279 if (TransactionManager
->MetaIndexParser
->IsArchitectureSupported("all") == false ||
1280 TransactionManager
->MetaIndexParser
->IsArchitectureAllSupportedFor(Target
) == false)
1282 new CleanupItem(Owner
, TransactionManager
, Target
);
1287 bool trypdiff
= Target
.OptionBool(IndexTarget::PDIFFS
);
1288 if (hasReleaseFile
== true)
1290 if (TransactionManager
->MetaIndexParser
->Exists(Target
.MetaKey
) == false)
1292 // optional targets that we do not have in the Release file are skipped
1293 if (hasHashes
== true && Target
.IsOptional
)
1295 new CleanupItem(Owner
, TransactionManager
, Target
);
1299 std::string
const &arch
= Target
.Option(IndexTarget::ARCHITECTURE
);
1300 if (arch
.empty() == false)
1302 if (TransactionManager
->MetaIndexParser
->IsArchitectureSupported(arch
) == false)
1304 new CleanupItem(Owner
, TransactionManager
, Target
);
1305 _error
->Notice(_("Skipping acquire of configured file '%s' as repository '%s' doesn't support architecture '%s'"),
1306 Target
.MetaKey
.c_str(), TransactionManager
->Target
.Description
.c_str(), arch
.c_str());
1309 // if the architecture is officially supported but currently no packages for it available,
1310 // ignore silently as this is pretty much the same as just shipping an empty file.
1311 // if we don't know which architectures are supported, we do NOT ignore it to notify user about this
1312 if (hasHashes
== true && TransactionManager
->MetaIndexParser
->IsArchitectureSupported("*undefined*") == false)
1314 new CleanupItem(Owner
, TransactionManager
, Target
);
1319 if (hasHashes
== true)
1321 Status
= StatAuthError
;
1322 strprintf(ErrorText
, _("Unable to find expected entry '%s' in Release file (Wrong sources.list entry or malformed file)"), Target
.MetaKey
.c_str());
1327 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
1333 auto const hashes
= GetExpectedHashesFor(Target
.MetaKey
);
1334 if (hashes
.empty() == false)
1336 if (hashes
.usable() == false)
1338 new CleanupItem(Owner
, TransactionManager
, Target
);
1339 _error
->Warning(_("Skipping acquire of configured file '%s' as repository '%s' provides only weak security information for it"),
1340 Target
.MetaKey
.c_str(), TransactionManager
->Target
.Description
.c_str());
1343 // empty files are skipped as acquiring the very small compressed files is a waste of time
1344 else if (hashes
.FileSize() == 0)
1346 new CleanupItem(Owner
, TransactionManager
, Target
);
1347 targetsSeen
.emplace(Target
.Option(IndexTarget::CREATED_BY
));
1353 // autoselect the compression method
1354 std::vector
<std::string
> types
= VectorizeString(Target
.Option(IndexTarget::COMPRESSIONTYPES
), ' ');
1355 types
.erase(std::remove_if(types
.begin(), types
.end(), [&](std::string
const &t
) {
1356 if (t
== "uncompressed")
1357 return TransactionManager
->MetaIndexParser
->Exists(Target
.MetaKey
) == false;
1358 std::string
const MetaKey
= Target
.MetaKey
+ "." + t
;
1359 return TransactionManager
->MetaIndexParser
->Exists(MetaKey
) == false;
1361 if (types
.empty() == false)
1363 std::ostringstream os
;
1364 // add the special compressiontype byhash first if supported
1365 std::string
const useByHashConf
= Target
.Option(IndexTarget::BY_HASH
);
1366 bool useByHash
= false;
1367 if(useByHashConf
== "force")
1370 useByHash
= StringToBool(useByHashConf
) == true && metaBaseSupportsByHash
;
1371 if (useByHash
== true)
1373 std::copy(types
.begin(), types
.end()-1, std::ostream_iterator
<std::string
>(os
, " "));
1374 os
<< *types
.rbegin();
1375 Target
.Options
["COMPRESSIONTYPES"] = os
.str();
1378 Target
.Options
["COMPRESSIONTYPES"].clear();
1380 std::string filename
= GetExistingFilename(GetFinalFileNameFromURI(Target
.URI
));
1381 if (filename
.empty() == false)
1383 // if the Release file is a hit and we have an index it must be the current one
1384 if (TransactionManager
->IMSHit
== true)
1386 else if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1388 // see if the file changed since the last Release file
1389 // we use the uncompressed files as we might compress differently compared to the server,
1390 // so the hashes might not match, even if they contain the same data.
1391 HashStringList
const newFile
= GetExpectedHashesFromFor(TransactionManager
->MetaIndexParser
, Target
.MetaKey
);
1392 HashStringList
const oldFile
= GetExpectedHashesFromFor(TransactionManager
->LastMetaIndexParser
, Target
.MetaKey
);
1393 if (newFile
!= oldFile
)
1400 trypdiff
= false; // no file to patch
1402 if (filename
.empty() == false)
1404 new NoActionItem(Owner
, Target
, filename
);
1405 std::string
const idxfilename
= GetFinalFileNameFromURI(GetDiffIndexURI(Target
));
1406 if (FileExists(idxfilename
))
1407 new NoActionItem(Owner
, Target
, idxfilename
);
1408 targetsSeen
.emplace(Target
.Option(IndexTarget::CREATED_BY
));
1412 // check if we have patches available
1413 trypdiff
&= TransactionManager
->MetaIndexParser
->Exists(GetDiffIndexFileName(Target
.MetaKey
));
1417 // if we have no file to patch, no point in trying
1418 trypdiff
&= (GetExistingFilename(GetFinalFileNameFromURI(Target
.URI
)).empty() == false);
1421 // no point in patching from local sources
1424 std::string
const proto
= Target
.URI
.substr(0, strlen("file:/"));
1425 if (proto
== "file:/" || proto
== "copy:/" || proto
== "cdrom:")
1429 // Queue the Index file (Packages, Sources, Translation-$foo, …)
1430 targetsSeen
.emplace(Target
.Option(IndexTarget::CREATED_BY
));
1432 new pkgAcqDiffIndex(Owner
, TransactionManager
, Target
);
1434 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
1438 bool pkgAcqMetaBase::VerifyVendor(string
const &) /*{{{*/
1440 string Transformed
= TransactionManager
->MetaIndexParser
->GetExpectedDist();
1442 if (Transformed
== "../project/experimental")
1444 Transformed
= "experimental";
1447 auto pos
= Transformed
.rfind('/');
1448 if (pos
!= string::npos
)
1450 Transformed
= Transformed
.substr(0, pos
);
1453 if (Transformed
== ".")
1458 if (TransactionManager
->MetaIndexParser
->GetValidUntil() > 0)
1460 time_t const invalid_since
= time(NULL
) - TransactionManager
->MetaIndexParser
->GetValidUntil();
1461 if (invalid_since
> 0)
1465 // TRANSLATOR: The first %s is the URL of the bad Release file, the second is
1466 // the time since then the file is invalid - formatted in the same way as in
1467 // the download progress display (e.g. 7d 3h 42min 1s)
1468 _("Release file for %s is expired (invalid since %s). "
1469 "Updates for this repository will not be applied."),
1470 Target
.URI
.c_str(), TimeToStr(invalid_since
).c_str());
1471 if (ErrorText
.empty())
1473 return _error
->Error("%s", errmsg
.c_str());
1477 /* Did we get a file older than what we have? This is a last minute IMS hit and doubles
1478 as a prevention of downgrading us to older (still valid) files */
1479 if (TransactionManager
->IMSHit
== false && TransactionManager
->LastMetaIndexParser
!= NULL
&&
1480 TransactionManager
->LastMetaIndexParser
->GetDate() > TransactionManager
->MetaIndexParser
->GetDate())
1482 TransactionManager
->IMSHit
= true;
1483 RemoveFile("VerifyVendor", DestFile
);
1484 PartialFile
= DestFile
= GetFinalFilename();
1485 // load the 'old' file in the 'new' one instead of flipping pointers as
1486 // the new one isn't owned by us, while the old one is so cleanup would be confused.
1487 TransactionManager
->MetaIndexParser
->swapLoad(TransactionManager
->LastMetaIndexParser
);
1488 delete TransactionManager
->LastMetaIndexParser
;
1489 TransactionManager
->LastMetaIndexParser
= NULL
;
1492 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1494 std::cerr
<< "Got Codename: " << TransactionManager
->MetaIndexParser
->GetCodename() << std::endl
;
1495 std::cerr
<< "Expecting Dist: " << TransactionManager
->MetaIndexParser
->GetExpectedDist() << std::endl
;
1496 std::cerr
<< "Transformed Dist: " << Transformed
<< std::endl
;
1499 if (TransactionManager
->MetaIndexParser
->CheckDist(Transformed
) == false)
1501 // This might become fatal one day
1502 // Status = StatAuthError;
1503 // ErrorText = "Conflicting distribution; expected "
1504 // + MetaIndexParser->GetExpectedDist() + " but got "
1505 // + MetaIndexParser->GetCodename();
1507 if (!Transformed
.empty())
1509 _error
->Warning(_("Conflicting distribution: %s (expected %s but got %s)"),
1510 Desc
.Description
.c_str(),
1511 Transformed
.c_str(),
1512 TransactionManager
->MetaIndexParser
->GetCodename().c_str());
1519 pkgAcqMetaBase::~pkgAcqMetaBase()
1523 pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire
* const Owner
, /*{{{*/
1524 IndexTarget
const &ClearsignedTarget
,
1525 IndexTarget
const &DetachedDataTarget
, IndexTarget
const &DetachedSigTarget
,
1526 metaIndex
* const MetaIndexParser
) :
1527 pkgAcqMetaIndex(Owner
, this, ClearsignedTarget
, DetachedSigTarget
),
1528 d(NULL
), ClearsignedTarget(ClearsignedTarget
),
1529 DetachedDataTarget(DetachedDataTarget
),
1530 MetaIndexParser(MetaIndexParser
), LastMetaIndexParser(NULL
)
1532 // index targets + (worst case:) Release/Release.gpg
1533 ExpectedAdditionalItems
= std::numeric_limits
<decltype(ExpectedAdditionalItems
)>::max();
1534 TransactionManager
->Add(this);
1537 pkgAcqMetaClearSig::~pkgAcqMetaClearSig() /*{{{*/
1539 if (LastMetaIndexParser
!= NULL
)
1540 delete LastMetaIndexParser
;
1543 // pkgAcqMetaClearSig::Custom600Headers - Insert custom request headers /*{{{*/
1544 string
pkgAcqMetaClearSig::Custom600Headers() const
1546 string Header
= pkgAcqMetaBase::Custom600Headers();
1547 Header
+= "\nFail-Ignore: true";
1548 std::string
const key
= TransactionManager
->MetaIndexParser
->GetSignedBy();
1549 if (key
.empty() == false)
1550 Header
+= "\nSigned-By: " + key
;
1555 void pkgAcqMetaClearSig::Finished() /*{{{*/
1557 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1558 std::clog
<< "Finished: " << DestFile
<<std::endl
;
1559 if(TransactionManager
->State
== TransactionStarted
&&
1560 TransactionManager
->TransactionHasError() == false)
1561 TransactionManager
->CommitTransaction();
1564 bool pkgAcqMetaClearSig::VerifyDone(std::string
const &Message
, /*{{{*/
1565 pkgAcquire::MethodConfig
const * const Cnf
)
1567 Item::VerifyDone(Message
, Cnf
);
1569 if (FileExists(DestFile
) && !StartsWithGPGClearTextSignature(DestFile
))
1570 return RenameOnError(NotClearsigned
);
1575 // pkgAcqMetaClearSig::Done - We got a file /*{{{*/
1576 void pkgAcqMetaClearSig::Done(std::string
const &Message
,
1577 HashStringList
const &Hashes
,
1578 pkgAcquire::MethodConfig
const * const Cnf
)
1580 Item::Done(Message
, Hashes
, Cnf
);
1582 if(AuthPass
== false)
1584 if(CheckDownloadDone(this, Message
, Hashes
) == true)
1585 QueueForSignatureVerify(this, DestFile
, DestFile
);
1588 else if(CheckAuthDone(Message
) == true)
1590 if (TransactionManager
->IMSHit
== false)
1591 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
1592 else if (RealFileExists(GetFinalFilename()) == false)
1594 // We got an InRelease file IMSHit, but we haven't one, which means
1595 // we had a valid Release/Release.gpg combo stepping in, which we have
1596 // to 'acquire' now to ensure list cleanup isn't removing them
1597 new NoActionItem(Owner
, DetachedDataTarget
);
1598 new NoActionItem(Owner
, DetachedSigTarget
);
1601 else if (Status
!= StatAuthError
)
1603 string
const FinalFile
= GetFinalFileNameFromURI(DetachedDataTarget
.URI
);
1604 string
const OldFile
= GetFinalFilename();
1605 if (TransactionManager
->IMSHit
== false)
1606 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
1607 else if (RealFileExists(OldFile
) == false)
1608 new NoActionItem(Owner
, DetachedDataTarget
);
1610 TransactionManager
->TransactionStageCopy(this, OldFile
, FinalFile
);
1614 void pkgAcqMetaClearSig::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
) /*{{{*/
1616 Item::Failed(Message
, Cnf
);
1618 if (AuthPass
== false)
1620 if (Status
== StatAuthError
|| Status
== StatTransientNetworkError
)
1622 // if we expected a ClearTextSignature (InRelease) but got a network
1623 // error or got a file, but it wasn't valid, we end up here (see VerifyDone).
1624 // As these is usually called by web-portals we do not try Release/Release.gpg
1625 // as this is gonna fail anyway and instead abort our try (LP#346386)
1626 TransactionManager
->AbortTransaction();
1630 // Queue the 'old' InRelease file for removal if we try Release.gpg
1631 // as otherwise the file will stay around and gives a false-auth
1632 // impression (CVE-2012-0214)
1633 TransactionManager
->TransactionStageRemoval(this, GetFinalFilename());
1636 new pkgAcqMetaIndex(Owner
, TransactionManager
, DetachedDataTarget
, DetachedSigTarget
);
1640 if(CheckStopAuthentication(this, Message
))
1643 if(AllowInsecureRepositories(InsecureType::UNSIGNED
, ClearsignedTarget
.Description
, TransactionManager
->MetaIndexParser
, TransactionManager
, this) == true)
1647 /* InRelease files become Release files, otherwise
1648 * they would be considered as trusted later on */
1649 string
const FinalRelease
= GetFinalFileNameFromURI(DetachedDataTarget
.URI
);
1650 string
const PartialRelease
= GetPartialFileNameFromURI(DetachedDataTarget
.URI
);
1651 string
const FinalReleasegpg
= GetFinalFileNameFromURI(DetachedSigTarget
.URI
);
1652 string
const FinalInRelease
= GetFinalFilename();
1653 Rename(DestFile
, PartialRelease
);
1654 TransactionManager
->TransactionStageCopy(this, PartialRelease
, FinalRelease
);
1655 LoadLastMetaIndexParser(TransactionManager
, FinalRelease
, FinalInRelease
);
1657 // we parse the indexes here because at this point the user wanted
1658 // a repository that may potentially harm him
1659 if (TransactionManager
->MetaIndexParser
->Load(PartialRelease
, &ErrorText
) == false || VerifyVendor(Message
) == false)
1660 /* expired Release files are still a problem you need extra force for */;
1662 TransactionManager
->QueueIndexes(true);
1668 pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire
* const Owner
, /*{{{*/
1669 pkgAcqMetaClearSig
* const TransactionManager
,
1670 IndexTarget
const &DataTarget
,
1671 IndexTarget
const &DetachedSigTarget
) :
1672 pkgAcqMetaBase(Owner
, TransactionManager
, DataTarget
), d(NULL
),
1673 DetachedSigTarget(DetachedSigTarget
)
1675 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1676 std::clog
<< "New pkgAcqMetaIndex with TransactionManager "
1677 << this->TransactionManager
<< std::endl
;
1679 DestFile
= GetPartialFileNameFromURI(DataTarget
.URI
);
1682 Desc
.Description
= DataTarget
.Description
;
1684 Desc
.ShortDesc
= DataTarget
.ShortDesc
;
1685 Desc
.URI
= DataTarget
.URI
;
1689 void pkgAcqMetaIndex::Done(string
const &Message
, /*{{{*/
1690 HashStringList
const &Hashes
,
1691 pkgAcquire::MethodConfig
const * const Cfg
)
1693 Item::Done(Message
,Hashes
,Cfg
);
1695 if(CheckDownloadDone(this, Message
, Hashes
))
1697 // we have a Release file, now download the Signature, all further
1698 // verify/queue for additional downloads will be done in the
1699 // pkgAcqMetaSig::Done() code
1700 new pkgAcqMetaSig(Owner
, TransactionManager
, DetachedSigTarget
, this);
1704 // pkgAcqMetaIndex::Failed - no Release file present /*{{{*/
1705 void pkgAcqMetaIndex::Failed(string
const &Message
,
1706 pkgAcquire::MethodConfig
const * const Cnf
)
1708 pkgAcquire::Item::Failed(Message
, Cnf
);
1711 // No Release file was present so fall
1712 // back to queueing Packages files without verification
1713 // only allow going further if the user explicitly wants it
1714 if(AllowInsecureRepositories(InsecureType::NORELEASE
, Target
.Description
, TransactionManager
->MetaIndexParser
, TransactionManager
, this) == true)
1716 // ensure old Release files are removed
1717 TransactionManager
->TransactionStageRemoval(this, GetFinalFilename());
1719 // queue without any kind of hashsum support
1720 TransactionManager
->QueueIndexes(false);
1724 std::string
pkgAcqMetaIndex::DescURI() const /*{{{*/
1729 pkgAcqMetaIndex::~pkgAcqMetaIndex() {}
1731 // AcqMetaSig::AcqMetaSig - Constructor /*{{{*/
1732 pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire
* const Owner
,
1733 pkgAcqMetaClearSig
* const TransactionManager
,
1734 IndexTarget
const &Target
,
1735 pkgAcqMetaIndex
* const MetaIndex
) :
1736 pkgAcqTransactionItem(Owner
, TransactionManager
, Target
), d(NULL
), MetaIndex(MetaIndex
)
1738 DestFile
= GetPartialFileNameFromURI(Target
.URI
);
1740 // remove any partial downloaded sig-file in partial/.
1741 // it may confuse proxies and is too small to warrant a
1742 // partial download anyway
1743 RemoveFile("pkgAcqMetaSig", DestFile
);
1745 // set the TransactionManager
1746 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1747 std::clog
<< "New pkgAcqMetaSig with TransactionManager "
1748 << TransactionManager
<< std::endl
;
1751 Desc
.Description
= Target
.Description
;
1753 Desc
.ShortDesc
= Target
.ShortDesc
;
1754 Desc
.URI
= Target
.URI
;
1756 // If we got a hit for Release, we will get one for Release.gpg too (or obscure errors),
1757 // so we skip the download step and go instantly to verification
1758 if (TransactionManager
->IMSHit
== true && RealFileExists(GetFinalFilename()))
1762 PartialFile
= DestFile
= GetFinalFilename();
1763 MetaIndexFileSignature
= DestFile
;
1764 MetaIndex
->QueueForSignatureVerify(this, MetaIndex
->DestFile
, DestFile
);
1770 pkgAcqMetaSig::~pkgAcqMetaSig() /*{{{*/
1774 // pkgAcqMetaSig::Custom600Headers - Insert custom request headers /*{{{*/
1775 std::string
pkgAcqMetaSig::Custom600Headers() const
1777 std::string Header
= pkgAcqTransactionItem::Custom600Headers();
1778 std::string
const key
= TransactionManager
->MetaIndexParser
->GetSignedBy();
1779 if (key
.empty() == false)
1780 Header
+= "\nSigned-By: " + key
;
1784 // AcqMetaSig::Done - The signature was downloaded/verified /*{{{*/
1785 void pkgAcqMetaSig::Done(string
const &Message
, HashStringList
const &Hashes
,
1786 pkgAcquire::MethodConfig
const * const Cfg
)
1788 if (MetaIndexFileSignature
.empty() == false)
1790 DestFile
= MetaIndexFileSignature
;
1791 MetaIndexFileSignature
.clear();
1793 Item::Done(Message
, Hashes
, Cfg
);
1795 if(MetaIndex
->AuthPass
== false)
1797 if(MetaIndex
->CheckDownloadDone(this, Message
, Hashes
) == true)
1799 // destfile will be modified to point to MetaIndexFile for the
1800 // gpgv method, so we need to save it here
1801 MetaIndexFileSignature
= DestFile
;
1802 MetaIndex
->QueueForSignatureVerify(this, MetaIndex
->DestFile
, DestFile
);
1806 else if(MetaIndex
->CheckAuthDone(Message
) == true)
1808 if (TransactionManager
->IMSHit
== false)
1810 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
1811 TransactionManager
->TransactionStageCopy(MetaIndex
, MetaIndex
->DestFile
, MetaIndex
->GetFinalFilename());
1814 else if (MetaIndex
->Status
!= StatAuthError
)
1816 std::string
const FinalFile
= MetaIndex
->GetFinalFilename();
1817 if (TransactionManager
->IMSHit
== false)
1818 TransactionManager
->TransactionStageCopy(MetaIndex
, MetaIndex
->DestFile
, FinalFile
);
1820 TransactionManager
->TransactionStageCopy(MetaIndex
, FinalFile
, FinalFile
);
1824 void pkgAcqMetaSig::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
1826 Item::Failed(Message
,Cnf
);
1828 // check if we need to fail at this point
1829 if (MetaIndex
->AuthPass
== true && MetaIndex
->CheckStopAuthentication(this, Message
))
1832 // ensures that a Release.gpg file in the lists/ is removed by the transaction
1833 TransactionManager
->TransactionStageRemoval(this, DestFile
);
1835 // only allow going further if the user explicitly wants it
1836 if (AllowInsecureRepositories(InsecureType::UNSIGNED
, MetaIndex
->Target
.Description
, TransactionManager
->MetaIndexParser
, TransactionManager
, this) == true)
1838 string
const FinalRelease
= MetaIndex
->GetFinalFilename();
1839 string
const FinalInRelease
= TransactionManager
->GetFinalFilename();
1840 LoadLastMetaIndexParser(TransactionManager
, FinalRelease
, FinalInRelease
);
1842 // we parse the indexes here because at this point the user wanted
1843 // a repository that may potentially harm him
1844 bool const GoodLoad
= TransactionManager
->MetaIndexParser
->Load(MetaIndex
->DestFile
, &ErrorText
);
1845 if (MetaIndex
->VerifyVendor(Message
) == false)
1846 /* expired Release files are still a problem you need extra force for */;
1848 TransactionManager
->QueueIndexes(GoodLoad
);
1850 TransactionManager
->TransactionStageCopy(MetaIndex
, MetaIndex
->DestFile
, FinalRelease
);
1852 else if (TransactionManager
->IMSHit
== false)
1853 Rename(MetaIndex
->DestFile
, MetaIndex
->DestFile
+ ".FAILED");
1855 // FIXME: this is used often (e.g. in pkgAcqIndexTrans) so refactor
1856 if (Cnf
->LocalOnly
== true ||
1857 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1866 // AcqBaseIndex - Constructor /*{{{*/
1867 pkgAcqBaseIndex::pkgAcqBaseIndex(pkgAcquire
* const Owner
,
1868 pkgAcqMetaClearSig
* const TransactionManager
,
1869 IndexTarget
const &Target
)
1870 : pkgAcqTransactionItem(Owner
, TransactionManager
, Target
), d(NULL
)
1874 void pkgAcqBaseIndex::Failed(std::string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
1876 pkgAcquire::Item::Failed(Message
, Cnf
);
1877 if (Status
!= StatAuthError
)
1880 ErrorText
.append("Release file created at: ");
1881 auto const timespec
= TransactionManager
->MetaIndexParser
->GetDate();
1883 ErrorText
.append("<unknown>");
1885 ErrorText
.append(TimeRFC1123(timespec
));
1886 ErrorText
.append("\n");
1889 pkgAcqBaseIndex::~pkgAcqBaseIndex() {}
1891 // AcqDiffIndex::AcqDiffIndex - Constructor /*{{{*/
1892 // ---------------------------------------------------------------------
1893 /* Get the DiffIndex file first and see if there are patches available
1894 * If so, create a pkgAcqIndexDiffs fetcher that will get and apply the
1895 * patches. If anything goes wrong in that process, it will fall back to
1896 * the original packages file
1898 pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire
* const Owner
,
1899 pkgAcqMetaClearSig
* const TransactionManager
,
1900 IndexTarget
const &Target
)
1901 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
), diffs(NULL
)
1903 // FIXME: Magic number as an upper bound on pdiffs we will reasonably acquire
1904 ExpectedAdditionalItems
= 40;
1906 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
1909 Desc
.Description
= GetDiffIndexFileName(Target
.Description
);
1910 Desc
.ShortDesc
= Target
.ShortDesc
;
1911 Desc
.URI
= GetDiffIndexURI(Target
);
1913 DestFile
= GetPartialFileNameFromURI(Desc
.URI
);
1916 std::clog
<< "pkgAcqDiffIndex: " << Desc
.URI
<< std::endl
;
1921 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
1922 // ---------------------------------------------------------------------
1923 /* The only header we use is the last-modified header. */
1924 string
pkgAcqDiffIndex::Custom600Headers() const
1926 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1927 return "\nIndex-File: true";
1929 string
const Final
= GetFinalFilename();
1932 std::clog
<< "Custom600Header-IMS: " << Final
<< std::endl
;
1935 if (stat(Final
.c_str(),&Buf
) != 0)
1936 return "\nIndex-File: true";
1938 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1941 void pkgAcqDiffIndex::QueueOnIMSHit() const /*{{{*/
1943 // list cleanup needs to know that this file as well as the already
1944 // present index is ours, so we create an empty diff to save it for us
1945 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
);
1948 bool pkgAcqDiffIndex::ParseDiffIndex(string
const &IndexDiffFile
) /*{{{*/
1950 ExpectedAdditionalItems
= 0;
1951 // failing here is fine: our caller will take care of trying to
1952 // get the complete file if patching fails
1954 std::clog
<< "pkgAcqDiffIndex::ParseIndexDiff() " << IndexDiffFile
1957 FileFd
Fd(IndexDiffFile
,FileFd::ReadOnly
);
1959 if (Fd
.IsOpen() == false || Fd
.Failed())
1963 if(unlikely(TF
.Step(Tags
) == false))
1966 HashStringList ServerHashes
;
1967 unsigned long long ServerSize
= 0;
1969 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
1971 std::string tagname
= *type
;
1972 tagname
.append("-Current");
1973 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1974 if (tmp
.empty() == true)
1978 unsigned long long size
;
1979 std::stringstream
ss(tmp
);
1981 if (unlikely(hash
.empty() == true))
1983 if (unlikely(ServerSize
!= 0 && ServerSize
!= size
))
1985 ServerHashes
.push_back(HashString(*type
, hash
));
1989 if (ServerHashes
.usable() == false)
1992 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": Did not find a good hashsum in the index" << std::endl
;
1996 std::string
const CurrentPackagesFile
= GetFinalFileNameFromURI(Target
.URI
);
1997 HashStringList
const TargetFileHashes
= GetExpectedHashesFor(Target
.MetaKey
);
1998 if (TargetFileHashes
.usable() == false || ServerHashes
!= TargetFileHashes
)
2002 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": Index has different hashes than parser, probably older, so fail pdiffing" << std::endl
;
2003 printHashSumComparison(CurrentPackagesFile
, ServerHashes
, TargetFileHashes
);
2008 HashStringList LocalHashes
;
2009 // try avoiding calculating the hash here as this is costly
2010 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
2011 LocalHashes
= GetExpectedHashesFromFor(TransactionManager
->LastMetaIndexParser
, Target
.MetaKey
);
2012 if (LocalHashes
.usable() == false)
2014 FileFd
fd(CurrentPackagesFile
, FileFd::ReadOnly
, FileFd::Auto
);
2015 Hashes
LocalHashesCalc(ServerHashes
);
2016 LocalHashesCalc
.AddFD(fd
);
2017 LocalHashes
= LocalHashesCalc
.GetHashStringList();
2020 if (ServerHashes
== LocalHashes
)
2022 // we have the same sha1 as the server so we are done here
2024 std::clog
<< "pkgAcqDiffIndex: Package file " << CurrentPackagesFile
<< " is up-to-date" << std::endl
;
2030 std::clog
<< "Server-Current: " << ServerHashes
.find(NULL
)->toStr() << " and we start at "
2031 << CurrentPackagesFile
<< " " << LocalHashes
.FileSize() << " " << LocalHashes
.find(NULL
)->toStr() << std::endl
;
2033 // historically, older hashes have more info than newer ones, so start
2034 // collecting with older ones first to avoid implementing complicated
2035 // information merging techniques… a failure is after all always
2036 // recoverable with a complete file and hashes aren't changed that often.
2037 std::vector
<char const *> types
;
2038 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
2039 types
.push_back(*type
);
2041 // parse all of (provided) history
2042 vector
<DiffInfo
> available_patches
;
2043 bool firstAcceptedHashes
= true;
2044 for (auto type
= types
.crbegin(); type
!= types
.crend(); ++type
)
2046 if (LocalHashes
.find(*type
) == NULL
)
2049 std::string tagname
= *type
;
2050 tagname
.append("-History");
2051 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
2052 if (tmp
.empty() == true)
2055 string hash
, filename
;
2056 unsigned long long size
;
2057 std::stringstream
ss(tmp
);
2059 while (ss
>> hash
>> size
>> filename
)
2061 if (unlikely(hash
.empty() == true || filename
.empty() == true))
2064 // see if we have a record for this file already
2065 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
2066 for (; cur
!= available_patches
.end(); ++cur
)
2068 if (cur
->file
!= filename
)
2070 cur
->result_hashes
.push_back(HashString(*type
, hash
));
2073 if (cur
!= available_patches
.end())
2075 if (firstAcceptedHashes
== true)
2078 next
.file
= filename
;
2079 next
.result_hashes
.push_back(HashString(*type
, hash
));
2080 next
.result_hashes
.FileSize(size
);
2081 available_patches
.push_back(next
);
2086 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
2087 << " wasn't in the list for the first parsed hash! (history)" << std::endl
;
2091 firstAcceptedHashes
= false;
2094 if (unlikely(available_patches
.empty() == true))
2097 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": "
2098 << "Couldn't find any patches for the patch series." << std::endl
;
2102 for (auto type
= types
.crbegin(); type
!= types
.crend(); ++type
)
2104 if (LocalHashes
.find(*type
) == NULL
)
2107 std::string tagname
= *type
;
2108 tagname
.append("-Patches");
2109 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
2110 if (tmp
.empty() == true)
2113 string hash
, filename
;
2114 unsigned long long size
;
2115 std::stringstream
ss(tmp
);
2117 while (ss
>> hash
>> size
>> filename
)
2119 if (unlikely(hash
.empty() == true || filename
.empty() == true))
2122 // see if we have a record for this file already
2123 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
2124 for (; cur
!= available_patches
.end(); ++cur
)
2126 if (cur
->file
!= filename
)
2128 if (cur
->patch_hashes
.empty())
2129 cur
->patch_hashes
.FileSize(size
);
2130 cur
->patch_hashes
.push_back(HashString(*type
, hash
));
2133 if (cur
!= available_patches
.end())
2136 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
2137 << " wasn't in the list for the first parsed hash! (patches)" << std::endl
;
2142 for (auto type
= types
.crbegin(); type
!= types
.crend(); ++type
)
2144 std::string tagname
= *type
;
2145 tagname
.append("-Download");
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
);
2154 // FIXME: all of pdiff supports only .gz compressed patches
2155 while (ss
>> hash
>> size
>> filename
)
2157 if (unlikely(hash
.empty() == true || filename
.empty() == true))
2159 if (unlikely(APT::String::Endswith(filename
, ".gz") == false))
2161 filename
.erase(filename
.length() - 3);
2163 // see if we have a record for this file already
2164 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
2165 for (; cur
!= available_patches
.end(); ++cur
)
2167 if (cur
->file
!= filename
)
2169 if (cur
->download_hashes
.empty())
2170 cur
->download_hashes
.FileSize(size
);
2171 cur
->download_hashes
.push_back(HashString(*type
, hash
));
2174 if (cur
!= available_patches
.end())
2177 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
2178 << " wasn't in the list for the first parsed hash! (download)" << std::endl
;
2184 bool foundStart
= false;
2185 for (std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
2186 cur
!= available_patches
.end(); ++cur
)
2188 if (LocalHashes
!= cur
->result_hashes
)
2191 available_patches
.erase(available_patches
.begin(), cur
);
2196 if (foundStart
== false || unlikely(available_patches
.empty() == true))
2199 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": "
2200 << "Couldn't find the start of the patch series." << std::endl
;
2204 for (auto const &patch
: available_patches
)
2205 if (patch
.result_hashes
.usable() == false ||
2206 patch
.patch_hashes
.usable() == false ||
2207 patch
.download_hashes
.usable() == false)
2210 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": provides no usable hashes for " << patch
.file
2211 << " so fallback to complete download" << std::endl
;
2215 // patching with too many files is rather slow compared to a fast download
2216 unsigned long const fileLimit
= _config
->FindI("Acquire::PDiffs::FileLimit", 0);
2217 if (fileLimit
!= 0 && fileLimit
< available_patches
.size())
2220 std::clog
<< "Need " << available_patches
.size() << " diffs (Limit is " << fileLimit
2221 << ") so fallback to complete download" << std::endl
;
2225 // calculate the size of all patches we have to get
2226 unsigned short const sizeLimitPercent
= _config
->FindI("Acquire::PDiffs::SizeLimit", 100);
2227 if (sizeLimitPercent
> 0)
2229 unsigned long long downloadSize
= std::accumulate(available_patches
.begin(),
2230 available_patches
.end(), 0llu, [](unsigned long long const T
, DiffInfo
const &I
) {
2231 return T
+ I
.download_hashes
.FileSize();
2233 if (downloadSize
!= 0)
2235 unsigned long long downloadSizeIdx
= 0;
2236 auto const types
= VectorizeString(Target
.Option(IndexTarget::COMPRESSIONTYPES
), ' ');
2237 for (auto const &t
: types
)
2239 std::string MetaKey
= Target
.MetaKey
;
2240 if (t
!= "uncompressed")
2242 HashStringList
const hsl
= GetExpectedHashesFor(MetaKey
);
2243 if (unlikely(hsl
.usable() == false))
2245 downloadSizeIdx
= hsl
.FileSize();
2248 unsigned long long const sizeLimit
= downloadSizeIdx
* sizeLimitPercent
;
2249 if ((sizeLimit
/100) < downloadSize
)
2252 std::clog
<< "Need " << downloadSize
<< " compressed bytes (Limit is " << (sizeLimit
/100) << ", "
2253 << "original is " << downloadSizeIdx
<< ") so fallback to complete download" << std::endl
;
2259 // we have something, queue the diffs
2260 string::size_type
const last_space
= Description
.rfind(" ");
2261 if(last_space
!= string::npos
)
2262 Description
.erase(last_space
, Description
.size()-last_space
);
2264 /* decide if we should download patches one by one or in one go:
2265 The first is good if the server merges patches, but many don't so client
2266 based merging can be attempt in which case the second is better.
2267 "bad things" will happen if patches are merged on the server,
2268 but client side merging is attempt as well */
2269 bool pdiff_merge
= _config
->FindB("Acquire::PDiffs::Merge", true);
2270 if (pdiff_merge
== true)
2272 // reprepro adds this flag if it has merged patches on the server
2273 std::string
const precedence
= Tags
.FindS("X-Patch-Precedence");
2274 pdiff_merge
= (precedence
!= "merged");
2279 std::string
const Final
= GetExistingFilename(CurrentPackagesFile
);
2280 if (unlikely(Final
.empty())) // because we wouldn't be called in such a case
2282 std::string
const PartialFile
= GetPartialFileNameFromURI(Target
.URI
);
2283 if (FileExists(PartialFile
) && RemoveFile("Bootstrap-linking", PartialFile
) == false)
2286 std::clog
<< "Bootstrap-linking for patching " << CurrentPackagesFile
2287 << " by removing stale " << PartialFile
<< " failed!" << std::endl
;
2290 for (auto const &ext
: APT::Configuration::getCompressorExtensions())
2292 std::string
const Partial
= PartialFile
+ ext
;
2293 if (FileExists(Partial
) && RemoveFile("Bootstrap-linking", Partial
) == false)
2296 std::clog
<< "Bootstrap-linking for patching " << CurrentPackagesFile
2297 << " by removing stale " << Partial
<< " failed!" << std::endl
;
2301 std::string
const Ext
= Final
.substr(CurrentPackagesFile
.length());
2302 std::string
const Partial
= PartialFile
+ Ext
;
2303 if (symlink(Final
.c_str(), Partial
.c_str()) != 0)
2306 std::clog
<< "Bootstrap-linking for patching " << CurrentPackagesFile
2307 << " by linking " << Final
<< " to " << Partial
<< " failed!" << std::endl
;
2312 if (pdiff_merge
== false)
2313 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
, available_patches
);
2316 diffs
= new std::vector
<pkgAcqIndexMergeDiffs
*>(available_patches
.size());
2317 for(size_t i
= 0; i
< available_patches
.size(); ++i
)
2318 (*diffs
)[i
] = new pkgAcqIndexMergeDiffs(Owner
, TransactionManager
,
2320 available_patches
[i
],
2330 void pkgAcqDiffIndex::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
2332 pkgAcqBaseIndex::Failed(Message
,Cnf
);
2334 ExpectedAdditionalItems
= 0;
2337 std::clog
<< "pkgAcqDiffIndex failed: " << Desc
.URI
<< " with " << Message
<< std::endl
2338 << "Falling back to normal index file acquire" << std::endl
;
2340 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
2343 void pkgAcqDiffIndex::Done(string
const &Message
,HashStringList
const &Hashes
, /*{{{*/
2344 pkgAcquire::MethodConfig
const * const Cnf
)
2347 std::clog
<< "pkgAcqDiffIndex::Done(): " << Desc
.URI
<< std::endl
;
2349 Item::Done(Message
, Hashes
, Cnf
);
2351 string
const FinalFile
= GetFinalFilename();
2352 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false))
2353 DestFile
= FinalFile
;
2355 if(ParseDiffIndex(DestFile
) == false)
2357 Failed("Message: Couldn't parse pdiff index", Cnf
);
2358 // queue for final move - this should happen even if we fail
2359 // while parsing (e.g. on sizelimit) and download the complete file.
2360 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
2364 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
2373 pkgAcqDiffIndex::~pkgAcqDiffIndex()
2379 // AcqIndexDiffs::AcqIndexDiffs - Constructor /*{{{*/
2380 // ---------------------------------------------------------------------
2381 /* The package diff is added to the queue. one object is constructed
2382 * for each diff and the index
2384 pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire
* const Owner
,
2385 pkgAcqMetaClearSig
* const TransactionManager
,
2386 IndexTarget
const &Target
,
2387 vector
<DiffInfo
> const &diffs
)
2388 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
),
2389 available_patches(diffs
)
2391 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
2393 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
2396 Description
= Target
.Description
;
2397 Desc
.ShortDesc
= Target
.ShortDesc
;
2399 if(available_patches
.empty() == true)
2401 // we are done (yeah!), check hashes against the final file
2402 DestFile
= GetKeepCompressedFileName(GetFinalFileNameFromURI(Target
.URI
), Target
);
2407 State
= StateFetchDiff
;
2412 void pkgAcqIndexDiffs::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
2414 pkgAcqBaseIndex::Failed(Message
,Cnf
);
2417 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
2419 std::clog
<< "pkgAcqIndexDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
2420 << "Falling back to normal index file acquire " << std::endl
;
2421 RenameOnError(PDiffError
);
2422 std::string
const patchname
= GetDiffsPatchFileName(DestFile
);
2423 if (RealFileExists(patchname
))
2424 Rename(patchname
, patchname
+ ".FAILED");
2425 std::string
const UnpatchedFile
= GetExistingFilename(GetPartialFileNameFromURI(Target
.URI
));
2426 if (UnpatchedFile
.empty() == false && FileExists(UnpatchedFile
))
2427 Rename(UnpatchedFile
, UnpatchedFile
+ ".FAILED");
2428 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
2432 // Finish - helper that cleans the item out of the fetcher queue /*{{{*/
2433 void pkgAcqIndexDiffs::Finish(bool allDone
)
2436 std::clog
<< "pkgAcqIndexDiffs::Finish(): "
2438 << Desc
.URI
<< std::endl
;
2440 // we restore the original name, this is required, otherwise
2441 // the file will be cleaned
2444 std::string
const Final
= GetKeepCompressedFileName(GetFinalFilename(), Target
);
2445 TransactionManager
->TransactionStageCopy(this, DestFile
, Final
);
2447 // this is for the "real" finish
2452 std::clog
<< "\n\nallDone: " << DestFile
<< "\n" << std::endl
;
2459 std::clog
<< "Finishing: " << Desc
.URI
<< std::endl
;
2466 bool pkgAcqIndexDiffs::QueueNextDiff() /*{{{*/
2468 // calc sha1 of the just patched file
2469 std::string
const PartialFile
= GetExistingFilename(GetPartialFileNameFromURI(Target
.URI
));
2470 if(unlikely(PartialFile
.empty()))
2472 Failed("Message: The file " + GetPartialFileNameFromURI(Target
.URI
) + " isn't available", NULL
);
2476 FileFd
fd(PartialFile
, FileFd::ReadOnly
, FileFd::Extension
);
2477 Hashes LocalHashesCalc
;
2478 LocalHashesCalc
.AddFD(fd
);
2479 HashStringList
const LocalHashes
= LocalHashesCalc
.GetHashStringList();
2482 std::clog
<< "QueueNextDiff: " << PartialFile
<< " (" << LocalHashes
.find(NULL
)->toStr() << ")" << std::endl
;
2484 HashStringList
const TargetFileHashes
= GetExpectedHashesFor(Target
.MetaKey
);
2485 if (unlikely(LocalHashes
.usable() == false || TargetFileHashes
.usable() == false))
2487 Failed("Local/Expected hashes are not usable for " + PartialFile
, NULL
);
2491 // final file reached before all patches are applied
2492 if(LocalHashes
== TargetFileHashes
)
2498 // remove all patches until the next matching patch is found
2499 // this requires the Index file to be ordered
2500 available_patches
.erase(available_patches
.begin(),
2501 std::find_if(available_patches
.begin(), available_patches
.end(), [&](DiffInfo
const &I
) {
2502 return I
.result_hashes
== LocalHashes
;
2505 // error checking and falling back if no patch was found
2506 if(available_patches
.empty() == true)
2508 Failed("No patches left to reach target for " + PartialFile
, NULL
);
2512 // queue the right diff
2513 Desc
.URI
= Target
.URI
+ ".diff/" + available_patches
[0].file
+ ".gz";
2514 Desc
.Description
= Description
+ " " + available_patches
[0].file
+ string(".pdiff");
2515 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
+ ".diff/" + available_patches
[0].file
), Target
);
2518 std::clog
<< "pkgAcqIndexDiffs::QueueNextDiff(): " << Desc
.URI
<< std::endl
;
2525 void pkgAcqIndexDiffs::Done(string
const &Message
, HashStringList
const &Hashes
, /*{{{*/
2526 pkgAcquire::MethodConfig
const * const Cnf
)
2529 std::clog
<< "pkgAcqIndexDiffs::Done(): " << Desc
.URI
<< std::endl
;
2531 Item::Done(Message
, Hashes
, Cnf
);
2533 std::string
const UncompressedUnpatchedFile
= GetPartialFileNameFromURI(Target
.URI
);
2534 std::string
const UnpatchedFile
= GetExistingFilename(UncompressedUnpatchedFile
);
2535 std::string
const PatchFile
= GetDiffsPatchFileName(UnpatchedFile
);
2536 std::string
const PatchedFile
= GetKeepCompressedFileName(UncompressedUnpatchedFile
, Target
);
2540 // success in downloading a diff, enter ApplyDiff state
2541 case StateFetchDiff
:
2542 Rename(DestFile
, PatchFile
);
2543 DestFile
= GetKeepCompressedFileName(UncompressedUnpatchedFile
+ "-patched", Target
);
2545 std::clog
<< "Sending to rred method: " << UnpatchedFile
<< std::endl
;
2546 State
= StateApplyDiff
;
2548 Desc
.URI
= "rred:" + UnpatchedFile
;
2550 SetActiveSubprocess("rred");
2552 // success in download/apply a diff, queue next (if needed)
2553 case StateApplyDiff
:
2554 // remove the just applied patch and base file
2555 available_patches
.erase(available_patches
.begin());
2556 RemoveFile("pkgAcqIndexDiffs::Done", PatchFile
);
2557 RemoveFile("pkgAcqIndexDiffs::Done", UnpatchedFile
);
2559 std::clog
<< "Moving patched file in place: " << std::endl
2560 << DestFile
<< " -> " << PatchedFile
<< std::endl
;
2561 Rename(DestFile
, PatchedFile
);
2563 // see if there is more to download
2564 if(available_patches
.empty() == false)
2566 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
, available_patches
);
2569 DestFile
= PatchedFile
;
2576 std::string
pkgAcqIndexDiffs::Custom600Headers() const /*{{{*/
2578 if(State
!= StateApplyDiff
)
2579 return pkgAcqBaseIndex::Custom600Headers();
2580 std::ostringstream patchhashes
;
2581 HashStringList
const ExpectedHashes
= available_patches
[0].patch_hashes
;
2582 for (HashStringList::const_iterator hs
= ExpectedHashes
.begin(); hs
!= ExpectedHashes
.end(); ++hs
)
2583 patchhashes
<< "\nPatch-0-" << hs
->HashType() << "-Hash: " << hs
->HashValue();
2584 patchhashes
<< pkgAcqBaseIndex::Custom600Headers();
2585 return patchhashes
.str();
2588 pkgAcqIndexDiffs::~pkgAcqIndexDiffs() {}
2590 // AcqIndexMergeDiffs::AcqIndexMergeDiffs - Constructor /*{{{*/
2591 pkgAcqIndexMergeDiffs::pkgAcqIndexMergeDiffs(pkgAcquire
* const Owner
,
2592 pkgAcqMetaClearSig
* const TransactionManager
,
2593 IndexTarget
const &Target
,
2594 DiffInfo
const &patch
,
2595 std::vector
<pkgAcqIndexMergeDiffs
*> const * const allPatches
)
2596 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
),
2597 patch(patch
), allPatches(allPatches
), State(StateFetchDiff
)
2599 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
2602 Description
= Target
.Description
;
2603 Desc
.ShortDesc
= Target
.ShortDesc
;
2604 Desc
.URI
= Target
.URI
+ ".diff/" + patch
.file
+ ".gz";
2605 Desc
.Description
= Description
+ " " + patch
.file
+ ".pdiff";
2606 DestFile
= GetPartialFileNameFromURI(Desc
.URI
);
2609 std::clog
<< "pkgAcqIndexMergeDiffs: " << Desc
.URI
<< std::endl
;
2614 void pkgAcqIndexMergeDiffs::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
2617 std::clog
<< "pkgAcqIndexMergeDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
;
2619 pkgAcqBaseIndex::Failed(Message
,Cnf
);
2622 // check if we are the first to fail, otherwise we are done here
2623 State
= StateDoneDiff
;
2624 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2625 I
!= allPatches
->end(); ++I
)
2626 if ((*I
)->State
== StateErrorDiff
)
2628 State
= StateErrorDiff
;
2632 // first failure means we should fallback
2633 State
= StateErrorDiff
;
2635 std::clog
<< "Falling back to normal index file acquire" << std::endl
;
2636 RenameOnError(PDiffError
);
2637 if (RealFileExists(DestFile
))
2638 Rename(DestFile
, DestFile
+ ".FAILED");
2639 std::string
const UnpatchedFile
= GetExistingFilename(GetPartialFileNameFromURI(Target
.URI
));
2640 if (UnpatchedFile
.empty() == false && FileExists(UnpatchedFile
))
2641 Rename(UnpatchedFile
, UnpatchedFile
+ ".FAILED");
2643 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
2646 void pkgAcqIndexMergeDiffs::Done(string
const &Message
, HashStringList
const &Hashes
, /*{{{*/
2647 pkgAcquire::MethodConfig
const * const Cnf
)
2650 std::clog
<< "pkgAcqIndexMergeDiffs::Done(): " << Desc
.URI
<< std::endl
;
2652 Item::Done(Message
, Hashes
, Cnf
);
2654 if (std::any_of(allPatches
->begin(), allPatches
->end(),
2655 [](pkgAcqIndexMergeDiffs
const * const P
) { return P
->State
== StateErrorDiff
; }))
2658 std::clog
<< "Another patch failed already, no point in processing this one." << std::endl
;
2659 State
= StateErrorDiff
;
2663 std::string
const UncompressedUnpatchedFile
= GetPartialFileNameFromURI(Target
.URI
);
2664 std::string
const UnpatchedFile
= GetExistingFilename(UncompressedUnpatchedFile
);
2665 if (UnpatchedFile
.empty())
2667 _error
->Fatal("Unpatched file %s doesn't exist (anymore)!", UncompressedUnpatchedFile
.c_str());
2668 State
= StateErrorDiff
;
2671 std::string
const PatchFile
= GetMergeDiffsPatchFileName(UnpatchedFile
, patch
.file
);
2672 std::string
const PatchedFile
= GetKeepCompressedFileName(UncompressedUnpatchedFile
, Target
);
2676 case StateFetchDiff
:
2677 Rename(DestFile
, PatchFile
);
2679 // check if this is the last completed diff
2680 State
= StateDoneDiff
;
2681 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2682 I
!= allPatches
->end(); ++I
)
2683 if ((*I
)->State
!= StateDoneDiff
)
2686 std::clog
<< "Not the last done diff in the batch: " << Desc
.URI
<< std::endl
;
2689 // this is the last completed diff, so we are ready to apply now
2690 DestFile
= GetKeepCompressedFileName(UncompressedUnpatchedFile
+ "-patched", Target
);
2692 std::clog
<< "Sending to rred method: " << UnpatchedFile
<< std::endl
;
2693 State
= StateApplyDiff
;
2695 Desc
.URI
= "rred:" + UnpatchedFile
;
2697 SetActiveSubprocess("rred");
2699 case StateApplyDiff
:
2700 // success in download & apply all diffs, finialize and clean up
2702 std::clog
<< "Queue patched file in place: " << std::endl
2703 << DestFile
<< " -> " << PatchedFile
<< std::endl
;
2705 // queue for copy by the transaction manager
2706 TransactionManager
->TransactionStageCopy(this, DestFile
, GetKeepCompressedFileName(GetFinalFilename(), Target
));
2708 // ensure the ed's are gone regardless of list-cleanup
2709 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2710 I
!= allPatches
->end(); ++I
)
2711 RemoveFile("pkgAcqIndexMergeDiffs::Done", GetMergeDiffsPatchFileName(UnpatchedFile
, (*I
)->patch
.file
));
2712 RemoveFile("pkgAcqIndexMergeDiffs::Done", UnpatchedFile
);
2717 std::clog
<< "allDone: " << DestFile
<< "\n" << std::endl
;
2719 case StateDoneDiff
: _error
->Fatal("Done called for %s which is in an invalid Done state", PatchFile
.c_str()); break;
2720 case StateErrorDiff
: _error
->Fatal("Done called for %s which is in an invalid Error state", PatchFile
.c_str()); break;
2724 std::string
pkgAcqIndexMergeDiffs::Custom600Headers() const /*{{{*/
2726 if(State
!= StateApplyDiff
)
2727 return pkgAcqBaseIndex::Custom600Headers();
2728 std::ostringstream patchhashes
;
2729 unsigned int seen_patches
= 0;
2730 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2731 I
!= allPatches
->end(); ++I
)
2733 HashStringList
const ExpectedHashes
= (*I
)->patch
.patch_hashes
;
2734 for (HashStringList::const_iterator hs
= ExpectedHashes
.begin(); hs
!= ExpectedHashes
.end(); ++hs
)
2735 patchhashes
<< "\nPatch-" << seen_patches
<< "-" << hs
->HashType() << "-Hash: " << hs
->HashValue();
2738 patchhashes
<< pkgAcqBaseIndex::Custom600Headers();
2739 return patchhashes
.str();
2742 pkgAcqIndexMergeDiffs::~pkgAcqIndexMergeDiffs() {}
2744 // AcqIndex::AcqIndex - Constructor /*{{{*/
2745 pkgAcqIndex::pkgAcqIndex(pkgAcquire
* const Owner
,
2746 pkgAcqMetaClearSig
* const TransactionManager
,
2747 IndexTarget
const &Target
)
2748 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
), Stage(STAGE_DOWNLOAD
),
2749 CompressionExtensions(Target
.Option(IndexTarget::COMPRESSIONTYPES
))
2751 Init(Target
.URI
, Target
.Description
, Target
.ShortDesc
);
2753 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
2754 std::clog
<< "New pkgIndex with TransactionManager "
2755 << TransactionManager
<< std::endl
;
2758 // AcqIndex::Init - defered Constructor /*{{{*/
2759 static void NextCompressionExtension(std::string
&CurrentCompressionExtension
, std::string
&CompressionExtensions
, bool const preview
)
2761 size_t const nextExt
= CompressionExtensions
.find(' ');
2762 if (nextExt
== std::string::npos
)
2764 CurrentCompressionExtension
= CompressionExtensions
;
2765 if (preview
== false)
2766 CompressionExtensions
.clear();
2770 CurrentCompressionExtension
= CompressionExtensions
.substr(0, nextExt
);
2771 if (preview
== false)
2772 CompressionExtensions
= CompressionExtensions
.substr(nextExt
+1);
2775 void pkgAcqIndex::Init(string
const &URI
, string
const &URIDesc
,
2776 string
const &ShortDesc
)
2778 Stage
= STAGE_DOWNLOAD
;
2780 DestFile
= GetPartialFileNameFromURI(URI
);
2781 NextCompressionExtension(CurrentCompressionExtension
, CompressionExtensions
, false);
2783 // store file size of the download to ensure the fetcher gives
2784 // accurate progress reporting
2785 FileSize
= GetExpectedHashes().FileSize();
2787 if (CurrentCompressionExtension
== "uncompressed")
2791 else if (CurrentCompressionExtension
== "by-hash")
2793 NextCompressionExtension(CurrentCompressionExtension
, CompressionExtensions
, true);
2794 if(unlikely(CurrentCompressionExtension
.empty()))
2796 if (CurrentCompressionExtension
!= "uncompressed")
2798 Desc
.URI
= URI
+ '.' + CurrentCompressionExtension
;
2799 DestFile
= DestFile
+ '.' + CurrentCompressionExtension
;
2802 HashStringList
const Hashes
= GetExpectedHashes();
2803 HashString
const * const TargetHash
= Hashes
.find(NULL
);
2804 if (unlikely(TargetHash
== nullptr))
2806 std::string
const ByHash
= "/by-hash/" + TargetHash
->HashType() + "/" + TargetHash
->HashValue();
2807 size_t const trailing_slash
= Desc
.URI
.find_last_of("/");
2808 if (unlikely(trailing_slash
== std::string::npos
))
2810 Desc
.URI
= Desc
.URI
.replace(
2812 Desc
.URI
.substr(trailing_slash
+1).size()+1,
2815 else if (unlikely(CurrentCompressionExtension
.empty()))
2819 Desc
.URI
= URI
+ '.' + CurrentCompressionExtension
;
2820 DestFile
= DestFile
+ '.' + CurrentCompressionExtension
;
2824 Desc
.Description
= URIDesc
;
2826 Desc
.ShortDesc
= ShortDesc
;
2831 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
2832 // ---------------------------------------------------------------------
2833 /* The only header we use is the last-modified header. */
2834 string
pkgAcqIndex::Custom600Headers() const
2837 string msg
= "\nIndex-File: true";
2839 if (TransactionManager
->LastMetaIndexParser
== NULL
)
2841 std::string
const Final
= GetFinalFilename();
2844 if (stat(Final
.c_str(),&Buf
) == 0)
2845 msg
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
2848 if(Target
.IsOptional
)
2849 msg
+= "\nFail-Ignore: true";
2854 // AcqIndex::Failed - getting the indexfile failed /*{{{*/
2855 void pkgAcqIndex::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)
2857 pkgAcqBaseIndex::Failed(Message
,Cnf
);
2859 // authorisation matches will not be fixed by other compression types
2860 if (Status
!= StatAuthError
)
2862 if (CompressionExtensions
.empty() == false)
2864 Init(Target
.URI
, Desc
.Description
, Desc
.ShortDesc
);
2870 if(Target
.IsOptional
&& GetExpectedHashes().empty() && Stage
== STAGE_DOWNLOAD
)
2873 TransactionManager
->AbortTransaction();
2876 // AcqIndex::Done - Finished a fetch /*{{{*/
2877 // ---------------------------------------------------------------------
2878 /* This goes through a number of states.. On the initial fetch the
2879 method could possibly return an alternate filename which points
2880 to the uncompressed version of the file. If this is so the file
2881 is copied into the partial directory. In all other cases the file
2882 is decompressed with a compressed uri. */
2883 void pkgAcqIndex::Done(string
const &Message
,
2884 HashStringList
const &Hashes
,
2885 pkgAcquire::MethodConfig
const * const Cfg
)
2887 Item::Done(Message
,Hashes
,Cfg
);
2891 case STAGE_DOWNLOAD
:
2892 StageDownloadDone(Message
);
2894 case STAGE_DECOMPRESS_AND_VERIFY
:
2895 StageDecompressDone();
2900 // AcqIndex::StageDownloadDone - Queue for decompress and verify /*{{{*/
2901 void pkgAcqIndex::StageDownloadDone(string
const &Message
)
2906 std::string
const AltFilename
= LookupTag(Message
,"Alt-Filename");
2907 std::string Filename
= LookupTag(Message
,"Filename");
2909 // we need to verify the file against the current Release file again
2910 // on if-modfied-since hit to avoid a stale attack against us
2911 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
2913 // copy FinalFile into partial/ so that we check the hash again
2914 string
const FinalFile
= GetExistingFilename(GetFinalFileNameFromURI(Target
.URI
));
2915 if (symlink(FinalFile
.c_str(), DestFile
.c_str()) != 0)
2916 _error
->WarningE("pkgAcqIndex::StageDownloadDone", "Symlinking final file %s back to %s failed", FinalFile
.c_str(), DestFile
.c_str());
2919 EraseFileName
= DestFile
;
2920 Filename
= DestFile
;
2922 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
2923 Desc
.URI
= "store:" + Filename
;
2925 SetActiveSubprocess(::URI(Desc
.URI
).Access
);
2928 // methods like file:// give us an alternative (uncompressed) file
2929 else if (Target
.KeepCompressed
== false && AltFilename
.empty() == false)
2931 Filename
= AltFilename
;
2932 EraseFileName
.clear();
2934 // Methods like e.g. "file:" will give us a (compressed) FileName that is
2935 // not the "DestFile" we set, in this case we uncompress from the local file
2936 else if (Filename
!= DestFile
&& RealFileExists(DestFile
) == false)
2938 // symlinking ensures that the filename can be used for compression detection
2939 // that is e.g. needed for by-hash which has no extension over file
2940 if (symlink(Filename
.c_str(),DestFile
.c_str()) != 0)
2941 _error
->WarningE("pkgAcqIndex::StageDownloadDone", "Symlinking file %s to %s failed", Filename
.c_str(), DestFile
.c_str());
2944 EraseFileName
= DestFile
;
2945 Filename
= DestFile
;
2949 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
2950 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
2951 if (Filename
!= DestFile
&& flExtension(Filename
) == flExtension(DestFile
))
2952 Desc
.URI
= "copy:" + Filename
;
2954 Desc
.URI
= "store:" + Filename
;
2955 if (DestFile
== Filename
)
2957 if (CurrentCompressionExtension
== "uncompressed")
2958 return StageDecompressDone();
2959 DestFile
= "/dev/null";
2962 if (EraseFileName
.empty() && Filename
!= AltFilename
)
2963 EraseFileName
= Filename
;
2965 // queue uri for the next stage
2967 SetActiveSubprocess(::URI(Desc
.URI
).Access
);
2970 // AcqIndex::StageDecompressDone - Final verification /*{{{*/
2971 void pkgAcqIndex::StageDecompressDone()
2973 if (DestFile
== "/dev/null")
2974 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
2976 // Done, queue for rename on transaction finished
2977 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
2980 pkgAcqIndex::~pkgAcqIndex() {}
2983 // AcqArchive::AcqArchive - Constructor /*{{{*/
2984 // ---------------------------------------------------------------------
2985 /* This just sets up the initial fetch environment and queues the first
2987 pkgAcqArchive::pkgAcqArchive(pkgAcquire
* const Owner
,pkgSourceList
* const Sources
,
2988 pkgRecords
* const Recs
,pkgCache::VerIterator
const &Version
,
2989 string
&StoreFilename
) :
2990 Item(Owner
), d(NULL
), LocalSource(false), Version(Version
), Sources(Sources
), Recs(Recs
),
2991 StoreFilename(StoreFilename
), Vf(Version
.FileList()),
2994 Retries
= _config
->FindI("Acquire::Retries",0);
2996 if (Version
.Arch() == 0)
2998 _error
->Error(_("I wasn't able to locate a file for the %s package. "
2999 "This might mean you need to manually fix this package. "
3000 "(due to missing arch)"),
3001 Version
.ParentPkg().FullName().c_str());
3005 /* We need to find a filename to determine the extension. We make the
3006 assumption here that all the available sources for this version share
3007 the same extension.. */
3008 // Skip not source sources, they do not have file fields.
3009 for (; Vf
.end() == false; ++Vf
)
3011 if (Vf
.File().Flagged(pkgCache::Flag::NotSource
))
3016 // Does not really matter here.. we are going to fail out below
3017 if (Vf
.end() != true)
3019 // If this fails to get a file name we will bomb out below.
3020 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
3021 if (_error
->PendingError() == true)
3024 // Generate the final file name as: package_version_arch.foo
3025 StoreFilename
= QuoteString(Version
.ParentPkg().Name(),"_:") + '_' +
3026 QuoteString(Version
.VerStr(),"_:") + '_' +
3027 QuoteString(Version
.Arch(),"_:.") +
3028 "." + flExtension(Parse
.FileName());
3031 // check if we have one trusted source for the package. if so, switch
3032 // to "TrustedOnly" mode - but only if not in AllowUnauthenticated mode
3033 bool const allowUnauth
= _config
->FindB("APT::Get::AllowUnauthenticated", false);
3034 bool const debugAuth
= _config
->FindB("Debug::pkgAcquire::Auth", false);
3035 bool seenUntrusted
= false;
3036 for (pkgCache::VerFileIterator i
= Version
.FileList(); i
.end() == false; ++i
)
3038 pkgIndexFile
*Index
;
3039 if (Sources
->FindIndex(i
.File(),Index
) == false)
3042 if (debugAuth
== true)
3043 std::cerr
<< "Checking index: " << Index
->Describe()
3044 << "(Trusted=" << Index
->IsTrusted() << ")" << std::endl
;
3046 if (Index
->IsTrusted() == true)
3049 if (allowUnauth
== false)
3053 seenUntrusted
= true;
3056 // "allow-unauthenticated" restores apts old fetching behaviour
3057 // that means that e.g. unauthenticated file:// uris are higher
3058 // priority than authenticated http:// uris
3059 if (allowUnauth
== true && seenUntrusted
== true)
3063 if (QueueNext() == false && _error
->PendingError() == false)
3064 _error
->Error(_("Can't find a source to download version '%s' of '%s'"),
3065 Version
.VerStr(), Version
.ParentPkg().FullName(false).c_str());
3068 // AcqArchive::QueueNext - Queue the next file source /*{{{*/
3069 // ---------------------------------------------------------------------
3070 /* This queues the next available file version for download. It checks if
3071 the archive is already available in the cache and stashs the MD5 for
3073 bool pkgAcqArchive::QueueNext()
3075 for (; Vf
.end() == false; ++Vf
)
3077 pkgCache::PkgFileIterator
const PkgF
= Vf
.File();
3078 // Ignore not source sources
3079 if (PkgF
.Flagged(pkgCache::Flag::NotSource
))
3082 // Try to cross match against the source list
3083 pkgIndexFile
*Index
;
3084 if (Sources
->FindIndex(PkgF
, Index
) == false)
3086 LocalSource
= PkgF
.Flagged(pkgCache::Flag::LocalSource
);
3088 // only try to get a trusted package from another source if that source
3090 if(Trusted
&& !Index
->IsTrusted())
3093 // Grab the text package record
3094 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
3095 if (_error
->PendingError() == true)
3098 string PkgFile
= Parse
.FileName();
3099 ExpectedHashes
= Parse
.Hashes();
3101 if (PkgFile
.empty() == true)
3102 return _error
->Error(_("The package index files are corrupted. No Filename: "
3103 "field for package %s."),
3104 Version
.ParentPkg().Name());
3106 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
3107 Desc
.Description
= Index
->ArchiveInfo(Version
);
3109 Desc
.ShortDesc
= Version
.ParentPkg().FullName(true);
3111 // See if we already have the file. (Legacy filenames)
3112 FileSize
= Version
->Size
;
3113 string FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile
);
3115 if (stat(FinalFile
.c_str(),&Buf
) == 0)
3117 // Make sure the size matches
3118 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
3123 StoreFilename
= DestFile
= FinalFile
;
3127 /* Hmm, we have a file and its size does not match, this means it is
3128 an old style mismatched arch */
3129 RemoveFile("pkgAcqArchive::QueueNext", FinalFile
);
3132 // Check it again using the new style output filenames
3133 FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
3134 if (stat(FinalFile
.c_str(),&Buf
) == 0)
3136 // Make sure the size matches
3137 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
3142 StoreFilename
= DestFile
= FinalFile
;
3146 /* Hmm, we have a file and its size does not match, this shouldn't
3148 RemoveFile("pkgAcqArchive::QueueNext", FinalFile
);
3151 DestFile
= _config
->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename
);
3153 // Check the destination file
3154 if (stat(DestFile
.c_str(),&Buf
) == 0)
3156 // Hmm, the partial file is too big, erase it
3157 if ((unsigned long long)Buf
.st_size
> Version
->Size
)
3158 RemoveFile("pkgAcqArchive::QueueNext", DestFile
);
3160 PartialSize
= Buf
.st_size
;
3163 // Disables download of archives - useful if no real installation follows,
3164 // e.g. if we are just interested in proposed installation order
3165 if (_config
->FindB("Debug::pkgAcqArchive::NoQueue", false) == true)
3170 StoreFilename
= DestFile
= FinalFile
;
3184 // AcqArchive::Done - Finished fetching /*{{{*/
3185 // ---------------------------------------------------------------------
3187 void pkgAcqArchive::Done(string
const &Message
, HashStringList
const &Hashes
,
3188 pkgAcquire::MethodConfig
const * const Cfg
)
3190 Item::Done(Message
, Hashes
, Cfg
);
3192 // Grab the output filename
3193 std::string
const FileName
= LookupTag(Message
,"Filename");
3194 if (DestFile
!= FileName
&& RealFileExists(DestFile
) == false)
3196 StoreFilename
= DestFile
= FileName
;
3202 // Done, move it into position
3203 string
const FinalFile
= GetFinalFilename();
3204 Rename(DestFile
,FinalFile
);
3205 StoreFilename
= DestFile
= FinalFile
;
3209 // AcqArchive::Failed - Failure handler /*{{{*/
3210 // ---------------------------------------------------------------------
3211 /* Here we try other sources */
3212 void pkgAcqArchive::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)
3214 Item::Failed(Message
,Cnf
);
3216 /* We don't really want to retry on failed media swaps, this prevents
3217 that. An interesting observation is that permanent failures are not
3219 if (Cnf
->Removable
== true &&
3220 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
3222 // Vf = Version.FileList();
3223 while (Vf
.end() == false) ++Vf
;
3224 StoreFilename
= string();
3229 if (QueueNext() == false)
3231 // This is the retry counter
3233 Cnf
->LocalOnly
== false &&
3234 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
3237 Vf
= Version
.FileList();
3238 if (QueueNext() == true)
3242 StoreFilename
= string();
3247 APT_PURE
bool pkgAcqArchive::IsTrusted() const /*{{{*/
3252 void pkgAcqArchive::Finished() /*{{{*/
3254 if (Status
== pkgAcquire::Item::StatDone
&&
3257 StoreFilename
= string();
3260 std::string
pkgAcqArchive::DescURI() const /*{{{*/
3265 std::string
pkgAcqArchive::ShortDesc() const /*{{{*/
3267 return Desc
.ShortDesc
;
3270 pkgAcqArchive::~pkgAcqArchive() {}
3272 // AcqChangelog::pkgAcqChangelog - Constructors /*{{{*/
3273 class pkgAcqChangelog::Private
3276 std::string FinalFile
;
3278 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire
* const Owner
, pkgCache::VerIterator
const &Ver
,
3279 std::string
const &DestDir
, std::string
const &DestFilename
) :
3280 pkgAcquire::Item(Owner
), d(new pkgAcqChangelog::Private()), SrcName(Ver
.SourcePkgName()), SrcVersion(Ver
.SourceVerStr())
3282 Desc
.URI
= URI(Ver
);
3283 Init(DestDir
, DestFilename
);
3285 // some parameters are char* here as they come likely from char* interfaces – which can also return NULL
3286 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire
* const Owner
, pkgCache::RlsFileIterator
const &RlsFile
,
3287 char const * const Component
, char const * const SrcName
, char const * const SrcVersion
,
3288 const string
&DestDir
, const string
&DestFilename
) :
3289 pkgAcquire::Item(Owner
), d(new pkgAcqChangelog::Private()), SrcName(SrcName
), SrcVersion(SrcVersion
)
3291 Desc
.URI
= URI(RlsFile
, Component
, SrcName
, SrcVersion
);
3292 Init(DestDir
, DestFilename
);
3294 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire
* const Owner
,
3295 std::string
const &URI
, char const * const SrcName
, char const * const SrcVersion
,
3296 const string
&DestDir
, const string
&DestFilename
) :
3297 pkgAcquire::Item(Owner
), d(new pkgAcqChangelog::Private()), SrcName(SrcName
), SrcVersion(SrcVersion
)
3300 Init(DestDir
, DestFilename
);
3302 void pkgAcqChangelog::Init(std::string
const &DestDir
, std::string
const &DestFilename
)
3304 if (Desc
.URI
.empty())
3307 // TRANSLATOR: %s=%s is sourcename=sourceversion, e.g. apt=1.1
3308 strprintf(ErrorText
, _("Changelog unavailable for %s=%s"), SrcName
.c_str(), SrcVersion
.c_str());
3309 // Let the error message print something sensible rather than "Failed to fetch /"
3310 if (DestFilename
.empty())
3311 DestFile
= SrcName
+ ".changelog";
3313 DestFile
= DestFilename
;
3314 Desc
.URI
= "changelog:/" + DestFile
;
3318 std::string DestFileName
;
3319 if (DestFilename
.empty())
3320 DestFileName
= flCombine(DestFile
, SrcName
+ ".changelog");
3322 DestFileName
= flCombine(DestFile
, DestFilename
);
3324 std::string
const SandboxUser
= _config
->Find("APT::Sandbox::User");
3325 std::string
const systemTemp
= GetTempDir(SandboxUser
);
3327 snprintf(tmpname
, sizeof(tmpname
), "%s/apt-changelog-XXXXXX", systemTemp
.c_str());
3328 if (NULL
== mkdtemp(tmpname
))
3330 _error
->Errno("mkdtemp", "mkdtemp failed in changelog acquire of %s %s", SrcName
.c_str(), SrcVersion
.c_str());
3334 TemporaryDirectory
= tmpname
;
3336 ChangeOwnerAndPermissionOfFile("Item::QueueURI", TemporaryDirectory
.c_str(),
3337 SandboxUser
.c_str(), "root", 0700);
3339 DestFile
= flCombine(TemporaryDirectory
, DestFileName
);
3340 if (DestDir
.empty() == false)
3342 d
->FinalFile
= flCombine(DestDir
, DestFileName
);
3343 if (RealFileExists(d
->FinalFile
))
3345 FileFd file1
, file2
;
3346 if (file1
.Open(DestFile
, FileFd::WriteOnly
| FileFd::Create
| FileFd::Exclusive
) &&
3347 file2
.Open(d
->FinalFile
, FileFd::ReadOnly
) && CopyFile(file2
, file1
))
3349 struct timeval times
[2];
3350 times
[0].tv_sec
= times
[1].tv_sec
= file2
.ModificationTime();
3351 times
[0].tv_usec
= times
[1].tv_usec
= 0;
3352 utimes(DestFile
.c_str(), times
);
3357 Desc
.ShortDesc
= "Changelog";
3358 strprintf(Desc
.Description
, "%s %s %s Changelog", URI::SiteOnly(Desc
.URI
).c_str(), SrcName
.c_str(), SrcVersion
.c_str());
3363 std::string
pkgAcqChangelog::URI(pkgCache::VerIterator
const &Ver
) /*{{{*/
3365 std::string
const confOnline
= "Acquire::Changelogs::AlwaysOnline";
3366 bool AlwaysOnline
= _config
->FindB(confOnline
, false);
3367 if (AlwaysOnline
== false)
3368 for (pkgCache::VerFileIterator VF
= Ver
.FileList(); VF
.end() == false; ++VF
)
3370 pkgCache::PkgFileIterator
const PF
= VF
.File();
3371 if (PF
.Flagged(pkgCache::Flag::NotSource
) || PF
->Release
== 0)
3373 pkgCache::RlsFileIterator
const RF
= PF
.ReleaseFile();
3374 if (RF
->Origin
!= 0 && _config
->FindB(confOnline
+ "::Origin::" + RF
.Origin(), false))
3376 AlwaysOnline
= true;
3380 if (AlwaysOnline
== false)
3382 pkgCache::PkgIterator
const Pkg
= Ver
.ParentPkg();
3383 if (Pkg
->CurrentVer
!= 0 && Pkg
.CurrentVer() == Ver
)
3385 std::string
const basename
= std::string("/usr/share/doc/") + Pkg
.Name() + "/changelog";
3386 std::string
const debianname
= basename
+ ".Debian";
3387 if (FileExists(debianname
))
3388 return "copy://" + debianname
;
3389 else if (FileExists(debianname
+ ".gz"))
3390 return "gzip://" + debianname
+ ".gz";
3391 else if (FileExists(basename
))
3392 return "copy://" + basename
;
3393 else if (FileExists(basename
+ ".gz"))
3394 return "gzip://" + basename
+ ".gz";
3398 char const * const SrcName
= Ver
.SourcePkgName();
3399 char const * const SrcVersion
= Ver
.SourceVerStr();
3400 // find the first source for this version which promises a changelog
3401 for (pkgCache::VerFileIterator VF
= Ver
.FileList(); VF
.end() == false; ++VF
)
3403 pkgCache::PkgFileIterator
const PF
= VF
.File();
3404 if (PF
.Flagged(pkgCache::Flag::NotSource
) || PF
->Release
== 0)
3406 pkgCache::RlsFileIterator
const RF
= PF
.ReleaseFile();
3407 std::string
const uri
= URI(RF
, PF
.Component(), SrcName
, SrcVersion
);
3414 std::string
pkgAcqChangelog::URITemplate(pkgCache::RlsFileIterator
const &Rls
)
3416 if (Rls
.end() == true || (Rls
->Label
== 0 && Rls
->Origin
== 0))
3418 std::string
const serverConfig
= "Acquire::Changelogs::URI";
3420 #define APT_EMPTY_SERVER \
3421 if (server.empty() == false) \
3423 if (server != "no") \
3427 #define APT_CHECK_SERVER(X, Y) \
3430 std::string const specialServerConfig = serverConfig + "::" + Y + #X + "::" + Rls.X(); \
3431 server = _config->Find(specialServerConfig); \
3434 // this way e.g. Debian-Security can fallback to Debian
3435 APT_CHECK_SERVER(Label
, "Override::")
3436 APT_CHECK_SERVER(Origin
, "Override::")
3438 if (RealFileExists(Rls
.FileName()))
3440 _error
->PushToStack();
3442 /* This can be costly. A caller wanting to get millions of URIs might
3443 want to do this on its own once and use Override settings.
3444 We don't do this here as Origin/Label are not as unique as they
3445 should be so this could produce request order-dependent anomalies */
3446 if (OpenMaybeClearSignedFile(Rls
.FileName(), rf
) == true)
3448 pkgTagFile
TagFile(&rf
, rf
.Size());
3449 pkgTagSection Section
;
3450 if (TagFile
.Step(Section
) == true)
3451 server
= Section
.FindS("Changelogs");
3453 _error
->RevertToStack();
3457 APT_CHECK_SERVER(Label
, "")
3458 APT_CHECK_SERVER(Origin
, "")
3459 #undef APT_CHECK_SERVER
3460 #undef APT_EMPTY_SERVER
3463 std::string
pkgAcqChangelog::URI(pkgCache::RlsFileIterator
const &Rls
,
3464 char const * const Component
, char const * const SrcName
,
3465 char const * const SrcVersion
)
3467 return URI(URITemplate(Rls
), Component
, SrcName
, SrcVersion
);
3469 std::string
pkgAcqChangelog::URI(std::string
const &Template
,
3470 char const * const Component
, char const * const SrcName
,
3471 char const * const SrcVersion
)
3473 if (Template
.find("@CHANGEPATH@") == std::string::npos
)
3476 // the path is: COMPONENT/SRC/SRCNAME/SRCNAME_SRCVER, e.g. main/a/apt/1.1 or contrib/liba/libapt/2.0
3477 std::string Src
= SrcName
;
3478 std::string path
= APT::String::Startswith(SrcName
, "lib") ? Src
.substr(0, 4) : Src
.substr(0,1);
3479 path
.append("/").append(Src
).append("/");
3480 path
.append(Src
).append("_").append(StripEpoch(SrcVersion
));
3481 // we omit component for releases without one (= flat-style repositories)
3482 if (Component
!= NULL
&& strlen(Component
) != 0)
3483 path
= std::string(Component
) + "/" + path
;
3485 return SubstVar(Template
, "@CHANGEPATH@", path
);
3488 // AcqChangelog::Failed - Failure handler /*{{{*/
3489 void pkgAcqChangelog::Failed(string
const &Message
, pkgAcquire::MethodConfig
const * const Cnf
)
3491 Item::Failed(Message
,Cnf
);
3493 std::string errText
;
3494 // TRANSLATOR: %s=%s is sourcename=sourceversion, e.g. apt=1.1
3495 strprintf(errText
, _("Changelog unavailable for %s=%s"), SrcName
.c_str(), SrcVersion
.c_str());
3497 // Error is probably something techy like 404 Not Found
3498 if (ErrorText
.empty())
3499 ErrorText
= errText
;
3501 ErrorText
= errText
+ " (" + ErrorText
+ ")";
3504 // AcqChangelog::Done - Item downloaded OK /*{{{*/
3505 void pkgAcqChangelog::Done(string
const &Message
,HashStringList
const &CalcHashes
,
3506 pkgAcquire::MethodConfig
const * const Cnf
)
3508 Item::Done(Message
,CalcHashes
,Cnf
);
3509 if (d
->FinalFile
.empty() == false)
3511 if (RemoveFile("pkgAcqChangelog::Done", d
->FinalFile
) == false ||
3512 Rename(DestFile
, d
->FinalFile
) == false)
3519 pkgAcqChangelog::~pkgAcqChangelog() /*{{{*/
3521 if (TemporaryDirectory
.empty() == false)
3523 RemoveFile("~pkgAcqChangelog", DestFile
);
3524 rmdir(TemporaryDirectory
.c_str());
3530 // AcqFile::pkgAcqFile - Constructor /*{{{*/
3531 pkgAcqFile::pkgAcqFile(pkgAcquire
* const Owner
,string
const &URI
, HashStringList
const &Hashes
,
3532 unsigned long long const Size
,string
const &Dsc
,string
const &ShortDesc
,
3533 const string
&DestDir
, const string
&DestFilename
,
3534 bool const IsIndexFile
) :
3535 Item(Owner
), d(NULL
), IsIndexFile(IsIndexFile
), ExpectedHashes(Hashes
)
3537 Retries
= _config
->FindI("Acquire::Retries",0);
3539 if(!DestFilename
.empty())
3540 DestFile
= DestFilename
;
3541 else if(!DestDir
.empty())
3542 DestFile
= DestDir
+ "/" + flNotDir(URI
);
3544 DestFile
= flNotDir(URI
);
3548 Desc
.Description
= Dsc
;
3551 // Set the short description to the archive component
3552 Desc
.ShortDesc
= ShortDesc
;
3554 // Get the transfer sizes
3557 if (stat(DestFile
.c_str(),&Buf
) == 0)
3559 // Hmm, the partial file is too big, erase it
3560 if ((Size
> 0) && (unsigned long long)Buf
.st_size
> Size
)
3561 RemoveFile("pkgAcqFile", DestFile
);
3563 PartialSize
= Buf
.st_size
;
3569 // AcqFile::Done - Item downloaded OK /*{{{*/
3570 void pkgAcqFile::Done(string
const &Message
,HashStringList
const &CalcHashes
,
3571 pkgAcquire::MethodConfig
const * const Cnf
)
3573 Item::Done(Message
,CalcHashes
,Cnf
);
3575 std::string
const FileName
= LookupTag(Message
,"Filename");
3578 // The files timestamp matches
3579 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
3582 // We have to copy it into place
3583 if (RealFileExists(DestFile
.c_str()) == false)
3586 if (_config
->FindB("Acquire::Source-Symlinks",true) == false ||
3587 Cnf
->Removable
== true)
3589 Desc
.URI
= "copy:" + FileName
;
3594 // Erase the file if it is a symlink so we can overwrite it
3596 if (lstat(DestFile
.c_str(),&St
) == 0)
3598 if (S_ISLNK(St
.st_mode
) != 0)
3599 RemoveFile("pkgAcqFile::Done", DestFile
);
3603 if (symlink(FileName
.c_str(),DestFile
.c_str()) != 0)
3605 _error
->PushToStack();
3606 _error
->Errno("pkgAcqFile::Done", "Symlinking file %s failed", DestFile
.c_str());
3607 std::stringstream msg
;
3608 _error
->DumpErrors(msg
, GlobalError::DEBUG
, false);
3609 _error
->RevertToStack();
3610 ErrorText
= msg
.str();
3617 // AcqFile::Failed - Failure handler /*{{{*/
3618 // ---------------------------------------------------------------------
3619 /* Here we try other sources */
3620 void pkgAcqFile::Failed(string
const &Message
, pkgAcquire::MethodConfig
const * const Cnf
)
3622 Item::Failed(Message
,Cnf
);
3624 // This is the retry counter
3626 Cnf
->LocalOnly
== false &&
3627 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
3637 string
pkgAcqFile::Custom600Headers() const /*{{{*/
3640 return "\nIndex-File: true";
3644 pkgAcqFile::~pkgAcqFile() {}