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 // AcqMetaBase - Constructor /*{{{*/
806 pkgAcqMetaBase::pkgAcqMetaBase(pkgAcquire
* const Owner
,
807 pkgAcqMetaClearSig
* const TransactionManager
,
808 std::vector
<IndexTarget
> const &IndexTargets
,
809 IndexTarget
const &DataTarget
)
810 : pkgAcqTransactionItem(Owner
, TransactionManager
, DataTarget
), d(NULL
),
811 IndexTargets(IndexTargets
),
812 AuthPass(false), IMSHit(false)
816 // AcqMetaBase::Add - Add a item to the current Transaction /*{{{*/
817 void pkgAcqMetaBase::Add(pkgAcqTransactionItem
* const I
)
819 Transaction
.push_back(I
);
822 // AcqMetaBase::AbortTransaction - Abort the current Transaction /*{{{*/
823 void pkgAcqMetaBase::AbortTransaction()
825 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
826 std::clog
<< "AbortTransaction: " << TransactionManager
<< std::endl
;
828 // ensure the toplevel is in error state too
829 for (std::vector
<pkgAcqTransactionItem
*>::iterator I
= Transaction
.begin();
830 I
!= Transaction
.end(); ++I
)
832 (*I
)->TransactionState(TransactionAbort
);
837 // AcqMetaBase::TransactionHasError - Check for errors in Transaction /*{{{*/
838 APT_PURE
bool pkgAcqMetaBase::TransactionHasError() const
840 for (std::vector
<pkgAcqTransactionItem
*>::const_iterator I
= Transaction
.begin();
841 I
!= Transaction
.end(); ++I
)
843 switch((*I
)->Status
) {
844 case StatDone
: break;
845 case StatIdle
: break;
846 case StatAuthError
: return true;
847 case StatError
: return true;
848 case StatTransientNetworkError
: return true;
849 case StatFetching
: break;
855 // AcqMetaBase::CommitTransaction - Commit a transaction /*{{{*/
856 void pkgAcqMetaBase::CommitTransaction()
858 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
859 std::clog
<< "CommitTransaction: " << this << std::endl
;
861 // move new files into place *and* remove files that are not
862 // part of the transaction but are still on disk
863 for (std::vector
<pkgAcqTransactionItem
*>::iterator I
= Transaction
.begin();
864 I
!= Transaction
.end(); ++I
)
866 (*I
)->TransactionState(TransactionCommit
);
871 // AcqMetaBase::TransactionStageCopy - Stage a file for copying /*{{{*/
872 void pkgAcqMetaBase::TransactionStageCopy(pkgAcqTransactionItem
* const I
,
873 const std::string
&From
,
874 const std::string
&To
)
876 I
->PartialFile
= From
;
880 // AcqMetaBase::TransactionStageRemoval - Stage a file for removal /*{{{*/
881 void pkgAcqMetaBase::TransactionStageRemoval(pkgAcqTransactionItem
* const I
,
882 const std::string
&FinalFile
)
885 I
->DestFile
= FinalFile
;
888 // AcqMetaBase::GenerateAuthWarning - Check gpg authentication error /*{{{*/
889 bool pkgAcqMetaBase::CheckStopAuthentication(pkgAcquire::Item
* const I
, const std::string
&Message
)
891 // FIXME: this entire function can do now that we disallow going to
892 // a unauthenticated state and can cleanly rollback
894 string
const Final
= I
->GetFinalFilename();
895 if(FileExists(Final
))
897 I
->Status
= StatTransientNetworkError
;
898 _error
->Warning(_("An error occurred during the signature "
899 "verification. The repository is not updated "
900 "and the previous index files will be used. "
901 "GPG error: %s: %s"),
902 Desc
.Description
.c_str(),
903 LookupTag(Message
,"Message").c_str());
904 RunScripts("APT::Update::Auth-Failure");
906 } else if (LookupTag(Message
,"Message").find("NODATA") != string::npos
) {
907 /* Invalid signature file, reject (LP: #346386) (Closes: #627642) */
908 _error
->Error(_("GPG error: %s: %s"),
909 Desc
.Description
.c_str(),
910 LookupTag(Message
,"Message").c_str());
911 I
->Status
= StatAuthError
;
914 _error
->Warning(_("GPG error: %s: %s"),
915 Desc
.Description
.c_str(),
916 LookupTag(Message
,"Message").c_str());
918 // gpgv method failed
919 ReportMirrorFailure("GPGFailure");
923 // AcqMetaBase::Custom600Headers - Get header for AcqMetaBase /*{{{*/
924 // ---------------------------------------------------------------------
925 string
pkgAcqMetaBase::Custom600Headers() const
927 std::string Header
= "\nIndex-File: true";
928 std::string MaximumSize
;
929 strprintf(MaximumSize
, "\nMaximum-Size: %i",
930 _config
->FindI("Acquire::MaxReleaseFileSize", 10*1000*1000));
931 Header
+= MaximumSize
;
933 string
const FinalFile
= GetFinalFilename();
935 if (stat(FinalFile
.c_str(),&Buf
) == 0)
936 Header
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
941 // AcqMetaBase::QueueForSignatureVerify /*{{{*/
942 void pkgAcqMetaBase::QueueForSignatureVerify(pkgAcqTransactionItem
* const I
, std::string
const &File
, std::string
const &Signature
)
945 I
->Desc
.URI
= "gpgv:" + Signature
;
948 I
->SetActiveSubprocess("gpgv");
951 // AcqMetaBase::CheckDownloadDone /*{{{*/
952 bool pkgAcqMetaBase::CheckDownloadDone(pkgAcqTransactionItem
* const I
, const std::string
&Message
, HashStringList
const &Hashes
) const
954 // We have just finished downloading a Release file (it is not
957 std::string
const FileName
= LookupTag(Message
,"Filename");
958 if (FileName
!= I
->DestFile
&& RealFileExists(I
->DestFile
) == false)
961 I
->Desc
.URI
= "copy:" + FileName
;
962 I
->QueueURI(I
->Desc
);
966 // make sure to verify against the right file on I-M-S hit
967 bool IMSHit
= StringToBool(LookupTag(Message
,"IMS-Hit"), false);
968 if (IMSHit
== false && Hashes
.usable())
970 // detect IMS-Hits servers haven't detected by Hash comparison
971 std::string
const FinalFile
= I
->GetFinalFilename();
972 if (RealFileExists(FinalFile
) && Hashes
.VerifyFile(FinalFile
) == true)
975 RemoveFile("CheckDownloadDone", I
->DestFile
);
981 // for simplicity, the transaction manager is always InRelease
982 // even if it doesn't exist.
983 if (TransactionManager
!= NULL
)
984 TransactionManager
->IMSHit
= true;
985 I
->PartialFile
= I
->DestFile
= I
->GetFinalFilename();
988 // set Item to complete as the remaining work is all local (verify etc)
994 bool pkgAcqMetaBase::CheckAuthDone(string
const &Message
) /*{{{*/
996 // At this point, the gpgv method has succeeded, so there is a
997 // valid signature from a key in the trusted keyring. We
998 // perform additional verification of its contents, and use them
999 // to verify the indexes we are about to download
1001 if (TransactionManager
->IMSHit
== false)
1003 // open the last (In)Release if we have it
1004 std::string
const FinalFile
= GetFinalFilename();
1005 std::string FinalRelease
;
1006 std::string FinalInRelease
;
1007 if (APT::String::Endswith(FinalFile
, "InRelease"))
1009 FinalInRelease
= FinalFile
;
1010 FinalRelease
= FinalFile
.substr(0, FinalFile
.length() - strlen("InRelease")) + "Release";
1014 FinalInRelease
= FinalFile
.substr(0, FinalFile
.length() - strlen("Release")) + "InRelease";
1015 FinalRelease
= FinalFile
;
1017 if (RealFileExists(FinalInRelease
) || RealFileExists(FinalRelease
))
1019 TransactionManager
->LastMetaIndexParser
= TransactionManager
->MetaIndexParser
->UnloadedClone();
1020 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1022 _error
->PushToStack();
1023 if (RealFileExists(FinalInRelease
))
1024 TransactionManager
->LastMetaIndexParser
->Load(FinalInRelease
, NULL
);
1026 TransactionManager
->LastMetaIndexParser
->Load(FinalRelease
, NULL
);
1027 // its unlikely to happen, but if what we have is bad ignore it
1028 if (_error
->PendingError())
1030 delete TransactionManager
->LastMetaIndexParser
;
1031 TransactionManager
->LastMetaIndexParser
= NULL
;
1033 _error
->RevertToStack();
1038 if (TransactionManager
->MetaIndexParser
->Load(DestFile
, &ErrorText
) == false)
1040 Status
= StatAuthError
;
1044 if (!VerifyVendor(Message
))
1046 Status
= StatAuthError
;
1050 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1051 std::cerr
<< "Signature verification succeeded: "
1052 << DestFile
<< std::endl
;
1054 // Download further indexes with verification
1060 void pkgAcqMetaBase::QueueIndexes(bool const verify
) /*{{{*/
1062 // at this point the real Items are loaded in the fetcher
1063 ExpectedAdditionalItems
= 0;
1065 bool metaBaseSupportsByHash
= false;
1066 if (TransactionManager
!= NULL
&& TransactionManager
->MetaIndexParser
!= NULL
)
1067 metaBaseSupportsByHash
= TransactionManager
->MetaIndexParser
->GetSupportsAcquireByHash();
1069 for (std::vector
<IndexTarget
>::iterator Target
= IndexTargets
.begin();
1070 Target
!= IndexTargets
.end();
1073 // all is an implementation detail. Users shouldn't use this as arch
1074 // We need this support trickery here as e.g. Debian has binary-all files already,
1075 // but arch:all packages are still in the arch:any files, so we would waste precious
1076 // download time, bandwidth and diskspace for nothing, BUT Debian doesn't feature all
1077 // in the set of supported architectures, so we can filter based on this property rather
1078 // than invent an entirely new flag we would need to carry for all of eternity.
1079 if (Target
->Option(IndexTarget::ARCHITECTURE
) == "all")
1081 if (TransactionManager
->MetaIndexParser
->IsArchitectureSupported("all") == false)
1083 if (TransactionManager
->MetaIndexParser
->IsArchitectureAllSupportedFor(*Target
) == false)
1087 bool trypdiff
= Target
->OptionBool(IndexTarget::PDIFFS
);
1090 if (TransactionManager
->MetaIndexParser
->Exists(Target
->MetaKey
) == false)
1092 // optional targets that we do not have in the Release file are skipped
1093 if (Target
->IsOptional
)
1096 std::string
const &arch
= Target
->Option(IndexTarget::ARCHITECTURE
);
1097 if (arch
.empty() == false)
1099 if (TransactionManager
->MetaIndexParser
->IsArchitectureSupported(arch
) == false)
1101 _error
->Notice(_("Skipping acquire of configured file '%s' as repository '%s' doesn't support architecture '%s'"),
1102 Target
->MetaKey
.c_str(), TransactionManager
->Target
.Description
.c_str(), arch
.c_str());
1105 // if the architecture is officially supported but currently no packages for it available,
1106 // ignore silently as this is pretty much the same as just shipping an empty file.
1107 // if we don't know which architectures are supported, we do NOT ignore it to notify user about this
1108 if (TransactionManager
->MetaIndexParser
->IsArchitectureSupported("*undefined*") == false)
1112 Status
= StatAuthError
;
1113 strprintf(ErrorText
, _("Unable to find expected entry '%s' in Release file (Wrong sources.list entry or malformed file)"), Target
->MetaKey
.c_str());
1118 auto const hashes
= GetExpectedHashesFor(Target
->MetaKey
);
1119 if (hashes
.usable() == false && hashes
.empty() == false)
1121 _error
->Warning(_("Skipping acquire of configured file '%s' as repository '%s' provides only weak security information for it"),
1122 Target
->MetaKey
.c_str(), TransactionManager
->Target
.Description
.c_str());
1127 // autoselect the compression method
1128 std::vector
<std::string
> types
= VectorizeString(Target
->Option(IndexTarget::COMPRESSIONTYPES
), ' ');
1129 types
.erase(std::remove_if(types
.begin(), types
.end(), [&](std::string
const &t
) {
1130 if (t
== "uncompressed")
1131 return TransactionManager
->MetaIndexParser
->Exists(Target
->MetaKey
) == false;
1132 std::string
const MetaKey
= Target
->MetaKey
+ "." + t
;
1133 return TransactionManager
->MetaIndexParser
->Exists(MetaKey
) == false;
1135 if (types
.empty() == false)
1137 std::ostringstream os
;
1138 // add the special compressiontype byhash first if supported
1139 std::string
const useByHashConf
= Target
->Option(IndexTarget::BY_HASH
);
1140 bool useByHash
= false;
1141 if(useByHashConf
== "force")
1144 useByHash
= StringToBool(useByHashConf
) == true && metaBaseSupportsByHash
;
1145 if (useByHash
== true)
1147 std::copy(types
.begin(), types
.end()-1, std::ostream_iterator
<std::string
>(os
, " "));
1148 os
<< *types
.rbegin();
1149 Target
->Options
["COMPRESSIONTYPES"] = os
.str();
1152 Target
->Options
["COMPRESSIONTYPES"].clear();
1154 std::string filename
= GetExistingFilename(GetFinalFileNameFromURI(Target
->URI
));
1155 if (filename
.empty() == false)
1157 // if the Release file is a hit and we have an index it must be the current one
1158 if (TransactionManager
->IMSHit
== true)
1160 else if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1162 // see if the file changed since the last Release file
1163 // we use the uncompressed files as we might compress differently compared to the server,
1164 // so the hashes might not match, even if they contain the same data.
1165 HashStringList
const newFile
= GetExpectedHashesFromFor(TransactionManager
->MetaIndexParser
, Target
->MetaKey
);
1166 HashStringList
const oldFile
= GetExpectedHashesFromFor(TransactionManager
->LastMetaIndexParser
, Target
->MetaKey
);
1167 if (newFile
!= oldFile
)
1174 trypdiff
= false; // no file to patch
1176 if (filename
.empty() == false)
1178 new NoActionItem(Owner
, *Target
, filename
);
1179 std::string
const idxfilename
= GetFinalFileNameFromURI(GetDiffIndexURI(*Target
));
1180 if (FileExists(idxfilename
))
1181 new NoActionItem(Owner
, *Target
, idxfilename
);
1185 // check if we have patches available
1186 trypdiff
&= TransactionManager
->MetaIndexParser
->Exists(GetDiffIndexFileName(Target
->MetaKey
));
1190 // if we have no file to patch, no point in trying
1191 trypdiff
&= (GetExistingFilename(GetFinalFileNameFromURI(Target
->URI
)).empty() == false);
1194 // no point in patching from local sources
1197 std::string
const proto
= Target
->URI
.substr(0, strlen("file:/"));
1198 if (proto
== "file:/" || proto
== "copy:/" || proto
== "cdrom:")
1202 // Queue the Index file (Packages, Sources, Translation-$foo, …)
1204 new pkgAcqDiffIndex(Owner
, TransactionManager
, *Target
);
1206 new pkgAcqIndex(Owner
, TransactionManager
, *Target
);
1210 bool pkgAcqMetaBase::VerifyVendor(string
const &Message
) /*{{{*/
1212 string::size_type pos
;
1214 // check for missing sigs (that where not fatal because otherwise we had
1217 string msg
= _("There is no public key available for the "
1218 "following key IDs:\n");
1219 pos
= Message
.find("NO_PUBKEY ");
1220 if (pos
!= std::string::npos
)
1222 string::size_type start
= pos
+strlen("NO_PUBKEY ");
1223 string Fingerprint
= Message
.substr(start
, Message
.find("\n")-start
);
1224 missingkeys
+= (Fingerprint
);
1226 if(!missingkeys
.empty())
1227 _error
->Warning("%s", (msg
+ missingkeys
).c_str());
1229 string Transformed
= TransactionManager
->MetaIndexParser
->GetExpectedDist();
1231 if (Transformed
== "../project/experimental")
1233 Transformed
= "experimental";
1236 pos
= Transformed
.rfind('/');
1237 if (pos
!= string::npos
)
1239 Transformed
= Transformed
.substr(0, pos
);
1242 if (Transformed
== ".")
1247 if (TransactionManager
->MetaIndexParser
->GetValidUntil() > 0)
1249 time_t const invalid_since
= time(NULL
) - TransactionManager
->MetaIndexParser
->GetValidUntil();
1250 if (invalid_since
> 0)
1254 // TRANSLATOR: The first %s is the URL of the bad Release file, the second is
1255 // the time since then the file is invalid - formatted in the same way as in
1256 // the download progress display (e.g. 7d 3h 42min 1s)
1257 _("Release file for %s is expired (invalid since %s). "
1258 "Updates for this repository will not be applied."),
1259 Target
.URI
.c_str(), TimeToStr(invalid_since
).c_str());
1260 if (ErrorText
.empty())
1262 return _error
->Error("%s", errmsg
.c_str());
1266 /* Did we get a file older than what we have? This is a last minute IMS hit and doubles
1267 as a prevention of downgrading us to older (still valid) files */
1268 if (TransactionManager
->IMSHit
== false && TransactionManager
->LastMetaIndexParser
!= NULL
&&
1269 TransactionManager
->LastMetaIndexParser
->GetDate() > TransactionManager
->MetaIndexParser
->GetDate())
1271 TransactionManager
->IMSHit
= true;
1272 RemoveFile("VerifyVendor", DestFile
);
1273 PartialFile
= DestFile
= GetFinalFilename();
1274 // load the 'old' file in the 'new' one instead of flipping pointers as
1275 // the new one isn't owned by us, while the old one is so cleanup would be confused.
1276 TransactionManager
->MetaIndexParser
->swapLoad(TransactionManager
->LastMetaIndexParser
);
1277 delete TransactionManager
->LastMetaIndexParser
;
1278 TransactionManager
->LastMetaIndexParser
= NULL
;
1281 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1283 std::cerr
<< "Got Codename: " << TransactionManager
->MetaIndexParser
->GetCodename() << std::endl
;
1284 std::cerr
<< "Expecting Dist: " << TransactionManager
->MetaIndexParser
->GetExpectedDist() << std::endl
;
1285 std::cerr
<< "Transformed Dist: " << Transformed
<< std::endl
;
1288 if (TransactionManager
->MetaIndexParser
->CheckDist(Transformed
) == false)
1290 // This might become fatal one day
1291 // Status = StatAuthError;
1292 // ErrorText = "Conflicting distribution; expected "
1293 // + MetaIndexParser->GetExpectedDist() + " but got "
1294 // + MetaIndexParser->GetCodename();
1296 if (!Transformed
.empty())
1298 _error
->Warning(_("Conflicting distribution: %s (expected %s but got %s)"),
1299 Desc
.Description
.c_str(),
1300 Transformed
.c_str(),
1301 TransactionManager
->MetaIndexParser
->GetCodename().c_str());
1308 pkgAcqMetaBase::~pkgAcqMetaBase()
1312 pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire
* const Owner
, /*{{{*/
1313 IndexTarget
const &ClearsignedTarget
,
1314 IndexTarget
const &DetachedDataTarget
, IndexTarget
const &DetachedSigTarget
,
1315 std::vector
<IndexTarget
> const &IndexTargets
,
1316 metaIndex
* const MetaIndexParser
) :
1317 pkgAcqMetaIndex(Owner
, this, ClearsignedTarget
, DetachedSigTarget
, IndexTargets
),
1318 d(NULL
), ClearsignedTarget(ClearsignedTarget
),
1319 DetachedDataTarget(DetachedDataTarget
),
1320 MetaIndexParser(MetaIndexParser
), LastMetaIndexParser(NULL
)
1322 // index targets + (worst case:) Release/Release.gpg
1323 ExpectedAdditionalItems
= IndexTargets
.size() + 2;
1324 TransactionManager
->Add(this);
1327 pkgAcqMetaClearSig::~pkgAcqMetaClearSig() /*{{{*/
1329 if (LastMetaIndexParser
!= NULL
)
1330 delete LastMetaIndexParser
;
1333 // pkgAcqMetaClearSig::Custom600Headers - Insert custom request headers /*{{{*/
1334 string
pkgAcqMetaClearSig::Custom600Headers() const
1336 string Header
= pkgAcqMetaBase::Custom600Headers();
1337 Header
+= "\nFail-Ignore: true";
1338 std::string
const key
= TransactionManager
->MetaIndexParser
->GetSignedBy();
1339 if (key
.empty() == false)
1340 Header
+= "\nSigned-By: " + key
;
1345 bool pkgAcqMetaClearSig::VerifyDone(std::string
const &Message
, /*{{{*/
1346 pkgAcquire::MethodConfig
const * const Cnf
)
1348 Item::VerifyDone(Message
, Cnf
);
1350 if (FileExists(DestFile
) && !StartsWithGPGClearTextSignature(DestFile
))
1351 return RenameOnError(NotClearsigned
);
1356 // pkgAcqMetaClearSig::Done - We got a file /*{{{*/
1357 void pkgAcqMetaClearSig::Done(std::string
const &Message
,
1358 HashStringList
const &Hashes
,
1359 pkgAcquire::MethodConfig
const * const Cnf
)
1361 Item::Done(Message
, Hashes
, Cnf
);
1363 if(AuthPass
== false)
1365 if(CheckDownloadDone(this, Message
, Hashes
) == true)
1366 QueueForSignatureVerify(this, DestFile
, DestFile
);
1369 else if(CheckAuthDone(Message
) == true)
1371 if (TransactionManager
->IMSHit
== false)
1372 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
1373 else if (RealFileExists(GetFinalFilename()) == false)
1375 // We got an InRelease file IMSHit, but we haven't one, which means
1376 // we had a valid Release/Release.gpg combo stepping in, which we have
1377 // to 'acquire' now to ensure list cleanup isn't removing them
1378 new NoActionItem(Owner
, DetachedDataTarget
);
1379 new NoActionItem(Owner
, DetachedSigTarget
);
1384 void pkgAcqMetaClearSig::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
) /*{{{*/
1386 Item::Failed(Message
, Cnf
);
1388 // we failed, we will not get additional items from this method
1389 ExpectedAdditionalItems
= 0;
1391 if (AuthPass
== false)
1393 if (Status
== StatAuthError
|| Status
== StatTransientNetworkError
)
1395 // if we expected a ClearTextSignature (InRelease) but got a network
1396 // error or got a file, but it wasn't valid, we end up here (see VerifyDone).
1397 // As these is usually called by web-portals we do not try Release/Release.gpg
1398 // as this is gonna fail anyway and instead abort our try (LP#346386)
1399 TransactionManager
->AbortTransaction();
1403 // Queue the 'old' InRelease file for removal if we try Release.gpg
1404 // as otherwise the file will stay around and gives a false-auth
1405 // impression (CVE-2012-0214)
1406 TransactionManager
->TransactionStageRemoval(this, GetFinalFilename());
1409 new pkgAcqMetaIndex(Owner
, TransactionManager
, DetachedDataTarget
, DetachedSigTarget
, IndexTargets
);
1413 if(CheckStopAuthentication(this, Message
))
1416 // No Release file was present, or verification failed, so fall
1417 // back to queueing Packages files without verification
1418 // only allow going further if the user explicitly wants it
1419 if(AllowInsecureRepositories(_("The repository '%s' is not signed."), ClearsignedTarget
.Description
, TransactionManager
->MetaIndexParser
, TransactionManager
, this) == true)
1423 /* InRelease files become Release files, otherwise
1424 * they would be considered as trusted later on */
1425 string
const FinalRelease
= GetFinalFileNameFromURI(DetachedDataTarget
.URI
);
1426 string
const PartialRelease
= GetPartialFileNameFromURI(DetachedDataTarget
.URI
);
1427 string
const FinalReleasegpg
= GetFinalFileNameFromURI(DetachedSigTarget
.URI
);
1428 string
const FinalInRelease
= GetFinalFilename();
1429 Rename(DestFile
, PartialRelease
);
1430 TransactionManager
->TransactionStageCopy(this, PartialRelease
, FinalRelease
);
1432 if (RealFileExists(FinalReleasegpg
) || RealFileExists(FinalInRelease
))
1434 // open the last Release if we have it
1435 if (TransactionManager
->IMSHit
== false)
1437 TransactionManager
->LastMetaIndexParser
= TransactionManager
->MetaIndexParser
->UnloadedClone();
1438 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1440 _error
->PushToStack();
1441 if (RealFileExists(FinalInRelease
))
1442 TransactionManager
->LastMetaIndexParser
->Load(FinalInRelease
, NULL
);
1444 TransactionManager
->LastMetaIndexParser
->Load(FinalRelease
, NULL
);
1445 // its unlikely to happen, but if what we have is bad ignore it
1446 if (_error
->PendingError())
1448 delete TransactionManager
->LastMetaIndexParser
;
1449 TransactionManager
->LastMetaIndexParser
= NULL
;
1451 _error
->RevertToStack();
1456 // we parse the indexes here because at this point the user wanted
1457 // a repository that may potentially harm him
1458 if (TransactionManager
->MetaIndexParser
->Load(PartialRelease
, &ErrorText
) == false || VerifyVendor(Message
) == false)
1459 /* expired Release files are still a problem you need extra force for */;
1467 pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire
* const Owner
, /*{{{*/
1468 pkgAcqMetaClearSig
* const TransactionManager
,
1469 IndexTarget
const &DataTarget
,
1470 IndexTarget
const &DetachedSigTarget
,
1471 vector
<IndexTarget
> const &IndexTargets
) :
1472 pkgAcqMetaBase(Owner
, TransactionManager
, IndexTargets
, DataTarget
), d(NULL
),
1473 DetachedSigTarget(DetachedSigTarget
)
1475 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1476 std::clog
<< "New pkgAcqMetaIndex with TransactionManager "
1477 << this->TransactionManager
<< std::endl
;
1479 DestFile
= GetPartialFileNameFromURI(DataTarget
.URI
);
1482 Desc
.Description
= DataTarget
.Description
;
1484 Desc
.ShortDesc
= DataTarget
.ShortDesc
;
1485 Desc
.URI
= DataTarget
.URI
;
1487 // we expect more item
1488 ExpectedAdditionalItems
= IndexTargets
.size();
1492 void pkgAcqMetaIndex::Done(string
const &Message
, /*{{{*/
1493 HashStringList
const &Hashes
,
1494 pkgAcquire::MethodConfig
const * const Cfg
)
1496 Item::Done(Message
,Hashes
,Cfg
);
1498 if(CheckDownloadDone(this, Message
, Hashes
))
1500 // we have a Release file, now download the Signature, all further
1501 // verify/queue for additional downloads will be done in the
1502 // pkgAcqMetaSig::Done() code
1503 new pkgAcqMetaSig(Owner
, TransactionManager
, DetachedSigTarget
, this);
1507 // pkgAcqMetaIndex::Failed - no Release file present /*{{{*/
1508 void pkgAcqMetaIndex::Failed(string
const &Message
,
1509 pkgAcquire::MethodConfig
const * const Cnf
)
1511 pkgAcquire::Item::Failed(Message
, Cnf
);
1514 // No Release file was present so fall
1515 // back to queueing Packages files without verification
1516 // only allow going further if the user explicitly wants it
1517 if(AllowInsecureRepositories(_("The repository '%s' does not have a Release file."), Target
.Description
, TransactionManager
->MetaIndexParser
, TransactionManager
, this) == true)
1519 // ensure old Release files are removed
1520 TransactionManager
->TransactionStageRemoval(this, GetFinalFilename());
1522 // queue without any kind of hashsum support
1523 QueueIndexes(false);
1527 void pkgAcqMetaIndex::Finished() /*{{{*/
1529 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1530 std::clog
<< "Finished: " << DestFile
<<std::endl
;
1531 if(TransactionManager
!= NULL
&&
1532 TransactionManager
->TransactionHasError() == false)
1533 TransactionManager
->CommitTransaction();
1536 std::string
pkgAcqMetaIndex::DescURI() const /*{{{*/
1541 pkgAcqMetaIndex::~pkgAcqMetaIndex() {}
1543 // AcqMetaSig::AcqMetaSig - Constructor /*{{{*/
1544 pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire
* const Owner
,
1545 pkgAcqMetaClearSig
* const TransactionManager
,
1546 IndexTarget
const &Target
,
1547 pkgAcqMetaIndex
* const MetaIndex
) :
1548 pkgAcqTransactionItem(Owner
, TransactionManager
, Target
), d(NULL
), MetaIndex(MetaIndex
)
1550 DestFile
= GetPartialFileNameFromURI(Target
.URI
);
1552 // remove any partial downloaded sig-file in partial/.
1553 // it may confuse proxies and is too small to warrant a
1554 // partial download anyway
1555 RemoveFile("pkgAcqMetaSig", DestFile
);
1557 // set the TransactionManager
1558 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1559 std::clog
<< "New pkgAcqMetaSig with TransactionManager "
1560 << TransactionManager
<< std::endl
;
1563 Desc
.Description
= Target
.Description
;
1565 Desc
.ShortDesc
= Target
.ShortDesc
;
1566 Desc
.URI
= Target
.URI
;
1568 // If we got a hit for Release, we will get one for Release.gpg too (or obscure errors),
1569 // so we skip the download step and go instantly to verification
1570 if (TransactionManager
->IMSHit
== true && RealFileExists(GetFinalFilename()))
1574 PartialFile
= DestFile
= GetFinalFilename();
1575 MetaIndexFileSignature
= DestFile
;
1576 MetaIndex
->QueueForSignatureVerify(this, MetaIndex
->DestFile
, DestFile
);
1582 pkgAcqMetaSig::~pkgAcqMetaSig() /*{{{*/
1586 // pkgAcqMetaSig::Custom600Headers - Insert custom request headers /*{{{*/
1587 std::string
pkgAcqMetaSig::Custom600Headers() const
1589 std::string Header
= pkgAcqTransactionItem::Custom600Headers();
1590 std::string
const key
= TransactionManager
->MetaIndexParser
->GetSignedBy();
1591 if (key
.empty() == false)
1592 Header
+= "\nSigned-By: " + key
;
1596 // AcqMetaSig::Done - The signature was downloaded/verified /*{{{*/
1597 void pkgAcqMetaSig::Done(string
const &Message
, HashStringList
const &Hashes
,
1598 pkgAcquire::MethodConfig
const * const Cfg
)
1600 if (MetaIndexFileSignature
.empty() == false)
1602 DestFile
= MetaIndexFileSignature
;
1603 MetaIndexFileSignature
.clear();
1605 Item::Done(Message
, Hashes
, Cfg
);
1607 if(MetaIndex
->AuthPass
== false)
1609 if(MetaIndex
->CheckDownloadDone(this, Message
, Hashes
) == true)
1611 // destfile will be modified to point to MetaIndexFile for the
1612 // gpgv method, so we need to save it here
1613 MetaIndexFileSignature
= DestFile
;
1614 MetaIndex
->QueueForSignatureVerify(this, MetaIndex
->DestFile
, DestFile
);
1618 else if(MetaIndex
->CheckAuthDone(Message
) == true)
1620 if (TransactionManager
->IMSHit
== false)
1622 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
1623 TransactionManager
->TransactionStageCopy(MetaIndex
, MetaIndex
->DestFile
, MetaIndex
->GetFinalFilename());
1628 void pkgAcqMetaSig::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
1630 Item::Failed(Message
,Cnf
);
1632 // check if we need to fail at this point
1633 if (MetaIndex
->AuthPass
== true && MetaIndex
->CheckStopAuthentication(this, Message
))
1636 string
const FinalRelease
= MetaIndex
->GetFinalFilename();
1637 string
const FinalReleasegpg
= GetFinalFilename();
1638 string
const FinalInRelease
= TransactionManager
->GetFinalFilename();
1640 if (RealFileExists(FinalReleasegpg
) || RealFileExists(FinalInRelease
))
1642 std::string downgrade_msg
;
1643 strprintf(downgrade_msg
, _("The repository '%s' is no longer signed."),
1644 MetaIndex
->Target
.Description
.c_str());
1645 if(_config
->FindB("Acquire::AllowDowngradeToInsecureRepositories"))
1647 // meh, the users wants to take risks (we still mark the packages
1648 // from this repository as unauthenticated)
1649 _error
->Warning("%s", downgrade_msg
.c_str());
1650 _error
->Warning(_("This is normally not allowed, but the option "
1651 "Acquire::AllowDowngradeToInsecureRepositories was "
1652 "given to override it."));
1655 MessageInsecureRepository(true, downgrade_msg
);
1656 if (TransactionManager
->IMSHit
== false)
1657 Rename(MetaIndex
->DestFile
, MetaIndex
->DestFile
+ ".FAILED");
1658 Item::Failed("Message: " + downgrade_msg
, Cnf
);
1659 TransactionManager
->AbortTransaction();
1664 // ensures that a Release.gpg file in the lists/ is removed by the transaction
1665 TransactionManager
->TransactionStageRemoval(this, DestFile
);
1667 // only allow going further if the user explicitly wants it
1668 if (AllowInsecureRepositories(_("The repository '%s' is not signed."), MetaIndex
->Target
.Description
, TransactionManager
->MetaIndexParser
, TransactionManager
, this) == true)
1670 if (RealFileExists(FinalReleasegpg
) || RealFileExists(FinalInRelease
))
1672 // open the last Release if we have it
1673 if (TransactionManager
->IMSHit
== false)
1675 TransactionManager
->LastMetaIndexParser
= TransactionManager
->MetaIndexParser
->UnloadedClone();
1676 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1678 _error
->PushToStack();
1679 if (RealFileExists(FinalInRelease
))
1680 TransactionManager
->LastMetaIndexParser
->Load(FinalInRelease
, NULL
);
1682 TransactionManager
->LastMetaIndexParser
->Load(FinalRelease
, NULL
);
1683 // its unlikely to happen, but if what we have is bad ignore it
1684 if (_error
->PendingError())
1686 delete TransactionManager
->LastMetaIndexParser
;
1687 TransactionManager
->LastMetaIndexParser
= NULL
;
1689 _error
->RevertToStack();
1694 // we parse the indexes here because at this point the user wanted
1695 // a repository that may potentially harm him
1696 bool const GoodLoad
= TransactionManager
->MetaIndexParser
->Load(MetaIndex
->DestFile
, &ErrorText
);
1697 if (MetaIndex
->VerifyVendor(Message
) == false)
1698 /* expired Release files are still a problem you need extra force for */;
1700 MetaIndex
->QueueIndexes(GoodLoad
);
1702 TransactionManager
->TransactionStageCopy(MetaIndex
, MetaIndex
->DestFile
, MetaIndex
->GetFinalFilename());
1705 // FIXME: this is used often (e.g. in pkgAcqIndexTrans) so refactor
1706 if (Cnf
->LocalOnly
== true ||
1707 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1716 // AcqBaseIndex - Constructor /*{{{*/
1717 pkgAcqBaseIndex::pkgAcqBaseIndex(pkgAcquire
* const Owner
,
1718 pkgAcqMetaClearSig
* const TransactionManager
,
1719 IndexTarget
const &Target
)
1720 : pkgAcqTransactionItem(Owner
, TransactionManager
, Target
), d(NULL
)
1724 pkgAcqBaseIndex::~pkgAcqBaseIndex() {}
1726 // AcqDiffIndex::AcqDiffIndex - Constructor /*{{{*/
1727 // ---------------------------------------------------------------------
1728 /* Get the DiffIndex file first and see if there are patches available
1729 * If so, create a pkgAcqIndexDiffs fetcher that will get and apply the
1730 * patches. If anything goes wrong in that process, it will fall back to
1731 * the original packages file
1733 pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire
* const Owner
,
1734 pkgAcqMetaClearSig
* const TransactionManager
,
1735 IndexTarget
const &Target
)
1736 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
), diffs(NULL
)
1738 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
1741 Desc
.Description
= GetDiffIndexFileName(Target
.Description
);
1742 Desc
.ShortDesc
= Target
.ShortDesc
;
1743 Desc
.URI
= GetDiffIndexURI(Target
);
1745 DestFile
= GetPartialFileNameFromURI(Desc
.URI
);
1748 std::clog
<< "pkgAcqDiffIndex: " << Desc
.URI
<< std::endl
;
1753 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
1754 // ---------------------------------------------------------------------
1755 /* The only header we use is the last-modified header. */
1756 string
pkgAcqDiffIndex::Custom600Headers() const
1758 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1759 return "\nIndex-File: true";
1761 string
const Final
= GetFinalFilename();
1764 std::clog
<< "Custom600Header-IMS: " << Final
<< std::endl
;
1767 if (stat(Final
.c_str(),&Buf
) != 0)
1768 return "\nIndex-File: true";
1770 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1773 void pkgAcqDiffIndex::QueueOnIMSHit() const /*{{{*/
1775 // list cleanup needs to know that this file as well as the already
1776 // present index is ours, so we create an empty diff to save it for us
1777 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
);
1780 bool pkgAcqDiffIndex::ParseDiffIndex(string
const &IndexDiffFile
) /*{{{*/
1782 // failing here is fine: our caller will take care of trying to
1783 // get the complete file if patching fails
1785 std::clog
<< "pkgAcqDiffIndex::ParseIndexDiff() " << IndexDiffFile
1788 FileFd
Fd(IndexDiffFile
,FileFd::ReadOnly
);
1790 if (Fd
.IsOpen() == false || Fd
.Failed())
1794 if(unlikely(TF
.Step(Tags
) == false))
1797 HashStringList ServerHashes
;
1798 unsigned long long ServerSize
= 0;
1800 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
1802 std::string tagname
= *type
;
1803 tagname
.append("-Current");
1804 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1805 if (tmp
.empty() == true)
1809 unsigned long long size
;
1810 std::stringstream
ss(tmp
);
1812 if (unlikely(hash
.empty() == true))
1814 if (unlikely(ServerSize
!= 0 && ServerSize
!= size
))
1816 ServerHashes
.push_back(HashString(*type
, hash
));
1820 if (ServerHashes
.usable() == false)
1823 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": Did not find a good hashsum in the index" << std::endl
;
1827 std::string
const CurrentPackagesFile
= GetFinalFileNameFromURI(Target
.URI
);
1828 HashStringList
const TargetFileHashes
= GetExpectedHashesFor(Target
.MetaKey
);
1829 if (TargetFileHashes
.usable() == false || ServerHashes
!= TargetFileHashes
)
1833 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": Index has different hashes than parser, probably older, so fail pdiffing" << std::endl
;
1834 printHashSumComparison(CurrentPackagesFile
, ServerHashes
, TargetFileHashes
);
1839 HashStringList LocalHashes
;
1840 // try avoiding calculating the hash here as this is costly
1841 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1842 LocalHashes
= GetExpectedHashesFromFor(TransactionManager
->LastMetaIndexParser
, Target
.MetaKey
);
1843 if (LocalHashes
.usable() == false)
1845 FileFd
fd(CurrentPackagesFile
, FileFd::ReadOnly
, FileFd::Auto
);
1846 Hashes
LocalHashesCalc(ServerHashes
);
1847 LocalHashesCalc
.AddFD(fd
);
1848 LocalHashes
= LocalHashesCalc
.GetHashStringList();
1851 if (ServerHashes
== LocalHashes
)
1853 // we have the same sha1 as the server so we are done here
1855 std::clog
<< "pkgAcqDiffIndex: Package file " << CurrentPackagesFile
<< " is up-to-date" << std::endl
;
1861 std::clog
<< "Server-Current: " << ServerHashes
.find(NULL
)->toStr() << " and we start at "
1862 << CurrentPackagesFile
<< " " << LocalHashes
.FileSize() << " " << LocalHashes
.find(NULL
)->toStr() << std::endl
;
1864 // historically, older hashes have more info than newer ones, so start
1865 // collecting with older ones first to avoid implementing complicated
1866 // information merging techniques… a failure is after all always
1867 // recoverable with a complete file and hashes aren't changed that often.
1868 std::vector
<char const *> types
;
1869 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
1870 types
.push_back(*type
);
1872 // parse all of (provided) history
1873 vector
<DiffInfo
> available_patches
;
1874 bool firstAcceptedHashes
= true;
1875 for (auto type
= types
.crbegin(); type
!= types
.crend(); ++type
)
1877 if (LocalHashes
.find(*type
) == NULL
)
1880 std::string tagname
= *type
;
1881 tagname
.append("-History");
1882 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1883 if (tmp
.empty() == true)
1886 string hash
, filename
;
1887 unsigned long long size
;
1888 std::stringstream
ss(tmp
);
1890 while (ss
>> hash
>> size
>> filename
)
1892 if (unlikely(hash
.empty() == true || filename
.empty() == true))
1895 // see if we have a record for this file already
1896 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
1897 for (; cur
!= available_patches
.end(); ++cur
)
1899 if (cur
->file
!= filename
)
1901 cur
->result_hashes
.push_back(HashString(*type
, hash
));
1904 if (cur
!= available_patches
.end())
1906 if (firstAcceptedHashes
== true)
1909 next
.file
= filename
;
1910 next
.result_hashes
.push_back(HashString(*type
, hash
));
1911 next
.result_hashes
.FileSize(size
);
1912 available_patches
.push_back(next
);
1917 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
1918 << " wasn't in the list for the first parsed hash! (history)" << std::endl
;
1922 firstAcceptedHashes
= false;
1925 if (unlikely(available_patches
.empty() == true))
1928 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": "
1929 << "Couldn't find any patches for the patch series." << std::endl
;
1933 for (auto type
= types
.crbegin(); type
!= types
.crend(); ++type
)
1935 if (LocalHashes
.find(*type
) == NULL
)
1938 std::string tagname
= *type
;
1939 tagname
.append("-Patches");
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 while (ss
>> hash
>> size
>> filename
)
1950 if (unlikely(hash
.empty() == true || filename
.empty() == true))
1953 // see if we have a record for this file already
1954 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
1955 for (; cur
!= available_patches
.end(); ++cur
)
1957 if (cur
->file
!= filename
)
1959 if (cur
->patch_hashes
.empty())
1960 cur
->patch_hashes
.FileSize(size
);
1961 cur
->patch_hashes
.push_back(HashString(*type
, hash
));
1964 if (cur
!= available_patches
.end())
1967 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
1968 << " wasn't in the list for the first parsed hash! (patches)" << std::endl
;
1973 for (auto type
= types
.crbegin(); type
!= types
.crend(); ++type
)
1975 std::string tagname
= *type
;
1976 tagname
.append("-Download");
1977 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1978 if (tmp
.empty() == true)
1981 string hash
, filename
;
1982 unsigned long long size
;
1983 std::stringstream
ss(tmp
);
1985 // FIXME: all of pdiff supports only .gz compressed patches
1986 while (ss
>> hash
>> size
>> filename
)
1988 if (unlikely(hash
.empty() == true || filename
.empty() == true))
1990 if (unlikely(APT::String::Endswith(filename
, ".gz") == false))
1992 filename
.erase(filename
.length() - 3);
1994 // see if we have a record for this file already
1995 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
1996 for (; cur
!= available_patches
.end(); ++cur
)
1998 if (cur
->file
!= filename
)
2000 if (cur
->download_hashes
.empty())
2001 cur
->download_hashes
.FileSize(size
);
2002 cur
->download_hashes
.push_back(HashString(*type
, hash
));
2005 if (cur
!= available_patches
.end())
2008 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
2009 << " wasn't in the list for the first parsed hash! (download)" << std::endl
;
2015 bool foundStart
= false;
2016 for (std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
2017 cur
!= available_patches
.end(); ++cur
)
2019 if (LocalHashes
!= cur
->result_hashes
)
2022 available_patches
.erase(available_patches
.begin(), cur
);
2027 if (foundStart
== false || unlikely(available_patches
.empty() == true))
2030 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": "
2031 << "Couldn't find the start of the patch series." << std::endl
;
2035 for (auto const &patch
: available_patches
)
2036 if (patch
.result_hashes
.usable() == false ||
2037 patch
.patch_hashes
.usable() == false ||
2038 patch
.download_hashes
.usable() == false)
2041 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": provides no usable hashes for " << patch
.file
2042 << " so fallback to complete download" << std::endl
;
2046 // patching with too many files is rather slow compared to a fast download
2047 unsigned long const fileLimit
= _config
->FindI("Acquire::PDiffs::FileLimit", 0);
2048 if (fileLimit
!= 0 && fileLimit
< available_patches
.size())
2051 std::clog
<< "Need " << available_patches
.size() << " diffs (Limit is " << fileLimit
2052 << ") so fallback to complete download" << std::endl
;
2056 // calculate the size of all patches we have to get
2057 unsigned short const sizeLimitPercent
= _config
->FindI("Acquire::PDiffs::SizeLimit", 100);
2058 if (sizeLimitPercent
> 0 && TransactionManager
->MetaIndexParser
!= nullptr)
2060 unsigned long long downloadSize
= std::accumulate(available_patches
.begin(),
2061 available_patches
.end(), 0llu, [](unsigned long long const T
, DiffInfo
const &I
) {
2062 return T
+ I
.download_hashes
.FileSize();
2064 if (downloadSize
!= 0)
2066 unsigned long long downloadSizeIdx
= 0;
2067 auto const types
= VectorizeString(Target
.Option(IndexTarget::COMPRESSIONTYPES
), ' ');
2068 for (auto const &t
: types
)
2070 std::string MetaKey
= Target
.MetaKey
;
2071 if (t
!= "uncompressed")
2073 HashStringList
const hsl
= GetExpectedHashesFor(MetaKey
);
2074 if (unlikely(hsl
.usable() == false))
2076 downloadSizeIdx
= hsl
.FileSize();
2079 unsigned long long const sizeLimit
= downloadSizeIdx
* sizeLimitPercent
;
2080 if ((sizeLimit
/100) < downloadSize
)
2083 std::clog
<< "Need " << downloadSize
<< " compressed bytes (Limit is " << (sizeLimit
/100) << ", "
2084 << "original is " << downloadSizeIdx
<< ") so fallback to complete download" << std::endl
;
2090 // we have something, queue the diffs
2091 string::size_type
const last_space
= Description
.rfind(" ");
2092 if(last_space
!= string::npos
)
2093 Description
.erase(last_space
, Description
.size()-last_space
);
2095 /* decide if we should download patches one by one or in one go:
2096 The first is good if the server merges patches, but many don't so client
2097 based merging can be attempt in which case the second is better.
2098 "bad things" will happen if patches are merged on the server,
2099 but client side merging is attempt as well */
2100 bool pdiff_merge
= _config
->FindB("Acquire::PDiffs::Merge", true);
2101 if (pdiff_merge
== true)
2103 // reprepro adds this flag if it has merged patches on the server
2104 std::string
const precedence
= Tags
.FindS("X-Patch-Precedence");
2105 pdiff_merge
= (precedence
!= "merged");
2110 std::string
const Final
= GetExistingFilename(CurrentPackagesFile
);
2111 if (unlikely(Final
.empty())) // because we wouldn't be called in such a case
2113 std::string
const PartialFile
= GetPartialFileNameFromURI(Target
.URI
);
2114 if (FileExists(PartialFile
) && RemoveFile("Bootstrap-linking", PartialFile
) == false)
2117 std::clog
<< "Bootstrap-linking for patching " << CurrentPackagesFile
2118 << " by removing stale " << PartialFile
<< " failed!" << std::endl
;
2121 for (auto const &ext
: APT::Configuration::getCompressorExtensions())
2123 std::string
const Partial
= PartialFile
+ ext
;
2124 if (FileExists(Partial
) && RemoveFile("Bootstrap-linking", Partial
) == false)
2127 std::clog
<< "Bootstrap-linking for patching " << CurrentPackagesFile
2128 << " by removing stale " << Partial
<< " failed!" << std::endl
;
2132 std::string
const Ext
= Final
.substr(CurrentPackagesFile
.length());
2133 std::string
const Partial
= PartialFile
+ Ext
;
2134 if (symlink(Final
.c_str(), Partial
.c_str()) != 0)
2137 std::clog
<< "Bootstrap-linking for patching " << CurrentPackagesFile
2138 << " by linking " << Final
<< " to " << Partial
<< " failed!" << std::endl
;
2143 if (pdiff_merge
== false)
2144 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
, available_patches
);
2147 diffs
= new std::vector
<pkgAcqIndexMergeDiffs
*>(available_patches
.size());
2148 for(size_t i
= 0; i
< available_patches
.size(); ++i
)
2149 (*diffs
)[i
] = new pkgAcqIndexMergeDiffs(Owner
, TransactionManager
,
2151 available_patches
[i
],
2161 void pkgAcqDiffIndex::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
2163 Item::Failed(Message
,Cnf
);
2167 std::clog
<< "pkgAcqDiffIndex failed: " << Desc
.URI
<< " with " << Message
<< std::endl
2168 << "Falling back to normal index file acquire" << std::endl
;
2170 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
2173 void pkgAcqDiffIndex::Done(string
const &Message
,HashStringList
const &Hashes
, /*{{{*/
2174 pkgAcquire::MethodConfig
const * const Cnf
)
2177 std::clog
<< "pkgAcqDiffIndex::Done(): " << Desc
.URI
<< std::endl
;
2179 Item::Done(Message
, Hashes
, Cnf
);
2181 string
const FinalFile
= GetFinalFilename();
2182 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false))
2183 DestFile
= FinalFile
;
2185 if(ParseDiffIndex(DestFile
) == false)
2187 Failed("Message: Couldn't parse pdiff index", Cnf
);
2188 // queue for final move - this should happen even if we fail
2189 // while parsing (e.g. on sizelimit) and download the complete file.
2190 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
2194 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
2203 pkgAcqDiffIndex::~pkgAcqDiffIndex()
2209 // AcqIndexDiffs::AcqIndexDiffs - Constructor /*{{{*/
2210 // ---------------------------------------------------------------------
2211 /* The package diff is added to the queue. one object is constructed
2212 * for each diff and the index
2214 pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire
* const Owner
,
2215 pkgAcqMetaClearSig
* const TransactionManager
,
2216 IndexTarget
const &Target
,
2217 vector
<DiffInfo
> const &diffs
)
2218 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
),
2219 available_patches(diffs
)
2221 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
2223 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
2226 Description
= Target
.Description
;
2227 Desc
.ShortDesc
= Target
.ShortDesc
;
2229 if(available_patches
.empty() == true)
2231 // we are done (yeah!), check hashes against the final file
2232 DestFile
= GetKeepCompressedFileName(GetFinalFileNameFromURI(Target
.URI
), Target
);
2237 State
= StateFetchDiff
;
2242 void pkgAcqIndexDiffs::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
2244 Item::Failed(Message
,Cnf
);
2247 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
2249 std::clog
<< "pkgAcqIndexDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
2250 << "Falling back to normal index file acquire " << std::endl
;
2251 RenameOnError(PDiffError
);
2252 std::string
const patchname
= GetDiffsPatchFileName(DestFile
);
2253 if (RealFileExists(patchname
))
2254 Rename(patchname
, patchname
+ ".FAILED");
2255 std::string
const UnpatchedFile
= GetExistingFilename(GetPartialFileNameFromURI(Target
.URI
));
2256 if (UnpatchedFile
.empty() == false && FileExists(UnpatchedFile
))
2257 Rename(UnpatchedFile
, UnpatchedFile
+ ".FAILED");
2258 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
2262 // Finish - helper that cleans the item out of the fetcher queue /*{{{*/
2263 void pkgAcqIndexDiffs::Finish(bool allDone
)
2266 std::clog
<< "pkgAcqIndexDiffs::Finish(): "
2268 << Desc
.URI
<< std::endl
;
2270 // we restore the original name, this is required, otherwise
2271 // the file will be cleaned
2274 std::string
const Final
= GetKeepCompressedFileName(GetFinalFilename(), Target
);
2275 TransactionManager
->TransactionStageCopy(this, DestFile
, Final
);
2277 // this is for the "real" finish
2282 std::clog
<< "\n\nallDone: " << DestFile
<< "\n" << std::endl
;
2289 std::clog
<< "Finishing: " << Desc
.URI
<< std::endl
;
2296 bool pkgAcqIndexDiffs::QueueNextDiff() /*{{{*/
2298 // calc sha1 of the just patched file
2299 std::string
const PartialFile
= GetExistingFilename(GetPartialFileNameFromURI(Target
.URI
));
2300 if(unlikely(PartialFile
.empty()))
2302 Failed("Message: The file " + GetPartialFileNameFromURI(Target
.URI
) + " isn't available", NULL
);
2306 FileFd
fd(PartialFile
, FileFd::ReadOnly
, FileFd::Extension
);
2307 Hashes LocalHashesCalc
;
2308 LocalHashesCalc
.AddFD(fd
);
2309 HashStringList
const LocalHashes
= LocalHashesCalc
.GetHashStringList();
2312 std::clog
<< "QueueNextDiff: " << PartialFile
<< " (" << LocalHashes
.find(NULL
)->toStr() << ")" << std::endl
;
2314 HashStringList
const TargetFileHashes
= GetExpectedHashesFor(Target
.MetaKey
);
2315 if (unlikely(LocalHashes
.usable() == false || TargetFileHashes
.usable() == false))
2317 Failed("Local/Expected hashes are not usable for " + PartialFile
, NULL
);
2321 // final file reached before all patches are applied
2322 if(LocalHashes
== TargetFileHashes
)
2328 // remove all patches until the next matching patch is found
2329 // this requires the Index file to be ordered
2330 available_patches
.erase(available_patches
.begin(),
2331 std::find_if(available_patches
.begin(), available_patches
.end(), [&](DiffInfo
const &I
) {
2332 return I
.result_hashes
== LocalHashes
;
2335 // error checking and falling back if no patch was found
2336 if(available_patches
.empty() == true)
2338 Failed("No patches left to reach target for " + PartialFile
, NULL
);
2342 // queue the right diff
2343 Desc
.URI
= Target
.URI
+ ".diff/" + available_patches
[0].file
+ ".gz";
2344 Desc
.Description
= Description
+ " " + available_patches
[0].file
+ string(".pdiff");
2345 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
+ ".diff/" + available_patches
[0].file
), Target
);
2348 std::clog
<< "pkgAcqIndexDiffs::QueueNextDiff(): " << Desc
.URI
<< std::endl
;
2355 void pkgAcqIndexDiffs::Done(string
const &Message
, HashStringList
const &Hashes
, /*{{{*/
2356 pkgAcquire::MethodConfig
const * const Cnf
)
2359 std::clog
<< "pkgAcqIndexDiffs::Done(): " << Desc
.URI
<< std::endl
;
2361 Item::Done(Message
, Hashes
, Cnf
);
2363 std::string
const UncompressedUnpatchedFile
= GetPartialFileNameFromURI(Target
.URI
);
2364 std::string
const UnpatchedFile
= GetExistingFilename(UncompressedUnpatchedFile
);
2365 std::string
const PatchFile
= GetDiffsPatchFileName(UnpatchedFile
);
2366 std::string
const PatchedFile
= GetKeepCompressedFileName(UncompressedUnpatchedFile
, Target
);
2370 // success in downloading a diff, enter ApplyDiff state
2371 case StateFetchDiff
:
2372 Rename(DestFile
, PatchFile
);
2373 DestFile
= GetKeepCompressedFileName(UncompressedUnpatchedFile
+ "-patched", Target
);
2375 std::clog
<< "Sending to rred method: " << UnpatchedFile
<< std::endl
;
2376 State
= StateApplyDiff
;
2378 Desc
.URI
= "rred:" + UnpatchedFile
;
2380 SetActiveSubprocess("rred");
2382 // success in download/apply a diff, queue next (if needed)
2383 case StateApplyDiff
:
2384 // remove the just applied patch and base file
2385 available_patches
.erase(available_patches
.begin());
2386 RemoveFile("pkgAcqIndexDiffs::Done", PatchFile
);
2387 RemoveFile("pkgAcqIndexDiffs::Done", UnpatchedFile
);
2389 std::clog
<< "Moving patched file in place: " << std::endl
2390 << DestFile
<< " -> " << PatchedFile
<< std::endl
;
2391 Rename(DestFile
, PatchedFile
);
2393 // see if there is more to download
2394 if(available_patches
.empty() == false)
2396 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
, available_patches
);
2399 DestFile
= PatchedFile
;
2406 std::string
pkgAcqIndexDiffs::Custom600Headers() const /*{{{*/
2408 if(State
!= StateApplyDiff
)
2409 return pkgAcqBaseIndex::Custom600Headers();
2410 std::ostringstream patchhashes
;
2411 HashStringList
const ExpectedHashes
= available_patches
[0].patch_hashes
;
2412 for (HashStringList::const_iterator hs
= ExpectedHashes
.begin(); hs
!= ExpectedHashes
.end(); ++hs
)
2413 patchhashes
<< "\nPatch-0-" << hs
->HashType() << "-Hash: " << hs
->HashValue();
2414 patchhashes
<< pkgAcqBaseIndex::Custom600Headers();
2415 return patchhashes
.str();
2418 pkgAcqIndexDiffs::~pkgAcqIndexDiffs() {}
2420 // AcqIndexMergeDiffs::AcqIndexMergeDiffs - Constructor /*{{{*/
2421 pkgAcqIndexMergeDiffs::pkgAcqIndexMergeDiffs(pkgAcquire
* const Owner
,
2422 pkgAcqMetaClearSig
* const TransactionManager
,
2423 IndexTarget
const &Target
,
2424 DiffInfo
const &patch
,
2425 std::vector
<pkgAcqIndexMergeDiffs
*> const * const allPatches
)
2426 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
),
2427 patch(patch
), allPatches(allPatches
), State(StateFetchDiff
)
2429 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
2432 Description
= Target
.Description
;
2433 Desc
.ShortDesc
= Target
.ShortDesc
;
2434 Desc
.URI
= Target
.URI
+ ".diff/" + patch
.file
+ ".gz";
2435 Desc
.Description
= Description
+ " " + patch
.file
+ ".pdiff";
2436 DestFile
= GetPartialFileNameFromURI(Desc
.URI
);
2439 std::clog
<< "pkgAcqIndexMergeDiffs: " << Desc
.URI
<< std::endl
;
2444 void pkgAcqIndexMergeDiffs::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
2447 std::clog
<< "pkgAcqIndexMergeDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
;
2449 Item::Failed(Message
,Cnf
);
2452 // check if we are the first to fail, otherwise we are done here
2453 State
= StateDoneDiff
;
2454 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2455 I
!= allPatches
->end(); ++I
)
2456 if ((*I
)->State
== StateErrorDiff
)
2458 State
= StateErrorDiff
;
2462 // first failure means we should fallback
2463 State
= StateErrorDiff
;
2465 std::clog
<< "Falling back to normal index file acquire" << std::endl
;
2466 RenameOnError(PDiffError
);
2467 if (RealFileExists(DestFile
))
2468 Rename(DestFile
, DestFile
+ ".FAILED");
2469 std::string
const UnpatchedFile
= GetExistingFilename(GetPartialFileNameFromURI(Target
.URI
));
2470 if (UnpatchedFile
.empty() == false && FileExists(UnpatchedFile
))
2471 Rename(UnpatchedFile
, UnpatchedFile
+ ".FAILED");
2473 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
2476 void pkgAcqIndexMergeDiffs::Done(string
const &Message
, HashStringList
const &Hashes
, /*{{{*/
2477 pkgAcquire::MethodConfig
const * const Cnf
)
2480 std::clog
<< "pkgAcqIndexMergeDiffs::Done(): " << Desc
.URI
<< std::endl
;
2482 Item::Done(Message
, Hashes
, Cnf
);
2484 if (std::any_of(allPatches
->begin(), allPatches
->end(),
2485 [](pkgAcqIndexMergeDiffs
const * const P
) { return P
->State
== StateErrorDiff
; }))
2488 std::clog
<< "Another patch failed already, no point in processing this one." << std::endl
;
2489 State
= StateErrorDiff
;
2493 std::string
const UncompressedUnpatchedFile
= GetPartialFileNameFromURI(Target
.URI
);
2494 std::string
const UnpatchedFile
= GetExistingFilename(UncompressedUnpatchedFile
);
2495 if (UnpatchedFile
.empty())
2497 _error
->Fatal("Unpatched file %s doesn't exist (anymore)!", UncompressedUnpatchedFile
.c_str());
2498 State
= StateErrorDiff
;
2501 std::string
const PatchFile
= GetMergeDiffsPatchFileName(UnpatchedFile
, patch
.file
);
2502 std::string
const PatchedFile
= GetKeepCompressedFileName(UncompressedUnpatchedFile
, Target
);
2506 case StateFetchDiff
:
2507 Rename(DestFile
, PatchFile
);
2509 // check if this is the last completed diff
2510 State
= StateDoneDiff
;
2511 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2512 I
!= allPatches
->end(); ++I
)
2513 if ((*I
)->State
!= StateDoneDiff
)
2516 std::clog
<< "Not the last done diff in the batch: " << Desc
.URI
<< std::endl
;
2519 // this is the last completed diff, so we are ready to apply now
2520 DestFile
= GetKeepCompressedFileName(UncompressedUnpatchedFile
+ "-patched", Target
);
2522 std::clog
<< "Sending to rred method: " << UnpatchedFile
<< std::endl
;
2523 State
= StateApplyDiff
;
2525 Desc
.URI
= "rred:" + UnpatchedFile
;
2527 SetActiveSubprocess("rred");
2529 case StateApplyDiff
:
2530 // success in download & apply all diffs, finialize and clean up
2532 std::clog
<< "Queue patched file in place: " << std::endl
2533 << DestFile
<< " -> " << PatchedFile
<< std::endl
;
2535 // queue for copy by the transaction manager
2536 TransactionManager
->TransactionStageCopy(this, DestFile
, GetKeepCompressedFileName(GetFinalFilename(), Target
));
2538 // ensure the ed's are gone regardless of list-cleanup
2539 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2540 I
!= allPatches
->end(); ++I
)
2541 RemoveFile("pkgAcqIndexMergeDiffs::Done", GetMergeDiffsPatchFileName(UnpatchedFile
, (*I
)->patch
.file
));
2542 RemoveFile("pkgAcqIndexMergeDiffs::Done", UnpatchedFile
);
2547 std::clog
<< "allDone: " << DestFile
<< "\n" << std::endl
;
2549 case StateDoneDiff
: _error
->Fatal("Done called for %s which is in an invalid Done state", PatchFile
.c_str()); break;
2550 case StateErrorDiff
: _error
->Fatal("Done called for %s which is in an invalid Error state", PatchFile
.c_str()); break;
2554 std::string
pkgAcqIndexMergeDiffs::Custom600Headers() const /*{{{*/
2556 if(State
!= StateApplyDiff
)
2557 return pkgAcqBaseIndex::Custom600Headers();
2558 std::ostringstream patchhashes
;
2559 unsigned int seen_patches
= 0;
2560 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2561 I
!= allPatches
->end(); ++I
)
2563 HashStringList
const ExpectedHashes
= (*I
)->patch
.patch_hashes
;
2564 for (HashStringList::const_iterator hs
= ExpectedHashes
.begin(); hs
!= ExpectedHashes
.end(); ++hs
)
2565 patchhashes
<< "\nPatch-" << seen_patches
<< "-" << hs
->HashType() << "-Hash: " << hs
->HashValue();
2568 patchhashes
<< pkgAcqBaseIndex::Custom600Headers();
2569 return patchhashes
.str();
2572 pkgAcqIndexMergeDiffs::~pkgAcqIndexMergeDiffs() {}
2574 // AcqIndex::AcqIndex - Constructor /*{{{*/
2575 pkgAcqIndex::pkgAcqIndex(pkgAcquire
* const Owner
,
2576 pkgAcqMetaClearSig
* const TransactionManager
,
2577 IndexTarget
const &Target
)
2578 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
), Stage(STAGE_DOWNLOAD
),
2579 CompressionExtensions(Target
.Option(IndexTarget::COMPRESSIONTYPES
))
2581 Init(Target
.URI
, Target
.Description
, Target
.ShortDesc
);
2583 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
2584 std::clog
<< "New pkgIndex with TransactionManager "
2585 << TransactionManager
<< std::endl
;
2588 // AcqIndex::Init - defered Constructor /*{{{*/
2589 static void NextCompressionExtension(std::string
&CurrentCompressionExtension
, std::string
&CompressionExtensions
, bool const preview
)
2591 size_t const nextExt
= CompressionExtensions
.find(' ');
2592 if (nextExt
== std::string::npos
)
2594 CurrentCompressionExtension
= CompressionExtensions
;
2595 if (preview
== false)
2596 CompressionExtensions
.clear();
2600 CurrentCompressionExtension
= CompressionExtensions
.substr(0, nextExt
);
2601 if (preview
== false)
2602 CompressionExtensions
= CompressionExtensions
.substr(nextExt
+1);
2605 void pkgAcqIndex::Init(string
const &URI
, string
const &URIDesc
,
2606 string
const &ShortDesc
)
2608 Stage
= STAGE_DOWNLOAD
;
2610 DestFile
= GetPartialFileNameFromURI(URI
);
2611 NextCompressionExtension(CurrentCompressionExtension
, CompressionExtensions
, false);
2613 if (CurrentCompressionExtension
== "uncompressed")
2617 else if (CurrentCompressionExtension
== "by-hash")
2619 NextCompressionExtension(CurrentCompressionExtension
, CompressionExtensions
, true);
2620 if(unlikely(TransactionManager
->MetaIndexParser
== NULL
|| CurrentCompressionExtension
.empty()))
2622 if (CurrentCompressionExtension
!= "uncompressed")
2624 Desc
.URI
= URI
+ '.' + CurrentCompressionExtension
;
2625 DestFile
= DestFile
+ '.' + CurrentCompressionExtension
;
2628 HashStringList
const Hashes
= GetExpectedHashes();
2629 HashString
const * const TargetHash
= Hashes
.find(NULL
);
2630 if (unlikely(TargetHash
== nullptr))
2632 std::string
const ByHash
= "/by-hash/" + TargetHash
->HashType() + "/" + TargetHash
->HashValue();
2633 size_t const trailing_slash
= Desc
.URI
.find_last_of("/");
2634 if (unlikely(trailing_slash
== std::string::npos
))
2636 Desc
.URI
= Desc
.URI
.replace(
2638 Desc
.URI
.substr(trailing_slash
+1).size()+1,
2641 else if (unlikely(CurrentCompressionExtension
.empty()))
2645 Desc
.URI
= URI
+ '.' + CurrentCompressionExtension
;
2646 DestFile
= DestFile
+ '.' + CurrentCompressionExtension
;
2650 Desc
.Description
= URIDesc
;
2652 Desc
.ShortDesc
= ShortDesc
;
2657 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
2658 // ---------------------------------------------------------------------
2659 /* The only header we use is the last-modified header. */
2660 string
pkgAcqIndex::Custom600Headers() const
2663 string msg
= "\nIndex-File: true";
2665 if (TransactionManager
->LastMetaIndexParser
== NULL
)
2667 std::string
const Final
= GetFinalFilename();
2670 if (stat(Final
.c_str(),&Buf
) == 0)
2671 msg
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
2674 if(Target
.IsOptional
)
2675 msg
+= "\nFail-Ignore: true";
2680 // AcqIndex::Failed - getting the indexfile failed /*{{{*/
2681 void pkgAcqIndex::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)
2683 Item::Failed(Message
,Cnf
);
2685 // authorisation matches will not be fixed by other compression types
2686 if (Status
!= StatAuthError
)
2688 if (CompressionExtensions
.empty() == false)
2690 Init(Target
.URI
, Desc
.Description
, Desc
.ShortDesc
);
2696 if(Target
.IsOptional
&& GetExpectedHashes().empty() && Stage
== STAGE_DOWNLOAD
)
2699 TransactionManager
->AbortTransaction();
2702 // AcqIndex::Done - Finished a fetch /*{{{*/
2703 // ---------------------------------------------------------------------
2704 /* This goes through a number of states.. On the initial fetch the
2705 method could possibly return an alternate filename which points
2706 to the uncompressed version of the file. If this is so the file
2707 is copied into the partial directory. In all other cases the file
2708 is decompressed with a compressed uri. */
2709 void pkgAcqIndex::Done(string
const &Message
,
2710 HashStringList
const &Hashes
,
2711 pkgAcquire::MethodConfig
const * const Cfg
)
2713 Item::Done(Message
,Hashes
,Cfg
);
2717 case STAGE_DOWNLOAD
:
2718 StageDownloadDone(Message
);
2720 case STAGE_DECOMPRESS_AND_VERIFY
:
2721 StageDecompressDone();
2726 // AcqIndex::StageDownloadDone - Queue for decompress and verify /*{{{*/
2727 void pkgAcqIndex::StageDownloadDone(string
const &Message
)
2732 std::string
const AltFilename
= LookupTag(Message
,"Alt-Filename");
2733 std::string Filename
= LookupTag(Message
,"Filename");
2735 // we need to verify the file against the current Release file again
2736 // on if-modfied-since hit to avoid a stale attack against us
2737 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
2739 // copy FinalFile into partial/ so that we check the hash again
2740 string
const FinalFile
= GetExistingFilename(GetFinalFileNameFromURI(Target
.URI
));
2741 if (symlink(FinalFile
.c_str(), DestFile
.c_str()) != 0)
2742 _error
->WarningE("pkgAcqIndex::StageDownloadDone", "Symlinking final file %s back to %s failed", FinalFile
.c_str(), DestFile
.c_str());
2745 EraseFileName
= DestFile
;
2746 Filename
= DestFile
;
2748 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
2749 Desc
.URI
= "store:" + Filename
;
2751 SetActiveSubprocess(::URI(Desc
.URI
).Access
);
2754 // methods like file:// give us an alternative (uncompressed) file
2755 else if (Target
.KeepCompressed
== false && AltFilename
.empty() == false)
2757 if (CurrentCompressionExtension
!= "uncompressed")
2758 DestFile
.erase(DestFile
.length() - (CurrentCompressionExtension
.length() + 1));
2759 Filename
= AltFilename
;
2761 // Methods like e.g. "file:" will give us a (compressed) FileName that is
2762 // not the "DestFile" we set, in this case we uncompress from the local file
2763 else if (Filename
!= DestFile
&& RealFileExists(DestFile
) == false)
2765 // symlinking ensures that the filename can be used for compression detection
2766 // that is e.g. needed for by-hash which has no extension over file
2767 if (symlink(Filename
.c_str(),DestFile
.c_str()) != 0)
2768 _error
->WarningE("pkgAcqIndex::StageDownloadDone", "Symlinking file %s to %s failed", Filename
.c_str(), DestFile
.c_str());
2771 EraseFileName
= DestFile
;
2772 Filename
= DestFile
;
2776 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
2777 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
2778 if (Filename
!= DestFile
&& flExtension(Filename
) == flExtension(DestFile
))
2779 Desc
.URI
= "copy:" + Filename
;
2781 Desc
.URI
= "store:" + Filename
;
2782 if (DestFile
== Filename
)
2784 if (CurrentCompressionExtension
== "uncompressed")
2785 return StageDecompressDone();
2786 DestFile
= "/dev/null";
2789 if (EraseFileName
.empty())
2790 EraseFileName
= Filename
;
2792 // queue uri for the next stage
2794 SetActiveSubprocess(::URI(Desc
.URI
).Access
);
2797 // AcqIndex::StageDecompressDone - Final verification /*{{{*/
2798 void pkgAcqIndex::StageDecompressDone()
2800 if (DestFile
== "/dev/null")
2801 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
2803 // Done, queue for rename on transaction finished
2804 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
2807 pkgAcqIndex::~pkgAcqIndex() {}
2810 // AcqArchive::AcqArchive - Constructor /*{{{*/
2811 // ---------------------------------------------------------------------
2812 /* This just sets up the initial fetch environment and queues the first
2814 pkgAcqArchive::pkgAcqArchive(pkgAcquire
* const Owner
,pkgSourceList
* const Sources
,
2815 pkgRecords
* const Recs
,pkgCache::VerIterator
const &Version
,
2816 string
&StoreFilename
) :
2817 Item(Owner
), d(NULL
), LocalSource(false), Version(Version
), Sources(Sources
), Recs(Recs
),
2818 StoreFilename(StoreFilename
), Vf(Version
.FileList()),
2821 Retries
= _config
->FindI("Acquire::Retries",0);
2823 if (Version
.Arch() == 0)
2825 _error
->Error(_("I wasn't able to locate a file for the %s package. "
2826 "This might mean you need to manually fix this package. "
2827 "(due to missing arch)"),
2828 Version
.ParentPkg().FullName().c_str());
2832 /* We need to find a filename to determine the extension. We make the
2833 assumption here that all the available sources for this version share
2834 the same extension.. */
2835 // Skip not source sources, they do not have file fields.
2836 for (; Vf
.end() == false; ++Vf
)
2838 if (Vf
.File().Flagged(pkgCache::Flag::NotSource
))
2843 // Does not really matter here.. we are going to fail out below
2844 if (Vf
.end() != true)
2846 // If this fails to get a file name we will bomb out below.
2847 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2848 if (_error
->PendingError() == true)
2851 // Generate the final file name as: package_version_arch.foo
2852 StoreFilename
= QuoteString(Version
.ParentPkg().Name(),"_:") + '_' +
2853 QuoteString(Version
.VerStr(),"_:") + '_' +
2854 QuoteString(Version
.Arch(),"_:.") +
2855 "." + flExtension(Parse
.FileName());
2858 // check if we have one trusted source for the package. if so, switch
2859 // to "TrustedOnly" mode - but only if not in AllowUnauthenticated mode
2860 bool const allowUnauth
= _config
->FindB("APT::Get::AllowUnauthenticated", false);
2861 bool const debugAuth
= _config
->FindB("Debug::pkgAcquire::Auth", false);
2862 bool seenUntrusted
= false;
2863 for (pkgCache::VerFileIterator i
= Version
.FileList(); i
.end() == false; ++i
)
2865 pkgIndexFile
*Index
;
2866 if (Sources
->FindIndex(i
.File(),Index
) == false)
2869 if (debugAuth
== true)
2870 std::cerr
<< "Checking index: " << Index
->Describe()
2871 << "(Trusted=" << Index
->IsTrusted() << ")" << std::endl
;
2873 if (Index
->IsTrusted() == true)
2876 if (allowUnauth
== false)
2880 seenUntrusted
= true;
2883 // "allow-unauthenticated" restores apts old fetching behaviour
2884 // that means that e.g. unauthenticated file:// uris are higher
2885 // priority than authenticated http:// uris
2886 if (allowUnauth
== true && seenUntrusted
== true)
2890 if (QueueNext() == false && _error
->PendingError() == false)
2891 _error
->Error(_("Can't find a source to download version '%s' of '%s'"),
2892 Version
.VerStr(), Version
.ParentPkg().FullName(false).c_str());
2895 // AcqArchive::QueueNext - Queue the next file source /*{{{*/
2896 // ---------------------------------------------------------------------
2897 /* This queues the next available file version for download. It checks if
2898 the archive is already available in the cache and stashs the MD5 for
2900 bool pkgAcqArchive::QueueNext()
2902 for (; Vf
.end() == false; ++Vf
)
2904 pkgCache::PkgFileIterator
const PkgF
= Vf
.File();
2905 // Ignore not source sources
2906 if (PkgF
.Flagged(pkgCache::Flag::NotSource
))
2909 // Try to cross match against the source list
2910 pkgIndexFile
*Index
;
2911 if (Sources
->FindIndex(PkgF
, Index
) == false)
2913 LocalSource
= PkgF
.Flagged(pkgCache::Flag::LocalSource
);
2915 // only try to get a trusted package from another source if that source
2917 if(Trusted
&& !Index
->IsTrusted())
2920 // Grab the text package record
2921 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2922 if (_error
->PendingError() == true)
2925 string PkgFile
= Parse
.FileName();
2926 ExpectedHashes
= Parse
.Hashes();
2928 if (PkgFile
.empty() == true)
2929 return _error
->Error(_("The package index files are corrupted. No Filename: "
2930 "field for package %s."),
2931 Version
.ParentPkg().Name());
2933 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
2934 Desc
.Description
= Index
->ArchiveInfo(Version
);
2936 Desc
.ShortDesc
= Version
.ParentPkg().FullName(true);
2938 // See if we already have the file. (Legacy filenames)
2939 FileSize
= Version
->Size
;
2940 string FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile
);
2942 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2944 // Make sure the size matches
2945 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2950 StoreFilename
= DestFile
= FinalFile
;
2954 /* Hmm, we have a file and its size does not match, this means it is
2955 an old style mismatched arch */
2956 RemoveFile("pkgAcqArchive::QueueNext", FinalFile
);
2959 // Check it again using the new style output filenames
2960 FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
2961 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2963 // Make sure the size matches
2964 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2969 StoreFilename
= DestFile
= FinalFile
;
2973 /* Hmm, we have a file and its size does not match, this shouldn't
2975 RemoveFile("pkgAcqArchive::QueueNext", FinalFile
);
2978 DestFile
= _config
->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename
);
2980 // Check the destination file
2981 if (stat(DestFile
.c_str(),&Buf
) == 0)
2983 // Hmm, the partial file is too big, erase it
2984 if ((unsigned long long)Buf
.st_size
> Version
->Size
)
2985 RemoveFile("pkgAcqArchive::QueueNext", DestFile
);
2987 PartialSize
= Buf
.st_size
;
2990 // Disables download of archives - useful if no real installation follows,
2991 // e.g. if we are just interested in proposed installation order
2992 if (_config
->FindB("Debug::pkgAcqArchive::NoQueue", false) == true)
2997 StoreFilename
= DestFile
= FinalFile
;
3011 // AcqArchive::Done - Finished fetching /*{{{*/
3012 // ---------------------------------------------------------------------
3014 void pkgAcqArchive::Done(string
const &Message
, HashStringList
const &Hashes
,
3015 pkgAcquire::MethodConfig
const * const Cfg
)
3017 Item::Done(Message
, Hashes
, Cfg
);
3019 // Grab the output filename
3020 std::string
const FileName
= LookupTag(Message
,"Filename");
3021 if (DestFile
!= FileName
&& RealFileExists(DestFile
) == false)
3023 StoreFilename
= DestFile
= FileName
;
3029 // Done, move it into position
3030 string
const FinalFile
= GetFinalFilename();
3031 Rename(DestFile
,FinalFile
);
3032 StoreFilename
= DestFile
= FinalFile
;
3036 // AcqArchive::Failed - Failure handler /*{{{*/
3037 // ---------------------------------------------------------------------
3038 /* Here we try other sources */
3039 void pkgAcqArchive::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)
3041 Item::Failed(Message
,Cnf
);
3043 /* We don't really want to retry on failed media swaps, this prevents
3044 that. An interesting observation is that permanent failures are not
3046 if (Cnf
->Removable
== true &&
3047 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
3049 // Vf = Version.FileList();
3050 while (Vf
.end() == false) ++Vf
;
3051 StoreFilename
= string();
3056 if (QueueNext() == false)
3058 // This is the retry counter
3060 Cnf
->LocalOnly
== false &&
3061 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
3064 Vf
= Version
.FileList();
3065 if (QueueNext() == true)
3069 StoreFilename
= string();
3074 APT_PURE
bool pkgAcqArchive::IsTrusted() const /*{{{*/
3079 void pkgAcqArchive::Finished() /*{{{*/
3081 if (Status
== pkgAcquire::Item::StatDone
&&
3084 StoreFilename
= string();
3087 std::string
pkgAcqArchive::DescURI() const /*{{{*/
3092 std::string
pkgAcqArchive::ShortDesc() const /*{{{*/
3094 return Desc
.ShortDesc
;
3097 pkgAcqArchive::~pkgAcqArchive() {}
3099 // AcqChangelog::pkgAcqChangelog - Constructors /*{{{*/
3100 class pkgAcqChangelog::Private
3103 std::string FinalFile
;
3105 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire
* const Owner
, pkgCache::VerIterator
const &Ver
,
3106 std::string
const &DestDir
, std::string
const &DestFilename
) :
3107 pkgAcquire::Item(Owner
), d(new pkgAcqChangelog::Private()), SrcName(Ver
.SourcePkgName()), SrcVersion(Ver
.SourceVerStr())
3109 Desc
.URI
= URI(Ver
);
3110 Init(DestDir
, DestFilename
);
3112 // some parameters are char* here as they come likely from char* interfaces – which can also return NULL
3113 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire
* const Owner
, pkgCache::RlsFileIterator
const &RlsFile
,
3114 char const * const Component
, char const * const SrcName
, char const * const SrcVersion
,
3115 const string
&DestDir
, const string
&DestFilename
) :
3116 pkgAcquire::Item(Owner
), d(new pkgAcqChangelog::Private()), SrcName(SrcName
), SrcVersion(SrcVersion
)
3118 Desc
.URI
= URI(RlsFile
, Component
, SrcName
, SrcVersion
);
3119 Init(DestDir
, DestFilename
);
3121 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire
* const Owner
,
3122 std::string
const &URI
, char const * const SrcName
, char const * const SrcVersion
,
3123 const string
&DestDir
, const string
&DestFilename
) :
3124 pkgAcquire::Item(Owner
), d(new pkgAcqChangelog::Private()), SrcName(SrcName
), SrcVersion(SrcVersion
)
3127 Init(DestDir
, DestFilename
);
3129 void pkgAcqChangelog::Init(std::string
const &DestDir
, std::string
const &DestFilename
)
3131 if (Desc
.URI
.empty())
3134 // TRANSLATOR: %s=%s is sourcename=sourceversion, e.g. apt=1.1
3135 strprintf(ErrorText
, _("Changelog unavailable for %s=%s"), SrcName
.c_str(), SrcVersion
.c_str());
3136 // Let the error message print something sensible rather than "Failed to fetch /"
3137 if (DestFilename
.empty())
3138 DestFile
= SrcName
+ ".changelog";
3140 DestFile
= DestFilename
;
3141 Desc
.URI
= "changelog:/" + DestFile
;
3145 std::string DestFileName
;
3146 if (DestFilename
.empty())
3147 DestFileName
= flCombine(DestFile
, SrcName
+ ".changelog");
3149 DestFileName
= flCombine(DestFile
, DestFilename
);
3151 std::string
const SandboxUser
= _config
->Find("APT::Sandbox::User");
3152 std::string
const systemTemp
= GetTempDir(SandboxUser
);
3154 snprintf(tmpname
, sizeof(tmpname
), "%s/apt-changelog-XXXXXX", systemTemp
.c_str());
3155 if (NULL
== mkdtemp(tmpname
))
3157 _error
->Errno("mkdtemp", "mkdtemp failed in changelog acquire of %s %s", SrcName
.c_str(), SrcVersion
.c_str());
3161 TemporaryDirectory
= tmpname
;
3163 ChangeOwnerAndPermissionOfFile("Item::QueueURI", TemporaryDirectory
.c_str(),
3164 SandboxUser
.c_str(), "root", 0700);
3166 DestFile
= flCombine(TemporaryDirectory
, DestFileName
);
3167 if (DestDir
.empty() == false)
3169 d
->FinalFile
= flCombine(DestDir
, DestFileName
);
3170 if (RealFileExists(d
->FinalFile
))
3172 FileFd file1
, file2
;
3173 if (file1
.Open(DestFile
, FileFd::WriteOnly
| FileFd::Create
| FileFd::Exclusive
) &&
3174 file2
.Open(d
->FinalFile
, FileFd::ReadOnly
) && CopyFile(file2
, file1
))
3176 struct timeval times
[2];
3177 times
[0].tv_sec
= times
[1].tv_sec
= file2
.ModificationTime();
3178 times
[0].tv_usec
= times
[1].tv_usec
= 0;
3179 utimes(DestFile
.c_str(), times
);
3184 Desc
.ShortDesc
= "Changelog";
3185 strprintf(Desc
.Description
, "%s %s %s Changelog", URI::SiteOnly(Desc
.URI
).c_str(), SrcName
.c_str(), SrcVersion
.c_str());
3190 std::string
pkgAcqChangelog::URI(pkgCache::VerIterator
const &Ver
) /*{{{*/
3192 std::string
const confOnline
= "Acquire::Changelogs::AlwaysOnline";
3193 bool AlwaysOnline
= _config
->FindB(confOnline
, false);
3194 if (AlwaysOnline
== false)
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 if (RF
->Origin
!= 0 && _config
->FindB(confOnline
+ "::Origin::" + RF
.Origin(), false))
3203 AlwaysOnline
= true;
3207 if (AlwaysOnline
== false)
3209 pkgCache::PkgIterator
const Pkg
= Ver
.ParentPkg();
3210 if (Pkg
->CurrentVer
!= 0 && Pkg
.CurrentVer() == Ver
)
3212 std::string
const basename
= std::string("/usr/share/doc/") + Pkg
.Name() + "/changelog";
3213 std::string
const debianname
= basename
+ ".Debian";
3214 if (FileExists(debianname
))
3215 return "copy://" + debianname
;
3216 else if (FileExists(debianname
+ ".gz"))
3217 return "gzip://" + debianname
+ ".gz";
3218 else if (FileExists(basename
))
3219 return "copy://" + basename
;
3220 else if (FileExists(basename
+ ".gz"))
3221 return "gzip://" + basename
+ ".gz";
3225 char const * const SrcName
= Ver
.SourcePkgName();
3226 char const * const SrcVersion
= Ver
.SourceVerStr();
3227 // find the first source for this version which promises a changelog
3228 for (pkgCache::VerFileIterator VF
= Ver
.FileList(); VF
.end() == false; ++VF
)
3230 pkgCache::PkgFileIterator
const PF
= VF
.File();
3231 if (PF
.Flagged(pkgCache::Flag::NotSource
) || PF
->Release
== 0)
3233 pkgCache::RlsFileIterator
const RF
= PF
.ReleaseFile();
3234 std::string
const uri
= URI(RF
, PF
.Component(), SrcName
, SrcVersion
);
3241 std::string
pkgAcqChangelog::URITemplate(pkgCache::RlsFileIterator
const &Rls
)
3243 if (Rls
.end() == true || (Rls
->Label
== 0 && Rls
->Origin
== 0))
3245 std::string
const serverConfig
= "Acquire::Changelogs::URI";
3247 #define APT_EMPTY_SERVER \
3248 if (server.empty() == false) \
3250 if (server != "no") \
3254 #define APT_CHECK_SERVER(X, Y) \
3257 std::string const specialServerConfig = serverConfig + "::" + Y + #X + "::" + Rls.X(); \
3258 server = _config->Find(specialServerConfig); \
3261 // this way e.g. Debian-Security can fallback to Debian
3262 APT_CHECK_SERVER(Label
, "Override::")
3263 APT_CHECK_SERVER(Origin
, "Override::")
3265 if (RealFileExists(Rls
.FileName()))
3267 _error
->PushToStack();
3269 /* This can be costly. A caller wanting to get millions of URIs might
3270 want to do this on its own once and use Override settings.
3271 We don't do this here as Origin/Label are not as unique as they
3272 should be so this could produce request order-dependent anomalies */
3273 if (OpenMaybeClearSignedFile(Rls
.FileName(), rf
) == true)
3275 pkgTagFile
TagFile(&rf
, rf
.Size());
3276 pkgTagSection Section
;
3277 if (TagFile
.Step(Section
) == true)
3278 server
= Section
.FindS("Changelogs");
3280 _error
->RevertToStack();
3284 APT_CHECK_SERVER(Label
, "")
3285 APT_CHECK_SERVER(Origin
, "")
3286 #undef APT_CHECK_SERVER
3287 #undef APT_EMPTY_SERVER
3290 std::string
pkgAcqChangelog::URI(pkgCache::RlsFileIterator
const &Rls
,
3291 char const * const Component
, char const * const SrcName
,
3292 char const * const SrcVersion
)
3294 return URI(URITemplate(Rls
), Component
, SrcName
, SrcVersion
);
3296 std::string
pkgAcqChangelog::URI(std::string
const &Template
,
3297 char const * const Component
, char const * const SrcName
,
3298 char const * const SrcVersion
)
3300 if (Template
.find("@CHANGEPATH@") == std::string::npos
)
3303 // the path is: COMPONENT/SRC/SRCNAME/SRCNAME_SRCVER, e.g. main/a/apt/1.1 or contrib/liba/libapt/2.0
3304 std::string Src
= SrcName
;
3305 std::string path
= APT::String::Startswith(SrcName
, "lib") ? Src
.substr(0, 4) : Src
.substr(0,1);
3306 path
.append("/").append(Src
).append("/");
3307 path
.append(Src
).append("_").append(StripEpoch(SrcVersion
));
3308 // we omit component for releases without one (= flat-style repositories)
3309 if (Component
!= NULL
&& strlen(Component
) != 0)
3310 path
= std::string(Component
) + "/" + path
;
3312 return SubstVar(Template
, "@CHANGEPATH@", path
);
3315 // AcqChangelog::Failed - Failure handler /*{{{*/
3316 void pkgAcqChangelog::Failed(string
const &Message
, pkgAcquire::MethodConfig
const * const Cnf
)
3318 Item::Failed(Message
,Cnf
);
3320 std::string errText
;
3321 // TRANSLATOR: %s=%s is sourcename=sourceversion, e.g. apt=1.1
3322 strprintf(errText
, _("Changelog unavailable for %s=%s"), SrcName
.c_str(), SrcVersion
.c_str());
3324 // Error is probably something techy like 404 Not Found
3325 if (ErrorText
.empty())
3326 ErrorText
= errText
;
3328 ErrorText
= errText
+ " (" + ErrorText
+ ")";
3331 // AcqChangelog::Done - Item downloaded OK /*{{{*/
3332 void pkgAcqChangelog::Done(string
const &Message
,HashStringList
const &CalcHashes
,
3333 pkgAcquire::MethodConfig
const * const Cnf
)
3335 Item::Done(Message
,CalcHashes
,Cnf
);
3336 if (d
->FinalFile
.empty() == false)
3338 if (RemoveFile("pkgAcqChangelog::Done", d
->FinalFile
) == false ||
3339 Rename(DestFile
, d
->FinalFile
) == false)
3346 pkgAcqChangelog::~pkgAcqChangelog() /*{{{*/
3348 if (TemporaryDirectory
.empty() == false)
3350 RemoveFile("~pkgAcqChangelog", DestFile
);
3351 rmdir(TemporaryDirectory
.c_str());
3357 // AcqFile::pkgAcqFile - Constructor /*{{{*/
3358 pkgAcqFile::pkgAcqFile(pkgAcquire
* const Owner
,string
const &URI
, HashStringList
const &Hashes
,
3359 unsigned long long const Size
,string
const &Dsc
,string
const &ShortDesc
,
3360 const string
&DestDir
, const string
&DestFilename
,
3361 bool const IsIndexFile
) :
3362 Item(Owner
), d(NULL
), IsIndexFile(IsIndexFile
), ExpectedHashes(Hashes
)
3364 Retries
= _config
->FindI("Acquire::Retries",0);
3366 if(!DestFilename
.empty())
3367 DestFile
= DestFilename
;
3368 else if(!DestDir
.empty())
3369 DestFile
= DestDir
+ "/" + flNotDir(URI
);
3371 DestFile
= flNotDir(URI
);
3375 Desc
.Description
= Dsc
;
3378 // Set the short description to the archive component
3379 Desc
.ShortDesc
= ShortDesc
;
3381 // Get the transfer sizes
3384 if (stat(DestFile
.c_str(),&Buf
) == 0)
3386 // Hmm, the partial file is too big, erase it
3387 if ((Size
> 0) && (unsigned long long)Buf
.st_size
> Size
)
3388 RemoveFile("pkgAcqFile", DestFile
);
3390 PartialSize
= Buf
.st_size
;
3396 // AcqFile::Done - Item downloaded OK /*{{{*/
3397 void pkgAcqFile::Done(string
const &Message
,HashStringList
const &CalcHashes
,
3398 pkgAcquire::MethodConfig
const * const Cnf
)
3400 Item::Done(Message
,CalcHashes
,Cnf
);
3402 std::string
const FileName
= LookupTag(Message
,"Filename");
3405 // The files timestamp matches
3406 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
3409 // We have to copy it into place
3410 if (RealFileExists(DestFile
.c_str()) == false)
3413 if (_config
->FindB("Acquire::Source-Symlinks",true) == false ||
3414 Cnf
->Removable
== true)
3416 Desc
.URI
= "copy:" + FileName
;
3421 // Erase the file if it is a symlink so we can overwrite it
3423 if (lstat(DestFile
.c_str(),&St
) == 0)
3425 if (S_ISLNK(St
.st_mode
) != 0)
3426 RemoveFile("pkgAcqFile::Done", DestFile
);
3430 if (symlink(FileName
.c_str(),DestFile
.c_str()) != 0)
3432 _error
->PushToStack();
3433 _error
->Errno("pkgAcqFile::Done", "Symlinking file %s failed", DestFile
.c_str());
3434 std::stringstream msg
;
3435 _error
->DumpErrors(msg
, GlobalError::DEBUG
, false);
3436 _error
->RevertToStack();
3437 ErrorText
= msg
.str();
3444 // AcqFile::Failed - Failure handler /*{{{*/
3445 // ---------------------------------------------------------------------
3446 /* Here we try other sources */
3447 void pkgAcqFile::Failed(string
const &Message
, pkgAcquire::MethodConfig
const * const Cnf
)
3449 Item::Failed(Message
,Cnf
);
3451 // This is the retry counter
3453 Cnf
->LocalOnly
== false &&
3454 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
3464 string
pkgAcqFile::Custom600Headers() const /*{{{*/
3467 return "\nIndex-File: true";
3471 pkgAcqFile::~pkgAcqFile() {}