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 bool MessageInsecureRepository(bool const isError
, std::string
const &msg
)/*{{{*/
139 _error
->Error("%s", msg
.c_str());
140 _error
->Notice("%s", _("Updating from such a repository can't be done securely, and is therefore disabled by default."));
144 _error
->Warning("%s", msg
.c_str());
145 _error
->Notice("%s", _("Data from such a repository can't be authenticated and is therefore potentially dangerous to use."));
147 _error
->Notice("%s", _("See apt-secure(8) manpage for repository creation and user configuration details."));
150 static bool MessageInsecureRepository(bool const isError
, char const * const msg
, std::string
const &repo
)
153 strprintf(m
, msg
, repo
.c_str());
154 return MessageInsecureRepository(isError
, m
);
157 static bool AllowInsecureRepositories(char const * const msg
, std::string
const &repo
,/*{{{*/
158 metaIndex
const * const MetaIndexParser
, pkgAcqMetaClearSig
* const TransactionManager
, pkgAcquire::Item
* const I
)
160 if(MetaIndexParser
->GetTrusted() == metaIndex::TRI_YES
)
163 if (_config
->FindB("Acquire::AllowInsecureRepositories") == true)
165 MessageInsecureRepository(false, msg
, repo
);
169 MessageInsecureRepository(true, msg
, repo
);
170 TransactionManager
->AbortTransaction();
171 I
->Status
= pkgAcquire::Item::StatError
;
175 static HashStringList
GetExpectedHashesFromFor(metaIndex
* const Parser
, std::string
const &MetaKey
)/*{{{*/
178 return HashStringList();
179 metaIndex::checkSum
* const R
= Parser
->Lookup(MetaKey
);
181 return HashStringList();
186 // all ::HashesRequired and ::GetExpectedHashes implementations /*{{{*/
187 /* ::GetExpectedHashes is abstract and has to be implemented by all subclasses.
188 It is best to implement it as broadly as possible, while ::HashesRequired defaults
189 to true and should be as restrictive as possible for false cases. Note that if
190 a hash is returned by ::GetExpectedHashes it must match. Only if it doesn't
191 ::HashesRequired is called to evaluate if its okay to have no hashes. */
192 APT_CONST
bool pkgAcqTransactionItem::HashesRequired() const
194 /* signed repositories obviously have a parser and good hashes.
195 unsigned repositories, too, as even if we can't trust them for security,
196 we can at least trust them for integrity of the download itself.
197 Only repositories without a Release file can (obviously) not have
198 hashes – and they are very uncommon and strongly discouraged */
199 return TransactionManager
->MetaIndexParser
!= NULL
&&
200 TransactionManager
->MetaIndexParser
->GetLoadedSuccessfully() == metaIndex::TRI_YES
;
202 HashStringList
pkgAcqTransactionItem::GetExpectedHashes() const
204 return GetExpectedHashesFor(GetMetaKey());
207 APT_CONST
bool pkgAcqMetaBase::HashesRequired() const
209 // Release and co have no hashes 'by design'.
212 HashStringList
pkgAcqMetaBase::GetExpectedHashes() const
214 return HashStringList();
217 APT_CONST
bool pkgAcqIndexDiffs::HashesRequired() const
219 /* We can't check hashes of rred result as we don't know what the
220 hash of the file will be. We just know the hash of the patch(es),
221 the hash of the file they will apply on and the hash of the resulting
223 if (State
== StateFetchDiff
)
227 HashStringList
pkgAcqIndexDiffs::GetExpectedHashes() const
229 if (State
== StateFetchDiff
)
230 return available_patches
[0].download_hashes
;
231 return HashStringList();
234 APT_CONST
bool pkgAcqIndexMergeDiffs::HashesRequired() const
236 /* @see #pkgAcqIndexDiffs::HashesRequired, with the difference that
237 we can check the rred result after all patches are applied as
238 we know the expected result rather than potentially apply more patches */
239 if (State
== StateFetchDiff
)
241 return State
== StateApplyDiff
;
243 HashStringList
pkgAcqIndexMergeDiffs::GetExpectedHashes() const
245 if (State
== StateFetchDiff
)
246 return patch
.download_hashes
;
247 else if (State
== StateApplyDiff
)
248 return GetExpectedHashesFor(Target
.MetaKey
);
249 return HashStringList();
252 APT_CONST
bool pkgAcqArchive::HashesRequired() const
254 return LocalSource
== false;
256 HashStringList
pkgAcqArchive::GetExpectedHashes() const
258 // figured out while parsing the records
259 return ExpectedHashes
;
262 APT_CONST
bool pkgAcqFile::HashesRequired() const
264 // supplied as parameter at creation time, so the caller decides
265 return ExpectedHashes
.usable();
267 HashStringList
pkgAcqFile::GetExpectedHashes() const
269 return ExpectedHashes
;
272 // Acquire::Item::QueueURI and specialisations from child classes /*{{{*/
273 bool pkgAcquire::Item::QueueURI(pkgAcquire::ItemDesc
&Item
)
275 Owner
->Enqueue(Item
);
278 /* The idea here is that an item isn't queued if it exists on disk and the
279 transition manager was a hit as this means that the files it contains
280 the checksums for can't be updated either (or they are and we are asking
281 for a hashsum mismatch to happen which helps nobody) */
282 bool pkgAcqTransactionItem::QueueURI(pkgAcquire::ItemDesc
&Item
)
284 std::string
const FinalFile
= GetFinalFilename();
285 if (TransactionManager
!= NULL
&& TransactionManager
->IMSHit
== true &&
286 FileExists(FinalFile
) == true)
288 PartialFile
= DestFile
= FinalFile
;
292 return pkgAcquire::Item::QueueURI(Item
);
294 /* The transition manager InRelease itself (or its older sisters-in-law
295 Release & Release.gpg) is always queued as this allows us to rerun gpgv
296 on it to verify that we aren't stalled with old files */
297 bool pkgAcqMetaBase::QueueURI(pkgAcquire::ItemDesc
&Item
)
299 return pkgAcquire::Item::QueueURI(Item
);
301 /* the Diff/Index needs to queue also the up-to-date complete index file
302 to ensure that the list cleaner isn't eating it */
303 bool pkgAcqDiffIndex::QueueURI(pkgAcquire::ItemDesc
&Item
)
305 if (pkgAcqTransactionItem::QueueURI(Item
) == true)
311 // Acquire::Item::GetFinalFilename and specialisations for child classes /*{{{*/
312 std::string
pkgAcquire::Item::GetFinalFilename() const
314 // Beware: Desc.URI is modified by redirections
315 return GetFinalFileNameFromURI(Desc
.URI
);
317 std::string
pkgAcqDiffIndex::GetFinalFilename() const
319 return GetFinalFileNameFromURI(GetDiffIndexURI(Target
));
321 std::string
pkgAcqIndex::GetFinalFilename() const
323 std::string
const FinalFile
= GetFinalFileNameFromURI(Target
.URI
);
324 return GetKeepCompressedFileName(FinalFile
, Target
);
326 std::string
pkgAcqMetaSig::GetFinalFilename() const
328 return GetFinalFileNameFromURI(Target
.URI
);
330 std::string
pkgAcqBaseIndex::GetFinalFilename() const
332 return GetFinalFileNameFromURI(Target
.URI
);
334 std::string
pkgAcqMetaBase::GetFinalFilename() const
336 return GetFinalFileNameFromURI(Target
.URI
);
338 std::string
pkgAcqArchive::GetFinalFilename() const
340 return _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
343 // pkgAcqTransactionItem::GetMetaKey and specialisations for child classes /*{{{*/
344 std::string
pkgAcqTransactionItem::GetMetaKey() const
346 return Target
.MetaKey
;
348 std::string
pkgAcqIndex::GetMetaKey() const
350 if (Stage
== STAGE_DECOMPRESS_AND_VERIFY
|| CurrentCompressionExtension
== "uncompressed")
351 return Target
.MetaKey
;
352 return Target
.MetaKey
+ "." + CurrentCompressionExtension
;
354 std::string
pkgAcqDiffIndex::GetMetaKey() const
356 return GetDiffIndexFileName(Target
.MetaKey
);
359 //pkgAcqTransactionItem::TransactionState and specialisations for child classes /*{{{*/
360 bool pkgAcqTransactionItem::TransactionState(TransactionStates
const state
)
362 bool const Debug
= _config
->FindB("Debug::Acquire::Transaction", false);
365 case TransactionAbort
:
367 std::clog
<< " Cancel: " << DestFile
<< std::endl
;
368 if (Status
== pkgAcquire::Item::StatIdle
)
370 Status
= pkgAcquire::Item::StatDone
;
374 case TransactionCommit
:
375 if(PartialFile
.empty() == false)
377 bool sameFile
= (PartialFile
== DestFile
);
378 // we use symlinks on IMS-Hit to avoid copies
379 if (RealFileExists(DestFile
))
382 if (lstat(PartialFile
.c_str(), &Buf
) != -1)
384 if (S_ISLNK(Buf
.st_mode
) && Buf
.st_size
> 0)
386 char partial
[Buf
.st_size
+ 1];
387 ssize_t
const sp
= readlink(PartialFile
.c_str(), partial
, Buf
.st_size
);
389 _error
->Errno("pkgAcqTransactionItem::TransactionState-sp", _("Failed to readlink %s"), PartialFile
.c_str());
393 sameFile
= (DestFile
== partial
);
398 _error
->Errno("pkgAcqTransactionItem::TransactionState-stat", _("Failed to stat %s"), PartialFile
.c_str());
400 if (sameFile
== false)
402 // ensure that even without lists-cleanup all compressions are nuked
403 std::string FinalFile
= GetFinalFileNameFromURI(Target
.URI
);
404 if (FileExists(FinalFile
))
407 std::clog
<< "rm " << FinalFile
<< " # " << DescURI() << std::endl
;
408 if (RemoveFile("TransactionStates-Cleanup", FinalFile
) == false)
411 for (auto const &ext
: APT::Configuration::getCompressorExtensions())
413 auto const Final
= FinalFile
+ ext
;
414 if (FileExists(Final
))
417 std::clog
<< "rm " << Final
<< " # " << DescURI() << std::endl
;
418 if (RemoveFile("TransactionStates-Cleanup", Final
) == false)
423 std::clog
<< "mv " << PartialFile
<< " -> "<< DestFile
<< " # " << DescURI() << std::endl
;
424 if (Rename(PartialFile
, DestFile
) == false)
427 else if(Debug
== true)
428 std::clog
<< "keep " << PartialFile
<< " # " << DescURI() << std::endl
;
432 std::clog
<< "rm " << DestFile
<< " # " << DescURI() << std::endl
;
433 if (RemoveFile("TransactionCommit", DestFile
) == false)
440 bool pkgAcqMetaBase::TransactionState(TransactionStates
const state
)
442 // Do not remove InRelease on IMSHit of Release.gpg [yes, this is very edgecasey]
443 if (TransactionManager
->IMSHit
== false)
444 return pkgAcqTransactionItem::TransactionState(state
);
447 bool pkgAcqIndex::TransactionState(TransactionStates
const state
)
449 if (pkgAcqTransactionItem::TransactionState(state
) == false)
454 case TransactionAbort
:
455 if (Stage
== STAGE_DECOMPRESS_AND_VERIFY
)
457 // keep the compressed file, but drop the decompressed
458 EraseFileName
.clear();
459 if (PartialFile
.empty() == false && flExtension(PartialFile
) != CurrentCompressionExtension
)
460 RemoveFile("TransactionAbort", PartialFile
);
463 case TransactionCommit
:
464 if (EraseFileName
.empty() == false)
465 RemoveFile("TransactionCommit", EraseFileName
);
470 bool pkgAcqDiffIndex::TransactionState(TransactionStates
const state
)
472 if (pkgAcqTransactionItem::TransactionState(state
) == false)
477 case TransactionCommit
:
479 case TransactionAbort
:
480 std::string
const Partial
= GetPartialFileNameFromURI(Target
.URI
);
481 RemoveFile("TransactionAbort", Partial
);
489 class APT_HIDDEN NoActionItem
: public pkgAcquire::Item
/*{{{*/
490 /* The sole purpose of this class is having an item which does nothing to
491 reach its done state to prevent cleanup deleting the mentioned file.
492 Handy in cases in which we know we have the file already, like IMS-Hits. */
494 IndexTarget
const Target
;
496 virtual std::string
DescURI() const APT_OVERRIDE
{return Target
.URI
;};
497 virtual HashStringList
GetExpectedHashes() const APT_OVERRIDE
{return HashStringList();};
499 NoActionItem(pkgAcquire
* const Owner
, IndexTarget
const &Target
) :
500 pkgAcquire::Item(Owner
), Target(Target
)
503 DestFile
= GetFinalFileNameFromURI(Target
.URI
);
505 NoActionItem(pkgAcquire
* const Owner
, IndexTarget
const &Target
, std::string
const &FinalFile
) :
506 pkgAcquire::Item(Owner
), Target(Target
)
509 DestFile
= FinalFile
;
514 // Acquire::Item::Item - Constructor /*{{{*/
515 APT_IGNORE_DEPRECATED_PUSH
516 pkgAcquire::Item::Item(pkgAcquire
* const owner
) :
517 FileSize(0), PartialSize(0), Mode(0), ID(0), Complete(false), Local(false),
518 QueueCounter(0), ExpectedAdditionalItems(0), Owner(owner
), d(NULL
)
523 APT_IGNORE_DEPRECATED_POP
525 // Acquire::Item::~Item - Destructor /*{{{*/
526 pkgAcquire::Item::~Item()
531 std::string
pkgAcquire::Item::Custom600Headers() const /*{{{*/
533 return std::string();
536 std::string
pkgAcquire::Item::ShortDesc() const /*{{{*/
541 APT_CONST
void pkgAcquire::Item::Finished() /*{{{*/
545 APT_PURE pkgAcquire
* pkgAcquire::Item::GetOwner() const /*{{{*/
550 APT_CONST
pkgAcquire::ItemDesc
&pkgAcquire::Item::GetItemDesc() /*{{{*/
555 APT_CONST
bool pkgAcquire::Item::IsTrusted() const /*{{{*/
560 // Acquire::Item::Failed - Item failed to download /*{{{*/
561 // ---------------------------------------------------------------------
562 /* We return to an idle state if there are still other queues that could
564 void pkgAcquire::Item::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)
566 if(ErrorText
.empty())
567 ErrorText
= LookupTag(Message
,"Message");
568 if (QueueCounter
<= 1)
570 /* This indicates that the file is not available right now but might
571 be sometime later. If we do a retry cycle then this should be
573 if (Cnf
!= NULL
&& Cnf
->LocalOnly
== true &&
574 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
590 case StatTransientNetworkError
:
597 string
const FailReason
= LookupTag(Message
, "FailReason");
598 if (FailReason
== "MaximumSizeExceeded")
599 RenameOnError(MaximumSizeExceeded
);
600 else if (Status
== StatAuthError
)
601 RenameOnError(HashSumMismatch
);
603 // report mirror failure back to LP if we actually use a mirror
604 if (FailReason
.empty() == false)
605 ReportMirrorFailure(FailReason
);
607 ReportMirrorFailure(ErrorText
);
609 if (QueueCounter
> 1)
613 // Acquire::Item::Start - Item has begun to download /*{{{*/
614 // ---------------------------------------------------------------------
615 /* Stash status and the file size. Note that setting Complete means
616 sub-phases of the acquire process such as decompresion are operating */
617 void pkgAcquire::Item::Start(string
const &/*Message*/, unsigned long long const Size
)
619 Status
= StatFetching
;
621 if (FileSize
== 0 && Complete
== false)
625 // Acquire::Item::VerifyDone - check if Item was downloaded OK /*{{{*/
626 /* Note that hash-verification is 'hardcoded' in acquire-worker and has
627 * already passed if this method is called. */
628 bool pkgAcquire::Item::VerifyDone(std::string
const &Message
,
629 pkgAcquire::MethodConfig
const * const /*Cnf*/)
631 std::string
const FileName
= LookupTag(Message
,"Filename");
632 if (FileName
.empty() == true)
635 ErrorText
= "Method gave a blank filename";
642 // Acquire::Item::Done - Item downloaded OK /*{{{*/
643 void pkgAcquire::Item::Done(string
const &/*Message*/, HashStringList
const &Hashes
,
644 pkgAcquire::MethodConfig
const * const /*Cnf*/)
646 // We just downloaded something..
649 unsigned long long const downloadedSize
= Hashes
.FileSize();
650 if (downloadedSize
!= 0)
652 FileSize
= downloadedSize
;
656 ErrorText
= string();
657 Owner
->Dequeue(this);
660 // Acquire::Item::Rename - Rename a file /*{{{*/
661 // ---------------------------------------------------------------------
662 /* This helper function is used by a lot of item methods as their final
664 bool pkgAcquire::Item::Rename(string
const &From
,string
const &To
)
666 if (From
== To
|| rename(From
.c_str(),To
.c_str()) == 0)
670 strprintf(S
, _("rename failed, %s (%s -> %s)."), strerror(errno
),
671 From
.c_str(),To
.c_str());
673 if (ErrorText
.empty())
676 ErrorText
= ErrorText
+ ": " + S
;
680 void pkgAcquire::Item::Dequeue() /*{{{*/
682 Owner
->Dequeue(this);
685 bool pkgAcquire::Item::RenameOnError(pkgAcquire::Item::RenameOnErrorState
const error
)/*{{{*/
687 if (RealFileExists(DestFile
))
688 Rename(DestFile
, DestFile
+ ".FAILED");
693 case HashSumMismatch
:
694 errtext
= _("Hash Sum mismatch");
695 Status
= StatAuthError
;
696 ReportMirrorFailure("HashChecksumFailure");
699 errtext
= _("Size mismatch");
700 Status
= StatAuthError
;
701 ReportMirrorFailure("SizeFailure");
704 errtext
= _("Invalid file format");
706 // do not report as usually its not the mirrors fault, but Portal/Proxy
709 errtext
= _("Signature error");
713 strprintf(errtext
, _("Clearsigned file isn't valid, got '%s' (does the network require authentication?)"), "NOSPLIT");
714 Status
= StatAuthError
;
716 case MaximumSizeExceeded
:
717 // the method is expected to report a good error for this
721 // no handling here, done by callers
724 if (ErrorText
.empty())
729 void pkgAcquire::Item::SetActiveSubprocess(const std::string
&subprocess
)/*{{{*/
731 ActiveSubprocess
= subprocess
;
732 APT_IGNORE_DEPRECATED(Mode
= ActiveSubprocess
.c_str();)
735 // Acquire::Item::ReportMirrorFailure /*{{{*/
736 void pkgAcquire::Item::ReportMirrorFailure(string
const &FailCode
)
738 // we only act if a mirror was used at all
739 if(UsedMirror
.empty())
742 std::cerr
<< "\nReportMirrorFailure: "
744 << " Uri: " << DescURI()
746 << FailCode
<< std::endl
;
748 string report
= _config
->Find("Methods::Mirror::ProblemReporting",
749 "/usr/lib/apt/apt-report-mirror-failure");
750 if(!FileExists(report
))
753 std::vector
<char const*> Args
;
754 Args
.push_back(report
.c_str());
755 Args
.push_back(UsedMirror
.c_str());
756 Args
.push_back(DescURI().c_str());
757 Args
.push_back(FailCode
.c_str());
758 Args
.push_back(NULL
);
760 pid_t pid
= ExecFork();
763 _error
->Error("ReportMirrorFailure Fork failed");
768 execvp(Args
[0], (char**)Args
.data());
769 std::cerr
<< "Could not exec " << Args
[0] << std::endl
;
772 if(!ExecWait(pid
, "report-mirror-failure"))
774 _error
->Warning("Couldn't report problem to '%s'",
775 _config
->Find("Methods::Mirror::ProblemReporting").c_str());
779 std::string
pkgAcquire::Item::HashSum() const /*{{{*/
781 HashStringList
const hashes
= GetExpectedHashes();
782 HashString
const * const hs
= hashes
.find(NULL
);
783 return hs
!= NULL
? hs
->toStr() : "";
787 pkgAcqTransactionItem::pkgAcqTransactionItem(pkgAcquire
* const Owner
, /*{{{*/
788 pkgAcqMetaClearSig
* const transactionManager
, IndexTarget
const &target
) :
789 pkgAcquire::Item(Owner
), d(NULL
), Target(target
), TransactionManager(transactionManager
)
791 if (TransactionManager
!= this)
792 TransactionManager
->Add(this);
795 pkgAcqTransactionItem::~pkgAcqTransactionItem() /*{{{*/
799 HashStringList
pkgAcqTransactionItem::GetExpectedHashesFor(std::string
const &MetaKey
) const /*{{{*/
801 return GetExpectedHashesFromFor(TransactionManager
->MetaIndexParser
, MetaKey
);
805 static void LoadLastMetaIndexParser(pkgAcqMetaClearSig
* const TransactionManager
, std::string
const &FinalRelease
, std::string
const &FinalInRelease
)/*{{{*/
807 if (TransactionManager
->IMSHit
== true)
809 if (RealFileExists(FinalInRelease
) || RealFileExists(FinalRelease
))
811 TransactionManager
->LastMetaIndexParser
= TransactionManager
->MetaIndexParser
->UnloadedClone();
812 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
814 _error
->PushToStack();
815 if (RealFileExists(FinalInRelease
))
816 TransactionManager
->LastMetaIndexParser
->Load(FinalInRelease
, NULL
);
818 TransactionManager
->LastMetaIndexParser
->Load(FinalRelease
, NULL
);
819 // its unlikely to happen, but if what we have is bad ignore it
820 if (_error
->PendingError())
822 delete TransactionManager
->LastMetaIndexParser
;
823 TransactionManager
->LastMetaIndexParser
= NULL
;
825 _error
->RevertToStack();
831 // AcqMetaBase - Constructor /*{{{*/
832 pkgAcqMetaBase::pkgAcqMetaBase(pkgAcquire
* const Owner
,
833 pkgAcqMetaClearSig
* const TransactionManager
,
834 std::vector
<IndexTarget
> const &IndexTargets
,
835 IndexTarget
const &DataTarget
)
836 : pkgAcqTransactionItem(Owner
, TransactionManager
, DataTarget
), d(NULL
),
837 IndexTargets(IndexTargets
),
838 AuthPass(false), IMSHit(false)
842 // AcqMetaBase::Add - Add a item to the current Transaction /*{{{*/
843 void pkgAcqMetaBase::Add(pkgAcqTransactionItem
* const I
)
845 Transaction
.push_back(I
);
848 // AcqMetaBase::AbortTransaction - Abort the current Transaction /*{{{*/
849 void pkgAcqMetaBase::AbortTransaction()
851 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
852 std::clog
<< "AbortTransaction: " << TransactionManager
<< std::endl
;
854 // ensure the toplevel is in error state too
855 for (std::vector
<pkgAcqTransactionItem
*>::iterator I
= Transaction
.begin();
856 I
!= Transaction
.end(); ++I
)
858 (*I
)->TransactionState(TransactionAbort
);
863 // AcqMetaBase::TransactionHasError - Check for errors in Transaction /*{{{*/
864 APT_PURE
bool pkgAcqMetaBase::TransactionHasError() const
866 for (std::vector
<pkgAcqTransactionItem
*>::const_iterator I
= Transaction
.begin();
867 I
!= Transaction
.end(); ++I
)
869 switch((*I
)->Status
) {
870 case StatDone
: break;
871 case StatIdle
: break;
872 case StatAuthError
: return true;
873 case StatError
: return true;
874 case StatTransientNetworkError
: return true;
875 case StatFetching
: break;
881 // AcqMetaBase::CommitTransaction - Commit a transaction /*{{{*/
882 void pkgAcqMetaBase::CommitTransaction()
884 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
885 std::clog
<< "CommitTransaction: " << this << std::endl
;
887 // move new files into place *and* remove files that are not
888 // part of the transaction but are still on disk
889 for (std::vector
<pkgAcqTransactionItem
*>::iterator I
= Transaction
.begin();
890 I
!= Transaction
.end(); ++I
)
892 (*I
)->TransactionState(TransactionCommit
);
897 // AcqMetaBase::TransactionStageCopy - Stage a file for copying /*{{{*/
898 void pkgAcqMetaBase::TransactionStageCopy(pkgAcqTransactionItem
* const I
,
899 const std::string
&From
,
900 const std::string
&To
)
902 I
->PartialFile
= From
;
906 // AcqMetaBase::TransactionStageRemoval - Stage a file for removal /*{{{*/
907 void pkgAcqMetaBase::TransactionStageRemoval(pkgAcqTransactionItem
* const I
,
908 const std::string
&FinalFile
)
911 I
->DestFile
= FinalFile
;
914 // AcqMetaBase::GenerateAuthWarning - Check gpg authentication error /*{{{*/
915 bool pkgAcqMetaBase::CheckStopAuthentication(pkgAcquire::Item
* const I
, const std::string
&Message
)
917 // FIXME: this entire function can do now that we disallow going to
918 // a unauthenticated state and can cleanly rollback
920 string
const Final
= I
->GetFinalFilename();
921 if(FileExists(Final
))
923 I
->Status
= StatTransientNetworkError
;
924 _error
->Warning(_("An error occurred during the signature "
925 "verification. The repository is not updated "
926 "and the previous index files will be used. "
927 "GPG error: %s: %s"),
928 Desc
.Description
.c_str(),
929 LookupTag(Message
,"Message").c_str());
930 RunScripts("APT::Update::Auth-Failure");
932 } else if (LookupTag(Message
,"Message").find("NODATA") != string::npos
) {
933 /* Invalid signature file, reject (LP: #346386) (Closes: #627642) */
934 _error
->Error(_("GPG error: %s: %s"),
935 Desc
.Description
.c_str(),
936 LookupTag(Message
,"Message").c_str());
937 I
->Status
= StatAuthError
;
940 _error
->Warning(_("GPG error: %s: %s"),
941 Desc
.Description
.c_str(),
942 LookupTag(Message
,"Message").c_str());
944 // gpgv method failed
945 ReportMirrorFailure("GPGFailure");
949 // AcqMetaBase::Custom600Headers - Get header for AcqMetaBase /*{{{*/
950 // ---------------------------------------------------------------------
951 string
pkgAcqMetaBase::Custom600Headers() const
953 std::string Header
= "\nIndex-File: true";
954 std::string MaximumSize
;
955 strprintf(MaximumSize
, "\nMaximum-Size: %i",
956 _config
->FindI("Acquire::MaxReleaseFileSize", 10*1000*1000));
957 Header
+= MaximumSize
;
959 string
const FinalFile
= GetFinalFilename();
961 if (stat(FinalFile
.c_str(),&Buf
) == 0)
962 Header
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
967 // AcqMetaBase::QueueForSignatureVerify /*{{{*/
968 void pkgAcqMetaBase::QueueForSignatureVerify(pkgAcqTransactionItem
* const I
, std::string
const &File
, std::string
const &Signature
)
971 I
->Desc
.URI
= "gpgv:" + Signature
;
974 I
->SetActiveSubprocess("gpgv");
977 // AcqMetaBase::CheckDownloadDone /*{{{*/
978 bool pkgAcqMetaBase::CheckDownloadDone(pkgAcqTransactionItem
* const I
, const std::string
&Message
, HashStringList
const &Hashes
) const
980 // We have just finished downloading a Release file (it is not
983 std::string
const FileName
= LookupTag(Message
,"Filename");
984 if (FileName
!= I
->DestFile
&& RealFileExists(I
->DestFile
) == false)
987 I
->Desc
.URI
= "copy:" + FileName
;
988 I
->QueueURI(I
->Desc
);
992 // make sure to verify against the right file on I-M-S hit
993 bool IMSHit
= StringToBool(LookupTag(Message
,"IMS-Hit"), false);
994 if (IMSHit
== false && Hashes
.usable())
996 // detect IMS-Hits servers haven't detected by Hash comparison
997 std::string
const FinalFile
= I
->GetFinalFilename();
998 if (RealFileExists(FinalFile
) && Hashes
.VerifyFile(FinalFile
) == true)
1001 RemoveFile("CheckDownloadDone", I
->DestFile
);
1007 // for simplicity, the transaction manager is always InRelease
1008 // even if it doesn't exist.
1009 if (TransactionManager
!= NULL
)
1010 TransactionManager
->IMSHit
= true;
1011 I
->PartialFile
= I
->DestFile
= I
->GetFinalFilename();
1014 // set Item to complete as the remaining work is all local (verify etc)
1020 bool pkgAcqMetaBase::CheckAuthDone(string
const &Message
) /*{{{*/
1022 // At this point, the gpgv method has succeeded, so there is a
1023 // valid signature from a key in the trusted keyring. We
1024 // perform additional verification of its contents, and use them
1025 // to verify the indexes we are about to download
1027 if (TransactionManager
->IMSHit
== false)
1029 // open the last (In)Release if we have it
1030 std::string
const FinalFile
= GetFinalFilename();
1031 std::string FinalRelease
;
1032 std::string FinalInRelease
;
1033 if (APT::String::Endswith(FinalFile
, "InRelease"))
1035 FinalInRelease
= FinalFile
;
1036 FinalRelease
= FinalFile
.substr(0, FinalFile
.length() - strlen("InRelease")) + "Release";
1040 FinalInRelease
= FinalFile
.substr(0, FinalFile
.length() - strlen("Release")) + "InRelease";
1041 FinalRelease
= FinalFile
;
1043 LoadLastMetaIndexParser(TransactionManager
, FinalRelease
, FinalInRelease
);
1046 if (TransactionManager
->MetaIndexParser
->Load(DestFile
, &ErrorText
) == false)
1048 Status
= StatAuthError
;
1052 if (!VerifyVendor(Message
))
1054 Status
= StatAuthError
;
1058 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1059 std::cerr
<< "Signature verification succeeded: "
1060 << DestFile
<< std::endl
;
1062 // Download further indexes with verification
1068 void pkgAcqMetaBase::QueueIndexes(bool const verify
) /*{{{*/
1070 // at this point the real Items are loaded in the fetcher
1071 ExpectedAdditionalItems
= 0;
1073 bool metaBaseSupportsByHash
= false;
1074 if (TransactionManager
!= NULL
&& TransactionManager
->MetaIndexParser
!= NULL
)
1075 metaBaseSupportsByHash
= TransactionManager
->MetaIndexParser
->GetSupportsAcquireByHash();
1077 for (std::vector
<IndexTarget
>::iterator Target
= IndexTargets
.begin();
1078 Target
!= IndexTargets
.end();
1081 // all is an implementation detail. Users shouldn't use this as arch
1082 // We need this support trickery here as e.g. Debian has binary-all files already,
1083 // but arch:all packages are still in the arch:any files, so we would waste precious
1084 // download time, bandwidth and diskspace for nothing, BUT Debian doesn't feature all
1085 // in the set of supported architectures, so we can filter based on this property rather
1086 // than invent an entirely new flag we would need to carry for all of eternity.
1087 if (Target
->Option(IndexTarget::ARCHITECTURE
) == "all")
1089 if (TransactionManager
->MetaIndexParser
->IsArchitectureSupported("all") == false)
1091 if (TransactionManager
->MetaIndexParser
->IsArchitectureAllSupportedFor(*Target
) == false)
1095 bool trypdiff
= Target
->OptionBool(IndexTarget::PDIFFS
);
1098 if (TransactionManager
->MetaIndexParser
->Exists(Target
->MetaKey
) == false)
1100 // optional targets that we do not have in the Release file are skipped
1101 if (Target
->IsOptional
)
1104 std::string
const &arch
= Target
->Option(IndexTarget::ARCHITECTURE
);
1105 if (arch
.empty() == false)
1107 if (TransactionManager
->MetaIndexParser
->IsArchitectureSupported(arch
) == false)
1109 _error
->Notice(_("Skipping acquire of configured file '%s' as repository '%s' doesn't support architecture '%s'"),
1110 Target
->MetaKey
.c_str(), TransactionManager
->Target
.Description
.c_str(), arch
.c_str());
1113 // if the architecture is officially supported but currently no packages for it available,
1114 // ignore silently as this is pretty much the same as just shipping an empty file.
1115 // if we don't know which architectures are supported, we do NOT ignore it to notify user about this
1116 if (TransactionManager
->MetaIndexParser
->IsArchitectureSupported("*undefined*") == false)
1120 Status
= StatAuthError
;
1121 strprintf(ErrorText
, _("Unable to find expected entry '%s' in Release file (Wrong sources.list entry or malformed file)"), Target
->MetaKey
.c_str());
1126 auto const hashes
= GetExpectedHashesFor(Target
->MetaKey
);
1127 if (hashes
.usable() == false && hashes
.empty() == false)
1129 _error
->Warning(_("Skipping acquire of configured file '%s' as repository '%s' provides only weak security information for it"),
1130 Target
->MetaKey
.c_str(), TransactionManager
->Target
.Description
.c_str());
1135 // autoselect the compression method
1136 std::vector
<std::string
> types
= VectorizeString(Target
->Option(IndexTarget::COMPRESSIONTYPES
), ' ');
1137 types
.erase(std::remove_if(types
.begin(), types
.end(), [&](std::string
const &t
) {
1138 if (t
== "uncompressed")
1139 return TransactionManager
->MetaIndexParser
->Exists(Target
->MetaKey
) == false;
1140 std::string
const MetaKey
= Target
->MetaKey
+ "." + t
;
1141 return TransactionManager
->MetaIndexParser
->Exists(MetaKey
) == false;
1143 if (types
.empty() == false)
1145 std::ostringstream os
;
1146 // add the special compressiontype byhash first if supported
1147 std::string
const useByHashConf
= Target
->Option(IndexTarget::BY_HASH
);
1148 bool useByHash
= false;
1149 if(useByHashConf
== "force")
1152 useByHash
= StringToBool(useByHashConf
) == true && metaBaseSupportsByHash
;
1153 if (useByHash
== true)
1155 std::copy(types
.begin(), types
.end()-1, std::ostream_iterator
<std::string
>(os
, " "));
1156 os
<< *types
.rbegin();
1157 Target
->Options
["COMPRESSIONTYPES"] = os
.str();
1160 Target
->Options
["COMPRESSIONTYPES"].clear();
1162 std::string filename
= GetExistingFilename(GetFinalFileNameFromURI(Target
->URI
));
1163 if (filename
.empty() == false)
1165 // if the Release file is a hit and we have an index it must be the current one
1166 if (TransactionManager
->IMSHit
== true)
1168 else if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1170 // see if the file changed since the last Release file
1171 // we use the uncompressed files as we might compress differently compared to the server,
1172 // so the hashes might not match, even if they contain the same data.
1173 HashStringList
const newFile
= GetExpectedHashesFromFor(TransactionManager
->MetaIndexParser
, Target
->MetaKey
);
1174 HashStringList
const oldFile
= GetExpectedHashesFromFor(TransactionManager
->LastMetaIndexParser
, Target
->MetaKey
);
1175 if (newFile
!= oldFile
)
1182 trypdiff
= false; // no file to patch
1184 if (filename
.empty() == false)
1186 new NoActionItem(Owner
, *Target
, filename
);
1187 std::string
const idxfilename
= GetFinalFileNameFromURI(GetDiffIndexURI(*Target
));
1188 if (FileExists(idxfilename
))
1189 new NoActionItem(Owner
, *Target
, idxfilename
);
1193 // check if we have patches available
1194 trypdiff
&= TransactionManager
->MetaIndexParser
->Exists(GetDiffIndexFileName(Target
->MetaKey
));
1198 // if we have no file to patch, no point in trying
1199 trypdiff
&= (GetExistingFilename(GetFinalFileNameFromURI(Target
->URI
)).empty() == false);
1202 // no point in patching from local sources
1205 std::string
const proto
= Target
->URI
.substr(0, strlen("file:/"));
1206 if (proto
== "file:/" || proto
== "copy:/" || proto
== "cdrom:")
1210 // Queue the Index file (Packages, Sources, Translation-$foo, …)
1212 new pkgAcqDiffIndex(Owner
, TransactionManager
, *Target
);
1214 new pkgAcqIndex(Owner
, TransactionManager
, *Target
);
1218 bool pkgAcqMetaBase::VerifyVendor(string
const &Message
) /*{{{*/
1220 string::size_type pos
;
1222 // check for missing sigs (that where not fatal because otherwise we had
1225 string msg
= _("There is no public key available for the "
1226 "following key IDs:\n");
1227 pos
= Message
.find("NO_PUBKEY ");
1228 if (pos
!= std::string::npos
)
1230 string::size_type start
= pos
+strlen("NO_PUBKEY ");
1231 string Fingerprint
= Message
.substr(start
, Message
.find("\n")-start
);
1232 missingkeys
+= (Fingerprint
);
1234 if(!missingkeys
.empty())
1235 _error
->Warning("%s", (msg
+ missingkeys
).c_str());
1237 string Transformed
= TransactionManager
->MetaIndexParser
->GetExpectedDist();
1239 if (Transformed
== "../project/experimental")
1241 Transformed
= "experimental";
1244 pos
= Transformed
.rfind('/');
1245 if (pos
!= string::npos
)
1247 Transformed
= Transformed
.substr(0, pos
);
1250 if (Transformed
== ".")
1255 if (TransactionManager
->MetaIndexParser
->GetValidUntil() > 0)
1257 time_t const invalid_since
= time(NULL
) - TransactionManager
->MetaIndexParser
->GetValidUntil();
1258 if (invalid_since
> 0)
1262 // TRANSLATOR: The first %s is the URL of the bad Release file, the second is
1263 // the time since then the file is invalid - formatted in the same way as in
1264 // the download progress display (e.g. 7d 3h 42min 1s)
1265 _("Release file for %s is expired (invalid since %s). "
1266 "Updates for this repository will not be applied."),
1267 Target
.URI
.c_str(), TimeToStr(invalid_since
).c_str());
1268 if (ErrorText
.empty())
1270 return _error
->Error("%s", errmsg
.c_str());
1274 /* Did we get a file older than what we have? This is a last minute IMS hit and doubles
1275 as a prevention of downgrading us to older (still valid) files */
1276 if (TransactionManager
->IMSHit
== false && TransactionManager
->LastMetaIndexParser
!= NULL
&&
1277 TransactionManager
->LastMetaIndexParser
->GetDate() > TransactionManager
->MetaIndexParser
->GetDate())
1279 TransactionManager
->IMSHit
= true;
1280 RemoveFile("VerifyVendor", DestFile
);
1281 PartialFile
= DestFile
= GetFinalFilename();
1282 // load the 'old' file in the 'new' one instead of flipping pointers as
1283 // the new one isn't owned by us, while the old one is so cleanup would be confused.
1284 TransactionManager
->MetaIndexParser
->swapLoad(TransactionManager
->LastMetaIndexParser
);
1285 delete TransactionManager
->LastMetaIndexParser
;
1286 TransactionManager
->LastMetaIndexParser
= NULL
;
1289 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1291 std::cerr
<< "Got Codename: " << TransactionManager
->MetaIndexParser
->GetCodename() << std::endl
;
1292 std::cerr
<< "Expecting Dist: " << TransactionManager
->MetaIndexParser
->GetExpectedDist() << std::endl
;
1293 std::cerr
<< "Transformed Dist: " << Transformed
<< std::endl
;
1296 if (TransactionManager
->MetaIndexParser
->CheckDist(Transformed
) == false)
1298 // This might become fatal one day
1299 // Status = StatAuthError;
1300 // ErrorText = "Conflicting distribution; expected "
1301 // + MetaIndexParser->GetExpectedDist() + " but got "
1302 // + MetaIndexParser->GetCodename();
1304 if (!Transformed
.empty())
1306 _error
->Warning(_("Conflicting distribution: %s (expected %s but got %s)"),
1307 Desc
.Description
.c_str(),
1308 Transformed
.c_str(),
1309 TransactionManager
->MetaIndexParser
->GetCodename().c_str());
1316 pkgAcqMetaBase::~pkgAcqMetaBase()
1320 pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire
* const Owner
, /*{{{*/
1321 IndexTarget
const &ClearsignedTarget
,
1322 IndexTarget
const &DetachedDataTarget
, IndexTarget
const &DetachedSigTarget
,
1323 std::vector
<IndexTarget
> const &IndexTargets
,
1324 metaIndex
* const MetaIndexParser
) :
1325 pkgAcqMetaIndex(Owner
, this, ClearsignedTarget
, DetachedSigTarget
, IndexTargets
),
1326 d(NULL
), ClearsignedTarget(ClearsignedTarget
),
1327 DetachedDataTarget(DetachedDataTarget
),
1328 MetaIndexParser(MetaIndexParser
), LastMetaIndexParser(NULL
)
1330 // index targets + (worst case:) Release/Release.gpg
1331 ExpectedAdditionalItems
= IndexTargets
.size() + 2;
1332 TransactionManager
->Add(this);
1335 pkgAcqMetaClearSig::~pkgAcqMetaClearSig() /*{{{*/
1337 if (LastMetaIndexParser
!= NULL
)
1338 delete LastMetaIndexParser
;
1341 // pkgAcqMetaClearSig::Custom600Headers - Insert custom request headers /*{{{*/
1342 string
pkgAcqMetaClearSig::Custom600Headers() const
1344 string Header
= pkgAcqMetaBase::Custom600Headers();
1345 Header
+= "\nFail-Ignore: true";
1346 std::string
const key
= TransactionManager
->MetaIndexParser
->GetSignedBy();
1347 if (key
.empty() == false)
1348 Header
+= "\nSigned-By: " + key
;
1353 bool pkgAcqMetaClearSig::VerifyDone(std::string
const &Message
, /*{{{*/
1354 pkgAcquire::MethodConfig
const * const Cnf
)
1356 Item::VerifyDone(Message
, Cnf
);
1358 if (FileExists(DestFile
) && !StartsWithGPGClearTextSignature(DestFile
))
1359 return RenameOnError(NotClearsigned
);
1364 // pkgAcqMetaClearSig::Done - We got a file /*{{{*/
1365 void pkgAcqMetaClearSig::Done(std::string
const &Message
,
1366 HashStringList
const &Hashes
,
1367 pkgAcquire::MethodConfig
const * const Cnf
)
1369 Item::Done(Message
, Hashes
, Cnf
);
1371 if(AuthPass
== false)
1373 if(CheckDownloadDone(this, Message
, Hashes
) == true)
1374 QueueForSignatureVerify(this, DestFile
, DestFile
);
1377 else if(CheckAuthDone(Message
) == true)
1379 if (TransactionManager
->IMSHit
== false)
1380 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
1381 else if (RealFileExists(GetFinalFilename()) == false)
1383 // We got an InRelease file IMSHit, but we haven't one, which means
1384 // we had a valid Release/Release.gpg combo stepping in, which we have
1385 // to 'acquire' now to ensure list cleanup isn't removing them
1386 new NoActionItem(Owner
, DetachedDataTarget
);
1387 new NoActionItem(Owner
, DetachedSigTarget
);
1392 void pkgAcqMetaClearSig::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
) /*{{{*/
1394 Item::Failed(Message
, Cnf
);
1396 // we failed, we will not get additional items from this method
1397 ExpectedAdditionalItems
= 0;
1399 if (AuthPass
== false)
1401 if (Status
== StatAuthError
|| Status
== StatTransientNetworkError
)
1403 // if we expected a ClearTextSignature (InRelease) but got a network
1404 // error or got a file, but it wasn't valid, we end up here (see VerifyDone).
1405 // As these is usually called by web-portals we do not try Release/Release.gpg
1406 // as this is gonna fail anyway and instead abort our try (LP#346386)
1407 TransactionManager
->AbortTransaction();
1411 // Queue the 'old' InRelease file for removal if we try Release.gpg
1412 // as otherwise the file will stay around and gives a false-auth
1413 // impression (CVE-2012-0214)
1414 TransactionManager
->TransactionStageRemoval(this, GetFinalFilename());
1417 new pkgAcqMetaIndex(Owner
, TransactionManager
, DetachedDataTarget
, DetachedSigTarget
, IndexTargets
);
1421 if(CheckStopAuthentication(this, Message
))
1424 // No Release file was present, or verification failed, so fall
1425 // back to queueing Packages files without verification
1426 // only allow going further if the user explicitly wants it
1427 if(AllowInsecureRepositories(_("The repository '%s' is not signed."), ClearsignedTarget
.Description
, TransactionManager
->MetaIndexParser
, TransactionManager
, this) == true)
1431 /* InRelease files become Release files, otherwise
1432 * they would be considered as trusted later on */
1433 string
const FinalRelease
= GetFinalFileNameFromURI(DetachedDataTarget
.URI
);
1434 string
const PartialRelease
= GetPartialFileNameFromURI(DetachedDataTarget
.URI
);
1435 string
const FinalReleasegpg
= GetFinalFileNameFromURI(DetachedSigTarget
.URI
);
1436 string
const FinalInRelease
= GetFinalFilename();
1437 Rename(DestFile
, PartialRelease
);
1438 TransactionManager
->TransactionStageCopy(this, PartialRelease
, FinalRelease
);
1439 LoadLastMetaIndexParser(TransactionManager
, FinalRelease
, FinalInRelease
);
1441 // we parse the indexes here because at this point the user wanted
1442 // a repository that may potentially harm him
1443 if (TransactionManager
->MetaIndexParser
->Load(PartialRelease
, &ErrorText
) == false || VerifyVendor(Message
) == false)
1444 /* expired Release files are still a problem you need extra force for */;
1452 pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire
* const Owner
, /*{{{*/
1453 pkgAcqMetaClearSig
* const TransactionManager
,
1454 IndexTarget
const &DataTarget
,
1455 IndexTarget
const &DetachedSigTarget
,
1456 vector
<IndexTarget
> const &IndexTargets
) :
1457 pkgAcqMetaBase(Owner
, TransactionManager
, IndexTargets
, DataTarget
), d(NULL
),
1458 DetachedSigTarget(DetachedSigTarget
)
1460 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1461 std::clog
<< "New pkgAcqMetaIndex with TransactionManager "
1462 << this->TransactionManager
<< std::endl
;
1464 DestFile
= GetPartialFileNameFromURI(DataTarget
.URI
);
1467 Desc
.Description
= DataTarget
.Description
;
1469 Desc
.ShortDesc
= DataTarget
.ShortDesc
;
1470 Desc
.URI
= DataTarget
.URI
;
1472 // we expect more item
1473 ExpectedAdditionalItems
= IndexTargets
.size();
1477 void pkgAcqMetaIndex::Done(string
const &Message
, /*{{{*/
1478 HashStringList
const &Hashes
,
1479 pkgAcquire::MethodConfig
const * const Cfg
)
1481 Item::Done(Message
,Hashes
,Cfg
);
1483 if(CheckDownloadDone(this, Message
, Hashes
))
1485 // we have a Release file, now download the Signature, all further
1486 // verify/queue for additional downloads will be done in the
1487 // pkgAcqMetaSig::Done() code
1488 new pkgAcqMetaSig(Owner
, TransactionManager
, DetachedSigTarget
, this);
1492 // pkgAcqMetaIndex::Failed - no Release file present /*{{{*/
1493 void pkgAcqMetaIndex::Failed(string
const &Message
,
1494 pkgAcquire::MethodConfig
const * const Cnf
)
1496 pkgAcquire::Item::Failed(Message
, Cnf
);
1499 // No Release file was present so fall
1500 // back to queueing Packages files without verification
1501 // only allow going further if the user explicitly wants it
1502 if(AllowInsecureRepositories(_("The repository '%s' does not have a Release file."), Target
.Description
, TransactionManager
->MetaIndexParser
, TransactionManager
, this) == true)
1504 // ensure old Release files are removed
1505 TransactionManager
->TransactionStageRemoval(this, GetFinalFilename());
1507 // queue without any kind of hashsum support
1508 QueueIndexes(false);
1512 void pkgAcqMetaIndex::Finished() /*{{{*/
1514 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1515 std::clog
<< "Finished: " << DestFile
<<std::endl
;
1516 if(TransactionManager
!= NULL
&&
1517 TransactionManager
->TransactionHasError() == false)
1518 TransactionManager
->CommitTransaction();
1521 std::string
pkgAcqMetaIndex::DescURI() const /*{{{*/
1526 pkgAcqMetaIndex::~pkgAcqMetaIndex() {}
1528 // AcqMetaSig::AcqMetaSig - Constructor /*{{{*/
1529 pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire
* const Owner
,
1530 pkgAcqMetaClearSig
* const TransactionManager
,
1531 IndexTarget
const &Target
,
1532 pkgAcqMetaIndex
* const MetaIndex
) :
1533 pkgAcqTransactionItem(Owner
, TransactionManager
, Target
), d(NULL
), MetaIndex(MetaIndex
)
1535 DestFile
= GetPartialFileNameFromURI(Target
.URI
);
1537 // remove any partial downloaded sig-file in partial/.
1538 // it may confuse proxies and is too small to warrant a
1539 // partial download anyway
1540 RemoveFile("pkgAcqMetaSig", DestFile
);
1542 // set the TransactionManager
1543 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1544 std::clog
<< "New pkgAcqMetaSig with TransactionManager "
1545 << TransactionManager
<< std::endl
;
1548 Desc
.Description
= Target
.Description
;
1550 Desc
.ShortDesc
= Target
.ShortDesc
;
1551 Desc
.URI
= Target
.URI
;
1553 // If we got a hit for Release, we will get one for Release.gpg too (or obscure errors),
1554 // so we skip the download step and go instantly to verification
1555 if (TransactionManager
->IMSHit
== true && RealFileExists(GetFinalFilename()))
1559 PartialFile
= DestFile
= GetFinalFilename();
1560 MetaIndexFileSignature
= DestFile
;
1561 MetaIndex
->QueueForSignatureVerify(this, MetaIndex
->DestFile
, DestFile
);
1567 pkgAcqMetaSig::~pkgAcqMetaSig() /*{{{*/
1571 // pkgAcqMetaSig::Custom600Headers - Insert custom request headers /*{{{*/
1572 std::string
pkgAcqMetaSig::Custom600Headers() const
1574 std::string Header
= pkgAcqTransactionItem::Custom600Headers();
1575 std::string
const key
= TransactionManager
->MetaIndexParser
->GetSignedBy();
1576 if (key
.empty() == false)
1577 Header
+= "\nSigned-By: " + key
;
1581 // AcqMetaSig::Done - The signature was downloaded/verified /*{{{*/
1582 void pkgAcqMetaSig::Done(string
const &Message
, HashStringList
const &Hashes
,
1583 pkgAcquire::MethodConfig
const * const Cfg
)
1585 if (MetaIndexFileSignature
.empty() == false)
1587 DestFile
= MetaIndexFileSignature
;
1588 MetaIndexFileSignature
.clear();
1590 Item::Done(Message
, Hashes
, Cfg
);
1592 if(MetaIndex
->AuthPass
== false)
1594 if(MetaIndex
->CheckDownloadDone(this, Message
, Hashes
) == true)
1596 // destfile will be modified to point to MetaIndexFile for the
1597 // gpgv method, so we need to save it here
1598 MetaIndexFileSignature
= DestFile
;
1599 MetaIndex
->QueueForSignatureVerify(this, MetaIndex
->DestFile
, DestFile
);
1603 else if(MetaIndex
->CheckAuthDone(Message
) == true)
1605 if (TransactionManager
->IMSHit
== false)
1607 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
1608 TransactionManager
->TransactionStageCopy(MetaIndex
, MetaIndex
->DestFile
, MetaIndex
->GetFinalFilename());
1613 void pkgAcqMetaSig::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
1615 Item::Failed(Message
,Cnf
);
1617 // check if we need to fail at this point
1618 if (MetaIndex
->AuthPass
== true && MetaIndex
->CheckStopAuthentication(this, Message
))
1621 string
const FinalRelease
= MetaIndex
->GetFinalFilename();
1622 string
const FinalReleasegpg
= GetFinalFilename();
1623 string
const FinalInRelease
= TransactionManager
->GetFinalFilename();
1625 if (RealFileExists(FinalReleasegpg
) || RealFileExists(FinalInRelease
))
1627 std::string downgrade_msg
;
1628 strprintf(downgrade_msg
, _("The repository '%s' is no longer signed."),
1629 MetaIndex
->Target
.Description
.c_str());
1630 if(_config
->FindB("Acquire::AllowDowngradeToInsecureRepositories"))
1632 // meh, the users wants to take risks (we still mark the packages
1633 // from this repository as unauthenticated)
1634 _error
->Warning("%s", downgrade_msg
.c_str());
1635 _error
->Warning(_("This is normally not allowed, but the option "
1636 "Acquire::AllowDowngradeToInsecureRepositories was "
1637 "given to override it."));
1640 MessageInsecureRepository(true, downgrade_msg
);
1641 if (TransactionManager
->IMSHit
== false)
1642 Rename(MetaIndex
->DestFile
, MetaIndex
->DestFile
+ ".FAILED");
1643 Item::Failed("Message: " + downgrade_msg
, Cnf
);
1644 TransactionManager
->AbortTransaction();
1649 // ensures that a Release.gpg file in the lists/ is removed by the transaction
1650 TransactionManager
->TransactionStageRemoval(this, DestFile
);
1652 // only allow going further if the user explicitly wants it
1653 if (AllowInsecureRepositories(_("The repository '%s' is not signed."), MetaIndex
->Target
.Description
, TransactionManager
->MetaIndexParser
, TransactionManager
, this) == true)
1655 LoadLastMetaIndexParser(TransactionManager
, FinalRelease
, FinalInRelease
);
1657 // we parse the indexes here because at this point the user wanted
1658 // a repository that may potentially harm him
1659 bool const GoodLoad
= TransactionManager
->MetaIndexParser
->Load(MetaIndex
->DestFile
, &ErrorText
);
1660 if (MetaIndex
->VerifyVendor(Message
) == false)
1661 /* expired Release files are still a problem you need extra force for */;
1663 MetaIndex
->QueueIndexes(GoodLoad
);
1665 TransactionManager
->TransactionStageCopy(MetaIndex
, MetaIndex
->DestFile
, MetaIndex
->GetFinalFilename());
1668 // FIXME: this is used often (e.g. in pkgAcqIndexTrans) so refactor
1669 if (Cnf
->LocalOnly
== true ||
1670 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1679 // AcqBaseIndex - Constructor /*{{{*/
1680 pkgAcqBaseIndex::pkgAcqBaseIndex(pkgAcquire
* const Owner
,
1681 pkgAcqMetaClearSig
* const TransactionManager
,
1682 IndexTarget
const &Target
)
1683 : pkgAcqTransactionItem(Owner
, TransactionManager
, Target
), d(NULL
)
1687 pkgAcqBaseIndex::~pkgAcqBaseIndex() {}
1689 // AcqDiffIndex::AcqDiffIndex - Constructor /*{{{*/
1690 // ---------------------------------------------------------------------
1691 /* Get the DiffIndex file first and see if there are patches available
1692 * If so, create a pkgAcqIndexDiffs fetcher that will get and apply the
1693 * patches. If anything goes wrong in that process, it will fall back to
1694 * the original packages file
1696 pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire
* const Owner
,
1697 pkgAcqMetaClearSig
* const TransactionManager
,
1698 IndexTarget
const &Target
)
1699 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
), diffs(NULL
)
1701 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
1704 Desc
.Description
= GetDiffIndexFileName(Target
.Description
);
1705 Desc
.ShortDesc
= Target
.ShortDesc
;
1706 Desc
.URI
= GetDiffIndexURI(Target
);
1708 DestFile
= GetPartialFileNameFromURI(Desc
.URI
);
1711 std::clog
<< "pkgAcqDiffIndex: " << Desc
.URI
<< std::endl
;
1716 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
1717 // ---------------------------------------------------------------------
1718 /* The only header we use is the last-modified header. */
1719 string
pkgAcqDiffIndex::Custom600Headers() const
1721 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1722 return "\nIndex-File: true";
1724 string
const Final
= GetFinalFilename();
1727 std::clog
<< "Custom600Header-IMS: " << Final
<< std::endl
;
1730 if (stat(Final
.c_str(),&Buf
) != 0)
1731 return "\nIndex-File: true";
1733 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1736 void pkgAcqDiffIndex::QueueOnIMSHit() const /*{{{*/
1738 // list cleanup needs to know that this file as well as the already
1739 // present index is ours, so we create an empty diff to save it for us
1740 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
);
1743 bool pkgAcqDiffIndex::ParseDiffIndex(string
const &IndexDiffFile
) /*{{{*/
1745 // failing here is fine: our caller will take care of trying to
1746 // get the complete file if patching fails
1748 std::clog
<< "pkgAcqDiffIndex::ParseIndexDiff() " << IndexDiffFile
1751 FileFd
Fd(IndexDiffFile
,FileFd::ReadOnly
);
1753 if (Fd
.IsOpen() == false || Fd
.Failed())
1757 if(unlikely(TF
.Step(Tags
) == false))
1760 HashStringList ServerHashes
;
1761 unsigned long long ServerSize
= 0;
1763 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
1765 std::string tagname
= *type
;
1766 tagname
.append("-Current");
1767 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1768 if (tmp
.empty() == true)
1772 unsigned long long size
;
1773 std::stringstream
ss(tmp
);
1775 if (unlikely(hash
.empty() == true))
1777 if (unlikely(ServerSize
!= 0 && ServerSize
!= size
))
1779 ServerHashes
.push_back(HashString(*type
, hash
));
1783 if (ServerHashes
.usable() == false)
1786 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": Did not find a good hashsum in the index" << std::endl
;
1790 std::string
const CurrentPackagesFile
= GetFinalFileNameFromURI(Target
.URI
);
1791 HashStringList
const TargetFileHashes
= GetExpectedHashesFor(Target
.MetaKey
);
1792 if (TargetFileHashes
.usable() == false || ServerHashes
!= TargetFileHashes
)
1796 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": Index has different hashes than parser, probably older, so fail pdiffing" << std::endl
;
1797 printHashSumComparison(CurrentPackagesFile
, ServerHashes
, TargetFileHashes
);
1802 HashStringList LocalHashes
;
1803 // try avoiding calculating the hash here as this is costly
1804 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1805 LocalHashes
= GetExpectedHashesFromFor(TransactionManager
->LastMetaIndexParser
, Target
.MetaKey
);
1806 if (LocalHashes
.usable() == false)
1808 FileFd
fd(CurrentPackagesFile
, FileFd::ReadOnly
, FileFd::Auto
);
1809 Hashes
LocalHashesCalc(ServerHashes
);
1810 LocalHashesCalc
.AddFD(fd
);
1811 LocalHashes
= LocalHashesCalc
.GetHashStringList();
1814 if (ServerHashes
== LocalHashes
)
1816 // we have the same sha1 as the server so we are done here
1818 std::clog
<< "pkgAcqDiffIndex: Package file " << CurrentPackagesFile
<< " is up-to-date" << std::endl
;
1824 std::clog
<< "Server-Current: " << ServerHashes
.find(NULL
)->toStr() << " and we start at "
1825 << CurrentPackagesFile
<< " " << LocalHashes
.FileSize() << " " << LocalHashes
.find(NULL
)->toStr() << std::endl
;
1827 // historically, older hashes have more info than newer ones, so start
1828 // collecting with older ones first to avoid implementing complicated
1829 // information merging techniques… a failure is after all always
1830 // recoverable with a complete file and hashes aren't changed that often.
1831 std::vector
<char const *> types
;
1832 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
1833 types
.push_back(*type
);
1835 // parse all of (provided) history
1836 vector
<DiffInfo
> available_patches
;
1837 bool firstAcceptedHashes
= true;
1838 for (auto type
= types
.crbegin(); type
!= types
.crend(); ++type
)
1840 if (LocalHashes
.find(*type
) == NULL
)
1843 std::string tagname
= *type
;
1844 tagname
.append("-History");
1845 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1846 if (tmp
.empty() == true)
1849 string hash
, filename
;
1850 unsigned long long size
;
1851 std::stringstream
ss(tmp
);
1853 while (ss
>> hash
>> size
>> filename
)
1855 if (unlikely(hash
.empty() == true || filename
.empty() == true))
1858 // see if we have a record for this file already
1859 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
1860 for (; cur
!= available_patches
.end(); ++cur
)
1862 if (cur
->file
!= filename
)
1864 cur
->result_hashes
.push_back(HashString(*type
, hash
));
1867 if (cur
!= available_patches
.end())
1869 if (firstAcceptedHashes
== true)
1872 next
.file
= filename
;
1873 next
.result_hashes
.push_back(HashString(*type
, hash
));
1874 next
.result_hashes
.FileSize(size
);
1875 available_patches
.push_back(next
);
1880 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
1881 << " wasn't in the list for the first parsed hash! (history)" << std::endl
;
1885 firstAcceptedHashes
= false;
1888 if (unlikely(available_patches
.empty() == true))
1891 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": "
1892 << "Couldn't find any patches for the patch series." << std::endl
;
1896 for (auto type
= types
.crbegin(); type
!= types
.crend(); ++type
)
1898 if (LocalHashes
.find(*type
) == NULL
)
1901 std::string tagname
= *type
;
1902 tagname
.append("-Patches");
1903 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1904 if (tmp
.empty() == true)
1907 string hash
, filename
;
1908 unsigned long long size
;
1909 std::stringstream
ss(tmp
);
1911 while (ss
>> hash
>> size
>> filename
)
1913 if (unlikely(hash
.empty() == true || filename
.empty() == true))
1916 // see if we have a record for this file already
1917 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
1918 for (; cur
!= available_patches
.end(); ++cur
)
1920 if (cur
->file
!= filename
)
1922 if (cur
->patch_hashes
.empty())
1923 cur
->patch_hashes
.FileSize(size
);
1924 cur
->patch_hashes
.push_back(HashString(*type
, hash
));
1927 if (cur
!= available_patches
.end())
1930 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
1931 << " wasn't in the list for the first parsed hash! (patches)" << std::endl
;
1936 for (auto type
= types
.crbegin(); type
!= types
.crend(); ++type
)
1938 std::string tagname
= *type
;
1939 tagname
.append("-Download");
1940 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1941 if (tmp
.empty() == true)
1944 string hash
, filename
;
1945 unsigned long long size
;
1946 std::stringstream
ss(tmp
);
1948 // FIXME: all of pdiff supports only .gz compressed patches
1949 while (ss
>> hash
>> size
>> filename
)
1951 if (unlikely(hash
.empty() == true || filename
.empty() == true))
1953 if (unlikely(APT::String::Endswith(filename
, ".gz") == false))
1955 filename
.erase(filename
.length() - 3);
1957 // see if we have a record for this file already
1958 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
1959 for (; cur
!= available_patches
.end(); ++cur
)
1961 if (cur
->file
!= filename
)
1963 if (cur
->download_hashes
.empty())
1964 cur
->download_hashes
.FileSize(size
);
1965 cur
->download_hashes
.push_back(HashString(*type
, hash
));
1968 if (cur
!= available_patches
.end())
1971 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
1972 << " wasn't in the list for the first parsed hash! (download)" << std::endl
;
1978 bool foundStart
= false;
1979 for (std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
1980 cur
!= available_patches
.end(); ++cur
)
1982 if (LocalHashes
!= cur
->result_hashes
)
1985 available_patches
.erase(available_patches
.begin(), cur
);
1990 if (foundStart
== false || unlikely(available_patches
.empty() == true))
1993 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": "
1994 << "Couldn't find the start of the patch series." << std::endl
;
1998 for (auto const &patch
: available_patches
)
1999 if (patch
.result_hashes
.usable() == false ||
2000 patch
.patch_hashes
.usable() == false ||
2001 patch
.download_hashes
.usable() == false)
2004 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": provides no usable hashes for " << patch
.file
2005 << " so fallback to complete download" << std::endl
;
2009 // patching with too many files is rather slow compared to a fast download
2010 unsigned long const fileLimit
= _config
->FindI("Acquire::PDiffs::FileLimit", 0);
2011 if (fileLimit
!= 0 && fileLimit
< available_patches
.size())
2014 std::clog
<< "Need " << available_patches
.size() << " diffs (Limit is " << fileLimit
2015 << ") so fallback to complete download" << std::endl
;
2019 // calculate the size of all patches we have to get
2020 unsigned short const sizeLimitPercent
= _config
->FindI("Acquire::PDiffs::SizeLimit", 100);
2021 if (sizeLimitPercent
> 0 && TransactionManager
->MetaIndexParser
!= nullptr)
2023 unsigned long long downloadSize
= std::accumulate(available_patches
.begin(),
2024 available_patches
.end(), 0llu, [](unsigned long long const T
, DiffInfo
const &I
) {
2025 return T
+ I
.download_hashes
.FileSize();
2027 if (downloadSize
!= 0)
2029 unsigned long long downloadSizeIdx
= 0;
2030 auto const types
= VectorizeString(Target
.Option(IndexTarget::COMPRESSIONTYPES
), ' ');
2031 for (auto const &t
: types
)
2033 std::string MetaKey
= Target
.MetaKey
;
2034 if (t
!= "uncompressed")
2036 HashStringList
const hsl
= GetExpectedHashesFor(MetaKey
);
2037 if (unlikely(hsl
.usable() == false))
2039 downloadSizeIdx
= hsl
.FileSize();
2042 unsigned long long const sizeLimit
= downloadSizeIdx
* sizeLimitPercent
;
2043 if ((sizeLimit
/100) < downloadSize
)
2046 std::clog
<< "Need " << downloadSize
<< " compressed bytes (Limit is " << (sizeLimit
/100) << ", "
2047 << "original is " << downloadSizeIdx
<< ") so fallback to complete download" << std::endl
;
2053 // we have something, queue the diffs
2054 string::size_type
const last_space
= Description
.rfind(" ");
2055 if(last_space
!= string::npos
)
2056 Description
.erase(last_space
, Description
.size()-last_space
);
2058 /* decide if we should download patches one by one or in one go:
2059 The first is good if the server merges patches, but many don't so client
2060 based merging can be attempt in which case the second is better.
2061 "bad things" will happen if patches are merged on the server,
2062 but client side merging is attempt as well */
2063 bool pdiff_merge
= _config
->FindB("Acquire::PDiffs::Merge", true);
2064 if (pdiff_merge
== true)
2066 // reprepro adds this flag if it has merged patches on the server
2067 std::string
const precedence
= Tags
.FindS("X-Patch-Precedence");
2068 pdiff_merge
= (precedence
!= "merged");
2073 std::string
const Final
= GetExistingFilename(CurrentPackagesFile
);
2074 if (unlikely(Final
.empty())) // because we wouldn't be called in such a case
2076 std::string
const PartialFile
= GetPartialFileNameFromURI(Target
.URI
);
2077 if (FileExists(PartialFile
) && RemoveFile("Bootstrap-linking", PartialFile
) == false)
2080 std::clog
<< "Bootstrap-linking for patching " << CurrentPackagesFile
2081 << " by removing stale " << PartialFile
<< " failed!" << std::endl
;
2084 for (auto const &ext
: APT::Configuration::getCompressorExtensions())
2086 std::string
const Partial
= PartialFile
+ ext
;
2087 if (FileExists(Partial
) && RemoveFile("Bootstrap-linking", Partial
) == false)
2090 std::clog
<< "Bootstrap-linking for patching " << CurrentPackagesFile
2091 << " by removing stale " << Partial
<< " failed!" << std::endl
;
2095 std::string
const Ext
= Final
.substr(CurrentPackagesFile
.length());
2096 std::string
const Partial
= PartialFile
+ Ext
;
2097 if (symlink(Final
.c_str(), Partial
.c_str()) != 0)
2100 std::clog
<< "Bootstrap-linking for patching " << CurrentPackagesFile
2101 << " by linking " << Final
<< " to " << Partial
<< " failed!" << std::endl
;
2106 if (pdiff_merge
== false)
2107 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
, available_patches
);
2110 diffs
= new std::vector
<pkgAcqIndexMergeDiffs
*>(available_patches
.size());
2111 for(size_t i
= 0; i
< available_patches
.size(); ++i
)
2112 (*diffs
)[i
] = new pkgAcqIndexMergeDiffs(Owner
, TransactionManager
,
2114 available_patches
[i
],
2124 void pkgAcqDiffIndex::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
2126 Item::Failed(Message
,Cnf
);
2130 std::clog
<< "pkgAcqDiffIndex failed: " << Desc
.URI
<< " with " << Message
<< std::endl
2131 << "Falling back to normal index file acquire" << std::endl
;
2133 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
2136 void pkgAcqDiffIndex::Done(string
const &Message
,HashStringList
const &Hashes
, /*{{{*/
2137 pkgAcquire::MethodConfig
const * const Cnf
)
2140 std::clog
<< "pkgAcqDiffIndex::Done(): " << Desc
.URI
<< std::endl
;
2142 Item::Done(Message
, Hashes
, Cnf
);
2144 string
const FinalFile
= GetFinalFilename();
2145 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false))
2146 DestFile
= FinalFile
;
2148 if(ParseDiffIndex(DestFile
) == false)
2150 Failed("Message: Couldn't parse pdiff index", Cnf
);
2151 // queue for final move - this should happen even if we fail
2152 // while parsing (e.g. on sizelimit) and download the complete file.
2153 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
2157 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
2166 pkgAcqDiffIndex::~pkgAcqDiffIndex()
2172 // AcqIndexDiffs::AcqIndexDiffs - Constructor /*{{{*/
2173 // ---------------------------------------------------------------------
2174 /* The package diff is added to the queue. one object is constructed
2175 * for each diff and the index
2177 pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire
* const Owner
,
2178 pkgAcqMetaClearSig
* const TransactionManager
,
2179 IndexTarget
const &Target
,
2180 vector
<DiffInfo
> const &diffs
)
2181 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
),
2182 available_patches(diffs
)
2184 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
2186 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
2189 Description
= Target
.Description
;
2190 Desc
.ShortDesc
= Target
.ShortDesc
;
2192 if(available_patches
.empty() == true)
2194 // we are done (yeah!), check hashes against the final file
2195 DestFile
= GetKeepCompressedFileName(GetFinalFileNameFromURI(Target
.URI
), Target
);
2200 State
= StateFetchDiff
;
2205 void pkgAcqIndexDiffs::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
2207 Item::Failed(Message
,Cnf
);
2210 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
2212 std::clog
<< "pkgAcqIndexDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
2213 << "Falling back to normal index file acquire " << std::endl
;
2214 RenameOnError(PDiffError
);
2215 std::string
const patchname
= GetDiffsPatchFileName(DestFile
);
2216 if (RealFileExists(patchname
))
2217 Rename(patchname
, patchname
+ ".FAILED");
2218 std::string
const UnpatchedFile
= GetExistingFilename(GetPartialFileNameFromURI(Target
.URI
));
2219 if (UnpatchedFile
.empty() == false && FileExists(UnpatchedFile
))
2220 Rename(UnpatchedFile
, UnpatchedFile
+ ".FAILED");
2221 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
2225 // Finish - helper that cleans the item out of the fetcher queue /*{{{*/
2226 void pkgAcqIndexDiffs::Finish(bool allDone
)
2229 std::clog
<< "pkgAcqIndexDiffs::Finish(): "
2231 << Desc
.URI
<< std::endl
;
2233 // we restore the original name, this is required, otherwise
2234 // the file will be cleaned
2237 std::string
const Final
= GetKeepCompressedFileName(GetFinalFilename(), Target
);
2238 TransactionManager
->TransactionStageCopy(this, DestFile
, Final
);
2240 // this is for the "real" finish
2245 std::clog
<< "\n\nallDone: " << DestFile
<< "\n" << std::endl
;
2252 std::clog
<< "Finishing: " << Desc
.URI
<< std::endl
;
2259 bool pkgAcqIndexDiffs::QueueNextDiff() /*{{{*/
2261 // calc sha1 of the just patched file
2262 std::string
const PartialFile
= GetExistingFilename(GetPartialFileNameFromURI(Target
.URI
));
2263 if(unlikely(PartialFile
.empty()))
2265 Failed("Message: The file " + GetPartialFileNameFromURI(Target
.URI
) + " isn't available", NULL
);
2269 FileFd
fd(PartialFile
, FileFd::ReadOnly
, FileFd::Extension
);
2270 Hashes LocalHashesCalc
;
2271 LocalHashesCalc
.AddFD(fd
);
2272 HashStringList
const LocalHashes
= LocalHashesCalc
.GetHashStringList();
2275 std::clog
<< "QueueNextDiff: " << PartialFile
<< " (" << LocalHashes
.find(NULL
)->toStr() << ")" << std::endl
;
2277 HashStringList
const TargetFileHashes
= GetExpectedHashesFor(Target
.MetaKey
);
2278 if (unlikely(LocalHashes
.usable() == false || TargetFileHashes
.usable() == false))
2280 Failed("Local/Expected hashes are not usable for " + PartialFile
, NULL
);
2284 // final file reached before all patches are applied
2285 if(LocalHashes
== TargetFileHashes
)
2291 // remove all patches until the next matching patch is found
2292 // this requires the Index file to be ordered
2293 available_patches
.erase(available_patches
.begin(),
2294 std::find_if(available_patches
.begin(), available_patches
.end(), [&](DiffInfo
const &I
) {
2295 return I
.result_hashes
== LocalHashes
;
2298 // error checking and falling back if no patch was found
2299 if(available_patches
.empty() == true)
2301 Failed("No patches left to reach target for " + PartialFile
, NULL
);
2305 // queue the right diff
2306 Desc
.URI
= Target
.URI
+ ".diff/" + available_patches
[0].file
+ ".gz";
2307 Desc
.Description
= Description
+ " " + available_patches
[0].file
+ string(".pdiff");
2308 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
+ ".diff/" + available_patches
[0].file
), Target
);
2311 std::clog
<< "pkgAcqIndexDiffs::QueueNextDiff(): " << Desc
.URI
<< std::endl
;
2318 void pkgAcqIndexDiffs::Done(string
const &Message
, HashStringList
const &Hashes
, /*{{{*/
2319 pkgAcquire::MethodConfig
const * const Cnf
)
2322 std::clog
<< "pkgAcqIndexDiffs::Done(): " << Desc
.URI
<< std::endl
;
2324 Item::Done(Message
, Hashes
, Cnf
);
2326 std::string
const UncompressedUnpatchedFile
= GetPartialFileNameFromURI(Target
.URI
);
2327 std::string
const UnpatchedFile
= GetExistingFilename(UncompressedUnpatchedFile
);
2328 std::string
const PatchFile
= GetDiffsPatchFileName(UnpatchedFile
);
2329 std::string
const PatchedFile
= GetKeepCompressedFileName(UncompressedUnpatchedFile
, Target
);
2333 // success in downloading a diff, enter ApplyDiff state
2334 case StateFetchDiff
:
2335 Rename(DestFile
, PatchFile
);
2336 DestFile
= GetKeepCompressedFileName(UncompressedUnpatchedFile
+ "-patched", Target
);
2338 std::clog
<< "Sending to rred method: " << UnpatchedFile
<< std::endl
;
2339 State
= StateApplyDiff
;
2341 Desc
.URI
= "rred:" + UnpatchedFile
;
2343 SetActiveSubprocess("rred");
2345 // success in download/apply a diff, queue next (if needed)
2346 case StateApplyDiff
:
2347 // remove the just applied patch and base file
2348 available_patches
.erase(available_patches
.begin());
2349 RemoveFile("pkgAcqIndexDiffs::Done", PatchFile
);
2350 RemoveFile("pkgAcqIndexDiffs::Done", UnpatchedFile
);
2352 std::clog
<< "Moving patched file in place: " << std::endl
2353 << DestFile
<< " -> " << PatchedFile
<< std::endl
;
2354 Rename(DestFile
, PatchedFile
);
2356 // see if there is more to download
2357 if(available_patches
.empty() == false)
2359 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
, available_patches
);
2362 DestFile
= PatchedFile
;
2369 std::string
pkgAcqIndexDiffs::Custom600Headers() const /*{{{*/
2371 if(State
!= StateApplyDiff
)
2372 return pkgAcqBaseIndex::Custom600Headers();
2373 std::ostringstream patchhashes
;
2374 HashStringList
const ExpectedHashes
= available_patches
[0].patch_hashes
;
2375 for (HashStringList::const_iterator hs
= ExpectedHashes
.begin(); hs
!= ExpectedHashes
.end(); ++hs
)
2376 patchhashes
<< "\nPatch-0-" << hs
->HashType() << "-Hash: " << hs
->HashValue();
2377 patchhashes
<< pkgAcqBaseIndex::Custom600Headers();
2378 return patchhashes
.str();
2381 pkgAcqIndexDiffs::~pkgAcqIndexDiffs() {}
2383 // AcqIndexMergeDiffs::AcqIndexMergeDiffs - Constructor /*{{{*/
2384 pkgAcqIndexMergeDiffs::pkgAcqIndexMergeDiffs(pkgAcquire
* const Owner
,
2385 pkgAcqMetaClearSig
* const TransactionManager
,
2386 IndexTarget
const &Target
,
2387 DiffInfo
const &patch
,
2388 std::vector
<pkgAcqIndexMergeDiffs
*> const * const allPatches
)
2389 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
),
2390 patch(patch
), allPatches(allPatches
), State(StateFetchDiff
)
2392 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
2395 Description
= Target
.Description
;
2396 Desc
.ShortDesc
= Target
.ShortDesc
;
2397 Desc
.URI
= Target
.URI
+ ".diff/" + patch
.file
+ ".gz";
2398 Desc
.Description
= Description
+ " " + patch
.file
+ ".pdiff";
2399 DestFile
= GetPartialFileNameFromURI(Desc
.URI
);
2402 std::clog
<< "pkgAcqIndexMergeDiffs: " << Desc
.URI
<< std::endl
;
2407 void pkgAcqIndexMergeDiffs::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
2410 std::clog
<< "pkgAcqIndexMergeDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
;
2412 Item::Failed(Message
,Cnf
);
2415 // check if we are the first to fail, otherwise we are done here
2416 State
= StateDoneDiff
;
2417 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2418 I
!= allPatches
->end(); ++I
)
2419 if ((*I
)->State
== StateErrorDiff
)
2421 State
= StateErrorDiff
;
2425 // first failure means we should fallback
2426 State
= StateErrorDiff
;
2428 std::clog
<< "Falling back to normal index file acquire" << std::endl
;
2429 RenameOnError(PDiffError
);
2430 if (RealFileExists(DestFile
))
2431 Rename(DestFile
, DestFile
+ ".FAILED");
2432 std::string
const UnpatchedFile
= GetExistingFilename(GetPartialFileNameFromURI(Target
.URI
));
2433 if (UnpatchedFile
.empty() == false && FileExists(UnpatchedFile
))
2434 Rename(UnpatchedFile
, UnpatchedFile
+ ".FAILED");
2436 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
2439 void pkgAcqIndexMergeDiffs::Done(string
const &Message
, HashStringList
const &Hashes
, /*{{{*/
2440 pkgAcquire::MethodConfig
const * const Cnf
)
2443 std::clog
<< "pkgAcqIndexMergeDiffs::Done(): " << Desc
.URI
<< std::endl
;
2445 Item::Done(Message
, Hashes
, Cnf
);
2447 if (std::any_of(allPatches
->begin(), allPatches
->end(),
2448 [](pkgAcqIndexMergeDiffs
const * const P
) { return P
->State
== StateErrorDiff
; }))
2451 std::clog
<< "Another patch failed already, no point in processing this one." << std::endl
;
2452 State
= StateErrorDiff
;
2456 std::string
const UncompressedUnpatchedFile
= GetPartialFileNameFromURI(Target
.URI
);
2457 std::string
const UnpatchedFile
= GetExistingFilename(UncompressedUnpatchedFile
);
2458 if (UnpatchedFile
.empty())
2460 _error
->Fatal("Unpatched file %s doesn't exist (anymore)!", UncompressedUnpatchedFile
.c_str());
2461 State
= StateErrorDiff
;
2464 std::string
const PatchFile
= GetMergeDiffsPatchFileName(UnpatchedFile
, patch
.file
);
2465 std::string
const PatchedFile
= GetKeepCompressedFileName(UncompressedUnpatchedFile
, Target
);
2469 case StateFetchDiff
:
2470 Rename(DestFile
, PatchFile
);
2472 // check if this is the last completed diff
2473 State
= StateDoneDiff
;
2474 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2475 I
!= allPatches
->end(); ++I
)
2476 if ((*I
)->State
!= StateDoneDiff
)
2479 std::clog
<< "Not the last done diff in the batch: " << Desc
.URI
<< std::endl
;
2482 // this is the last completed diff, so we are ready to apply now
2483 DestFile
= GetKeepCompressedFileName(UncompressedUnpatchedFile
+ "-patched", Target
);
2485 std::clog
<< "Sending to rred method: " << UnpatchedFile
<< std::endl
;
2486 State
= StateApplyDiff
;
2488 Desc
.URI
= "rred:" + UnpatchedFile
;
2490 SetActiveSubprocess("rred");
2492 case StateApplyDiff
:
2493 // success in download & apply all diffs, finialize and clean up
2495 std::clog
<< "Queue patched file in place: " << std::endl
2496 << DestFile
<< " -> " << PatchedFile
<< std::endl
;
2498 // queue for copy by the transaction manager
2499 TransactionManager
->TransactionStageCopy(this, DestFile
, GetKeepCompressedFileName(GetFinalFilename(), Target
));
2501 // ensure the ed's are gone regardless of list-cleanup
2502 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2503 I
!= allPatches
->end(); ++I
)
2504 RemoveFile("pkgAcqIndexMergeDiffs::Done", GetMergeDiffsPatchFileName(UnpatchedFile
, (*I
)->patch
.file
));
2505 RemoveFile("pkgAcqIndexMergeDiffs::Done", UnpatchedFile
);
2510 std::clog
<< "allDone: " << DestFile
<< "\n" << std::endl
;
2512 case StateDoneDiff
: _error
->Fatal("Done called for %s which is in an invalid Done state", PatchFile
.c_str()); break;
2513 case StateErrorDiff
: _error
->Fatal("Done called for %s which is in an invalid Error state", PatchFile
.c_str()); break;
2517 std::string
pkgAcqIndexMergeDiffs::Custom600Headers() const /*{{{*/
2519 if(State
!= StateApplyDiff
)
2520 return pkgAcqBaseIndex::Custom600Headers();
2521 std::ostringstream patchhashes
;
2522 unsigned int seen_patches
= 0;
2523 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2524 I
!= allPatches
->end(); ++I
)
2526 HashStringList
const ExpectedHashes
= (*I
)->patch
.patch_hashes
;
2527 for (HashStringList::const_iterator hs
= ExpectedHashes
.begin(); hs
!= ExpectedHashes
.end(); ++hs
)
2528 patchhashes
<< "\nPatch-" << seen_patches
<< "-" << hs
->HashType() << "-Hash: " << hs
->HashValue();
2531 patchhashes
<< pkgAcqBaseIndex::Custom600Headers();
2532 return patchhashes
.str();
2535 pkgAcqIndexMergeDiffs::~pkgAcqIndexMergeDiffs() {}
2537 // AcqIndex::AcqIndex - Constructor /*{{{*/
2538 pkgAcqIndex::pkgAcqIndex(pkgAcquire
* const Owner
,
2539 pkgAcqMetaClearSig
* const TransactionManager
,
2540 IndexTarget
const &Target
)
2541 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
), Stage(STAGE_DOWNLOAD
),
2542 CompressionExtensions(Target
.Option(IndexTarget::COMPRESSIONTYPES
))
2544 Init(Target
.URI
, Target
.Description
, Target
.ShortDesc
);
2546 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
2547 std::clog
<< "New pkgIndex with TransactionManager "
2548 << TransactionManager
<< std::endl
;
2551 // AcqIndex::Init - defered Constructor /*{{{*/
2552 static void NextCompressionExtension(std::string
&CurrentCompressionExtension
, std::string
&CompressionExtensions
, bool const preview
)
2554 size_t const nextExt
= CompressionExtensions
.find(' ');
2555 if (nextExt
== std::string::npos
)
2557 CurrentCompressionExtension
= CompressionExtensions
;
2558 if (preview
== false)
2559 CompressionExtensions
.clear();
2563 CurrentCompressionExtension
= CompressionExtensions
.substr(0, nextExt
);
2564 if (preview
== false)
2565 CompressionExtensions
= CompressionExtensions
.substr(nextExt
+1);
2568 void pkgAcqIndex::Init(string
const &URI
, string
const &URIDesc
,
2569 string
const &ShortDesc
)
2571 Stage
= STAGE_DOWNLOAD
;
2573 DestFile
= GetPartialFileNameFromURI(URI
);
2574 NextCompressionExtension(CurrentCompressionExtension
, CompressionExtensions
, false);
2576 // store file size of the download to ensure the fetcher gives
2577 // accurate progress reporting
2578 FileSize
= GetExpectedHashes().FileSize();
2580 if (CurrentCompressionExtension
== "uncompressed")
2584 else if (CurrentCompressionExtension
== "by-hash")
2586 NextCompressionExtension(CurrentCompressionExtension
, CompressionExtensions
, true);
2587 if(unlikely(TransactionManager
->MetaIndexParser
== NULL
|| CurrentCompressionExtension
.empty()))
2589 if (CurrentCompressionExtension
!= "uncompressed")
2591 Desc
.URI
= URI
+ '.' + CurrentCompressionExtension
;
2592 DestFile
= DestFile
+ '.' + CurrentCompressionExtension
;
2595 HashStringList
const Hashes
= GetExpectedHashes();
2596 HashString
const * const TargetHash
= Hashes
.find(NULL
);
2597 if (unlikely(TargetHash
== nullptr))
2599 std::string
const ByHash
= "/by-hash/" + TargetHash
->HashType() + "/" + TargetHash
->HashValue();
2600 size_t const trailing_slash
= Desc
.URI
.find_last_of("/");
2601 if (unlikely(trailing_slash
== std::string::npos
))
2603 Desc
.URI
= Desc
.URI
.replace(
2605 Desc
.URI
.substr(trailing_slash
+1).size()+1,
2608 else if (unlikely(CurrentCompressionExtension
.empty()))
2612 Desc
.URI
= URI
+ '.' + CurrentCompressionExtension
;
2613 DestFile
= DestFile
+ '.' + CurrentCompressionExtension
;
2617 Desc
.Description
= URIDesc
;
2619 Desc
.ShortDesc
= ShortDesc
;
2624 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
2625 // ---------------------------------------------------------------------
2626 /* The only header we use is the last-modified header. */
2627 string
pkgAcqIndex::Custom600Headers() const
2630 string msg
= "\nIndex-File: true";
2632 if (TransactionManager
->LastMetaIndexParser
== NULL
)
2634 std::string
const Final
= GetFinalFilename();
2637 if (stat(Final
.c_str(),&Buf
) == 0)
2638 msg
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
2641 if(Target
.IsOptional
)
2642 msg
+= "\nFail-Ignore: true";
2647 // AcqIndex::Failed - getting the indexfile failed /*{{{*/
2648 void pkgAcqIndex::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)
2650 Item::Failed(Message
,Cnf
);
2652 // authorisation matches will not be fixed by other compression types
2653 if (Status
!= StatAuthError
)
2655 if (CompressionExtensions
.empty() == false)
2657 Init(Target
.URI
, Desc
.Description
, Desc
.ShortDesc
);
2663 if(Target
.IsOptional
&& GetExpectedHashes().empty() && Stage
== STAGE_DOWNLOAD
)
2666 TransactionManager
->AbortTransaction();
2669 // AcqIndex::Done - Finished a fetch /*{{{*/
2670 // ---------------------------------------------------------------------
2671 /* This goes through a number of states.. On the initial fetch the
2672 method could possibly return an alternate filename which points
2673 to the uncompressed version of the file. If this is so the file
2674 is copied into the partial directory. In all other cases the file
2675 is decompressed with a compressed uri. */
2676 void pkgAcqIndex::Done(string
const &Message
,
2677 HashStringList
const &Hashes
,
2678 pkgAcquire::MethodConfig
const * const Cfg
)
2680 Item::Done(Message
,Hashes
,Cfg
);
2684 case STAGE_DOWNLOAD
:
2685 StageDownloadDone(Message
);
2687 case STAGE_DECOMPRESS_AND_VERIFY
:
2688 StageDecompressDone();
2693 // AcqIndex::StageDownloadDone - Queue for decompress and verify /*{{{*/
2694 void pkgAcqIndex::StageDownloadDone(string
const &Message
)
2699 std::string
const AltFilename
= LookupTag(Message
,"Alt-Filename");
2700 std::string Filename
= LookupTag(Message
,"Filename");
2702 // we need to verify the file against the current Release file again
2703 // on if-modfied-since hit to avoid a stale attack against us
2704 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
2706 // copy FinalFile into partial/ so that we check the hash again
2707 string
const FinalFile
= GetExistingFilename(GetFinalFileNameFromURI(Target
.URI
));
2708 if (symlink(FinalFile
.c_str(), DestFile
.c_str()) != 0)
2709 _error
->WarningE("pkgAcqIndex::StageDownloadDone", "Symlinking final file %s back to %s failed", FinalFile
.c_str(), DestFile
.c_str());
2712 EraseFileName
= DestFile
;
2713 Filename
= DestFile
;
2715 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
2716 Desc
.URI
= "store:" + Filename
;
2718 SetActiveSubprocess(::URI(Desc
.URI
).Access
);
2721 // methods like file:// give us an alternative (uncompressed) file
2722 else if (Target
.KeepCompressed
== false && AltFilename
.empty() == false)
2724 if (CurrentCompressionExtension
!= "uncompressed")
2725 DestFile
.erase(DestFile
.length() - (CurrentCompressionExtension
.length() + 1));
2726 Filename
= AltFilename
;
2728 // Methods like e.g. "file:" will give us a (compressed) FileName that is
2729 // not the "DestFile" we set, in this case we uncompress from the local file
2730 else if (Filename
!= DestFile
&& RealFileExists(DestFile
) == false)
2732 // symlinking ensures that the filename can be used for compression detection
2733 // that is e.g. needed for by-hash which has no extension over file
2734 if (symlink(Filename
.c_str(),DestFile
.c_str()) != 0)
2735 _error
->WarningE("pkgAcqIndex::StageDownloadDone", "Symlinking file %s to %s failed", Filename
.c_str(), DestFile
.c_str());
2738 EraseFileName
= DestFile
;
2739 Filename
= DestFile
;
2743 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
2744 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
2745 if (Filename
!= DestFile
&& flExtension(Filename
) == flExtension(DestFile
))
2746 Desc
.URI
= "copy:" + Filename
;
2748 Desc
.URI
= "store:" + Filename
;
2749 if (DestFile
== Filename
)
2751 if (CurrentCompressionExtension
== "uncompressed")
2752 return StageDecompressDone();
2753 DestFile
= "/dev/null";
2756 if (EraseFileName
.empty())
2757 EraseFileName
= Filename
;
2759 // queue uri for the next stage
2761 SetActiveSubprocess(::URI(Desc
.URI
).Access
);
2764 // AcqIndex::StageDecompressDone - Final verification /*{{{*/
2765 void pkgAcqIndex::StageDecompressDone()
2767 if (DestFile
== "/dev/null")
2768 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
2770 // Done, queue for rename on transaction finished
2771 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
2774 pkgAcqIndex::~pkgAcqIndex() {}
2777 // AcqArchive::AcqArchive - Constructor /*{{{*/
2778 // ---------------------------------------------------------------------
2779 /* This just sets up the initial fetch environment and queues the first
2781 pkgAcqArchive::pkgAcqArchive(pkgAcquire
* const Owner
,pkgSourceList
* const Sources
,
2782 pkgRecords
* const Recs
,pkgCache::VerIterator
const &Version
,
2783 string
&StoreFilename
) :
2784 Item(Owner
), d(NULL
), LocalSource(false), Version(Version
), Sources(Sources
), Recs(Recs
),
2785 StoreFilename(StoreFilename
), Vf(Version
.FileList()),
2788 Retries
= _config
->FindI("Acquire::Retries",0);
2790 if (Version
.Arch() == 0)
2792 _error
->Error(_("I wasn't able to locate a file for the %s package. "
2793 "This might mean you need to manually fix this package. "
2794 "(due to missing arch)"),
2795 Version
.ParentPkg().FullName().c_str());
2799 /* We need to find a filename to determine the extension. We make the
2800 assumption here that all the available sources for this version share
2801 the same extension.. */
2802 // Skip not source sources, they do not have file fields.
2803 for (; Vf
.end() == false; ++Vf
)
2805 if (Vf
.File().Flagged(pkgCache::Flag::NotSource
))
2810 // Does not really matter here.. we are going to fail out below
2811 if (Vf
.end() != true)
2813 // If this fails to get a file name we will bomb out below.
2814 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2815 if (_error
->PendingError() == true)
2818 // Generate the final file name as: package_version_arch.foo
2819 StoreFilename
= QuoteString(Version
.ParentPkg().Name(),"_:") + '_' +
2820 QuoteString(Version
.VerStr(),"_:") + '_' +
2821 QuoteString(Version
.Arch(),"_:.") +
2822 "." + flExtension(Parse
.FileName());
2825 // check if we have one trusted source for the package. if so, switch
2826 // to "TrustedOnly" mode - but only if not in AllowUnauthenticated mode
2827 bool const allowUnauth
= _config
->FindB("APT::Get::AllowUnauthenticated", false);
2828 bool const debugAuth
= _config
->FindB("Debug::pkgAcquire::Auth", false);
2829 bool seenUntrusted
= false;
2830 for (pkgCache::VerFileIterator i
= Version
.FileList(); i
.end() == false; ++i
)
2832 pkgIndexFile
*Index
;
2833 if (Sources
->FindIndex(i
.File(),Index
) == false)
2836 if (debugAuth
== true)
2837 std::cerr
<< "Checking index: " << Index
->Describe()
2838 << "(Trusted=" << Index
->IsTrusted() << ")" << std::endl
;
2840 if (Index
->IsTrusted() == true)
2843 if (allowUnauth
== false)
2847 seenUntrusted
= true;
2850 // "allow-unauthenticated" restores apts old fetching behaviour
2851 // that means that e.g. unauthenticated file:// uris are higher
2852 // priority than authenticated http:// uris
2853 if (allowUnauth
== true && seenUntrusted
== true)
2857 if (QueueNext() == false && _error
->PendingError() == false)
2858 _error
->Error(_("Can't find a source to download version '%s' of '%s'"),
2859 Version
.VerStr(), Version
.ParentPkg().FullName(false).c_str());
2862 // AcqArchive::QueueNext - Queue the next file source /*{{{*/
2863 // ---------------------------------------------------------------------
2864 /* This queues the next available file version for download. It checks if
2865 the archive is already available in the cache and stashs the MD5 for
2867 bool pkgAcqArchive::QueueNext()
2869 for (; Vf
.end() == false; ++Vf
)
2871 pkgCache::PkgFileIterator
const PkgF
= Vf
.File();
2872 // Ignore not source sources
2873 if (PkgF
.Flagged(pkgCache::Flag::NotSource
))
2876 // Try to cross match against the source list
2877 pkgIndexFile
*Index
;
2878 if (Sources
->FindIndex(PkgF
, Index
) == false)
2880 LocalSource
= PkgF
.Flagged(pkgCache::Flag::LocalSource
);
2882 // only try to get a trusted package from another source if that source
2884 if(Trusted
&& !Index
->IsTrusted())
2887 // Grab the text package record
2888 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2889 if (_error
->PendingError() == true)
2892 string PkgFile
= Parse
.FileName();
2893 ExpectedHashes
= Parse
.Hashes();
2895 if (PkgFile
.empty() == true)
2896 return _error
->Error(_("The package index files are corrupted. No Filename: "
2897 "field for package %s."),
2898 Version
.ParentPkg().Name());
2900 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
2901 Desc
.Description
= Index
->ArchiveInfo(Version
);
2903 Desc
.ShortDesc
= Version
.ParentPkg().FullName(true);
2905 // See if we already have the file. (Legacy filenames)
2906 FileSize
= Version
->Size
;
2907 string FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile
);
2909 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2911 // Make sure the size matches
2912 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2917 StoreFilename
= DestFile
= FinalFile
;
2921 /* Hmm, we have a file and its size does not match, this means it is
2922 an old style mismatched arch */
2923 RemoveFile("pkgAcqArchive::QueueNext", FinalFile
);
2926 // Check it again using the new style output filenames
2927 FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
2928 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2930 // Make sure the size matches
2931 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2936 StoreFilename
= DestFile
= FinalFile
;
2940 /* Hmm, we have a file and its size does not match, this shouldn't
2942 RemoveFile("pkgAcqArchive::QueueNext", FinalFile
);
2945 DestFile
= _config
->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename
);
2947 // Check the destination file
2948 if (stat(DestFile
.c_str(),&Buf
) == 0)
2950 // Hmm, the partial file is too big, erase it
2951 if ((unsigned long long)Buf
.st_size
> Version
->Size
)
2952 RemoveFile("pkgAcqArchive::QueueNext", DestFile
);
2954 PartialSize
= Buf
.st_size
;
2957 // Disables download of archives - useful if no real installation follows,
2958 // e.g. if we are just interested in proposed installation order
2959 if (_config
->FindB("Debug::pkgAcqArchive::NoQueue", false) == true)
2964 StoreFilename
= DestFile
= FinalFile
;
2978 // AcqArchive::Done - Finished fetching /*{{{*/
2979 // ---------------------------------------------------------------------
2981 void pkgAcqArchive::Done(string
const &Message
, HashStringList
const &Hashes
,
2982 pkgAcquire::MethodConfig
const * const Cfg
)
2984 Item::Done(Message
, Hashes
, Cfg
);
2986 // Grab the output filename
2987 std::string
const FileName
= LookupTag(Message
,"Filename");
2988 if (DestFile
!= FileName
&& RealFileExists(DestFile
) == false)
2990 StoreFilename
= DestFile
= FileName
;
2996 // Done, move it into position
2997 string
const FinalFile
= GetFinalFilename();
2998 Rename(DestFile
,FinalFile
);
2999 StoreFilename
= DestFile
= FinalFile
;
3003 // AcqArchive::Failed - Failure handler /*{{{*/
3004 // ---------------------------------------------------------------------
3005 /* Here we try other sources */
3006 void pkgAcqArchive::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)
3008 Item::Failed(Message
,Cnf
);
3010 /* We don't really want to retry on failed media swaps, this prevents
3011 that. An interesting observation is that permanent failures are not
3013 if (Cnf
->Removable
== true &&
3014 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
3016 // Vf = Version.FileList();
3017 while (Vf
.end() == false) ++Vf
;
3018 StoreFilename
= string();
3023 if (QueueNext() == false)
3025 // This is the retry counter
3027 Cnf
->LocalOnly
== false &&
3028 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
3031 Vf
= Version
.FileList();
3032 if (QueueNext() == true)
3036 StoreFilename
= string();
3041 APT_PURE
bool pkgAcqArchive::IsTrusted() const /*{{{*/
3046 void pkgAcqArchive::Finished() /*{{{*/
3048 if (Status
== pkgAcquire::Item::StatDone
&&
3051 StoreFilename
= string();
3054 std::string
pkgAcqArchive::DescURI() const /*{{{*/
3059 std::string
pkgAcqArchive::ShortDesc() const /*{{{*/
3061 return Desc
.ShortDesc
;
3064 pkgAcqArchive::~pkgAcqArchive() {}
3066 // AcqChangelog::pkgAcqChangelog - Constructors /*{{{*/
3067 class pkgAcqChangelog::Private
3070 std::string FinalFile
;
3072 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire
* const Owner
, pkgCache::VerIterator
const &Ver
,
3073 std::string
const &DestDir
, std::string
const &DestFilename
) :
3074 pkgAcquire::Item(Owner
), d(new pkgAcqChangelog::Private()), SrcName(Ver
.SourcePkgName()), SrcVersion(Ver
.SourceVerStr())
3076 Desc
.URI
= URI(Ver
);
3077 Init(DestDir
, DestFilename
);
3079 // some parameters are char* here as they come likely from char* interfaces – which can also return NULL
3080 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire
* const Owner
, pkgCache::RlsFileIterator
const &RlsFile
,
3081 char const * const Component
, char const * const SrcName
, char const * const SrcVersion
,
3082 const string
&DestDir
, const string
&DestFilename
) :
3083 pkgAcquire::Item(Owner
), d(new pkgAcqChangelog::Private()), SrcName(SrcName
), SrcVersion(SrcVersion
)
3085 Desc
.URI
= URI(RlsFile
, Component
, SrcName
, SrcVersion
);
3086 Init(DestDir
, DestFilename
);
3088 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire
* const Owner
,
3089 std::string
const &URI
, char const * const SrcName
, char const * const SrcVersion
,
3090 const string
&DestDir
, const string
&DestFilename
) :
3091 pkgAcquire::Item(Owner
), d(new pkgAcqChangelog::Private()), SrcName(SrcName
), SrcVersion(SrcVersion
)
3094 Init(DestDir
, DestFilename
);
3096 void pkgAcqChangelog::Init(std::string
const &DestDir
, std::string
const &DestFilename
)
3098 if (Desc
.URI
.empty())
3101 // TRANSLATOR: %s=%s is sourcename=sourceversion, e.g. apt=1.1
3102 strprintf(ErrorText
, _("Changelog unavailable for %s=%s"), SrcName
.c_str(), SrcVersion
.c_str());
3103 // Let the error message print something sensible rather than "Failed to fetch /"
3104 if (DestFilename
.empty())
3105 DestFile
= SrcName
+ ".changelog";
3107 DestFile
= DestFilename
;
3108 Desc
.URI
= "changelog:/" + DestFile
;
3112 std::string DestFileName
;
3113 if (DestFilename
.empty())
3114 DestFileName
= flCombine(DestFile
, SrcName
+ ".changelog");
3116 DestFileName
= flCombine(DestFile
, DestFilename
);
3118 std::string
const SandboxUser
= _config
->Find("APT::Sandbox::User");
3119 std::string
const systemTemp
= GetTempDir(SandboxUser
);
3121 snprintf(tmpname
, sizeof(tmpname
), "%s/apt-changelog-XXXXXX", systemTemp
.c_str());
3122 if (NULL
== mkdtemp(tmpname
))
3124 _error
->Errno("mkdtemp", "mkdtemp failed in changelog acquire of %s %s", SrcName
.c_str(), SrcVersion
.c_str());
3128 TemporaryDirectory
= tmpname
;
3130 ChangeOwnerAndPermissionOfFile("Item::QueueURI", TemporaryDirectory
.c_str(),
3131 SandboxUser
.c_str(), "root", 0700);
3133 DestFile
= flCombine(TemporaryDirectory
, DestFileName
);
3134 if (DestDir
.empty() == false)
3136 d
->FinalFile
= flCombine(DestDir
, DestFileName
);
3137 if (RealFileExists(d
->FinalFile
))
3139 FileFd file1
, file2
;
3140 if (file1
.Open(DestFile
, FileFd::WriteOnly
| FileFd::Create
| FileFd::Exclusive
) &&
3141 file2
.Open(d
->FinalFile
, FileFd::ReadOnly
) && CopyFile(file2
, file1
))
3143 struct timeval times
[2];
3144 times
[0].tv_sec
= times
[1].tv_sec
= file2
.ModificationTime();
3145 times
[0].tv_usec
= times
[1].tv_usec
= 0;
3146 utimes(DestFile
.c_str(), times
);
3151 Desc
.ShortDesc
= "Changelog";
3152 strprintf(Desc
.Description
, "%s %s %s Changelog", URI::SiteOnly(Desc
.URI
).c_str(), SrcName
.c_str(), SrcVersion
.c_str());
3157 std::string
pkgAcqChangelog::URI(pkgCache::VerIterator
const &Ver
) /*{{{*/
3159 std::string
const confOnline
= "Acquire::Changelogs::AlwaysOnline";
3160 bool AlwaysOnline
= _config
->FindB(confOnline
, false);
3161 if (AlwaysOnline
== false)
3162 for (pkgCache::VerFileIterator VF
= Ver
.FileList(); VF
.end() == false; ++VF
)
3164 pkgCache::PkgFileIterator
const PF
= VF
.File();
3165 if (PF
.Flagged(pkgCache::Flag::NotSource
) || PF
->Release
== 0)
3167 pkgCache::RlsFileIterator
const RF
= PF
.ReleaseFile();
3168 if (RF
->Origin
!= 0 && _config
->FindB(confOnline
+ "::Origin::" + RF
.Origin(), false))
3170 AlwaysOnline
= true;
3174 if (AlwaysOnline
== false)
3176 pkgCache::PkgIterator
const Pkg
= Ver
.ParentPkg();
3177 if (Pkg
->CurrentVer
!= 0 && Pkg
.CurrentVer() == Ver
)
3179 std::string
const basename
= std::string("/usr/share/doc/") + Pkg
.Name() + "/changelog";
3180 std::string
const debianname
= basename
+ ".Debian";
3181 if (FileExists(debianname
))
3182 return "copy://" + debianname
;
3183 else if (FileExists(debianname
+ ".gz"))
3184 return "gzip://" + debianname
+ ".gz";
3185 else if (FileExists(basename
))
3186 return "copy://" + basename
;
3187 else if (FileExists(basename
+ ".gz"))
3188 return "gzip://" + basename
+ ".gz";
3192 char const * const SrcName
= Ver
.SourcePkgName();
3193 char const * const SrcVersion
= Ver
.SourceVerStr();
3194 // find the first source for this version which promises a changelog
3195 for (pkgCache::VerFileIterator VF
= Ver
.FileList(); VF
.end() == false; ++VF
)
3197 pkgCache::PkgFileIterator
const PF
= VF
.File();
3198 if (PF
.Flagged(pkgCache::Flag::NotSource
) || PF
->Release
== 0)
3200 pkgCache::RlsFileIterator
const RF
= PF
.ReleaseFile();
3201 std::string
const uri
= URI(RF
, PF
.Component(), SrcName
, SrcVersion
);
3208 std::string
pkgAcqChangelog::URITemplate(pkgCache::RlsFileIterator
const &Rls
)
3210 if (Rls
.end() == true || (Rls
->Label
== 0 && Rls
->Origin
== 0))
3212 std::string
const serverConfig
= "Acquire::Changelogs::URI";
3214 #define APT_EMPTY_SERVER \
3215 if (server.empty() == false) \
3217 if (server != "no") \
3221 #define APT_CHECK_SERVER(X, Y) \
3224 std::string const specialServerConfig = serverConfig + "::" + Y + #X + "::" + Rls.X(); \
3225 server = _config->Find(specialServerConfig); \
3228 // this way e.g. Debian-Security can fallback to Debian
3229 APT_CHECK_SERVER(Label
, "Override::")
3230 APT_CHECK_SERVER(Origin
, "Override::")
3232 if (RealFileExists(Rls
.FileName()))
3234 _error
->PushToStack();
3236 /* This can be costly. A caller wanting to get millions of URIs might
3237 want to do this on its own once and use Override settings.
3238 We don't do this here as Origin/Label are not as unique as they
3239 should be so this could produce request order-dependent anomalies */
3240 if (OpenMaybeClearSignedFile(Rls
.FileName(), rf
) == true)
3242 pkgTagFile
TagFile(&rf
, rf
.Size());
3243 pkgTagSection Section
;
3244 if (TagFile
.Step(Section
) == true)
3245 server
= Section
.FindS("Changelogs");
3247 _error
->RevertToStack();
3251 APT_CHECK_SERVER(Label
, "")
3252 APT_CHECK_SERVER(Origin
, "")
3253 #undef APT_CHECK_SERVER
3254 #undef APT_EMPTY_SERVER
3257 std::string
pkgAcqChangelog::URI(pkgCache::RlsFileIterator
const &Rls
,
3258 char const * const Component
, char const * const SrcName
,
3259 char const * const SrcVersion
)
3261 return URI(URITemplate(Rls
), Component
, SrcName
, SrcVersion
);
3263 std::string
pkgAcqChangelog::URI(std::string
const &Template
,
3264 char const * const Component
, char const * const SrcName
,
3265 char const * const SrcVersion
)
3267 if (Template
.find("@CHANGEPATH@") == std::string::npos
)
3270 // the path is: COMPONENT/SRC/SRCNAME/SRCNAME_SRCVER, e.g. main/a/apt/1.1 or contrib/liba/libapt/2.0
3271 std::string Src
= SrcName
;
3272 std::string path
= APT::String::Startswith(SrcName
, "lib") ? Src
.substr(0, 4) : Src
.substr(0,1);
3273 path
.append("/").append(Src
).append("/");
3274 path
.append(Src
).append("_").append(StripEpoch(SrcVersion
));
3275 // we omit component for releases without one (= flat-style repositories)
3276 if (Component
!= NULL
&& strlen(Component
) != 0)
3277 path
= std::string(Component
) + "/" + path
;
3279 return SubstVar(Template
, "@CHANGEPATH@", path
);
3282 // AcqChangelog::Failed - Failure handler /*{{{*/
3283 void pkgAcqChangelog::Failed(string
const &Message
, pkgAcquire::MethodConfig
const * const Cnf
)
3285 Item::Failed(Message
,Cnf
);
3287 std::string errText
;
3288 // TRANSLATOR: %s=%s is sourcename=sourceversion, e.g. apt=1.1
3289 strprintf(errText
, _("Changelog unavailable for %s=%s"), SrcName
.c_str(), SrcVersion
.c_str());
3291 // Error is probably something techy like 404 Not Found
3292 if (ErrorText
.empty())
3293 ErrorText
= errText
;
3295 ErrorText
= errText
+ " (" + ErrorText
+ ")";
3298 // AcqChangelog::Done - Item downloaded OK /*{{{*/
3299 void pkgAcqChangelog::Done(string
const &Message
,HashStringList
const &CalcHashes
,
3300 pkgAcquire::MethodConfig
const * const Cnf
)
3302 Item::Done(Message
,CalcHashes
,Cnf
);
3303 if (d
->FinalFile
.empty() == false)
3305 if (RemoveFile("pkgAcqChangelog::Done", d
->FinalFile
) == false ||
3306 Rename(DestFile
, d
->FinalFile
) == false)
3313 pkgAcqChangelog::~pkgAcqChangelog() /*{{{*/
3315 if (TemporaryDirectory
.empty() == false)
3317 RemoveFile("~pkgAcqChangelog", DestFile
);
3318 rmdir(TemporaryDirectory
.c_str());
3324 // AcqFile::pkgAcqFile - Constructor /*{{{*/
3325 pkgAcqFile::pkgAcqFile(pkgAcquire
* const Owner
,string
const &URI
, HashStringList
const &Hashes
,
3326 unsigned long long const Size
,string
const &Dsc
,string
const &ShortDesc
,
3327 const string
&DestDir
, const string
&DestFilename
,
3328 bool const IsIndexFile
) :
3329 Item(Owner
), d(NULL
), IsIndexFile(IsIndexFile
), ExpectedHashes(Hashes
)
3331 Retries
= _config
->FindI("Acquire::Retries",0);
3333 if(!DestFilename
.empty())
3334 DestFile
= DestFilename
;
3335 else if(!DestDir
.empty())
3336 DestFile
= DestDir
+ "/" + flNotDir(URI
);
3338 DestFile
= flNotDir(URI
);
3342 Desc
.Description
= Dsc
;
3345 // Set the short description to the archive component
3346 Desc
.ShortDesc
= ShortDesc
;
3348 // Get the transfer sizes
3351 if (stat(DestFile
.c_str(),&Buf
) == 0)
3353 // Hmm, the partial file is too big, erase it
3354 if ((Size
> 0) && (unsigned long long)Buf
.st_size
> Size
)
3355 RemoveFile("pkgAcqFile", DestFile
);
3357 PartialSize
= Buf
.st_size
;
3363 // AcqFile::Done - Item downloaded OK /*{{{*/
3364 void pkgAcqFile::Done(string
const &Message
,HashStringList
const &CalcHashes
,
3365 pkgAcquire::MethodConfig
const * const Cnf
)
3367 Item::Done(Message
,CalcHashes
,Cnf
);
3369 std::string
const FileName
= LookupTag(Message
,"Filename");
3372 // The files timestamp matches
3373 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
3376 // We have to copy it into place
3377 if (RealFileExists(DestFile
.c_str()) == false)
3380 if (_config
->FindB("Acquire::Source-Symlinks",true) == false ||
3381 Cnf
->Removable
== true)
3383 Desc
.URI
= "copy:" + FileName
;
3388 // Erase the file if it is a symlink so we can overwrite it
3390 if (lstat(DestFile
.c_str(),&St
) == 0)
3392 if (S_ISLNK(St
.st_mode
) != 0)
3393 RemoveFile("pkgAcqFile::Done", DestFile
);
3397 if (symlink(FileName
.c_str(),DestFile
.c_str()) != 0)
3399 _error
->PushToStack();
3400 _error
->Errno("pkgAcqFile::Done", "Symlinking file %s failed", DestFile
.c_str());
3401 std::stringstream msg
;
3402 _error
->DumpErrors(msg
, GlobalError::DEBUG
, false);
3403 _error
->RevertToStack();
3404 ErrorText
= msg
.str();
3411 // AcqFile::Failed - Failure handler /*{{{*/
3412 // ---------------------------------------------------------------------
3413 /* Here we try other sources */
3414 void pkgAcqFile::Failed(string
const &Message
, pkgAcquire::MethodConfig
const * const Cnf
)
3416 Item::Failed(Message
,Cnf
);
3418 // This is the retry counter
3420 Cnf
->LocalOnly
== false &&
3421 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
3431 string
pkgAcqFile::Custom600Headers() const /*{{{*/
3434 return "\nIndex-File: true";
3438 pkgAcqFile::~pkgAcqFile() {}