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
, std::string
const &msg
)/*{{{*/
182 _error
->Error("%s", msg
.c_str());
183 _error
->Notice("%s", _("Updating from such a repository can't be done securely, and is therefore disabled by default."));
187 _error
->Warning("%s", msg
.c_str());
188 _error
->Notice("%s", _("Data from such a repository can't be authenticated and is therefore potentially dangerous to use."));
190 _error
->Notice("%s", _("See apt-secure(8) manpage for repository creation and user configuration details."));
193 static bool MessageInsecureRepository(bool const isError
, char const * const msg
, std::string
const &repo
)
196 strprintf(m
, msg
, repo
.c_str());
197 return MessageInsecureRepository(isError
, m
);
200 static bool AllowInsecureRepositories(char const * const msg
, std::string
const &repo
,/*{{{*/
201 metaIndex
const * const MetaIndexParser
, pkgAcqMetaClearSig
* const TransactionManager
, pkgAcquire::Item
* const I
)
203 if(MetaIndexParser
->GetTrusted() == metaIndex::TRI_YES
)
206 if (_config
->FindB("Acquire::AllowInsecureRepositories") == true)
208 MessageInsecureRepository(false, msg
, repo
);
212 MessageInsecureRepository(true, msg
, repo
);
213 TransactionManager
->AbortTransaction();
214 I
->Status
= pkgAcquire::Item::StatError
;
218 static HashStringList
GetExpectedHashesFromFor(metaIndex
* const Parser
, std::string
const &MetaKey
)/*{{{*/
221 return HashStringList();
222 metaIndex::checkSum
* const R
= Parser
->Lookup(MetaKey
);
224 return HashStringList();
229 // all ::HashesRequired and ::GetExpectedHashes implementations /*{{{*/
230 /* ::GetExpectedHashes is abstract and has to be implemented by all subclasses.
231 It is best to implement it as broadly as possible, while ::HashesRequired defaults
232 to true and should be as restrictive as possible for false cases. Note that if
233 a hash is returned by ::GetExpectedHashes it must match. Only if it doesn't
234 ::HashesRequired is called to evaluate if its okay to have no hashes. */
235 APT_CONST
bool pkgAcqTransactionItem::HashesRequired() const
237 /* signed repositories obviously have a parser and good hashes.
238 unsigned repositories, too, as even if we can't trust them for security,
239 we can at least trust them for integrity of the download itself.
240 Only repositories without a Release file can (obviously) not have
241 hashes – and they are very uncommon and strongly discouraged */
242 return TransactionManager
->MetaIndexParser
!= NULL
&&
243 TransactionManager
->MetaIndexParser
->GetLoadedSuccessfully() == metaIndex::TRI_YES
;
245 HashStringList
pkgAcqTransactionItem::GetExpectedHashes() const
247 return GetExpectedHashesFor(GetMetaKey());
250 APT_CONST
bool pkgAcqMetaBase::HashesRequired() const
252 // Release and co have no hashes 'by design'.
255 HashStringList
pkgAcqMetaBase::GetExpectedHashes() const
257 return HashStringList();
260 APT_CONST
bool pkgAcqIndexDiffs::HashesRequired() const
262 /* We can't check hashes of rred result as we don't know what the
263 hash of the file will be. We just know the hash of the patch(es),
264 the hash of the file they will apply on and the hash of the resulting
266 if (State
== StateFetchDiff
)
270 HashStringList
pkgAcqIndexDiffs::GetExpectedHashes() const
272 if (State
== StateFetchDiff
)
273 return available_patches
[0].download_hashes
;
274 return HashStringList();
277 APT_CONST
bool pkgAcqIndexMergeDiffs::HashesRequired() const
279 /* @see #pkgAcqIndexDiffs::HashesRequired, with the difference that
280 we can check the rred result after all patches are applied as
281 we know the expected result rather than potentially apply more patches */
282 if (State
== StateFetchDiff
)
284 return State
== StateApplyDiff
;
286 HashStringList
pkgAcqIndexMergeDiffs::GetExpectedHashes() const
288 if (State
== StateFetchDiff
)
289 return patch
.download_hashes
;
290 else if (State
== StateApplyDiff
)
291 return GetExpectedHashesFor(Target
.MetaKey
);
292 return HashStringList();
295 APT_CONST
bool pkgAcqArchive::HashesRequired() const
297 return LocalSource
== false;
299 HashStringList
pkgAcqArchive::GetExpectedHashes() const
301 // figured out while parsing the records
302 return ExpectedHashes
;
305 APT_CONST
bool pkgAcqFile::HashesRequired() const
307 // supplied as parameter at creation time, so the caller decides
308 return ExpectedHashes
.usable();
310 HashStringList
pkgAcqFile::GetExpectedHashes() const
312 return ExpectedHashes
;
315 // Acquire::Item::QueueURI and specialisations from child classes /*{{{*/
316 bool pkgAcquire::Item::QueueURI(pkgAcquire::ItemDesc
&Item
)
318 Owner
->Enqueue(Item
);
321 /* The idea here is that an item isn't queued if it exists on disk and the
322 transition manager was a hit as this means that the files it contains
323 the checksums for can't be updated either (or they are and we are asking
324 for a hashsum mismatch to happen which helps nobody) */
325 bool pkgAcqTransactionItem::QueueURI(pkgAcquire::ItemDesc
&Item
)
327 if (TransactionManager
->State
!= TransactionStarted
)
329 if (_config
->FindB("Debug::Acquire::Transaction", false))
330 std::clog
<< "Skip " << Target
.URI
<< " as transaction was already dealt with!" << std::endl
;
333 std::string
const FinalFile
= GetFinalFilename();
334 if (TransactionManager
!= NULL
&& TransactionManager
->IMSHit
== true &&
335 FileExists(FinalFile
) == true)
337 PartialFile
= DestFile
= FinalFile
;
341 // If we got the InRelease file via a mirror, pick all indexes directly from this mirror, too
342 if (TransactionManager
!= nullptr && TransactionManager
->BaseURI
.empty() == false &&
343 URI::SiteOnly(Item
.URI
) != URI::SiteOnly(TransactionManager
->BaseURI
))
345 // this ensures we rewrite only once and only the first step
346 auto const OldBaseURI
= Target
.Option(IndexTarget::BASE_URI
);
347 if (OldBaseURI
.empty() == false && APT::String::Startswith(Item
.URI
, OldBaseURI
))
349 auto const ExtraPath
= Item
.URI
.substr(OldBaseURI
.length());
350 Item
.URI
= flCombine(TransactionManager
->BaseURI
, ExtraPath
);
351 UsedMirror
= TransactionManager
->UsedMirror
;
352 if (Item
.Description
.find(" ") != string::npos
)
353 Item
.Description
.replace(0, Item
.Description
.find(" "), UsedMirror
);
356 return pkgAcquire::Item::QueueURI(Item
);
358 /* The transition manager InRelease itself (or its older sisters-in-law
359 Release & Release.gpg) is always queued as this allows us to rerun gpgv
360 on it to verify that we aren't stalled with old files */
361 bool pkgAcqMetaBase::QueueURI(pkgAcquire::ItemDesc
&Item
)
363 return pkgAcquire::Item::QueueURI(Item
);
365 /* the Diff/Index needs to queue also the up-to-date complete index file
366 to ensure that the list cleaner isn't eating it */
367 bool pkgAcqDiffIndex::QueueURI(pkgAcquire::ItemDesc
&Item
)
369 if (pkgAcqTransactionItem::QueueURI(Item
) == true)
375 // Acquire::Item::GetFinalFilename and specialisations for child classes /*{{{*/
376 std::string
pkgAcquire::Item::GetFinalFilename() const
378 // Beware: Desc.URI is modified by redirections
379 return GetFinalFileNameFromURI(Desc
.URI
);
381 std::string
pkgAcqDiffIndex::GetFinalFilename() const
383 return GetFinalFileNameFromURI(GetDiffIndexURI(Target
));
385 std::string
pkgAcqIndex::GetFinalFilename() const
387 std::string
const FinalFile
= GetFinalFileNameFromURI(Target
.URI
);
388 return GetKeepCompressedFileName(FinalFile
, Target
);
390 std::string
pkgAcqMetaSig::GetFinalFilename() const
392 return GetFinalFileNameFromURI(Target
.URI
);
394 std::string
pkgAcqBaseIndex::GetFinalFilename() const
396 return GetFinalFileNameFromURI(Target
.URI
);
398 std::string
pkgAcqMetaBase::GetFinalFilename() const
400 return GetFinalFileNameFromURI(Target
.URI
);
402 std::string
pkgAcqArchive::GetFinalFilename() const
404 return _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
407 // pkgAcqTransactionItem::GetMetaKey and specialisations for child classes /*{{{*/
408 std::string
pkgAcqTransactionItem::GetMetaKey() const
410 return Target
.MetaKey
;
412 std::string
pkgAcqIndex::GetMetaKey() const
414 if (Stage
== STAGE_DECOMPRESS_AND_VERIFY
|| CurrentCompressionExtension
== "uncompressed")
415 return Target
.MetaKey
;
416 return Target
.MetaKey
+ "." + CurrentCompressionExtension
;
418 std::string
pkgAcqDiffIndex::GetMetaKey() const
420 return GetDiffIndexFileName(Target
.MetaKey
);
423 //pkgAcqTransactionItem::TransactionState and specialisations for child classes /*{{{*/
424 bool pkgAcqTransactionItem::TransactionState(TransactionStates
const state
)
426 bool const Debug
= _config
->FindB("Debug::Acquire::Transaction", false);
429 case TransactionStarted
: _error
->Fatal("Item %s changed to invalid transaction start state!", Target
.URI
.c_str()); break;
430 case TransactionAbort
:
432 std::clog
<< " Cancel: " << DestFile
<< std::endl
;
433 if (Status
== pkgAcquire::Item::StatIdle
)
435 Status
= pkgAcquire::Item::StatDone
;
439 case TransactionCommit
:
440 if(PartialFile
.empty() == false)
442 bool sameFile
= (PartialFile
== DestFile
);
443 // we use symlinks on IMS-Hit to avoid copies
444 if (RealFileExists(DestFile
))
447 if (lstat(PartialFile
.c_str(), &Buf
) != -1)
449 if (S_ISLNK(Buf
.st_mode
) && Buf
.st_size
> 0)
451 char partial
[Buf
.st_size
+ 1];
452 ssize_t
const sp
= readlink(PartialFile
.c_str(), partial
, Buf
.st_size
);
454 _error
->Errno("pkgAcqTransactionItem::TransactionState-sp", _("Failed to readlink %s"), PartialFile
.c_str());
458 sameFile
= (DestFile
== partial
);
463 _error
->Errno("pkgAcqTransactionItem::TransactionState-stat", _("Failed to stat %s"), PartialFile
.c_str());
465 if (sameFile
== false)
467 // ensure that even without lists-cleanup all compressions are nuked
468 std::string FinalFile
= GetFinalFileNameFromURI(Target
.URI
);
469 if (FileExists(FinalFile
))
472 std::clog
<< "rm " << FinalFile
<< " # " << DescURI() << std::endl
;
473 if (RemoveFile("TransactionStates-Cleanup", FinalFile
) == false)
476 for (auto const &ext
: APT::Configuration::getCompressorExtensions())
478 auto const Final
= FinalFile
+ ext
;
479 if (FileExists(Final
))
482 std::clog
<< "rm " << Final
<< " # " << DescURI() << std::endl
;
483 if (RemoveFile("TransactionStates-Cleanup", Final
) == false)
488 std::clog
<< "mv " << PartialFile
<< " -> "<< DestFile
<< " # " << DescURI() << std::endl
;
489 if (Rename(PartialFile
, DestFile
) == false)
492 else if(Debug
== true)
493 std::clog
<< "keep " << PartialFile
<< " # " << DescURI() << std::endl
;
497 std::clog
<< "rm " << DestFile
<< " # " << DescURI() << std::endl
;
498 if (RemoveFile("TransItem::TransactionCommit", DestFile
) == false)
505 bool pkgAcqMetaBase::TransactionState(TransactionStates
const state
)
507 // Do not remove InRelease on IMSHit of Release.gpg [yes, this is very edgecasey]
508 if (TransactionManager
->IMSHit
== false)
509 return pkgAcqTransactionItem::TransactionState(state
);
512 bool pkgAcqIndex::TransactionState(TransactionStates
const state
)
514 if (pkgAcqTransactionItem::TransactionState(state
) == false)
519 case TransactionStarted
: _error
->Fatal("AcqIndex %s changed to invalid transaction start state!", Target
.URI
.c_str()); break;
520 case TransactionAbort
:
521 if (Stage
== STAGE_DECOMPRESS_AND_VERIFY
)
523 // keep the compressed file, but drop the decompressed
524 EraseFileName
.clear();
525 if (PartialFile
.empty() == false && flExtension(PartialFile
) != CurrentCompressionExtension
)
526 RemoveFile("TransactionAbort", PartialFile
);
529 case TransactionCommit
:
530 if (EraseFileName
.empty() == false)
531 RemoveFile("AcqIndex::TransactionCommit", EraseFileName
);
536 bool pkgAcqDiffIndex::TransactionState(TransactionStates
const state
)
538 if (pkgAcqTransactionItem::TransactionState(state
) == false)
543 case TransactionStarted
: _error
->Fatal("Item %s changed to invalid transaction start state!", Target
.URI
.c_str()); break;
544 case TransactionCommit
:
546 case TransactionAbort
:
547 std::string
const Partial
= GetPartialFileNameFromURI(Target
.URI
);
548 RemoveFile("TransactionAbort", Partial
);
556 class APT_HIDDEN NoActionItem
: public pkgAcquire::Item
/*{{{*/
557 /* The sole purpose of this class is having an item which does nothing to
558 reach its done state to prevent cleanup deleting the mentioned file.
559 Handy in cases in which we know we have the file already, like IMS-Hits. */
561 IndexTarget
const Target
;
563 virtual std::string
DescURI() const APT_OVERRIDE
{return Target
.URI
;};
564 virtual HashStringList
GetExpectedHashes() const APT_OVERRIDE
{return HashStringList();};
566 NoActionItem(pkgAcquire
* const Owner
, IndexTarget
const &Target
) :
567 pkgAcquire::Item(Owner
), Target(Target
)
570 DestFile
= GetFinalFileNameFromURI(Target
.URI
);
572 NoActionItem(pkgAcquire
* const Owner
, IndexTarget
const &Target
, std::string
const &FinalFile
) :
573 pkgAcquire::Item(Owner
), Target(Target
)
576 DestFile
= FinalFile
;
580 class APT_HIDDEN CleanupItem
: public pkgAcqTransactionItem
/*{{{*/
581 /* This class ensures that a file which was configured but isn't downloaded
582 for various reasons isn't kept in an old version in the lists directory.
583 In a way its the reverse of NoActionItem as it helps with removing files
584 even if the lists-cleanup is deactivated. */
587 virtual std::string
DescURI() const APT_OVERRIDE
{return Target
.URI
;};
588 virtual HashStringList
GetExpectedHashes() const APT_OVERRIDE
{return HashStringList();};
590 CleanupItem(pkgAcquire
* const Owner
, pkgAcqMetaClearSig
* const TransactionManager
, IndexTarget
const &Target
) :
591 pkgAcqTransactionItem(Owner
, TransactionManager
, Target
)
594 DestFile
= GetFinalFileNameFromURI(Target
.URI
);
596 bool TransactionState(TransactionStates
const state
) APT_OVERRIDE
600 case TransactionStarted
:
602 case TransactionAbort
:
604 case TransactionCommit
:
605 if (_config
->FindB("Debug::Acquire::Transaction", false) == true)
606 std::clog
<< "rm " << DestFile
<< " # " << DescURI() << std::endl
;
607 if (RemoveFile("TransItem::TransactionCommit", DestFile
) == false)
616 // Acquire::Item::Item - Constructor /*{{{*/
617 APT_IGNORE_DEPRECATED_PUSH
618 pkgAcquire::Item::Item(pkgAcquire
* const owner
) :
619 FileSize(0), PartialSize(0), Mode(0), ID(0), Complete(false), Local(false),
620 QueueCounter(0), ExpectedAdditionalItems(0), Owner(owner
), d(NULL
)
625 APT_IGNORE_DEPRECATED_POP
627 // Acquire::Item::~Item - Destructor /*{{{*/
628 pkgAcquire::Item::~Item()
633 std::string
pkgAcquire::Item::Custom600Headers() const /*{{{*/
635 return std::string();
638 std::string
pkgAcquire::Item::ShortDesc() const /*{{{*/
643 APT_CONST
void pkgAcquire::Item::Finished() /*{{{*/
647 APT_PURE pkgAcquire
* pkgAcquire::Item::GetOwner() const /*{{{*/
652 APT_CONST
pkgAcquire::ItemDesc
&pkgAcquire::Item::GetItemDesc() /*{{{*/
657 APT_CONST
bool pkgAcquire::Item::IsTrusted() const /*{{{*/
662 // Acquire::Item::Failed - Item failed to download /*{{{*/
663 // ---------------------------------------------------------------------
664 /* We return to an idle state if there are still other queues that could
666 void pkgAcquire::Item::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)
668 if (QueueCounter
<= 1)
670 /* This indicates that the file is not available right now but might
671 be sometime later. If we do a retry cycle then this should be
673 if (Cnf
!= NULL
&& Cnf
->LocalOnly
== true &&
674 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
690 case StatTransientNetworkError
:
697 string
const FailReason
= LookupTag(Message
, "FailReason");
698 enum { MAXIMUM_SIZE_EXCEEDED
, HASHSUM_MISMATCH
, OTHER
} failreason
= OTHER
;
699 if ( FailReason
== "MaximumSizeExceeded")
700 failreason
= MAXIMUM_SIZE_EXCEEDED
;
701 else if (Status
== StatAuthError
)
702 failreason
= HASHSUM_MISMATCH
;
704 if(ErrorText
.empty())
706 if (Status
== StatAuthError
)
708 std::ostringstream out
;
711 case HASHSUM_MISMATCH
:
712 out
<< _("Hash Sum mismatch") << std::endl
;
714 case MAXIMUM_SIZE_EXCEEDED
:
716 out
<< LookupTag(Message
, "Message") << std::endl
;
719 auto const ExpectedHashes
= GetExpectedHashes();
720 if (ExpectedHashes
.empty() == false)
722 out
<< "Hashes of expected file:" << std::endl
;
723 for (auto const &hs
: ExpectedHashes
)
724 out
<< " - " << hs
.toStr() << std::endl
;
726 if (failreason
== HASHSUM_MISMATCH
)
728 out
<< "Hashes of received file:" << std::endl
;
729 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
731 std::string
const tagname
= std::string(*type
) + "-Hash";
732 std::string
const hashsum
= LookupTag(Message
, tagname
.c_str());
733 if (hashsum
.empty() == false)
734 out
<< " - " << HashString(*type
, hashsum
).toStr() << std::endl
;
736 out
<< "Last modification reported: " << LookupTag(Message
, "Last-Modified", "<none>") << std::endl
;
738 ErrorText
= out
.str();
741 ErrorText
= LookupTag(Message
,"Message");
746 case MAXIMUM_SIZE_EXCEEDED
: RenameOnError(MaximumSizeExceeded
); break;
747 case HASHSUM_MISMATCH
: RenameOnError(HashSumMismatch
); break;
751 if (FailReason
.empty() == false)
752 ReportMirrorFailureToCentral(*this, FailReason
, ErrorText
);
754 ReportMirrorFailureToCentral(*this, ErrorText
, ErrorText
);
756 if (QueueCounter
> 1)
760 // Acquire::Item::Start - Item has begun to download /*{{{*/
761 // ---------------------------------------------------------------------
762 /* Stash status and the file size. Note that setting Complete means
763 sub-phases of the acquire process such as decompresion are operating */
764 void pkgAcquire::Item::Start(string
const &/*Message*/, unsigned long long const Size
)
766 Status
= StatFetching
;
768 if (FileSize
== 0 && Complete
== false)
772 // Acquire::Item::VerifyDone - check if Item was downloaded OK /*{{{*/
773 /* Note that hash-verification is 'hardcoded' in acquire-worker and has
774 * already passed if this method is called. */
775 bool pkgAcquire::Item::VerifyDone(std::string
const &Message
,
776 pkgAcquire::MethodConfig
const * const /*Cnf*/)
778 std::string
const FileName
= LookupTag(Message
,"Filename");
779 if (FileName
.empty() == true)
782 ErrorText
= "Method gave a blank filename";
789 // Acquire::Item::Done - Item downloaded OK /*{{{*/
790 void pkgAcquire::Item::Done(string
const &/*Message*/, HashStringList
const &Hashes
,
791 pkgAcquire::MethodConfig
const * const /*Cnf*/)
793 // We just downloaded something..
796 unsigned long long const downloadedSize
= Hashes
.FileSize();
797 if (downloadedSize
!= 0)
799 FileSize
= downloadedSize
;
803 ErrorText
= string();
804 Owner
->Dequeue(this);
807 // Acquire::Item::Rename - Rename a file /*{{{*/
808 // ---------------------------------------------------------------------
809 /* This helper function is used by a lot of item methods as their final
811 bool pkgAcquire::Item::Rename(string
const &From
,string
const &To
)
813 if (From
== To
|| rename(From
.c_str(),To
.c_str()) == 0)
817 strprintf(S
, _("rename failed, %s (%s -> %s)."), strerror(errno
),
818 From
.c_str(),To
.c_str());
820 if (ErrorText
.empty())
823 ErrorText
= ErrorText
+ ": " + S
;
827 void pkgAcquire::Item::Dequeue() /*{{{*/
829 Owner
->Dequeue(this);
832 bool pkgAcquire::Item::RenameOnError(pkgAcquire::Item::RenameOnErrorState
const error
)/*{{{*/
834 if (RealFileExists(DestFile
))
835 Rename(DestFile
, DestFile
+ ".FAILED");
840 case HashSumMismatch
:
841 errtext
= _("Hash Sum mismatch");
844 errtext
= _("Size mismatch");
845 Status
= StatAuthError
;
848 errtext
= _("Invalid file format");
850 // do not report as usually its not the mirrors fault, but Portal/Proxy
853 errtext
= _("Signature error");
857 strprintf(errtext
, _("Clearsigned file isn't valid, got '%s' (does the network require authentication?)"), "NOSPLIT");
858 Status
= StatAuthError
;
860 case MaximumSizeExceeded
:
861 // the method is expected to report a good error for this
864 // no handling here, done by callers
867 if (ErrorText
.empty())
872 void pkgAcquire::Item::SetActiveSubprocess(const std::string
&subprocess
)/*{{{*/
874 ActiveSubprocess
= subprocess
;
875 APT_IGNORE_DEPRECATED(Mode
= ActiveSubprocess
.c_str();)
878 // Acquire::Item::ReportMirrorFailure /*{{{*/
879 void pkgAcquire::Item::ReportMirrorFailure(std::string
const &FailCode
)
881 ReportMirrorFailureToCentral(*this, FailCode
, FailCode
);
884 std::string
pkgAcquire::Item::HashSum() const /*{{{*/
886 HashStringList
const hashes
= GetExpectedHashes();
887 HashString
const * const hs
= hashes
.find(NULL
);
888 return hs
!= NULL
? hs
->toStr() : "";
892 pkgAcqTransactionItem::pkgAcqTransactionItem(pkgAcquire
* const Owner
, /*{{{*/
893 pkgAcqMetaClearSig
* const transactionManager
, IndexTarget
const &target
) :
894 pkgAcquire::Item(Owner
), d(NULL
), Target(target
), TransactionManager(transactionManager
)
896 if (TransactionManager
!= this)
897 TransactionManager
->Add(this);
900 pkgAcqTransactionItem::~pkgAcqTransactionItem() /*{{{*/
904 HashStringList
pkgAcqTransactionItem::GetExpectedHashesFor(std::string
const &MetaKey
) const /*{{{*/
906 return GetExpectedHashesFromFor(TransactionManager
->MetaIndexParser
, MetaKey
);
910 static void LoadLastMetaIndexParser(pkgAcqMetaClearSig
* const TransactionManager
, std::string
const &FinalRelease
, std::string
const &FinalInRelease
)/*{{{*/
912 if (TransactionManager
->IMSHit
== true)
914 if (RealFileExists(FinalInRelease
) || RealFileExists(FinalRelease
))
916 TransactionManager
->LastMetaIndexParser
= TransactionManager
->MetaIndexParser
->UnloadedClone();
917 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
919 _error
->PushToStack();
920 if (RealFileExists(FinalInRelease
))
921 TransactionManager
->LastMetaIndexParser
->Load(FinalInRelease
, NULL
);
923 TransactionManager
->LastMetaIndexParser
->Load(FinalRelease
, NULL
);
924 // its unlikely to happen, but if what we have is bad ignore it
925 if (_error
->PendingError())
927 delete TransactionManager
->LastMetaIndexParser
;
928 TransactionManager
->LastMetaIndexParser
= NULL
;
930 _error
->RevertToStack();
936 // AcqMetaBase - Constructor /*{{{*/
937 pkgAcqMetaBase::pkgAcqMetaBase(pkgAcquire
* const Owner
,
938 pkgAcqMetaClearSig
* const TransactionManager
,
939 std::vector
<IndexTarget
> const &IndexTargets
,
940 IndexTarget
const &DataTarget
)
941 : pkgAcqTransactionItem(Owner
, TransactionManager
, DataTarget
), d(NULL
),
942 IndexTargets(IndexTargets
),
943 AuthPass(false), IMSHit(false), State(TransactionStarted
)
947 // AcqMetaBase::Add - Add a item to the current Transaction /*{{{*/
948 void pkgAcqMetaBase::Add(pkgAcqTransactionItem
* const I
)
950 Transaction
.push_back(I
);
953 // AcqMetaBase::AbortTransaction - Abort the current Transaction /*{{{*/
954 void pkgAcqMetaBase::AbortTransaction()
956 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
957 std::clog
<< "AbortTransaction: " << TransactionManager
<< std::endl
;
959 switch (TransactionManager
->State
)
961 case TransactionStarted
: break;
962 case TransactionAbort
: _error
->Fatal("Transaction %s was already aborted and is aborted again", TransactionManager
->Target
.URI
.c_str()); return;
963 case TransactionCommit
: _error
->Fatal("Transaction %s was already aborted and is now commited", TransactionManager
->Target
.URI
.c_str()); return;
965 TransactionManager
->State
= TransactionAbort
;
967 // ensure the toplevel is in error state too
968 for (std::vector
<pkgAcqTransactionItem
*>::iterator I
= Transaction
.begin();
969 I
!= Transaction
.end(); ++I
)
971 if ((*I
)->Status
!= pkgAcquire::Item::StatFetching
)
973 (*I
)->TransactionState(TransactionAbort
);
978 // AcqMetaBase::TransactionHasError - Check for errors in Transaction /*{{{*/
979 APT_PURE
bool pkgAcqMetaBase::TransactionHasError() const
981 for (std::vector
<pkgAcqTransactionItem
*>::const_iterator I
= Transaction
.begin();
982 I
!= Transaction
.end(); ++I
)
984 switch((*I
)->Status
) {
985 case StatDone
: break;
986 case StatIdle
: break;
987 case StatAuthError
: return true;
988 case StatError
: return true;
989 case StatTransientNetworkError
: return true;
990 case StatFetching
: break;
996 // AcqMetaBase::CommitTransaction - Commit a transaction /*{{{*/
997 void pkgAcqMetaBase::CommitTransaction()
999 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1000 std::clog
<< "CommitTransaction: " << this << std::endl
;
1002 switch (TransactionManager
->State
)
1004 case TransactionStarted
: break;
1005 case TransactionAbort
: _error
->Fatal("Transaction %s was already commited and is now aborted", TransactionManager
->Target
.URI
.c_str()); return;
1006 case TransactionCommit
: _error
->Fatal("Transaction %s was already commited and is again commited", TransactionManager
->Target
.URI
.c_str()); return;
1008 TransactionManager
->State
= TransactionCommit
;
1010 // move new files into place *and* remove files that are not
1011 // part of the transaction but are still on disk
1012 for (std::vector
<pkgAcqTransactionItem
*>::iterator I
= Transaction
.begin();
1013 I
!= Transaction
.end(); ++I
)
1015 (*I
)->TransactionState(TransactionCommit
);
1017 Transaction
.clear();
1020 // AcqMetaBase::TransactionStageCopy - Stage a file for copying /*{{{*/
1021 void pkgAcqMetaBase::TransactionStageCopy(pkgAcqTransactionItem
* const I
,
1022 const std::string
&From
,
1023 const std::string
&To
)
1025 I
->PartialFile
= From
;
1029 // AcqMetaBase::TransactionStageRemoval - Stage a file for removal /*{{{*/
1030 void pkgAcqMetaBase::TransactionStageRemoval(pkgAcqTransactionItem
* const I
,
1031 const std::string
&FinalFile
)
1033 I
->PartialFile
= "";
1034 I
->DestFile
= FinalFile
;
1037 // AcqMetaBase::GenerateAuthWarning - Check gpg authentication error /*{{{*/
1038 /* This method is called from ::Failed handlers. If it returns true,
1039 no fallback to other files or modi is performed */
1040 bool pkgAcqMetaBase::CheckStopAuthentication(pkgAcquire::Item
* const I
, const std::string
&Message
)
1042 string
const Final
= I
->GetFinalFilename();
1043 std::string
const GPGError
= LookupTag(Message
, "Message");
1044 if (FileExists(Final
))
1046 I
->Status
= StatTransientNetworkError
;
1047 _error
->Warning(_("An error occurred during the signature verification. "
1048 "The repository is not updated and the previous index files will be used. "
1049 "GPG error: %s: %s"),
1050 Desc
.Description
.c_str(),
1052 RunScripts("APT::Update::Auth-Failure");
1054 } else if (LookupTag(Message
,"Message").find("NODATA") != string::npos
) {
1055 /* Invalid signature file, reject (LP: #346386) (Closes: #627642) */
1056 _error
->Error(_("GPG error: %s: %s"),
1057 Desc
.Description
.c_str(),
1059 I
->Status
= StatAuthError
;
1062 _error
->Warning(_("GPG error: %s: %s"),
1063 Desc
.Description
.c_str(),
1066 // gpgv method failed
1067 ReportMirrorFailureToCentral(*this, "GPGFailure", GPGError
);
1071 // AcqMetaBase::Custom600Headers - Get header for AcqMetaBase /*{{{*/
1072 // ---------------------------------------------------------------------
1073 string
pkgAcqMetaBase::Custom600Headers() const
1075 std::string Header
= "\nIndex-File: true";
1076 std::string MaximumSize
;
1077 strprintf(MaximumSize
, "\nMaximum-Size: %i",
1078 _config
->FindI("Acquire::MaxReleaseFileSize", 10*1000*1000));
1079 Header
+= MaximumSize
;
1081 string
const FinalFile
= GetFinalFilename();
1083 if (stat(FinalFile
.c_str(),&Buf
) == 0)
1084 Header
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1089 // AcqMetaBase::QueueForSignatureVerify /*{{{*/
1090 void pkgAcqMetaBase::QueueForSignatureVerify(pkgAcqTransactionItem
* const I
, std::string
const &File
, std::string
const &Signature
)
1093 I
->Desc
.URI
= "gpgv:" + Signature
;
1096 I
->SetActiveSubprocess("gpgv");
1099 // AcqMetaBase::CheckDownloadDone /*{{{*/
1100 bool pkgAcqMetaBase::CheckDownloadDone(pkgAcqTransactionItem
* const I
, const std::string
&Message
, HashStringList
const &Hashes
) const
1102 // We have just finished downloading a Release file (it is not
1105 // Save the final base URI we got this Release file from
1106 if (I
->UsedMirror
.empty() == false && _config
->FindB("Acquire::SameMirrorForAllIndexes", true))
1108 if (APT::String::Endswith(I
->Desc
.URI
, "InRelease"))
1109 TransactionManager
->BaseURI
= I
->Desc
.URI
.substr(0, I
->Desc
.URI
.length() - strlen("InRelease"));
1110 else if (APT::String::Endswith(I
->Desc
.URI
, "Release"))
1111 TransactionManager
->BaseURI
= I
->Desc
.URI
.substr(0, I
->Desc
.URI
.length() - strlen("Release"));
1114 std::string
const FileName
= LookupTag(Message
,"Filename");
1115 if (FileName
!= I
->DestFile
&& RealFileExists(I
->DestFile
) == false)
1118 I
->Desc
.URI
= "copy:" + FileName
;
1119 I
->QueueURI(I
->Desc
);
1123 // make sure to verify against the right file on I-M-S hit
1124 bool IMSHit
= StringToBool(LookupTag(Message
,"IMS-Hit"), false);
1125 if (IMSHit
== false && Hashes
.usable())
1127 // detect IMS-Hits servers haven't detected by Hash comparison
1128 std::string
const FinalFile
= I
->GetFinalFilename();
1129 if (RealFileExists(FinalFile
) && Hashes
.VerifyFile(FinalFile
) == true)
1132 RemoveFile("CheckDownloadDone", I
->DestFile
);
1138 // for simplicity, the transaction manager is always InRelease
1139 // even if it doesn't exist.
1140 if (TransactionManager
!= NULL
)
1141 TransactionManager
->IMSHit
= true;
1142 I
->PartialFile
= I
->DestFile
= I
->GetFinalFilename();
1145 // set Item to complete as the remaining work is all local (verify etc)
1151 bool pkgAcqMetaBase::CheckAuthDone(string
const &Message
) /*{{{*/
1153 // At this point, the gpgv method has succeeded, so there is a
1154 // valid signature from a key in the trusted keyring. We
1155 // perform additional verification of its contents, and use them
1156 // to verify the indexes we are about to download
1158 if (TransactionManager
->IMSHit
== false)
1160 // open the last (In)Release if we have it
1161 std::string
const FinalFile
= GetFinalFilename();
1162 std::string FinalRelease
;
1163 std::string FinalInRelease
;
1164 if (APT::String::Endswith(FinalFile
, "InRelease"))
1166 FinalInRelease
= FinalFile
;
1167 FinalRelease
= FinalFile
.substr(0, FinalFile
.length() - strlen("InRelease")) + "Release";
1171 FinalInRelease
= FinalFile
.substr(0, FinalFile
.length() - strlen("Release")) + "InRelease";
1172 FinalRelease
= FinalFile
;
1174 LoadLastMetaIndexParser(TransactionManager
, FinalRelease
, FinalInRelease
);
1177 if (TransactionManager
->MetaIndexParser
->Load(DestFile
, &ErrorText
) == false)
1179 Status
= StatAuthError
;
1183 if (!VerifyVendor(Message
))
1185 Status
= StatAuthError
;
1189 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1190 std::cerr
<< "Signature verification succeeded: "
1191 << DestFile
<< std::endl
;
1193 // Download further indexes with verification
1199 void pkgAcqMetaBase::QueueIndexes(bool const verify
) /*{{{*/
1201 // at this point the real Items are loaded in the fetcher
1202 ExpectedAdditionalItems
= 0;
1204 bool metaBaseSupportsByHash
= false;
1205 if (TransactionManager
!= NULL
&& TransactionManager
->MetaIndexParser
!= NULL
)
1206 metaBaseSupportsByHash
= TransactionManager
->MetaIndexParser
->GetSupportsAcquireByHash();
1208 for (std::vector
<IndexTarget
>::iterator Target
= IndexTargets
.begin();
1209 Target
!= IndexTargets
.end();
1212 // all is an implementation detail. Users shouldn't use this as arch
1213 // We need this support trickery here as e.g. Debian has binary-all files already,
1214 // but arch:all packages are still in the arch:any files, so we would waste precious
1215 // download time, bandwidth and diskspace for nothing, BUT Debian doesn't feature all
1216 // in the set of supported architectures, so we can filter based on this property rather
1217 // than invent an entirely new flag we would need to carry for all of eternity.
1218 if (Target
->Option(IndexTarget::ARCHITECTURE
) == "all")
1220 if (TransactionManager
->MetaIndexParser
->IsArchitectureSupported("all") == false ||
1221 TransactionManager
->MetaIndexParser
->IsArchitectureAllSupportedFor(*Target
) == false)
1223 new CleanupItem(Owner
, TransactionManager
, *Target
);
1228 bool trypdiff
= Target
->OptionBool(IndexTarget::PDIFFS
);
1231 if (TransactionManager
->MetaIndexParser
->Exists(Target
->MetaKey
) == false)
1233 // optional targets that we do not have in the Release file are skipped
1234 if (Target
->IsOptional
)
1236 new CleanupItem(Owner
, TransactionManager
, *Target
);
1240 std::string
const &arch
= Target
->Option(IndexTarget::ARCHITECTURE
);
1241 if (arch
.empty() == false)
1243 if (TransactionManager
->MetaIndexParser
->IsArchitectureSupported(arch
) == false)
1245 new CleanupItem(Owner
, TransactionManager
, *Target
);
1246 _error
->Notice(_("Skipping acquire of configured file '%s' as repository '%s' doesn't support architecture '%s'"),
1247 Target
->MetaKey
.c_str(), TransactionManager
->Target
.Description
.c_str(), arch
.c_str());
1250 // if the architecture is officially supported but currently no packages for it available,
1251 // ignore silently as this is pretty much the same as just shipping an empty file.
1252 // if we don't know which architectures are supported, we do NOT ignore it to notify user about this
1253 if (TransactionManager
->MetaIndexParser
->IsArchitectureSupported("*undefined*") == false)
1255 new CleanupItem(Owner
, TransactionManager
, *Target
);
1260 Status
= StatAuthError
;
1261 strprintf(ErrorText
, _("Unable to find expected entry '%s' in Release file (Wrong sources.list entry or malformed file)"), Target
->MetaKey
.c_str());
1266 auto const hashes
= GetExpectedHashesFor(Target
->MetaKey
);
1267 if (hashes
.empty() == false)
1269 if (hashes
.usable() == false)
1271 new CleanupItem(Owner
, TransactionManager
, *Target
);
1272 _error
->Warning(_("Skipping acquire of configured file '%s' as repository '%s' provides only weak security information for it"),
1273 Target
->MetaKey
.c_str(), TransactionManager
->Target
.Description
.c_str());
1276 // empty files are skipped as acquiring the very small compressed files is a waste of time
1277 else if (hashes
.FileSize() == 0)
1279 new CleanupItem(Owner
, TransactionManager
, *Target
);
1285 // autoselect the compression method
1286 std::vector
<std::string
> types
= VectorizeString(Target
->Option(IndexTarget::COMPRESSIONTYPES
), ' ');
1287 types
.erase(std::remove_if(types
.begin(), types
.end(), [&](std::string
const &t
) {
1288 if (t
== "uncompressed")
1289 return TransactionManager
->MetaIndexParser
->Exists(Target
->MetaKey
) == false;
1290 std::string
const MetaKey
= Target
->MetaKey
+ "." + t
;
1291 return TransactionManager
->MetaIndexParser
->Exists(MetaKey
) == false;
1293 if (types
.empty() == false)
1295 std::ostringstream os
;
1296 // add the special compressiontype byhash first if supported
1297 std::string
const useByHashConf
= Target
->Option(IndexTarget::BY_HASH
);
1298 bool useByHash
= false;
1299 if(useByHashConf
== "force")
1302 useByHash
= StringToBool(useByHashConf
) == true && metaBaseSupportsByHash
;
1303 if (useByHash
== true)
1305 std::copy(types
.begin(), types
.end()-1, std::ostream_iterator
<std::string
>(os
, " "));
1306 os
<< *types
.rbegin();
1307 Target
->Options
["COMPRESSIONTYPES"] = os
.str();
1310 Target
->Options
["COMPRESSIONTYPES"].clear();
1312 std::string filename
= GetExistingFilename(GetFinalFileNameFromURI(Target
->URI
));
1313 if (filename
.empty() == false)
1315 // if the Release file is a hit and we have an index it must be the current one
1316 if (TransactionManager
->IMSHit
== true)
1318 else if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1320 // see if the file changed since the last Release file
1321 // we use the uncompressed files as we might compress differently compared to the server,
1322 // so the hashes might not match, even if they contain the same data.
1323 HashStringList
const newFile
= GetExpectedHashesFromFor(TransactionManager
->MetaIndexParser
, Target
->MetaKey
);
1324 HashStringList
const oldFile
= GetExpectedHashesFromFor(TransactionManager
->LastMetaIndexParser
, Target
->MetaKey
);
1325 if (newFile
!= oldFile
)
1332 trypdiff
= false; // no file to patch
1334 if (filename
.empty() == false)
1336 new NoActionItem(Owner
, *Target
, filename
);
1337 std::string
const idxfilename
= GetFinalFileNameFromURI(GetDiffIndexURI(*Target
));
1338 if (FileExists(idxfilename
))
1339 new NoActionItem(Owner
, *Target
, idxfilename
);
1343 // check if we have patches available
1344 trypdiff
&= TransactionManager
->MetaIndexParser
->Exists(GetDiffIndexFileName(Target
->MetaKey
));
1348 // if we have no file to patch, no point in trying
1349 trypdiff
&= (GetExistingFilename(GetFinalFileNameFromURI(Target
->URI
)).empty() == false);
1352 // no point in patching from local sources
1355 std::string
const proto
= Target
->URI
.substr(0, strlen("file:/"));
1356 if (proto
== "file:/" || proto
== "copy:/" || proto
== "cdrom:")
1360 // Queue the Index file (Packages, Sources, Translation-$foo, …)
1362 new pkgAcqDiffIndex(Owner
, TransactionManager
, *Target
);
1364 new pkgAcqIndex(Owner
, TransactionManager
, *Target
);
1368 bool pkgAcqMetaBase::VerifyVendor(string
const &) /*{{{*/
1370 string Transformed
= TransactionManager
->MetaIndexParser
->GetExpectedDist();
1372 if (Transformed
== "../project/experimental")
1374 Transformed
= "experimental";
1377 auto pos
= Transformed
.rfind('/');
1378 if (pos
!= string::npos
)
1380 Transformed
= Transformed
.substr(0, pos
);
1383 if (Transformed
== ".")
1388 if (TransactionManager
->MetaIndexParser
->GetValidUntil() > 0)
1390 time_t const invalid_since
= time(NULL
) - TransactionManager
->MetaIndexParser
->GetValidUntil();
1391 if (invalid_since
> 0)
1395 // TRANSLATOR: The first %s is the URL of the bad Release file, the second is
1396 // the time since then the file is invalid - formatted in the same way as in
1397 // the download progress display (e.g. 7d 3h 42min 1s)
1398 _("Release file for %s is expired (invalid since %s). "
1399 "Updates for this repository will not be applied."),
1400 Target
.URI
.c_str(), TimeToStr(invalid_since
).c_str());
1401 if (ErrorText
.empty())
1403 return _error
->Error("%s", errmsg
.c_str());
1407 /* Did we get a file older than what we have? This is a last minute IMS hit and doubles
1408 as a prevention of downgrading us to older (still valid) files */
1409 if (TransactionManager
->IMSHit
== false && TransactionManager
->LastMetaIndexParser
!= NULL
&&
1410 TransactionManager
->LastMetaIndexParser
->GetDate() > TransactionManager
->MetaIndexParser
->GetDate())
1412 TransactionManager
->IMSHit
= true;
1413 RemoveFile("VerifyVendor", DestFile
);
1414 PartialFile
= DestFile
= GetFinalFilename();
1415 // load the 'old' file in the 'new' one instead of flipping pointers as
1416 // the new one isn't owned by us, while the old one is so cleanup would be confused.
1417 TransactionManager
->MetaIndexParser
->swapLoad(TransactionManager
->LastMetaIndexParser
);
1418 delete TransactionManager
->LastMetaIndexParser
;
1419 TransactionManager
->LastMetaIndexParser
= NULL
;
1422 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1424 std::cerr
<< "Got Codename: " << TransactionManager
->MetaIndexParser
->GetCodename() << std::endl
;
1425 std::cerr
<< "Expecting Dist: " << TransactionManager
->MetaIndexParser
->GetExpectedDist() << std::endl
;
1426 std::cerr
<< "Transformed Dist: " << Transformed
<< std::endl
;
1429 if (TransactionManager
->MetaIndexParser
->CheckDist(Transformed
) == false)
1431 // This might become fatal one day
1432 // Status = StatAuthError;
1433 // ErrorText = "Conflicting distribution; expected "
1434 // + MetaIndexParser->GetExpectedDist() + " but got "
1435 // + MetaIndexParser->GetCodename();
1437 if (!Transformed
.empty())
1439 _error
->Warning(_("Conflicting distribution: %s (expected %s but got %s)"),
1440 Desc
.Description
.c_str(),
1441 Transformed
.c_str(),
1442 TransactionManager
->MetaIndexParser
->GetCodename().c_str());
1449 pkgAcqMetaBase::~pkgAcqMetaBase()
1453 pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire
* const Owner
, /*{{{*/
1454 IndexTarget
const &ClearsignedTarget
,
1455 IndexTarget
const &DetachedDataTarget
, IndexTarget
const &DetachedSigTarget
,
1456 std::vector
<IndexTarget
> const &IndexTargets
,
1457 metaIndex
* const MetaIndexParser
) :
1458 pkgAcqMetaIndex(Owner
, this, ClearsignedTarget
, DetachedSigTarget
, IndexTargets
),
1459 d(NULL
), ClearsignedTarget(ClearsignedTarget
),
1460 DetachedDataTarget(DetachedDataTarget
),
1461 MetaIndexParser(MetaIndexParser
), LastMetaIndexParser(NULL
)
1463 // index targets + (worst case:) Release/Release.gpg
1464 ExpectedAdditionalItems
= IndexTargets
.size() + 2;
1465 TransactionManager
->Add(this);
1468 pkgAcqMetaClearSig::~pkgAcqMetaClearSig() /*{{{*/
1470 if (LastMetaIndexParser
!= NULL
)
1471 delete LastMetaIndexParser
;
1474 // pkgAcqMetaClearSig::Custom600Headers - Insert custom request headers /*{{{*/
1475 string
pkgAcqMetaClearSig::Custom600Headers() const
1477 string Header
= pkgAcqMetaBase::Custom600Headers();
1478 Header
+= "\nFail-Ignore: true";
1479 std::string
const key
= TransactionManager
->MetaIndexParser
->GetSignedBy();
1480 if (key
.empty() == false)
1481 Header
+= "\nSigned-By: " + key
;
1486 void pkgAcqMetaClearSig::Finished() /*{{{*/
1488 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1489 std::clog
<< "Finished: " << DestFile
<<std::endl
;
1490 if(TransactionManager
!= NULL
&& TransactionManager
->State
== TransactionStarted
&&
1491 TransactionManager
->TransactionHasError() == false)
1492 TransactionManager
->CommitTransaction();
1495 bool pkgAcqMetaClearSig::VerifyDone(std::string
const &Message
, /*{{{*/
1496 pkgAcquire::MethodConfig
const * const Cnf
)
1498 Item::VerifyDone(Message
, Cnf
);
1500 if (FileExists(DestFile
) && !StartsWithGPGClearTextSignature(DestFile
))
1501 return RenameOnError(NotClearsigned
);
1506 // pkgAcqMetaClearSig::Done - We got a file /*{{{*/
1507 void pkgAcqMetaClearSig::Done(std::string
const &Message
,
1508 HashStringList
const &Hashes
,
1509 pkgAcquire::MethodConfig
const * const Cnf
)
1511 Item::Done(Message
, Hashes
, Cnf
);
1513 if(AuthPass
== false)
1515 if(CheckDownloadDone(this, Message
, Hashes
) == true)
1516 QueueForSignatureVerify(this, DestFile
, DestFile
);
1519 else if(CheckAuthDone(Message
) == true)
1521 if (TransactionManager
->IMSHit
== false)
1522 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
1523 else if (RealFileExists(GetFinalFilename()) == false)
1525 // We got an InRelease file IMSHit, but we haven't one, which means
1526 // we had a valid Release/Release.gpg combo stepping in, which we have
1527 // to 'acquire' now to ensure list cleanup isn't removing them
1528 new NoActionItem(Owner
, DetachedDataTarget
);
1529 new NoActionItem(Owner
, DetachedSigTarget
);
1534 void pkgAcqMetaClearSig::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
) /*{{{*/
1536 Item::Failed(Message
, Cnf
);
1538 // we failed, we will not get additional items from this method
1539 ExpectedAdditionalItems
= 0;
1541 if (AuthPass
== false)
1543 if (Status
== StatAuthError
|| Status
== StatTransientNetworkError
)
1545 // if we expected a ClearTextSignature (InRelease) but got a network
1546 // error or got a file, but it wasn't valid, we end up here (see VerifyDone).
1547 // As these is usually called by web-portals we do not try Release/Release.gpg
1548 // as this is gonna fail anyway and instead abort our try (LP#346386)
1549 TransactionManager
->AbortTransaction();
1553 // Queue the 'old' InRelease file for removal if we try Release.gpg
1554 // as otherwise the file will stay around and gives a false-auth
1555 // impression (CVE-2012-0214)
1556 TransactionManager
->TransactionStageRemoval(this, GetFinalFilename());
1559 new pkgAcqMetaIndex(Owner
, TransactionManager
, DetachedDataTarget
, DetachedSigTarget
, IndexTargets
);
1563 if(CheckStopAuthentication(this, Message
))
1566 // No Release file was present, or verification failed, so fall
1567 // back to queueing Packages files without verification
1568 // only allow going further if the user explicitly wants it
1569 if(AllowInsecureRepositories(_("The repository '%s' is not signed."), ClearsignedTarget
.Description
, TransactionManager
->MetaIndexParser
, TransactionManager
, this) == true)
1573 /* InRelease files become Release files, otherwise
1574 * they would be considered as trusted later on */
1575 string
const FinalRelease
= GetFinalFileNameFromURI(DetachedDataTarget
.URI
);
1576 string
const PartialRelease
= GetPartialFileNameFromURI(DetachedDataTarget
.URI
);
1577 string
const FinalReleasegpg
= GetFinalFileNameFromURI(DetachedSigTarget
.URI
);
1578 string
const FinalInRelease
= GetFinalFilename();
1579 Rename(DestFile
, PartialRelease
);
1580 TransactionManager
->TransactionStageCopy(this, PartialRelease
, FinalRelease
);
1581 LoadLastMetaIndexParser(TransactionManager
, FinalRelease
, FinalInRelease
);
1583 // we parse the indexes here because at this point the user wanted
1584 // a repository that may potentially harm him
1585 if (TransactionManager
->MetaIndexParser
->Load(PartialRelease
, &ErrorText
) == false || VerifyVendor(Message
) == false)
1586 /* expired Release files are still a problem you need extra force for */;
1594 pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire
* const Owner
, /*{{{*/
1595 pkgAcqMetaClearSig
* const TransactionManager
,
1596 IndexTarget
const &DataTarget
,
1597 IndexTarget
const &DetachedSigTarget
,
1598 vector
<IndexTarget
> const &IndexTargets
) :
1599 pkgAcqMetaBase(Owner
, TransactionManager
, IndexTargets
, DataTarget
), d(NULL
),
1600 DetachedSigTarget(DetachedSigTarget
)
1602 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1603 std::clog
<< "New pkgAcqMetaIndex with TransactionManager "
1604 << this->TransactionManager
<< std::endl
;
1606 DestFile
= GetPartialFileNameFromURI(DataTarget
.URI
);
1609 Desc
.Description
= DataTarget
.Description
;
1611 Desc
.ShortDesc
= DataTarget
.ShortDesc
;
1612 Desc
.URI
= DataTarget
.URI
;
1614 // we expect more item
1615 ExpectedAdditionalItems
= IndexTargets
.size();
1619 void pkgAcqMetaIndex::Done(string
const &Message
, /*{{{*/
1620 HashStringList
const &Hashes
,
1621 pkgAcquire::MethodConfig
const * const Cfg
)
1623 Item::Done(Message
,Hashes
,Cfg
);
1625 if(CheckDownloadDone(this, Message
, Hashes
))
1627 // we have a Release file, now download the Signature, all further
1628 // verify/queue for additional downloads will be done in the
1629 // pkgAcqMetaSig::Done() code
1630 new pkgAcqMetaSig(Owner
, TransactionManager
, DetachedSigTarget
, this);
1634 // pkgAcqMetaIndex::Failed - no Release file present /*{{{*/
1635 void pkgAcqMetaIndex::Failed(string
const &Message
,
1636 pkgAcquire::MethodConfig
const * const Cnf
)
1638 pkgAcquire::Item::Failed(Message
, Cnf
);
1641 // No Release file was present so fall
1642 // back to queueing Packages files without verification
1643 // only allow going further if the user explicitly wants it
1644 if(AllowInsecureRepositories(_("The repository '%s' does not have a Release file."), Target
.Description
, TransactionManager
->MetaIndexParser
, TransactionManager
, this) == true)
1646 // ensure old Release files are removed
1647 TransactionManager
->TransactionStageRemoval(this, GetFinalFilename());
1649 // queue without any kind of hashsum support
1650 QueueIndexes(false);
1654 std::string
pkgAcqMetaIndex::DescURI() const /*{{{*/
1659 pkgAcqMetaIndex::~pkgAcqMetaIndex() {}
1661 // AcqMetaSig::AcqMetaSig - Constructor /*{{{*/
1662 pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire
* const Owner
,
1663 pkgAcqMetaClearSig
* const TransactionManager
,
1664 IndexTarget
const &Target
,
1665 pkgAcqMetaIndex
* const MetaIndex
) :
1666 pkgAcqTransactionItem(Owner
, TransactionManager
, Target
), d(NULL
), MetaIndex(MetaIndex
)
1668 DestFile
= GetPartialFileNameFromURI(Target
.URI
);
1670 // remove any partial downloaded sig-file in partial/.
1671 // it may confuse proxies and is too small to warrant a
1672 // partial download anyway
1673 RemoveFile("pkgAcqMetaSig", DestFile
);
1675 // set the TransactionManager
1676 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1677 std::clog
<< "New pkgAcqMetaSig with TransactionManager "
1678 << TransactionManager
<< std::endl
;
1681 Desc
.Description
= Target
.Description
;
1683 Desc
.ShortDesc
= Target
.ShortDesc
;
1684 Desc
.URI
= Target
.URI
;
1686 // If we got a hit for Release, we will get one for Release.gpg too (or obscure errors),
1687 // so we skip the download step and go instantly to verification
1688 if (TransactionManager
->IMSHit
== true && RealFileExists(GetFinalFilename()))
1692 PartialFile
= DestFile
= GetFinalFilename();
1693 MetaIndexFileSignature
= DestFile
;
1694 MetaIndex
->QueueForSignatureVerify(this, MetaIndex
->DestFile
, DestFile
);
1700 pkgAcqMetaSig::~pkgAcqMetaSig() /*{{{*/
1704 // pkgAcqMetaSig::Custom600Headers - Insert custom request headers /*{{{*/
1705 std::string
pkgAcqMetaSig::Custom600Headers() const
1707 std::string Header
= pkgAcqTransactionItem::Custom600Headers();
1708 std::string
const key
= TransactionManager
->MetaIndexParser
->GetSignedBy();
1709 if (key
.empty() == false)
1710 Header
+= "\nSigned-By: " + key
;
1714 // AcqMetaSig::Done - The signature was downloaded/verified /*{{{*/
1715 void pkgAcqMetaSig::Done(string
const &Message
, HashStringList
const &Hashes
,
1716 pkgAcquire::MethodConfig
const * const Cfg
)
1718 if (MetaIndexFileSignature
.empty() == false)
1720 DestFile
= MetaIndexFileSignature
;
1721 MetaIndexFileSignature
.clear();
1723 Item::Done(Message
, Hashes
, Cfg
);
1725 if(MetaIndex
->AuthPass
== false)
1727 if(MetaIndex
->CheckDownloadDone(this, Message
, Hashes
) == true)
1729 // destfile will be modified to point to MetaIndexFile for the
1730 // gpgv method, so we need to save it here
1731 MetaIndexFileSignature
= DestFile
;
1732 MetaIndex
->QueueForSignatureVerify(this, MetaIndex
->DestFile
, DestFile
);
1736 else if(MetaIndex
->CheckAuthDone(Message
) == true)
1738 if (TransactionManager
->IMSHit
== false)
1740 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
1741 TransactionManager
->TransactionStageCopy(MetaIndex
, MetaIndex
->DestFile
, MetaIndex
->GetFinalFilename());
1746 void pkgAcqMetaSig::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
1748 Item::Failed(Message
,Cnf
);
1750 // check if we need to fail at this point
1751 if (MetaIndex
->AuthPass
== true && MetaIndex
->CheckStopAuthentication(this, Message
))
1754 string
const FinalRelease
= MetaIndex
->GetFinalFilename();
1755 string
const FinalReleasegpg
= GetFinalFilename();
1756 string
const FinalInRelease
= TransactionManager
->GetFinalFilename();
1758 if (RealFileExists(FinalReleasegpg
) || RealFileExists(FinalInRelease
))
1760 std::string downgrade_msg
;
1761 strprintf(downgrade_msg
, _("The repository '%s' is no longer signed."),
1762 MetaIndex
->Target
.Description
.c_str());
1763 if(_config
->FindB("Acquire::AllowDowngradeToInsecureRepositories"))
1765 // meh, the users wants to take risks (we still mark the packages
1766 // from this repository as unauthenticated)
1767 _error
->Warning("%s", downgrade_msg
.c_str());
1768 _error
->Warning(_("This is normally not allowed, but the option "
1769 "Acquire::AllowDowngradeToInsecureRepositories was "
1770 "given to override it."));
1773 MessageInsecureRepository(true, downgrade_msg
);
1774 if (TransactionManager
->IMSHit
== false)
1775 Rename(MetaIndex
->DestFile
, MetaIndex
->DestFile
+ ".FAILED");
1776 Item::Failed("Message: " + downgrade_msg
, Cnf
);
1777 TransactionManager
->AbortTransaction();
1782 // ensures that a Release.gpg file in the lists/ is removed by the transaction
1783 TransactionManager
->TransactionStageRemoval(this, DestFile
);
1785 // only allow going further if the user explicitly wants it
1786 if (AllowInsecureRepositories(_("The repository '%s' is not signed."), MetaIndex
->Target
.Description
, TransactionManager
->MetaIndexParser
, TransactionManager
, this) == true)
1788 LoadLastMetaIndexParser(TransactionManager
, FinalRelease
, FinalInRelease
);
1790 // we parse the indexes here because at this point the user wanted
1791 // a repository that may potentially harm him
1792 bool const GoodLoad
= TransactionManager
->MetaIndexParser
->Load(MetaIndex
->DestFile
, &ErrorText
);
1793 if (MetaIndex
->VerifyVendor(Message
) == false)
1794 /* expired Release files are still a problem you need extra force for */;
1796 MetaIndex
->QueueIndexes(GoodLoad
);
1798 TransactionManager
->TransactionStageCopy(MetaIndex
, MetaIndex
->DestFile
, MetaIndex
->GetFinalFilename());
1801 // FIXME: this is used often (e.g. in pkgAcqIndexTrans) so refactor
1802 if (Cnf
->LocalOnly
== true ||
1803 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1812 // AcqBaseIndex - Constructor /*{{{*/
1813 pkgAcqBaseIndex::pkgAcqBaseIndex(pkgAcquire
* const Owner
,
1814 pkgAcqMetaClearSig
* const TransactionManager
,
1815 IndexTarget
const &Target
)
1816 : pkgAcqTransactionItem(Owner
, TransactionManager
, Target
), d(NULL
)
1820 void pkgAcqBaseIndex::Failed(std::string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
1822 pkgAcquire::Item::Failed(Message
, Cnf
);
1823 if (TransactionManager
== nullptr || TransactionManager
->MetaIndexParser
== nullptr ||
1824 Status
!= StatAuthError
)
1827 ErrorText
.append("Release file created at: ");
1828 auto const timespec
= TransactionManager
->MetaIndexParser
->GetDate();
1830 ErrorText
.append("<unknown>");
1832 ErrorText
.append(TimeRFC1123(timespec
));
1833 ErrorText
.append("\n");
1836 pkgAcqBaseIndex::~pkgAcqBaseIndex() {}
1838 // AcqDiffIndex::AcqDiffIndex - Constructor /*{{{*/
1839 // ---------------------------------------------------------------------
1840 /* Get the DiffIndex file first and see if there are patches available
1841 * If so, create a pkgAcqIndexDiffs fetcher that will get and apply the
1842 * patches. If anything goes wrong in that process, it will fall back to
1843 * the original packages file
1845 pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire
* const Owner
,
1846 pkgAcqMetaClearSig
* const TransactionManager
,
1847 IndexTarget
const &Target
)
1848 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
), diffs(NULL
)
1850 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
1853 Desc
.Description
= GetDiffIndexFileName(Target
.Description
);
1854 Desc
.ShortDesc
= Target
.ShortDesc
;
1855 Desc
.URI
= GetDiffIndexURI(Target
);
1857 DestFile
= GetPartialFileNameFromURI(Desc
.URI
);
1860 std::clog
<< "pkgAcqDiffIndex: " << Desc
.URI
<< std::endl
;
1865 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
1866 // ---------------------------------------------------------------------
1867 /* The only header we use is the last-modified header. */
1868 string
pkgAcqDiffIndex::Custom600Headers() const
1870 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1871 return "\nIndex-File: true";
1873 string
const Final
= GetFinalFilename();
1876 std::clog
<< "Custom600Header-IMS: " << Final
<< std::endl
;
1879 if (stat(Final
.c_str(),&Buf
) != 0)
1880 return "\nIndex-File: true";
1882 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1885 void pkgAcqDiffIndex::QueueOnIMSHit() const /*{{{*/
1887 // list cleanup needs to know that this file as well as the already
1888 // present index is ours, so we create an empty diff to save it for us
1889 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
);
1892 bool pkgAcqDiffIndex::ParseDiffIndex(string
const &IndexDiffFile
) /*{{{*/
1894 // failing here is fine: our caller will take care of trying to
1895 // get the complete file if patching fails
1897 std::clog
<< "pkgAcqDiffIndex::ParseIndexDiff() " << IndexDiffFile
1900 FileFd
Fd(IndexDiffFile
,FileFd::ReadOnly
);
1902 if (Fd
.IsOpen() == false || Fd
.Failed())
1906 if(unlikely(TF
.Step(Tags
) == false))
1909 HashStringList ServerHashes
;
1910 unsigned long long ServerSize
= 0;
1912 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
1914 std::string tagname
= *type
;
1915 tagname
.append("-Current");
1916 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1917 if (tmp
.empty() == true)
1921 unsigned long long size
;
1922 std::stringstream
ss(tmp
);
1924 if (unlikely(hash
.empty() == true))
1926 if (unlikely(ServerSize
!= 0 && ServerSize
!= size
))
1928 ServerHashes
.push_back(HashString(*type
, hash
));
1932 if (ServerHashes
.usable() == false)
1935 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": Did not find a good hashsum in the index" << std::endl
;
1939 std::string
const CurrentPackagesFile
= GetFinalFileNameFromURI(Target
.URI
);
1940 HashStringList
const TargetFileHashes
= GetExpectedHashesFor(Target
.MetaKey
);
1941 if (TargetFileHashes
.usable() == false || ServerHashes
!= TargetFileHashes
)
1945 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": Index has different hashes than parser, probably older, so fail pdiffing" << std::endl
;
1946 printHashSumComparison(CurrentPackagesFile
, ServerHashes
, TargetFileHashes
);
1951 HashStringList LocalHashes
;
1952 // try avoiding calculating the hash here as this is costly
1953 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1954 LocalHashes
= GetExpectedHashesFromFor(TransactionManager
->LastMetaIndexParser
, Target
.MetaKey
);
1955 if (LocalHashes
.usable() == false)
1957 FileFd
fd(CurrentPackagesFile
, FileFd::ReadOnly
, FileFd::Auto
);
1958 Hashes
LocalHashesCalc(ServerHashes
);
1959 LocalHashesCalc
.AddFD(fd
);
1960 LocalHashes
= LocalHashesCalc
.GetHashStringList();
1963 if (ServerHashes
== LocalHashes
)
1965 // we have the same sha1 as the server so we are done here
1967 std::clog
<< "pkgAcqDiffIndex: Package file " << CurrentPackagesFile
<< " is up-to-date" << std::endl
;
1973 std::clog
<< "Server-Current: " << ServerHashes
.find(NULL
)->toStr() << " and we start at "
1974 << CurrentPackagesFile
<< " " << LocalHashes
.FileSize() << " " << LocalHashes
.find(NULL
)->toStr() << std::endl
;
1976 // historically, older hashes have more info than newer ones, so start
1977 // collecting with older ones first to avoid implementing complicated
1978 // information merging techniques… a failure is after all always
1979 // recoverable with a complete file and hashes aren't changed that often.
1980 std::vector
<char const *> types
;
1981 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
1982 types
.push_back(*type
);
1984 // parse all of (provided) history
1985 vector
<DiffInfo
> available_patches
;
1986 bool firstAcceptedHashes
= true;
1987 for (auto type
= types
.crbegin(); type
!= types
.crend(); ++type
)
1989 if (LocalHashes
.find(*type
) == NULL
)
1992 std::string tagname
= *type
;
1993 tagname
.append("-History");
1994 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1995 if (tmp
.empty() == true)
1998 string hash
, filename
;
1999 unsigned long long size
;
2000 std::stringstream
ss(tmp
);
2002 while (ss
>> hash
>> size
>> filename
)
2004 if (unlikely(hash
.empty() == true || filename
.empty() == true))
2007 // see if we have a record for this file already
2008 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
2009 for (; cur
!= available_patches
.end(); ++cur
)
2011 if (cur
->file
!= filename
)
2013 cur
->result_hashes
.push_back(HashString(*type
, hash
));
2016 if (cur
!= available_patches
.end())
2018 if (firstAcceptedHashes
== true)
2021 next
.file
= filename
;
2022 next
.result_hashes
.push_back(HashString(*type
, hash
));
2023 next
.result_hashes
.FileSize(size
);
2024 available_patches
.push_back(next
);
2029 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
2030 << " wasn't in the list for the first parsed hash! (history)" << std::endl
;
2034 firstAcceptedHashes
= false;
2037 if (unlikely(available_patches
.empty() == true))
2040 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": "
2041 << "Couldn't find any patches for the patch series." << std::endl
;
2045 for (auto type
= types
.crbegin(); type
!= types
.crend(); ++type
)
2047 if (LocalHashes
.find(*type
) == NULL
)
2050 std::string tagname
= *type
;
2051 tagname
.append("-Patches");
2052 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
2053 if (tmp
.empty() == true)
2056 string hash
, filename
;
2057 unsigned long long size
;
2058 std::stringstream
ss(tmp
);
2060 while (ss
>> hash
>> size
>> filename
)
2062 if (unlikely(hash
.empty() == true || filename
.empty() == true))
2065 // see if we have a record for this file already
2066 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
2067 for (; cur
!= available_patches
.end(); ++cur
)
2069 if (cur
->file
!= filename
)
2071 if (cur
->patch_hashes
.empty())
2072 cur
->patch_hashes
.FileSize(size
);
2073 cur
->patch_hashes
.push_back(HashString(*type
, hash
));
2076 if (cur
!= available_patches
.end())
2079 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
2080 << " wasn't in the list for the first parsed hash! (patches)" << std::endl
;
2085 for (auto type
= types
.crbegin(); type
!= types
.crend(); ++type
)
2087 std::string tagname
= *type
;
2088 tagname
.append("-Download");
2089 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
2090 if (tmp
.empty() == true)
2093 string hash
, filename
;
2094 unsigned long long size
;
2095 std::stringstream
ss(tmp
);
2097 // FIXME: all of pdiff supports only .gz compressed patches
2098 while (ss
>> hash
>> size
>> filename
)
2100 if (unlikely(hash
.empty() == true || filename
.empty() == true))
2102 if (unlikely(APT::String::Endswith(filename
, ".gz") == false))
2104 filename
.erase(filename
.length() - 3);
2106 // see if we have a record for this file already
2107 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
2108 for (; cur
!= available_patches
.end(); ++cur
)
2110 if (cur
->file
!= filename
)
2112 if (cur
->download_hashes
.empty())
2113 cur
->download_hashes
.FileSize(size
);
2114 cur
->download_hashes
.push_back(HashString(*type
, hash
));
2117 if (cur
!= available_patches
.end())
2120 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
2121 << " wasn't in the list for the first parsed hash! (download)" << std::endl
;
2127 bool foundStart
= false;
2128 for (std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
2129 cur
!= available_patches
.end(); ++cur
)
2131 if (LocalHashes
!= cur
->result_hashes
)
2134 available_patches
.erase(available_patches
.begin(), cur
);
2139 if (foundStart
== false || unlikely(available_patches
.empty() == true))
2142 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": "
2143 << "Couldn't find the start of the patch series." << std::endl
;
2147 for (auto const &patch
: available_patches
)
2148 if (patch
.result_hashes
.usable() == false ||
2149 patch
.patch_hashes
.usable() == false ||
2150 patch
.download_hashes
.usable() == false)
2153 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": provides no usable hashes for " << patch
.file
2154 << " so fallback to complete download" << std::endl
;
2158 // patching with too many files is rather slow compared to a fast download
2159 unsigned long const fileLimit
= _config
->FindI("Acquire::PDiffs::FileLimit", 0);
2160 if (fileLimit
!= 0 && fileLimit
< available_patches
.size())
2163 std::clog
<< "Need " << available_patches
.size() << " diffs (Limit is " << fileLimit
2164 << ") so fallback to complete download" << std::endl
;
2168 // calculate the size of all patches we have to get
2169 unsigned short const sizeLimitPercent
= _config
->FindI("Acquire::PDiffs::SizeLimit", 100);
2170 if (sizeLimitPercent
> 0 && TransactionManager
->MetaIndexParser
!= nullptr)
2172 unsigned long long downloadSize
= std::accumulate(available_patches
.begin(),
2173 available_patches
.end(), 0llu, [](unsigned long long const T
, DiffInfo
const &I
) {
2174 return T
+ I
.download_hashes
.FileSize();
2176 if (downloadSize
!= 0)
2178 unsigned long long downloadSizeIdx
= 0;
2179 auto const types
= VectorizeString(Target
.Option(IndexTarget::COMPRESSIONTYPES
), ' ');
2180 for (auto const &t
: types
)
2182 std::string MetaKey
= Target
.MetaKey
;
2183 if (t
!= "uncompressed")
2185 HashStringList
const hsl
= GetExpectedHashesFor(MetaKey
);
2186 if (unlikely(hsl
.usable() == false))
2188 downloadSizeIdx
= hsl
.FileSize();
2191 unsigned long long const sizeLimit
= downloadSizeIdx
* sizeLimitPercent
;
2192 if ((sizeLimit
/100) < downloadSize
)
2195 std::clog
<< "Need " << downloadSize
<< " compressed bytes (Limit is " << (sizeLimit
/100) << ", "
2196 << "original is " << downloadSizeIdx
<< ") so fallback to complete download" << std::endl
;
2202 // we have something, queue the diffs
2203 string::size_type
const last_space
= Description
.rfind(" ");
2204 if(last_space
!= string::npos
)
2205 Description
.erase(last_space
, Description
.size()-last_space
);
2207 /* decide if we should download patches one by one or in one go:
2208 The first is good if the server merges patches, but many don't so client
2209 based merging can be attempt in which case the second is better.
2210 "bad things" will happen if patches are merged on the server,
2211 but client side merging is attempt as well */
2212 bool pdiff_merge
= _config
->FindB("Acquire::PDiffs::Merge", true);
2213 if (pdiff_merge
== true)
2215 // reprepro adds this flag if it has merged patches on the server
2216 std::string
const precedence
= Tags
.FindS("X-Patch-Precedence");
2217 pdiff_merge
= (precedence
!= "merged");
2222 std::string
const Final
= GetExistingFilename(CurrentPackagesFile
);
2223 if (unlikely(Final
.empty())) // because we wouldn't be called in such a case
2225 std::string
const PartialFile
= GetPartialFileNameFromURI(Target
.URI
);
2226 if (FileExists(PartialFile
) && RemoveFile("Bootstrap-linking", PartialFile
) == false)
2229 std::clog
<< "Bootstrap-linking for patching " << CurrentPackagesFile
2230 << " by removing stale " << PartialFile
<< " failed!" << std::endl
;
2233 for (auto const &ext
: APT::Configuration::getCompressorExtensions())
2235 std::string
const Partial
= PartialFile
+ ext
;
2236 if (FileExists(Partial
) && RemoveFile("Bootstrap-linking", Partial
) == false)
2239 std::clog
<< "Bootstrap-linking for patching " << CurrentPackagesFile
2240 << " by removing stale " << Partial
<< " failed!" << std::endl
;
2244 std::string
const Ext
= Final
.substr(CurrentPackagesFile
.length());
2245 std::string
const Partial
= PartialFile
+ Ext
;
2246 if (symlink(Final
.c_str(), Partial
.c_str()) != 0)
2249 std::clog
<< "Bootstrap-linking for patching " << CurrentPackagesFile
2250 << " by linking " << Final
<< " to " << Partial
<< " failed!" << std::endl
;
2255 if (pdiff_merge
== false)
2256 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
, available_patches
);
2259 diffs
= new std::vector
<pkgAcqIndexMergeDiffs
*>(available_patches
.size());
2260 for(size_t i
= 0; i
< available_patches
.size(); ++i
)
2261 (*diffs
)[i
] = new pkgAcqIndexMergeDiffs(Owner
, TransactionManager
,
2263 available_patches
[i
],
2273 void pkgAcqDiffIndex::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
2275 pkgAcqBaseIndex::Failed(Message
,Cnf
);
2279 std::clog
<< "pkgAcqDiffIndex failed: " << Desc
.URI
<< " with " << Message
<< std::endl
2280 << "Falling back to normal index file acquire" << std::endl
;
2282 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
2285 void pkgAcqDiffIndex::Done(string
const &Message
,HashStringList
const &Hashes
, /*{{{*/
2286 pkgAcquire::MethodConfig
const * const Cnf
)
2289 std::clog
<< "pkgAcqDiffIndex::Done(): " << Desc
.URI
<< std::endl
;
2291 Item::Done(Message
, Hashes
, Cnf
);
2293 string
const FinalFile
= GetFinalFilename();
2294 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false))
2295 DestFile
= FinalFile
;
2297 if(ParseDiffIndex(DestFile
) == false)
2299 Failed("Message: Couldn't parse pdiff index", Cnf
);
2300 // queue for final move - this should happen even if we fail
2301 // while parsing (e.g. on sizelimit) and download the complete file.
2302 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
2306 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
2315 pkgAcqDiffIndex::~pkgAcqDiffIndex()
2321 // AcqIndexDiffs::AcqIndexDiffs - Constructor /*{{{*/
2322 // ---------------------------------------------------------------------
2323 /* The package diff is added to the queue. one object is constructed
2324 * for each diff and the index
2326 pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire
* const Owner
,
2327 pkgAcqMetaClearSig
* const TransactionManager
,
2328 IndexTarget
const &Target
,
2329 vector
<DiffInfo
> const &diffs
)
2330 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
),
2331 available_patches(diffs
)
2333 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
2335 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
2338 Description
= Target
.Description
;
2339 Desc
.ShortDesc
= Target
.ShortDesc
;
2341 if(available_patches
.empty() == true)
2343 // we are done (yeah!), check hashes against the final file
2344 DestFile
= GetKeepCompressedFileName(GetFinalFileNameFromURI(Target
.URI
), Target
);
2349 State
= StateFetchDiff
;
2354 void pkgAcqIndexDiffs::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
2356 pkgAcqBaseIndex::Failed(Message
,Cnf
);
2359 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
2361 std::clog
<< "pkgAcqIndexDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
2362 << "Falling back to normal index file acquire " << std::endl
;
2363 RenameOnError(PDiffError
);
2364 std::string
const patchname
= GetDiffsPatchFileName(DestFile
);
2365 if (RealFileExists(patchname
))
2366 Rename(patchname
, patchname
+ ".FAILED");
2367 std::string
const UnpatchedFile
= GetExistingFilename(GetPartialFileNameFromURI(Target
.URI
));
2368 if (UnpatchedFile
.empty() == false && FileExists(UnpatchedFile
))
2369 Rename(UnpatchedFile
, UnpatchedFile
+ ".FAILED");
2370 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
2374 // Finish - helper that cleans the item out of the fetcher queue /*{{{*/
2375 void pkgAcqIndexDiffs::Finish(bool allDone
)
2378 std::clog
<< "pkgAcqIndexDiffs::Finish(): "
2380 << Desc
.URI
<< std::endl
;
2382 // we restore the original name, this is required, otherwise
2383 // the file will be cleaned
2386 std::string
const Final
= GetKeepCompressedFileName(GetFinalFilename(), Target
);
2387 TransactionManager
->TransactionStageCopy(this, DestFile
, Final
);
2389 // this is for the "real" finish
2394 std::clog
<< "\n\nallDone: " << DestFile
<< "\n" << std::endl
;
2401 std::clog
<< "Finishing: " << Desc
.URI
<< std::endl
;
2408 bool pkgAcqIndexDiffs::QueueNextDiff() /*{{{*/
2410 // calc sha1 of the just patched file
2411 std::string
const PartialFile
= GetExistingFilename(GetPartialFileNameFromURI(Target
.URI
));
2412 if(unlikely(PartialFile
.empty()))
2414 Failed("Message: The file " + GetPartialFileNameFromURI(Target
.URI
) + " isn't available", NULL
);
2418 FileFd
fd(PartialFile
, FileFd::ReadOnly
, FileFd::Extension
);
2419 Hashes LocalHashesCalc
;
2420 LocalHashesCalc
.AddFD(fd
);
2421 HashStringList
const LocalHashes
= LocalHashesCalc
.GetHashStringList();
2424 std::clog
<< "QueueNextDiff: " << PartialFile
<< " (" << LocalHashes
.find(NULL
)->toStr() << ")" << std::endl
;
2426 HashStringList
const TargetFileHashes
= GetExpectedHashesFor(Target
.MetaKey
);
2427 if (unlikely(LocalHashes
.usable() == false || TargetFileHashes
.usable() == false))
2429 Failed("Local/Expected hashes are not usable for " + PartialFile
, NULL
);
2433 // final file reached before all patches are applied
2434 if(LocalHashes
== TargetFileHashes
)
2440 // remove all patches until the next matching patch is found
2441 // this requires the Index file to be ordered
2442 available_patches
.erase(available_patches
.begin(),
2443 std::find_if(available_patches
.begin(), available_patches
.end(), [&](DiffInfo
const &I
) {
2444 return I
.result_hashes
== LocalHashes
;
2447 // error checking and falling back if no patch was found
2448 if(available_patches
.empty() == true)
2450 Failed("No patches left to reach target for " + PartialFile
, NULL
);
2454 // queue the right diff
2455 Desc
.URI
= Target
.URI
+ ".diff/" + available_patches
[0].file
+ ".gz";
2456 Desc
.Description
= Description
+ " " + available_patches
[0].file
+ string(".pdiff");
2457 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
+ ".diff/" + available_patches
[0].file
), Target
);
2460 std::clog
<< "pkgAcqIndexDiffs::QueueNextDiff(): " << Desc
.URI
<< std::endl
;
2467 void pkgAcqIndexDiffs::Done(string
const &Message
, HashStringList
const &Hashes
, /*{{{*/
2468 pkgAcquire::MethodConfig
const * const Cnf
)
2471 std::clog
<< "pkgAcqIndexDiffs::Done(): " << Desc
.URI
<< std::endl
;
2473 Item::Done(Message
, Hashes
, Cnf
);
2475 std::string
const UncompressedUnpatchedFile
= GetPartialFileNameFromURI(Target
.URI
);
2476 std::string
const UnpatchedFile
= GetExistingFilename(UncompressedUnpatchedFile
);
2477 std::string
const PatchFile
= GetDiffsPatchFileName(UnpatchedFile
);
2478 std::string
const PatchedFile
= GetKeepCompressedFileName(UncompressedUnpatchedFile
, Target
);
2482 // success in downloading a diff, enter ApplyDiff state
2483 case StateFetchDiff
:
2484 Rename(DestFile
, PatchFile
);
2485 DestFile
= GetKeepCompressedFileName(UncompressedUnpatchedFile
+ "-patched", Target
);
2487 std::clog
<< "Sending to rred method: " << UnpatchedFile
<< std::endl
;
2488 State
= StateApplyDiff
;
2490 Desc
.URI
= "rred:" + UnpatchedFile
;
2492 SetActiveSubprocess("rred");
2494 // success in download/apply a diff, queue next (if needed)
2495 case StateApplyDiff
:
2496 // remove the just applied patch and base file
2497 available_patches
.erase(available_patches
.begin());
2498 RemoveFile("pkgAcqIndexDiffs::Done", PatchFile
);
2499 RemoveFile("pkgAcqIndexDiffs::Done", UnpatchedFile
);
2501 std::clog
<< "Moving patched file in place: " << std::endl
2502 << DestFile
<< " -> " << PatchedFile
<< std::endl
;
2503 Rename(DestFile
, PatchedFile
);
2505 // see if there is more to download
2506 if(available_patches
.empty() == false)
2508 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
, available_patches
);
2511 DestFile
= PatchedFile
;
2518 std::string
pkgAcqIndexDiffs::Custom600Headers() const /*{{{*/
2520 if(State
!= StateApplyDiff
)
2521 return pkgAcqBaseIndex::Custom600Headers();
2522 std::ostringstream patchhashes
;
2523 HashStringList
const ExpectedHashes
= available_patches
[0].patch_hashes
;
2524 for (HashStringList::const_iterator hs
= ExpectedHashes
.begin(); hs
!= ExpectedHashes
.end(); ++hs
)
2525 patchhashes
<< "\nPatch-0-" << hs
->HashType() << "-Hash: " << hs
->HashValue();
2526 patchhashes
<< pkgAcqBaseIndex::Custom600Headers();
2527 return patchhashes
.str();
2530 pkgAcqIndexDiffs::~pkgAcqIndexDiffs() {}
2532 // AcqIndexMergeDiffs::AcqIndexMergeDiffs - Constructor /*{{{*/
2533 pkgAcqIndexMergeDiffs::pkgAcqIndexMergeDiffs(pkgAcquire
* const Owner
,
2534 pkgAcqMetaClearSig
* const TransactionManager
,
2535 IndexTarget
const &Target
,
2536 DiffInfo
const &patch
,
2537 std::vector
<pkgAcqIndexMergeDiffs
*> const * const allPatches
)
2538 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
),
2539 patch(patch
), allPatches(allPatches
), State(StateFetchDiff
)
2541 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
2544 Description
= Target
.Description
;
2545 Desc
.ShortDesc
= Target
.ShortDesc
;
2546 Desc
.URI
= Target
.URI
+ ".diff/" + patch
.file
+ ".gz";
2547 Desc
.Description
= Description
+ " " + patch
.file
+ ".pdiff";
2548 DestFile
= GetPartialFileNameFromURI(Desc
.URI
);
2551 std::clog
<< "pkgAcqIndexMergeDiffs: " << Desc
.URI
<< std::endl
;
2556 void pkgAcqIndexMergeDiffs::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
2559 std::clog
<< "pkgAcqIndexMergeDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
;
2561 pkgAcqBaseIndex::Failed(Message
,Cnf
);
2564 // check if we are the first to fail, otherwise we are done here
2565 State
= StateDoneDiff
;
2566 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2567 I
!= allPatches
->end(); ++I
)
2568 if ((*I
)->State
== StateErrorDiff
)
2570 State
= StateErrorDiff
;
2574 // first failure means we should fallback
2575 State
= StateErrorDiff
;
2577 std::clog
<< "Falling back to normal index file acquire" << std::endl
;
2578 RenameOnError(PDiffError
);
2579 if (RealFileExists(DestFile
))
2580 Rename(DestFile
, DestFile
+ ".FAILED");
2581 std::string
const UnpatchedFile
= GetExistingFilename(GetPartialFileNameFromURI(Target
.URI
));
2582 if (UnpatchedFile
.empty() == false && FileExists(UnpatchedFile
))
2583 Rename(UnpatchedFile
, UnpatchedFile
+ ".FAILED");
2585 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
2588 void pkgAcqIndexMergeDiffs::Done(string
const &Message
, HashStringList
const &Hashes
, /*{{{*/
2589 pkgAcquire::MethodConfig
const * const Cnf
)
2592 std::clog
<< "pkgAcqIndexMergeDiffs::Done(): " << Desc
.URI
<< std::endl
;
2594 Item::Done(Message
, Hashes
, Cnf
);
2596 if (std::any_of(allPatches
->begin(), allPatches
->end(),
2597 [](pkgAcqIndexMergeDiffs
const * const P
) { return P
->State
== StateErrorDiff
; }))
2600 std::clog
<< "Another patch failed already, no point in processing this one." << std::endl
;
2601 State
= StateErrorDiff
;
2605 std::string
const UncompressedUnpatchedFile
= GetPartialFileNameFromURI(Target
.URI
);
2606 std::string
const UnpatchedFile
= GetExistingFilename(UncompressedUnpatchedFile
);
2607 if (UnpatchedFile
.empty())
2609 _error
->Fatal("Unpatched file %s doesn't exist (anymore)!", UncompressedUnpatchedFile
.c_str());
2610 State
= StateErrorDiff
;
2613 std::string
const PatchFile
= GetMergeDiffsPatchFileName(UnpatchedFile
, patch
.file
);
2614 std::string
const PatchedFile
= GetKeepCompressedFileName(UncompressedUnpatchedFile
, Target
);
2618 case StateFetchDiff
:
2619 Rename(DestFile
, PatchFile
);
2621 // check if this is the last completed diff
2622 State
= StateDoneDiff
;
2623 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2624 I
!= allPatches
->end(); ++I
)
2625 if ((*I
)->State
!= StateDoneDiff
)
2628 std::clog
<< "Not the last done diff in the batch: " << Desc
.URI
<< std::endl
;
2631 // this is the last completed diff, so we are ready to apply now
2632 DestFile
= GetKeepCompressedFileName(UncompressedUnpatchedFile
+ "-patched", Target
);
2634 std::clog
<< "Sending to rred method: " << UnpatchedFile
<< std::endl
;
2635 State
= StateApplyDiff
;
2637 Desc
.URI
= "rred:" + UnpatchedFile
;
2639 SetActiveSubprocess("rred");
2641 case StateApplyDiff
:
2642 // success in download & apply all diffs, finialize and clean up
2644 std::clog
<< "Queue patched file in place: " << std::endl
2645 << DestFile
<< " -> " << PatchedFile
<< std::endl
;
2647 // queue for copy by the transaction manager
2648 TransactionManager
->TransactionStageCopy(this, DestFile
, GetKeepCompressedFileName(GetFinalFilename(), Target
));
2650 // ensure the ed's are gone regardless of list-cleanup
2651 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2652 I
!= allPatches
->end(); ++I
)
2653 RemoveFile("pkgAcqIndexMergeDiffs::Done", GetMergeDiffsPatchFileName(UnpatchedFile
, (*I
)->patch
.file
));
2654 RemoveFile("pkgAcqIndexMergeDiffs::Done", UnpatchedFile
);
2659 std::clog
<< "allDone: " << DestFile
<< "\n" << std::endl
;
2661 case StateDoneDiff
: _error
->Fatal("Done called for %s which is in an invalid Done state", PatchFile
.c_str()); break;
2662 case StateErrorDiff
: _error
->Fatal("Done called for %s which is in an invalid Error state", PatchFile
.c_str()); break;
2666 std::string
pkgAcqIndexMergeDiffs::Custom600Headers() const /*{{{*/
2668 if(State
!= StateApplyDiff
)
2669 return pkgAcqBaseIndex::Custom600Headers();
2670 std::ostringstream patchhashes
;
2671 unsigned int seen_patches
= 0;
2672 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2673 I
!= allPatches
->end(); ++I
)
2675 HashStringList
const ExpectedHashes
= (*I
)->patch
.patch_hashes
;
2676 for (HashStringList::const_iterator hs
= ExpectedHashes
.begin(); hs
!= ExpectedHashes
.end(); ++hs
)
2677 patchhashes
<< "\nPatch-" << seen_patches
<< "-" << hs
->HashType() << "-Hash: " << hs
->HashValue();
2680 patchhashes
<< pkgAcqBaseIndex::Custom600Headers();
2681 return patchhashes
.str();
2684 pkgAcqIndexMergeDiffs::~pkgAcqIndexMergeDiffs() {}
2686 // AcqIndex::AcqIndex - Constructor /*{{{*/
2687 pkgAcqIndex::pkgAcqIndex(pkgAcquire
* const Owner
,
2688 pkgAcqMetaClearSig
* const TransactionManager
,
2689 IndexTarget
const &Target
)
2690 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
), Stage(STAGE_DOWNLOAD
),
2691 CompressionExtensions(Target
.Option(IndexTarget::COMPRESSIONTYPES
))
2693 Init(Target
.URI
, Target
.Description
, Target
.ShortDesc
);
2695 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
2696 std::clog
<< "New pkgIndex with TransactionManager "
2697 << TransactionManager
<< std::endl
;
2700 // AcqIndex::Init - defered Constructor /*{{{*/
2701 static void NextCompressionExtension(std::string
&CurrentCompressionExtension
, std::string
&CompressionExtensions
, bool const preview
)
2703 size_t const nextExt
= CompressionExtensions
.find(' ');
2704 if (nextExt
== std::string::npos
)
2706 CurrentCompressionExtension
= CompressionExtensions
;
2707 if (preview
== false)
2708 CompressionExtensions
.clear();
2712 CurrentCompressionExtension
= CompressionExtensions
.substr(0, nextExt
);
2713 if (preview
== false)
2714 CompressionExtensions
= CompressionExtensions
.substr(nextExt
+1);
2717 void pkgAcqIndex::Init(string
const &URI
, string
const &URIDesc
,
2718 string
const &ShortDesc
)
2720 Stage
= STAGE_DOWNLOAD
;
2722 DestFile
= GetPartialFileNameFromURI(URI
);
2723 NextCompressionExtension(CurrentCompressionExtension
, CompressionExtensions
, false);
2725 // store file size of the download to ensure the fetcher gives
2726 // accurate progress reporting
2727 FileSize
= GetExpectedHashes().FileSize();
2729 if (CurrentCompressionExtension
== "uncompressed")
2733 else if (CurrentCompressionExtension
== "by-hash")
2735 NextCompressionExtension(CurrentCompressionExtension
, CompressionExtensions
, true);
2736 if(unlikely(TransactionManager
->MetaIndexParser
== NULL
|| CurrentCompressionExtension
.empty()))
2738 if (CurrentCompressionExtension
!= "uncompressed")
2740 Desc
.URI
= URI
+ '.' + CurrentCompressionExtension
;
2741 DestFile
= DestFile
+ '.' + CurrentCompressionExtension
;
2744 HashStringList
const Hashes
= GetExpectedHashes();
2745 HashString
const * const TargetHash
= Hashes
.find(NULL
);
2746 if (unlikely(TargetHash
== nullptr))
2748 std::string
const ByHash
= "/by-hash/" + TargetHash
->HashType() + "/" + TargetHash
->HashValue();
2749 size_t const trailing_slash
= Desc
.URI
.find_last_of("/");
2750 if (unlikely(trailing_slash
== std::string::npos
))
2752 Desc
.URI
= Desc
.URI
.replace(
2754 Desc
.URI
.substr(trailing_slash
+1).size()+1,
2757 else if (unlikely(CurrentCompressionExtension
.empty()))
2761 Desc
.URI
= URI
+ '.' + CurrentCompressionExtension
;
2762 DestFile
= DestFile
+ '.' + CurrentCompressionExtension
;
2766 Desc
.Description
= URIDesc
;
2768 Desc
.ShortDesc
= ShortDesc
;
2773 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
2774 // ---------------------------------------------------------------------
2775 /* The only header we use is the last-modified header. */
2776 string
pkgAcqIndex::Custom600Headers() const
2779 string msg
= "\nIndex-File: true";
2781 if (TransactionManager
->LastMetaIndexParser
== NULL
)
2783 std::string
const Final
= GetFinalFilename();
2786 if (stat(Final
.c_str(),&Buf
) == 0)
2787 msg
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
2790 if(Target
.IsOptional
)
2791 msg
+= "\nFail-Ignore: true";
2796 // AcqIndex::Failed - getting the indexfile failed /*{{{*/
2797 void pkgAcqIndex::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)
2799 pkgAcqBaseIndex::Failed(Message
,Cnf
);
2801 // authorisation matches will not be fixed by other compression types
2802 if (Status
!= StatAuthError
)
2804 if (CompressionExtensions
.empty() == false)
2806 Init(Target
.URI
, Desc
.Description
, Desc
.ShortDesc
);
2812 if(Target
.IsOptional
&& GetExpectedHashes().empty() && Stage
== STAGE_DOWNLOAD
)
2815 TransactionManager
->AbortTransaction();
2818 // AcqIndex::Done - Finished a fetch /*{{{*/
2819 // ---------------------------------------------------------------------
2820 /* This goes through a number of states.. On the initial fetch the
2821 method could possibly return an alternate filename which points
2822 to the uncompressed version of the file. If this is so the file
2823 is copied into the partial directory. In all other cases the file
2824 is decompressed with a compressed uri. */
2825 void pkgAcqIndex::Done(string
const &Message
,
2826 HashStringList
const &Hashes
,
2827 pkgAcquire::MethodConfig
const * const Cfg
)
2829 Item::Done(Message
,Hashes
,Cfg
);
2833 case STAGE_DOWNLOAD
:
2834 StageDownloadDone(Message
);
2836 case STAGE_DECOMPRESS_AND_VERIFY
:
2837 StageDecompressDone();
2842 // AcqIndex::StageDownloadDone - Queue for decompress and verify /*{{{*/
2843 void pkgAcqIndex::StageDownloadDone(string
const &Message
)
2848 std::string
const AltFilename
= LookupTag(Message
,"Alt-Filename");
2849 std::string Filename
= LookupTag(Message
,"Filename");
2851 // we need to verify the file against the current Release file again
2852 // on if-modfied-since hit to avoid a stale attack against us
2853 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
2855 // copy FinalFile into partial/ so that we check the hash again
2856 string
const FinalFile
= GetExistingFilename(GetFinalFileNameFromURI(Target
.URI
));
2857 if (symlink(FinalFile
.c_str(), DestFile
.c_str()) != 0)
2858 _error
->WarningE("pkgAcqIndex::StageDownloadDone", "Symlinking final file %s back to %s failed", FinalFile
.c_str(), DestFile
.c_str());
2861 EraseFileName
= DestFile
;
2862 Filename
= DestFile
;
2864 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
2865 Desc
.URI
= "store:" + Filename
;
2867 SetActiveSubprocess(::URI(Desc
.URI
).Access
);
2870 // methods like file:// give us an alternative (uncompressed) file
2871 else if (Target
.KeepCompressed
== false && AltFilename
.empty() == false)
2873 Filename
= AltFilename
;
2874 EraseFileName
.clear();
2876 // Methods like e.g. "file:" will give us a (compressed) FileName that is
2877 // not the "DestFile" we set, in this case we uncompress from the local file
2878 else if (Filename
!= DestFile
&& RealFileExists(DestFile
) == false)
2880 // symlinking ensures that the filename can be used for compression detection
2881 // that is e.g. needed for by-hash which has no extension over file
2882 if (symlink(Filename
.c_str(),DestFile
.c_str()) != 0)
2883 _error
->WarningE("pkgAcqIndex::StageDownloadDone", "Symlinking file %s to %s failed", Filename
.c_str(), DestFile
.c_str());
2886 EraseFileName
= DestFile
;
2887 Filename
= DestFile
;
2891 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
2892 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
2893 if (Filename
!= DestFile
&& flExtension(Filename
) == flExtension(DestFile
))
2894 Desc
.URI
= "copy:" + Filename
;
2896 Desc
.URI
= "store:" + Filename
;
2897 if (DestFile
== Filename
)
2899 if (CurrentCompressionExtension
== "uncompressed")
2900 return StageDecompressDone();
2901 DestFile
= "/dev/null";
2904 if (EraseFileName
.empty() && Filename
!= AltFilename
)
2905 EraseFileName
= Filename
;
2907 // queue uri for the next stage
2909 SetActiveSubprocess(::URI(Desc
.URI
).Access
);
2912 // AcqIndex::StageDecompressDone - Final verification /*{{{*/
2913 void pkgAcqIndex::StageDecompressDone()
2915 if (DestFile
== "/dev/null")
2916 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
2918 // Done, queue for rename on transaction finished
2919 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
2922 pkgAcqIndex::~pkgAcqIndex() {}
2925 // AcqArchive::AcqArchive - Constructor /*{{{*/
2926 // ---------------------------------------------------------------------
2927 /* This just sets up the initial fetch environment and queues the first
2929 pkgAcqArchive::pkgAcqArchive(pkgAcquire
* const Owner
,pkgSourceList
* const Sources
,
2930 pkgRecords
* const Recs
,pkgCache::VerIterator
const &Version
,
2931 string
&StoreFilename
) :
2932 Item(Owner
), d(NULL
), LocalSource(false), Version(Version
), Sources(Sources
), Recs(Recs
),
2933 StoreFilename(StoreFilename
), Vf(Version
.FileList()),
2936 Retries
= _config
->FindI("Acquire::Retries",0);
2938 if (Version
.Arch() == 0)
2940 _error
->Error(_("I wasn't able to locate a file for the %s package. "
2941 "This might mean you need to manually fix this package. "
2942 "(due to missing arch)"),
2943 Version
.ParentPkg().FullName().c_str());
2947 /* We need to find a filename to determine the extension. We make the
2948 assumption here that all the available sources for this version share
2949 the same extension.. */
2950 // Skip not source sources, they do not have file fields.
2951 for (; Vf
.end() == false; ++Vf
)
2953 if (Vf
.File().Flagged(pkgCache::Flag::NotSource
))
2958 // Does not really matter here.. we are going to fail out below
2959 if (Vf
.end() != true)
2961 // If this fails to get a file name we will bomb out below.
2962 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2963 if (_error
->PendingError() == true)
2966 // Generate the final file name as: package_version_arch.foo
2967 StoreFilename
= QuoteString(Version
.ParentPkg().Name(),"_:") + '_' +
2968 QuoteString(Version
.VerStr(),"_:") + '_' +
2969 QuoteString(Version
.Arch(),"_:.") +
2970 "." + flExtension(Parse
.FileName());
2973 // check if we have one trusted source for the package. if so, switch
2974 // to "TrustedOnly" mode - but only if not in AllowUnauthenticated mode
2975 bool const allowUnauth
= _config
->FindB("APT::Get::AllowUnauthenticated", false);
2976 bool const debugAuth
= _config
->FindB("Debug::pkgAcquire::Auth", false);
2977 bool seenUntrusted
= false;
2978 for (pkgCache::VerFileIterator i
= Version
.FileList(); i
.end() == false; ++i
)
2980 pkgIndexFile
*Index
;
2981 if (Sources
->FindIndex(i
.File(),Index
) == false)
2984 if (debugAuth
== true)
2985 std::cerr
<< "Checking index: " << Index
->Describe()
2986 << "(Trusted=" << Index
->IsTrusted() << ")" << std::endl
;
2988 if (Index
->IsTrusted() == true)
2991 if (allowUnauth
== false)
2995 seenUntrusted
= true;
2998 // "allow-unauthenticated" restores apts old fetching behaviour
2999 // that means that e.g. unauthenticated file:// uris are higher
3000 // priority than authenticated http:// uris
3001 if (allowUnauth
== true && seenUntrusted
== true)
3005 if (QueueNext() == false && _error
->PendingError() == false)
3006 _error
->Error(_("Can't find a source to download version '%s' of '%s'"),
3007 Version
.VerStr(), Version
.ParentPkg().FullName(false).c_str());
3010 // AcqArchive::QueueNext - Queue the next file source /*{{{*/
3011 // ---------------------------------------------------------------------
3012 /* This queues the next available file version for download. It checks if
3013 the archive is already available in the cache and stashs the MD5 for
3015 bool pkgAcqArchive::QueueNext()
3017 for (; Vf
.end() == false; ++Vf
)
3019 pkgCache::PkgFileIterator
const PkgF
= Vf
.File();
3020 // Ignore not source sources
3021 if (PkgF
.Flagged(pkgCache::Flag::NotSource
))
3024 // Try to cross match against the source list
3025 pkgIndexFile
*Index
;
3026 if (Sources
->FindIndex(PkgF
, Index
) == false)
3028 LocalSource
= PkgF
.Flagged(pkgCache::Flag::LocalSource
);
3030 // only try to get a trusted package from another source if that source
3032 if(Trusted
&& !Index
->IsTrusted())
3035 // Grab the text package record
3036 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
3037 if (_error
->PendingError() == true)
3040 string PkgFile
= Parse
.FileName();
3041 ExpectedHashes
= Parse
.Hashes();
3043 if (PkgFile
.empty() == true)
3044 return _error
->Error(_("The package index files are corrupted. No Filename: "
3045 "field for package %s."),
3046 Version
.ParentPkg().Name());
3048 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
3049 Desc
.Description
= Index
->ArchiveInfo(Version
);
3051 Desc
.ShortDesc
= Version
.ParentPkg().FullName(true);
3053 // See if we already have the file. (Legacy filenames)
3054 FileSize
= Version
->Size
;
3055 string FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile
);
3057 if (stat(FinalFile
.c_str(),&Buf
) == 0)
3059 // Make sure the size matches
3060 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
3065 StoreFilename
= DestFile
= FinalFile
;
3069 /* Hmm, we have a file and its size does not match, this means it is
3070 an old style mismatched arch */
3071 RemoveFile("pkgAcqArchive::QueueNext", FinalFile
);
3074 // Check it again using the new style output filenames
3075 FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
3076 if (stat(FinalFile
.c_str(),&Buf
) == 0)
3078 // Make sure the size matches
3079 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
3084 StoreFilename
= DestFile
= FinalFile
;
3088 /* Hmm, we have a file and its size does not match, this shouldn't
3090 RemoveFile("pkgAcqArchive::QueueNext", FinalFile
);
3093 DestFile
= _config
->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename
);
3095 // Check the destination file
3096 if (stat(DestFile
.c_str(),&Buf
) == 0)
3098 // Hmm, the partial file is too big, erase it
3099 if ((unsigned long long)Buf
.st_size
> Version
->Size
)
3100 RemoveFile("pkgAcqArchive::QueueNext", DestFile
);
3102 PartialSize
= Buf
.st_size
;
3105 // Disables download of archives - useful if no real installation follows,
3106 // e.g. if we are just interested in proposed installation order
3107 if (_config
->FindB("Debug::pkgAcqArchive::NoQueue", false) == true)
3112 StoreFilename
= DestFile
= FinalFile
;
3126 // AcqArchive::Done - Finished fetching /*{{{*/
3127 // ---------------------------------------------------------------------
3129 void pkgAcqArchive::Done(string
const &Message
, HashStringList
const &Hashes
,
3130 pkgAcquire::MethodConfig
const * const Cfg
)
3132 Item::Done(Message
, Hashes
, Cfg
);
3134 // Grab the output filename
3135 std::string
const FileName
= LookupTag(Message
,"Filename");
3136 if (DestFile
!= FileName
&& RealFileExists(DestFile
) == false)
3138 StoreFilename
= DestFile
= FileName
;
3144 // Done, move it into position
3145 string
const FinalFile
= GetFinalFilename();
3146 Rename(DestFile
,FinalFile
);
3147 StoreFilename
= DestFile
= FinalFile
;
3151 // AcqArchive::Failed - Failure handler /*{{{*/
3152 // ---------------------------------------------------------------------
3153 /* Here we try other sources */
3154 void pkgAcqArchive::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)
3156 Item::Failed(Message
,Cnf
);
3158 /* We don't really want to retry on failed media swaps, this prevents
3159 that. An interesting observation is that permanent failures are not
3161 if (Cnf
->Removable
== true &&
3162 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
3164 // Vf = Version.FileList();
3165 while (Vf
.end() == false) ++Vf
;
3166 StoreFilename
= string();
3171 if (QueueNext() == false)
3173 // This is the retry counter
3175 Cnf
->LocalOnly
== false &&
3176 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
3179 Vf
= Version
.FileList();
3180 if (QueueNext() == true)
3184 StoreFilename
= string();
3189 APT_PURE
bool pkgAcqArchive::IsTrusted() const /*{{{*/
3194 void pkgAcqArchive::Finished() /*{{{*/
3196 if (Status
== pkgAcquire::Item::StatDone
&&
3199 StoreFilename
= string();
3202 std::string
pkgAcqArchive::DescURI() const /*{{{*/
3207 std::string
pkgAcqArchive::ShortDesc() const /*{{{*/
3209 return Desc
.ShortDesc
;
3212 pkgAcqArchive::~pkgAcqArchive() {}
3214 // AcqChangelog::pkgAcqChangelog - Constructors /*{{{*/
3215 class pkgAcqChangelog::Private
3218 std::string FinalFile
;
3220 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire
* const Owner
, pkgCache::VerIterator
const &Ver
,
3221 std::string
const &DestDir
, std::string
const &DestFilename
) :
3222 pkgAcquire::Item(Owner
), d(new pkgAcqChangelog::Private()), SrcName(Ver
.SourcePkgName()), SrcVersion(Ver
.SourceVerStr())
3224 Desc
.URI
= URI(Ver
);
3225 Init(DestDir
, DestFilename
);
3227 // some parameters are char* here as they come likely from char* interfaces – which can also return NULL
3228 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire
* const Owner
, pkgCache::RlsFileIterator
const &RlsFile
,
3229 char const * const Component
, char const * const SrcName
, char const * const SrcVersion
,
3230 const string
&DestDir
, const string
&DestFilename
) :
3231 pkgAcquire::Item(Owner
), d(new pkgAcqChangelog::Private()), SrcName(SrcName
), SrcVersion(SrcVersion
)
3233 Desc
.URI
= URI(RlsFile
, Component
, SrcName
, SrcVersion
);
3234 Init(DestDir
, DestFilename
);
3236 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire
* const Owner
,
3237 std::string
const &URI
, char const * const SrcName
, char const * const SrcVersion
,
3238 const string
&DestDir
, const string
&DestFilename
) :
3239 pkgAcquire::Item(Owner
), d(new pkgAcqChangelog::Private()), SrcName(SrcName
), SrcVersion(SrcVersion
)
3242 Init(DestDir
, DestFilename
);
3244 void pkgAcqChangelog::Init(std::string
const &DestDir
, std::string
const &DestFilename
)
3246 if (Desc
.URI
.empty())
3249 // TRANSLATOR: %s=%s is sourcename=sourceversion, e.g. apt=1.1
3250 strprintf(ErrorText
, _("Changelog unavailable for %s=%s"), SrcName
.c_str(), SrcVersion
.c_str());
3251 // Let the error message print something sensible rather than "Failed to fetch /"
3252 if (DestFilename
.empty())
3253 DestFile
= SrcName
+ ".changelog";
3255 DestFile
= DestFilename
;
3256 Desc
.URI
= "changelog:/" + DestFile
;
3260 std::string DestFileName
;
3261 if (DestFilename
.empty())
3262 DestFileName
= flCombine(DestFile
, SrcName
+ ".changelog");
3264 DestFileName
= flCombine(DestFile
, DestFilename
);
3266 std::string
const SandboxUser
= _config
->Find("APT::Sandbox::User");
3267 std::string
const systemTemp
= GetTempDir(SandboxUser
);
3269 snprintf(tmpname
, sizeof(tmpname
), "%s/apt-changelog-XXXXXX", systemTemp
.c_str());
3270 if (NULL
== mkdtemp(tmpname
))
3272 _error
->Errno("mkdtemp", "mkdtemp failed in changelog acquire of %s %s", SrcName
.c_str(), SrcVersion
.c_str());
3276 TemporaryDirectory
= tmpname
;
3278 ChangeOwnerAndPermissionOfFile("Item::QueueURI", TemporaryDirectory
.c_str(),
3279 SandboxUser
.c_str(), "root", 0700);
3281 DestFile
= flCombine(TemporaryDirectory
, DestFileName
);
3282 if (DestDir
.empty() == false)
3284 d
->FinalFile
= flCombine(DestDir
, DestFileName
);
3285 if (RealFileExists(d
->FinalFile
))
3287 FileFd file1
, file2
;
3288 if (file1
.Open(DestFile
, FileFd::WriteOnly
| FileFd::Create
| FileFd::Exclusive
) &&
3289 file2
.Open(d
->FinalFile
, FileFd::ReadOnly
) && CopyFile(file2
, file1
))
3291 struct timeval times
[2];
3292 times
[0].tv_sec
= times
[1].tv_sec
= file2
.ModificationTime();
3293 times
[0].tv_usec
= times
[1].tv_usec
= 0;
3294 utimes(DestFile
.c_str(), times
);
3299 Desc
.ShortDesc
= "Changelog";
3300 strprintf(Desc
.Description
, "%s %s %s Changelog", URI::SiteOnly(Desc
.URI
).c_str(), SrcName
.c_str(), SrcVersion
.c_str());
3305 std::string
pkgAcqChangelog::URI(pkgCache::VerIterator
const &Ver
) /*{{{*/
3307 std::string
const confOnline
= "Acquire::Changelogs::AlwaysOnline";
3308 bool AlwaysOnline
= _config
->FindB(confOnline
, false);
3309 if (AlwaysOnline
== false)
3310 for (pkgCache::VerFileIterator VF
= Ver
.FileList(); VF
.end() == false; ++VF
)
3312 pkgCache::PkgFileIterator
const PF
= VF
.File();
3313 if (PF
.Flagged(pkgCache::Flag::NotSource
) || PF
->Release
== 0)
3315 pkgCache::RlsFileIterator
const RF
= PF
.ReleaseFile();
3316 if (RF
->Origin
!= 0 && _config
->FindB(confOnline
+ "::Origin::" + RF
.Origin(), false))
3318 AlwaysOnline
= true;
3322 if (AlwaysOnline
== false)
3324 pkgCache::PkgIterator
const Pkg
= Ver
.ParentPkg();
3325 if (Pkg
->CurrentVer
!= 0 && Pkg
.CurrentVer() == Ver
)
3327 std::string
const basename
= std::string("/usr/share/doc/") + Pkg
.Name() + "/changelog";
3328 std::string
const debianname
= basename
+ ".Debian";
3329 if (FileExists(debianname
))
3330 return "copy://" + debianname
;
3331 else if (FileExists(debianname
+ ".gz"))
3332 return "gzip://" + debianname
+ ".gz";
3333 else if (FileExists(basename
))
3334 return "copy://" + basename
;
3335 else if (FileExists(basename
+ ".gz"))
3336 return "gzip://" + basename
+ ".gz";
3340 char const * const SrcName
= Ver
.SourcePkgName();
3341 char const * const SrcVersion
= Ver
.SourceVerStr();
3342 // find the first source for this version which promises a changelog
3343 for (pkgCache::VerFileIterator VF
= Ver
.FileList(); VF
.end() == false; ++VF
)
3345 pkgCache::PkgFileIterator
const PF
= VF
.File();
3346 if (PF
.Flagged(pkgCache::Flag::NotSource
) || PF
->Release
== 0)
3348 pkgCache::RlsFileIterator
const RF
= PF
.ReleaseFile();
3349 std::string
const uri
= URI(RF
, PF
.Component(), SrcName
, SrcVersion
);
3356 std::string
pkgAcqChangelog::URITemplate(pkgCache::RlsFileIterator
const &Rls
)
3358 if (Rls
.end() == true || (Rls
->Label
== 0 && Rls
->Origin
== 0))
3360 std::string
const serverConfig
= "Acquire::Changelogs::URI";
3362 #define APT_EMPTY_SERVER \
3363 if (server.empty() == false) \
3365 if (server != "no") \
3369 #define APT_CHECK_SERVER(X, Y) \
3372 std::string const specialServerConfig = serverConfig + "::" + Y + #X + "::" + Rls.X(); \
3373 server = _config->Find(specialServerConfig); \
3376 // this way e.g. Debian-Security can fallback to Debian
3377 APT_CHECK_SERVER(Label
, "Override::")
3378 APT_CHECK_SERVER(Origin
, "Override::")
3380 if (RealFileExists(Rls
.FileName()))
3382 _error
->PushToStack();
3384 /* This can be costly. A caller wanting to get millions of URIs might
3385 want to do this on its own once and use Override settings.
3386 We don't do this here as Origin/Label are not as unique as they
3387 should be so this could produce request order-dependent anomalies */
3388 if (OpenMaybeClearSignedFile(Rls
.FileName(), rf
) == true)
3390 pkgTagFile
TagFile(&rf
, rf
.Size());
3391 pkgTagSection Section
;
3392 if (TagFile
.Step(Section
) == true)
3393 server
= Section
.FindS("Changelogs");
3395 _error
->RevertToStack();
3399 APT_CHECK_SERVER(Label
, "")
3400 APT_CHECK_SERVER(Origin
, "")
3401 #undef APT_CHECK_SERVER
3402 #undef APT_EMPTY_SERVER
3405 std::string
pkgAcqChangelog::URI(pkgCache::RlsFileIterator
const &Rls
,
3406 char const * const Component
, char const * const SrcName
,
3407 char const * const SrcVersion
)
3409 return URI(URITemplate(Rls
), Component
, SrcName
, SrcVersion
);
3411 std::string
pkgAcqChangelog::URI(std::string
const &Template
,
3412 char const * const Component
, char const * const SrcName
,
3413 char const * const SrcVersion
)
3415 if (Template
.find("@CHANGEPATH@") == std::string::npos
)
3418 // the path is: COMPONENT/SRC/SRCNAME/SRCNAME_SRCVER, e.g. main/a/apt/1.1 or contrib/liba/libapt/2.0
3419 std::string Src
= SrcName
;
3420 std::string path
= APT::String::Startswith(SrcName
, "lib") ? Src
.substr(0, 4) : Src
.substr(0,1);
3421 path
.append("/").append(Src
).append("/");
3422 path
.append(Src
).append("_").append(StripEpoch(SrcVersion
));
3423 // we omit component for releases without one (= flat-style repositories)
3424 if (Component
!= NULL
&& strlen(Component
) != 0)
3425 path
= std::string(Component
) + "/" + path
;
3427 return SubstVar(Template
, "@CHANGEPATH@", path
);
3430 // AcqChangelog::Failed - Failure handler /*{{{*/
3431 void pkgAcqChangelog::Failed(string
const &Message
, pkgAcquire::MethodConfig
const * const Cnf
)
3433 Item::Failed(Message
,Cnf
);
3435 std::string errText
;
3436 // TRANSLATOR: %s=%s is sourcename=sourceversion, e.g. apt=1.1
3437 strprintf(errText
, _("Changelog unavailable for %s=%s"), SrcName
.c_str(), SrcVersion
.c_str());
3439 // Error is probably something techy like 404 Not Found
3440 if (ErrorText
.empty())
3441 ErrorText
= errText
;
3443 ErrorText
= errText
+ " (" + ErrorText
+ ")";
3446 // AcqChangelog::Done - Item downloaded OK /*{{{*/
3447 void pkgAcqChangelog::Done(string
const &Message
,HashStringList
const &CalcHashes
,
3448 pkgAcquire::MethodConfig
const * const Cnf
)
3450 Item::Done(Message
,CalcHashes
,Cnf
);
3451 if (d
->FinalFile
.empty() == false)
3453 if (RemoveFile("pkgAcqChangelog::Done", d
->FinalFile
) == false ||
3454 Rename(DestFile
, d
->FinalFile
) == false)
3461 pkgAcqChangelog::~pkgAcqChangelog() /*{{{*/
3463 if (TemporaryDirectory
.empty() == false)
3465 RemoveFile("~pkgAcqChangelog", DestFile
);
3466 rmdir(TemporaryDirectory
.c_str());
3472 // AcqFile::pkgAcqFile - Constructor /*{{{*/
3473 pkgAcqFile::pkgAcqFile(pkgAcquire
* const Owner
,string
const &URI
, HashStringList
const &Hashes
,
3474 unsigned long long const Size
,string
const &Dsc
,string
const &ShortDesc
,
3475 const string
&DestDir
, const string
&DestFilename
,
3476 bool const IsIndexFile
) :
3477 Item(Owner
), d(NULL
), IsIndexFile(IsIndexFile
), ExpectedHashes(Hashes
)
3479 Retries
= _config
->FindI("Acquire::Retries",0);
3481 if(!DestFilename
.empty())
3482 DestFile
= DestFilename
;
3483 else if(!DestDir
.empty())
3484 DestFile
= DestDir
+ "/" + flNotDir(URI
);
3486 DestFile
= flNotDir(URI
);
3490 Desc
.Description
= Dsc
;
3493 // Set the short description to the archive component
3494 Desc
.ShortDesc
= ShortDesc
;
3496 // Get the transfer sizes
3499 if (stat(DestFile
.c_str(),&Buf
) == 0)
3501 // Hmm, the partial file is too big, erase it
3502 if ((Size
> 0) && (unsigned long long)Buf
.st_size
> Size
)
3503 RemoveFile("pkgAcqFile", DestFile
);
3505 PartialSize
= Buf
.st_size
;
3511 // AcqFile::Done - Item downloaded OK /*{{{*/
3512 void pkgAcqFile::Done(string
const &Message
,HashStringList
const &CalcHashes
,
3513 pkgAcquire::MethodConfig
const * const Cnf
)
3515 Item::Done(Message
,CalcHashes
,Cnf
);
3517 std::string
const FileName
= LookupTag(Message
,"Filename");
3520 // The files timestamp matches
3521 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
3524 // We have to copy it into place
3525 if (RealFileExists(DestFile
.c_str()) == false)
3528 if (_config
->FindB("Acquire::Source-Symlinks",true) == false ||
3529 Cnf
->Removable
== true)
3531 Desc
.URI
= "copy:" + FileName
;
3536 // Erase the file if it is a symlink so we can overwrite it
3538 if (lstat(DestFile
.c_str(),&St
) == 0)
3540 if (S_ISLNK(St
.st_mode
) != 0)
3541 RemoveFile("pkgAcqFile::Done", DestFile
);
3545 if (symlink(FileName
.c_str(),DestFile
.c_str()) != 0)
3547 _error
->PushToStack();
3548 _error
->Errno("pkgAcqFile::Done", "Symlinking file %s failed", DestFile
.c_str());
3549 std::stringstream msg
;
3550 _error
->DumpErrors(msg
, GlobalError::DEBUG
, false);
3551 _error
->RevertToStack();
3552 ErrorText
= msg
.str();
3559 // AcqFile::Failed - Failure handler /*{{{*/
3560 // ---------------------------------------------------------------------
3561 /* Here we try other sources */
3562 void pkgAcqFile::Failed(string
const &Message
, pkgAcquire::MethodConfig
const * const Cnf
)
3564 Item::Failed(Message
,Cnf
);
3566 // This is the retry counter
3568 Cnf
->LocalOnly
== false &&
3569 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
3579 string
pkgAcqFile::Custom600Headers() const /*{{{*/
3582 return "\nIndex-File: true";
3586 pkgAcqFile::~pkgAcqFile() {}