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>
54 static void printHashSumComparision(std::string
const &URI
, HashStringList
const &Expected
, HashStringList
const &Actual
) /*{{{*/
56 if (_config
->FindB("Debug::Acquire::HashSumMismatch", false) == false)
58 std::cerr
<< std::endl
<< URI
<< ":" << std::endl
<< " Expected Hash: " << std::endl
;
59 for (HashStringList::const_iterator hs
= Expected
.begin(); hs
!= Expected
.end(); ++hs
)
60 std::cerr
<< "\t- " << hs
->toStr() << std::endl
;
61 std::cerr
<< " Actual Hash: " << std::endl
;
62 for (HashStringList::const_iterator hs
= Actual
.begin(); hs
!= Actual
.end(); ++hs
)
63 std::cerr
<< "\t- " << hs
->toStr() << std::endl
;
66 static std::string
GetPartialFileName(std::string
const &file
) /*{{{*/
68 std::string DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
73 static std::string
GetPartialFileNameFromURI(std::string
const &uri
) /*{{{*/
75 return GetPartialFileName(URItoFileName(uri
));
78 static std::string
GetFinalFileNameFromURI(std::string
const &uri
) /*{{{*/
80 return _config
->FindDir("Dir::State::lists") + URItoFileName(uri
);
83 static std::string
GetKeepCompressedFileName(std::string file
, IndexTarget
const &Target
)/*{{{*/
85 if (Target
.KeepCompressed
== false)
88 std::string
const CompressionTypes
= Target
.Option(IndexTarget::COMPRESSIONTYPES
);
89 if (CompressionTypes
.empty() == false)
91 std::string
const ext
= CompressionTypes
.substr(0, CompressionTypes
.find(' '));
92 if (ext
!= "uncompressed")
93 file
.append(".").append(ext
);
98 static std::string
GetCompressedFileName(IndexTarget
const &Target
, std::string
const &Name
, std::string
const &Ext
) /*{{{*/
100 if (Ext
.empty() || Ext
== "uncompressed")
103 // do not reverify cdrom sources as apt-cdrom may rewrite the Packages
104 // file when its doing the indexcopy
105 if (Target
.URI
.substr(0,6) == "cdrom:")
108 // adjust DestFile if its compressed on disk
109 if (Target
.KeepCompressed
== true)
110 return Name
+ '.' + Ext
;
114 static std::string
GetMergeDiffsPatchFileName(std::string
const &Final
, std::string
const &Patch
)/*{{{*/
116 // rred expects the patch as $FinalFile.ed.$patchname.gz
117 return Final
+ ".ed." + Patch
+ ".gz";
120 static std::string
GetDiffsPatchFileName(std::string
const &Final
) /*{{{*/
122 // rred expects the patch as $FinalFile.ed
123 return Final
+ ".ed";
126 static bool BootstrapPDiffWith(std::string
const &PartialFile
, std::string
const &FinalFile
, IndexTarget
const &Target
)/*{{{*/
128 // patching needs to be bootstrapped with the 'old' version
129 std::vector
<std::string
> types
= VectorizeString(Target
.Option(IndexTarget::COMPRESSIONTYPES
), ' ');
130 auto typeItr
= types
.cbegin();
131 for (; typeItr
!= types
.cend(); ++typeItr
)
133 std::string Final
= FinalFile
;
134 if (*typeItr
!= "uncompressed")
135 Final
.append(".").append(*typeItr
);
136 if (RealFileExists(Final
) == false)
138 std::string Partial
= PartialFile
;
139 if (*typeItr
!= "uncompressed")
140 Partial
.append(".").append(*typeItr
);
141 if (FileExists(Partial
.c_str()) == true)
143 if (symlink(Final
.c_str(), Partial
.c_str()) != 0)
147 return typeItr
!= types
.cend();
151 static bool MessageInsecureRepository(bool const isError
, std::string
const &msg
)/*{{{*/
155 _error
->Error("%s", msg
.c_str());
156 _error
->Notice("%s", _("Updating from such a repository can't be done securely, and is therefore disabled by default."));
160 _error
->Warning("%s", msg
.c_str());
161 _error
->Notice("%s", _("Data from such a repository can't be authenticated and is therefore potentially dangerous to use."));
163 _error
->Notice("%s", _("See apt-secure(8) manpage for repository creation and user configuration details."));
166 static bool MessageInsecureRepository(bool const isError
, char const * const msg
, std::string
const &repo
)
169 strprintf(m
, msg
, repo
.c_str());
170 return MessageInsecureRepository(isError
, m
);
173 static bool AllowInsecureRepositories(char const * const msg
, std::string
const &repo
,/*{{{*/
174 metaIndex
const * const MetaIndexParser
, pkgAcqMetaClearSig
* const TransactionManager
, pkgAcquire::Item
* const I
)
176 if(MetaIndexParser
->GetTrusted() == metaIndex::TRI_YES
)
179 if (_config
->FindB("Acquire::AllowInsecureRepositories") == true)
181 MessageInsecureRepository(false, msg
, repo
);
185 MessageInsecureRepository(true, msg
, repo
);
186 TransactionManager
->AbortTransaction();
187 I
->Status
= pkgAcquire::Item::StatError
;
191 static HashStringList
GetExpectedHashesFromFor(metaIndex
* const Parser
, std::string
const &MetaKey
)/*{{{*/
194 return HashStringList();
195 metaIndex::checkSum
* const R
= Parser
->Lookup(MetaKey
);
197 return HashStringList();
202 // all ::HashesRequired and ::GetExpectedHashes implementations /*{{{*/
203 /* ::GetExpectedHashes is abstract and has to be implemented by all subclasses.
204 It is best to implement it as broadly as possible, while ::HashesRequired defaults
205 to true and should be as restrictive as possible for false cases. Note that if
206 a hash is returned by ::GetExpectedHashes it must match. Only if it doesn't
207 ::HashesRequired is called to evaluate if its okay to have no hashes. */
208 APT_CONST
bool pkgAcqTransactionItem::HashesRequired() const
210 /* signed repositories obviously have a parser and good hashes.
211 unsigned repositories, too, as even if we can't trust them for security,
212 we can at least trust them for integrity of the download itself.
213 Only repositories without a Release file can (obviously) not have
214 hashes – and they are very uncommon and strongly discouraged */
215 return TransactionManager
->MetaIndexParser
!= NULL
&&
216 TransactionManager
->MetaIndexParser
->GetLoadedSuccessfully() == metaIndex::TRI_YES
;
218 HashStringList
pkgAcqTransactionItem::GetExpectedHashes() const
220 return GetExpectedHashesFor(GetMetaKey());
223 APT_CONST
bool pkgAcqMetaBase::HashesRequired() const
225 // Release and co have no hashes 'by design'.
228 HashStringList
pkgAcqMetaBase::GetExpectedHashes() const
230 return HashStringList();
233 APT_CONST
bool pkgAcqIndexDiffs::HashesRequired() const
235 /* We don't always have the diff of the downloaded pdiff file.
236 What we have for sure is hashes for the uncompressed file,
237 but rred uncompresses them on the fly while parsing, so not handled here.
238 Hashes are (also) checked while searching for (next) patch to apply. */
239 if (State
== StateFetchDiff
)
240 return available_patches
[0].download_hashes
.empty() == false;
243 HashStringList
pkgAcqIndexDiffs::GetExpectedHashes() const
245 if (State
== StateFetchDiff
)
246 return available_patches
[0].download_hashes
;
247 return HashStringList();
250 APT_CONST
bool pkgAcqIndexMergeDiffs::HashesRequired() const
252 /* @see #pkgAcqIndexDiffs::HashesRequired, with the difference that
253 we can check the rred result after all patches are applied as
254 we know the expected result rather than potentially apply more patches */
255 if (State
== StateFetchDiff
)
256 return patch
.download_hashes
.empty() == false;
257 return State
== StateApplyDiff
;
259 HashStringList
pkgAcqIndexMergeDiffs::GetExpectedHashes() const
261 if (State
== StateFetchDiff
)
262 return patch
.download_hashes
;
263 else if (State
== StateApplyDiff
)
264 return GetExpectedHashesFor(Target
.MetaKey
);
265 return HashStringList();
268 APT_CONST
bool pkgAcqArchive::HashesRequired() const
270 return LocalSource
== false;
272 HashStringList
pkgAcqArchive::GetExpectedHashes() const
274 // figured out while parsing the records
275 return ExpectedHashes
;
278 APT_CONST
bool pkgAcqFile::HashesRequired() const
280 // supplied as parameter at creation time, so the caller decides
281 return ExpectedHashes
.usable();
283 HashStringList
pkgAcqFile::GetExpectedHashes() const
285 return ExpectedHashes
;
288 // Acquire::Item::QueueURI and specialisations from child classes /*{{{*/
289 bool pkgAcquire::Item::QueueURI(pkgAcquire::ItemDesc
&Item
)
291 Owner
->Enqueue(Item
);
294 /* The idea here is that an item isn't queued if it exists on disk and the
295 transition manager was a hit as this means that the files it contains
296 the checksums for can't be updated either (or they are and we are asking
297 for a hashsum mismatch to happen which helps nobody) */
298 bool pkgAcqTransactionItem::QueueURI(pkgAcquire::ItemDesc
&Item
)
300 std::string
const FinalFile
= GetFinalFilename();
301 if (TransactionManager
!= NULL
&& TransactionManager
->IMSHit
== true &&
302 FileExists(FinalFile
) == true)
304 PartialFile
= DestFile
= FinalFile
;
308 return pkgAcquire::Item::QueueURI(Item
);
310 /* The transition manager InRelease itself (or its older sisters-in-law
311 Release & Release.gpg) is always queued as this allows us to rerun gpgv
312 on it to verify that we aren't stalled with old files */
313 bool pkgAcqMetaBase::QueueURI(pkgAcquire::ItemDesc
&Item
)
315 return pkgAcquire::Item::QueueURI(Item
);
317 /* the Diff/Index needs to queue also the up-to-date complete index file
318 to ensure that the list cleaner isn't eating it */
319 bool pkgAcqDiffIndex::QueueURI(pkgAcquire::ItemDesc
&Item
)
321 if (pkgAcqTransactionItem::QueueURI(Item
) == true)
327 // Acquire::Item::GetFinalFilename and specialisations for child classes /*{{{*/
328 std::string
pkgAcquire::Item::GetFinalFilename() const
330 return GetFinalFileNameFromURI(Desc
.URI
);
332 std::string
pkgAcqDiffIndex::GetFinalFilename() const
334 // the logic we inherent from pkgAcqBaseIndex isn't what we need here
335 return pkgAcquire::Item::GetFinalFilename();
337 std::string
pkgAcqIndex::GetFinalFilename() const
339 std::string
const FinalFile
= GetFinalFileNameFromURI(Target
.URI
);
340 return GetCompressedFileName(Target
, FinalFile
, CurrentCompressionExtension
);
342 std::string
pkgAcqMetaSig::GetFinalFilename() const
344 return GetFinalFileNameFromURI(Target
.URI
);
346 std::string
pkgAcqBaseIndex::GetFinalFilename() const
348 return GetFinalFileNameFromURI(Target
.URI
);
350 std::string
pkgAcqMetaBase::GetFinalFilename() const
352 return GetFinalFileNameFromURI(Target
.URI
);
354 std::string
pkgAcqArchive::GetFinalFilename() const
356 return _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
359 // pkgAcqTransactionItem::GetMetaKey and specialisations for child classes /*{{{*/
360 std::string
pkgAcqTransactionItem::GetMetaKey() const
362 return Target
.MetaKey
;
364 std::string
pkgAcqIndex::GetMetaKey() const
366 if (Stage
== STAGE_DECOMPRESS_AND_VERIFY
|| CurrentCompressionExtension
== "uncompressed")
367 return Target
.MetaKey
;
368 return Target
.MetaKey
+ "." + CurrentCompressionExtension
;
370 std::string
pkgAcqDiffIndex::GetMetaKey() const
372 return Target
.MetaKey
+ ".diff/Index";
375 //pkgAcqTransactionItem::TransactionState and specialisations for child classes /*{{{*/
376 bool pkgAcqTransactionItem::TransactionState(TransactionStates
const state
)
378 bool const Debug
= _config
->FindB("Debug::Acquire::Transaction", false);
381 case TransactionAbort
:
383 std::clog
<< " Cancel: " << DestFile
<< std::endl
;
384 if (Status
== pkgAcquire::Item::StatIdle
)
386 Status
= pkgAcquire::Item::StatDone
;
390 case TransactionCommit
:
391 if(PartialFile
.empty() == false)
393 if (PartialFile
!= DestFile
)
395 // ensure that even without lists-cleanup all compressions are nuked
396 std::string FinalFile
= GetFinalFileNameFromURI(Target
.URI
);
397 if (FileExists(FinalFile
))
400 std::clog
<< "rm " << FinalFile
<< " # " << DescURI() << std::endl
;
401 if (RemoveFile("TransactionStates-Cleanup", FinalFile
) == false)
404 for (auto const &ext
: APT::Configuration::getCompressorExtensions())
406 auto const Final
= FinalFile
+ ext
;
407 if (FileExists(Final
))
410 std::clog
<< "rm " << Final
<< " # " << DescURI() << std::endl
;
411 if (RemoveFile("TransactionStates-Cleanup", Final
) == false)
416 std::clog
<< "mv " << PartialFile
<< " -> "<< DestFile
<< " # " << DescURI() << std::endl
;
417 if (Rename(PartialFile
, DestFile
) == false)
420 else if(Debug
== true)
421 std::clog
<< "keep " << PartialFile
<< " # " << DescURI() << std::endl
;
425 std::clog
<< "rm " << DestFile
<< " # " << DescURI() << std::endl
;
426 if (RemoveFile("TransactionCommit", DestFile
) == false)
433 bool pkgAcqMetaBase::TransactionState(TransactionStates
const state
)
435 // Do not remove InRelease on IMSHit of Release.gpg [yes, this is very edgecasey]
436 if (TransactionManager
->IMSHit
== false)
437 return pkgAcqTransactionItem::TransactionState(state
);
440 bool pkgAcqIndex::TransactionState(TransactionStates
const state
)
442 if (pkgAcqTransactionItem::TransactionState(state
) == false)
447 case TransactionAbort
:
448 if (Stage
== STAGE_DECOMPRESS_AND_VERIFY
)
450 // keep the compressed file, but drop the decompressed
451 EraseFileName
.clear();
452 if (PartialFile
.empty() == false && flExtension(PartialFile
) != CurrentCompressionExtension
)
453 RemoveFile("TransactionAbort", PartialFile
);
456 case TransactionCommit
:
457 if (EraseFileName
.empty() == false)
458 RemoveFile("TransactionCommit", EraseFileName
);
463 bool pkgAcqDiffIndex::TransactionState(TransactionStates
const state
)
465 if (pkgAcqTransactionItem::TransactionState(state
) == false)
470 case TransactionCommit
:
472 case TransactionAbort
:
473 std::string
const Partial
= GetPartialFileNameFromURI(Target
.URI
);
474 RemoveFile("TransactionAbort", Partial
);
482 class APT_HIDDEN NoActionItem
: public pkgAcquire::Item
/*{{{*/
483 /* The sole purpose of this class is having an item which does nothing to
484 reach its done state to prevent cleanup deleting the mentioned file.
485 Handy in cases in which we know we have the file already, like IMS-Hits. */
487 IndexTarget
const Target
;
489 virtual std::string
DescURI() const APT_OVERRIDE
{return Target
.URI
;};
490 virtual HashStringList
GetExpectedHashes() const APT_OVERRIDE
{return HashStringList();};
492 NoActionItem(pkgAcquire
* const Owner
, IndexTarget
const &Target
) :
493 pkgAcquire::Item(Owner
), Target(Target
)
496 DestFile
= GetFinalFileNameFromURI(Target
.URI
);
498 NoActionItem(pkgAcquire
* const Owner
, IndexTarget
const &Target
, std::string
const &FinalFile
) :
499 pkgAcquire::Item(Owner
), Target(Target
)
502 DestFile
= FinalFile
;
507 // Acquire::Item::Item - Constructor /*{{{*/
508 APT_IGNORE_DEPRECATED_PUSH
509 pkgAcquire::Item::Item(pkgAcquire
* const owner
) :
510 FileSize(0), PartialSize(0), Mode(0), ID(0), Complete(false), Local(false),
511 QueueCounter(0), ExpectedAdditionalItems(0), Owner(owner
), d(NULL
)
516 APT_IGNORE_DEPRECATED_POP
518 // Acquire::Item::~Item - Destructor /*{{{*/
519 pkgAcquire::Item::~Item()
524 std::string
pkgAcquire::Item::Custom600Headers() const /*{{{*/
526 return std::string();
529 std::string
pkgAcquire::Item::ShortDesc() const /*{{{*/
534 APT_CONST
void pkgAcquire::Item::Finished() /*{{{*/
538 APT_PURE pkgAcquire
* pkgAcquire::Item::GetOwner() const /*{{{*/
543 APT_CONST
pkgAcquire::ItemDesc
&pkgAcquire::Item::GetItemDesc() /*{{{*/
548 APT_CONST
bool pkgAcquire::Item::IsTrusted() const /*{{{*/
553 // Acquire::Item::Failed - Item failed to download /*{{{*/
554 // ---------------------------------------------------------------------
555 /* We return to an idle state if there are still other queues that could
557 void pkgAcquire::Item::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)
559 if(ErrorText
.empty())
560 ErrorText
= LookupTag(Message
,"Message");
561 if (QueueCounter
<= 1)
563 /* This indicates that the file is not available right now but might
564 be sometime later. If we do a retry cycle then this should be
566 if (Cnf
!= NULL
&& Cnf
->LocalOnly
== true &&
567 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
583 case StatTransientNetworkError
:
590 string
const FailReason
= LookupTag(Message
, "FailReason");
591 if (FailReason
== "MaximumSizeExceeded")
592 RenameOnError(MaximumSizeExceeded
);
593 else if (Status
== StatAuthError
)
594 RenameOnError(HashSumMismatch
);
596 // report mirror failure back to LP if we actually use a mirror
597 if (FailReason
.empty() == false)
598 ReportMirrorFailure(FailReason
);
600 ReportMirrorFailure(ErrorText
);
602 if (QueueCounter
> 1)
606 // Acquire::Item::Start - Item has begun to download /*{{{*/
607 // ---------------------------------------------------------------------
608 /* Stash status and the file size. Note that setting Complete means
609 sub-phases of the acquire process such as decompresion are operating */
610 void pkgAcquire::Item::Start(string
const &/*Message*/, unsigned long long const Size
)
612 Status
= StatFetching
;
614 if (FileSize
== 0 && Complete
== false)
618 // Acquire::Item::VerifyDone - check if Item was downloaded OK /*{{{*/
619 /* Note that hash-verification is 'hardcoded' in acquire-worker and has
620 * already passed if this method is called. */
621 bool pkgAcquire::Item::VerifyDone(std::string
const &Message
,
622 pkgAcquire::MethodConfig
const * const /*Cnf*/)
624 std::string
const FileName
= LookupTag(Message
,"Filename");
625 if (FileName
.empty() == true)
628 ErrorText
= "Method gave a blank filename";
635 // Acquire::Item::Done - Item downloaded OK /*{{{*/
636 void pkgAcquire::Item::Done(string
const &/*Message*/, HashStringList
const &Hashes
,
637 pkgAcquire::MethodConfig
const * const /*Cnf*/)
639 // We just downloaded something..
642 unsigned long long const downloadedSize
= Hashes
.FileSize();
643 if (downloadedSize
!= 0)
645 FileSize
= downloadedSize
;
649 ErrorText
= string();
650 Owner
->Dequeue(this);
653 // Acquire::Item::Rename - Rename a file /*{{{*/
654 // ---------------------------------------------------------------------
655 /* This helper function is used by a lot of item methods as their final
657 bool pkgAcquire::Item::Rename(string
const &From
,string
const &To
)
659 if (From
== To
|| rename(From
.c_str(),To
.c_str()) == 0)
663 strprintf(S
, _("rename failed, %s (%s -> %s)."), strerror(errno
),
664 From
.c_str(),To
.c_str());
666 if (ErrorText
.empty())
669 ErrorText
= ErrorText
+ ": " + S
;
673 void pkgAcquire::Item::Dequeue() /*{{{*/
675 Owner
->Dequeue(this);
678 bool pkgAcquire::Item::RenameOnError(pkgAcquire::Item::RenameOnErrorState
const error
)/*{{{*/
680 if (RealFileExists(DestFile
))
681 Rename(DestFile
, DestFile
+ ".FAILED");
686 case HashSumMismatch
:
687 errtext
= _("Hash Sum mismatch");
688 Status
= StatAuthError
;
689 ReportMirrorFailure("HashChecksumFailure");
692 errtext
= _("Size mismatch");
693 Status
= StatAuthError
;
694 ReportMirrorFailure("SizeFailure");
697 errtext
= _("Invalid file format");
699 // do not report as usually its not the mirrors fault, but Portal/Proxy
702 errtext
= _("Signature error");
706 strprintf(errtext
, _("Clearsigned file isn't valid, got '%s' (does the network require authentication?)"), "NOSPLIT");
707 Status
= StatAuthError
;
709 case MaximumSizeExceeded
:
710 // the method is expected to report a good error for this
714 // no handling here, done by callers
717 if (ErrorText
.empty())
722 void pkgAcquire::Item::SetActiveSubprocess(const std::string
&subprocess
)/*{{{*/
724 ActiveSubprocess
= subprocess
;
725 APT_IGNORE_DEPRECATED(Mode
= ActiveSubprocess
.c_str();)
728 // Acquire::Item::ReportMirrorFailure /*{{{*/
729 void pkgAcquire::Item::ReportMirrorFailure(string
const &FailCode
)
731 // we only act if a mirror was used at all
732 if(UsedMirror
.empty())
735 std::cerr
<< "\nReportMirrorFailure: "
737 << " Uri: " << DescURI()
739 << FailCode
<< std::endl
;
741 string report
= _config
->Find("Methods::Mirror::ProblemReporting",
742 "/usr/lib/apt/apt-report-mirror-failure");
743 if(!FileExists(report
))
746 std::vector
<char const*> Args
;
747 Args
.push_back(report
.c_str());
748 Args
.push_back(UsedMirror
.c_str());
749 Args
.push_back(DescURI().c_str());
750 Args
.push_back(FailCode
.c_str());
751 Args
.push_back(NULL
);
753 pid_t pid
= ExecFork();
756 _error
->Error("ReportMirrorFailure Fork failed");
761 execvp(Args
[0], (char**)Args
.data());
762 std::cerr
<< "Could not exec " << Args
[0] << std::endl
;
765 if(!ExecWait(pid
, "report-mirror-failure"))
767 _error
->Warning("Couldn't report problem to '%s'",
768 _config
->Find("Methods::Mirror::ProblemReporting").c_str());
772 std::string
pkgAcquire::Item::HashSum() const /*{{{*/
774 HashStringList
const hashes
= GetExpectedHashes();
775 HashString
const * const hs
= hashes
.find(NULL
);
776 return hs
!= NULL
? hs
->toStr() : "";
780 pkgAcqTransactionItem::pkgAcqTransactionItem(pkgAcquire
* const Owner
, /*{{{*/
781 pkgAcqMetaClearSig
* const transactionManager
, IndexTarget
const &target
) :
782 pkgAcquire::Item(Owner
), d(NULL
), Target(target
), TransactionManager(transactionManager
)
784 if (TransactionManager
!= this)
785 TransactionManager
->Add(this);
788 pkgAcqTransactionItem::~pkgAcqTransactionItem() /*{{{*/
792 HashStringList
pkgAcqTransactionItem::GetExpectedHashesFor(std::string
const &MetaKey
) const /*{{{*/
794 return GetExpectedHashesFromFor(TransactionManager
->MetaIndexParser
, MetaKey
);
798 // AcqMetaBase - Constructor /*{{{*/
799 pkgAcqMetaBase::pkgAcqMetaBase(pkgAcquire
* const Owner
,
800 pkgAcqMetaClearSig
* const TransactionManager
,
801 std::vector
<IndexTarget
> const &IndexTargets
,
802 IndexTarget
const &DataTarget
)
803 : pkgAcqTransactionItem(Owner
, TransactionManager
, DataTarget
), d(NULL
),
804 IndexTargets(IndexTargets
),
805 AuthPass(false), IMSHit(false)
809 // AcqMetaBase::Add - Add a item to the current Transaction /*{{{*/
810 void pkgAcqMetaBase::Add(pkgAcqTransactionItem
* const I
)
812 Transaction
.push_back(I
);
815 // AcqMetaBase::AbortTransaction - Abort the current Transaction /*{{{*/
816 void pkgAcqMetaBase::AbortTransaction()
818 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
819 std::clog
<< "AbortTransaction: " << TransactionManager
<< std::endl
;
821 // ensure the toplevel is in error state too
822 for (std::vector
<pkgAcqTransactionItem
*>::iterator I
= Transaction
.begin();
823 I
!= Transaction
.end(); ++I
)
825 (*I
)->TransactionState(TransactionAbort
);
830 // AcqMetaBase::TransactionHasError - Check for errors in Transaction /*{{{*/
831 APT_PURE
bool pkgAcqMetaBase::TransactionHasError() const
833 for (std::vector
<pkgAcqTransactionItem
*>::const_iterator I
= Transaction
.begin();
834 I
!= Transaction
.end(); ++I
)
836 switch((*I
)->Status
) {
837 case StatDone
: break;
838 case StatIdle
: break;
839 case StatAuthError
: return true;
840 case StatError
: return true;
841 case StatTransientNetworkError
: return true;
842 case StatFetching
: break;
848 // AcqMetaBase::CommitTransaction - Commit a transaction /*{{{*/
849 void pkgAcqMetaBase::CommitTransaction()
851 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
852 std::clog
<< "CommitTransaction: " << this << std::endl
;
854 // move new files into place *and* remove files that are not
855 // part of the transaction but are still on disk
856 for (std::vector
<pkgAcqTransactionItem
*>::iterator I
= Transaction
.begin();
857 I
!= Transaction
.end(); ++I
)
859 (*I
)->TransactionState(TransactionCommit
);
864 // AcqMetaBase::TransactionStageCopy - Stage a file for copying /*{{{*/
865 void pkgAcqMetaBase::TransactionStageCopy(pkgAcqTransactionItem
* const I
,
866 const std::string
&From
,
867 const std::string
&To
)
869 I
->PartialFile
= From
;
873 // AcqMetaBase::TransactionStageRemoval - Stage a file for removal /*{{{*/
874 void pkgAcqMetaBase::TransactionStageRemoval(pkgAcqTransactionItem
* const I
,
875 const std::string
&FinalFile
)
878 I
->DestFile
= FinalFile
;
881 // AcqMetaBase::GenerateAuthWarning - Check gpg authentication error /*{{{*/
882 bool pkgAcqMetaBase::CheckStopAuthentication(pkgAcquire::Item
* const I
, const std::string
&Message
)
884 // FIXME: this entire function can do now that we disallow going to
885 // a unauthenticated state and can cleanly rollback
887 string
const Final
= I
->GetFinalFilename();
888 if(FileExists(Final
))
890 I
->Status
= StatTransientNetworkError
;
891 _error
->Warning(_("An error occurred during the signature "
892 "verification. The repository is not updated "
893 "and the previous index files will be used. "
894 "GPG error: %s: %s"),
895 Desc
.Description
.c_str(),
896 LookupTag(Message
,"Message").c_str());
897 RunScripts("APT::Update::Auth-Failure");
899 } else if (LookupTag(Message
,"Message").find("NODATA") != string::npos
) {
900 /* Invalid signature file, reject (LP: #346386) (Closes: #627642) */
901 _error
->Error(_("GPG error: %s: %s"),
902 Desc
.Description
.c_str(),
903 LookupTag(Message
,"Message").c_str());
904 I
->Status
= StatAuthError
;
907 _error
->Warning(_("GPG error: %s: %s"),
908 Desc
.Description
.c_str(),
909 LookupTag(Message
,"Message").c_str());
911 // gpgv method failed
912 ReportMirrorFailure("GPGFailure");
916 // AcqMetaBase::Custom600Headers - Get header for AcqMetaBase /*{{{*/
917 // ---------------------------------------------------------------------
918 string
pkgAcqMetaBase::Custom600Headers() const
920 std::string Header
= "\nIndex-File: true";
921 std::string MaximumSize
;
922 strprintf(MaximumSize
, "\nMaximum-Size: %i",
923 _config
->FindI("Acquire::MaxReleaseFileSize", 10*1000*1000));
924 Header
+= MaximumSize
;
926 string
const FinalFile
= GetFinalFilename();
928 if (stat(FinalFile
.c_str(),&Buf
) == 0)
929 Header
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
934 // AcqMetaBase::QueueForSignatureVerify /*{{{*/
935 void pkgAcqMetaBase::QueueForSignatureVerify(pkgAcqTransactionItem
* const I
, std::string
const &File
, std::string
const &Signature
)
938 I
->Desc
.URI
= "gpgv:" + Signature
;
941 I
->SetActiveSubprocess("gpgv");
944 // AcqMetaBase::CheckDownloadDone /*{{{*/
945 bool pkgAcqMetaBase::CheckDownloadDone(pkgAcqTransactionItem
* const I
, const std::string
&Message
, HashStringList
const &Hashes
) const
947 // We have just finished downloading a Release file (it is not
950 std::string
const FileName
= LookupTag(Message
,"Filename");
951 if (FileName
!= I
->DestFile
&& RealFileExists(I
->DestFile
) == false)
954 I
->Desc
.URI
= "copy:" + FileName
;
955 I
->QueueURI(I
->Desc
);
959 // make sure to verify against the right file on I-M-S hit
960 bool IMSHit
= StringToBool(LookupTag(Message
,"IMS-Hit"), false);
961 if (IMSHit
== false && Hashes
.usable())
963 // detect IMS-Hits servers haven't detected by Hash comparison
964 std::string
const FinalFile
= I
->GetFinalFilename();
965 if (RealFileExists(FinalFile
) && Hashes
.VerifyFile(FinalFile
) == true)
968 RemoveFile("CheckDownloadDone", I
->DestFile
);
974 // for simplicity, the transaction manager is always InRelease
975 // even if it doesn't exist.
976 if (TransactionManager
!= NULL
)
977 TransactionManager
->IMSHit
= true;
978 I
->PartialFile
= I
->DestFile
= I
->GetFinalFilename();
981 // set Item to complete as the remaining work is all local (verify etc)
987 bool pkgAcqMetaBase::CheckAuthDone(string
const &Message
) /*{{{*/
989 // At this point, the gpgv method has succeeded, so there is a
990 // valid signature from a key in the trusted keyring. We
991 // perform additional verification of its contents, and use them
992 // to verify the indexes we are about to download
994 if (TransactionManager
->IMSHit
== false)
996 // open the last (In)Release if we have it
997 std::string
const FinalFile
= GetFinalFilename();
998 std::string FinalRelease
;
999 std::string FinalInRelease
;
1000 if (APT::String::Endswith(FinalFile
, "InRelease"))
1002 FinalInRelease
= FinalFile
;
1003 FinalRelease
= FinalFile
.substr(0, FinalFile
.length() - strlen("InRelease")) + "Release";
1007 FinalInRelease
= FinalFile
.substr(0, FinalFile
.length() - strlen("Release")) + "InRelease";
1008 FinalRelease
= FinalFile
;
1010 if (RealFileExists(FinalInRelease
) || RealFileExists(FinalRelease
))
1012 TransactionManager
->LastMetaIndexParser
= TransactionManager
->MetaIndexParser
->UnloadedClone();
1013 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1015 _error
->PushToStack();
1016 if (RealFileExists(FinalInRelease
))
1017 TransactionManager
->LastMetaIndexParser
->Load(FinalInRelease
, NULL
);
1019 TransactionManager
->LastMetaIndexParser
->Load(FinalRelease
, NULL
);
1020 // its unlikely to happen, but if what we have is bad ignore it
1021 if (_error
->PendingError())
1023 delete TransactionManager
->LastMetaIndexParser
;
1024 TransactionManager
->LastMetaIndexParser
= NULL
;
1026 _error
->RevertToStack();
1031 if (TransactionManager
->MetaIndexParser
->Load(DestFile
, &ErrorText
) == false)
1033 Status
= StatAuthError
;
1037 if (!VerifyVendor(Message
))
1039 Status
= StatAuthError
;
1043 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1044 std::cerr
<< "Signature verification succeeded: "
1045 << DestFile
<< std::endl
;
1047 // Download further indexes with verification
1053 void pkgAcqMetaBase::QueueIndexes(bool const verify
) /*{{{*/
1055 // at this point the real Items are loaded in the fetcher
1056 ExpectedAdditionalItems
= 0;
1058 bool metaBaseSupportsByHash
= false;
1059 if (TransactionManager
!= NULL
&& TransactionManager
->MetaIndexParser
!= NULL
)
1060 metaBaseSupportsByHash
= TransactionManager
->MetaIndexParser
->GetSupportsAcquireByHash();
1062 for (std::vector
<IndexTarget
>::iterator Target
= IndexTargets
.begin();
1063 Target
!= IndexTargets
.end();
1066 // all is an implementation detail. Users shouldn't use this as arch
1067 // We need this support trickery here as e.g. Debian has binary-all files already,
1068 // but arch:all packages are still in the arch:any files, so we would waste precious
1069 // download time, bandwidth and diskspace for nothing, BUT Debian doesn't feature all
1070 // in the set of supported architectures, so we can filter based on this property rather
1071 // than invent an entirely new flag we would need to carry for all of eternity.
1072 if (Target
->Option(IndexTarget::ARCHITECTURE
) == "all")
1074 if (TransactionManager
->MetaIndexParser
->IsArchitectureSupported("all") == false)
1076 if (TransactionManager
->MetaIndexParser
->IsArchitectureAllSupportedFor(*Target
) == false)
1080 bool trypdiff
= Target
->OptionBool(IndexTarget::PDIFFS
);
1083 if (TransactionManager
->MetaIndexParser
->Exists(Target
->MetaKey
) == false)
1085 // optional targets that we do not have in the Release file are skipped
1086 if (Target
->IsOptional
)
1089 std::string
const &arch
= Target
->Option(IndexTarget::ARCHITECTURE
);
1090 if (arch
.empty() == false)
1092 if (TransactionManager
->MetaIndexParser
->IsArchitectureSupported(arch
) == false)
1094 _error
->Notice(_("Skipping acquire of configured file '%s' as repository '%s' doesn't support architecture '%s'"),
1095 Target
->MetaKey
.c_str(), TransactionManager
->Target
.Description
.c_str(), arch
.c_str());
1098 // if the architecture is officially supported but currently no packages for it available,
1099 // ignore silently as this is pretty much the same as just shipping an empty file.
1100 // if we don't know which architectures are supported, we do NOT ignore it to notify user about this
1101 if (TransactionManager
->MetaIndexParser
->IsArchitectureSupported("*undefined*") == false)
1105 Status
= StatAuthError
;
1106 strprintf(ErrorText
, _("Unable to find expected entry '%s' in Release file (Wrong sources.list entry or malformed file)"), Target
->MetaKey
.c_str());
1111 auto const hashes
= GetExpectedHashesFor(Target
->MetaKey
);
1112 if (hashes
.usable() == false && hashes
.empty() == false)
1114 _error
->Warning(_("Skipping acquire of configured file '%s' as repository '%s' provides only weak security information for it"),
1115 Target
->MetaKey
.c_str(), TransactionManager
->Target
.Description
.c_str());
1120 // autoselect the compression method
1121 std::vector
<std::string
> types
= VectorizeString(Target
->Option(IndexTarget::COMPRESSIONTYPES
), ' ');
1122 types
.erase(std::remove_if(types
.begin(), types
.end(), [&](std::string
const &t
) {
1123 if (t
== "uncompressed")
1124 return TransactionManager
->MetaIndexParser
->Exists(Target
->MetaKey
) == false;
1125 std::string
const MetaKey
= Target
->MetaKey
+ "." + t
;
1126 return TransactionManager
->MetaIndexParser
->Exists(MetaKey
) == false;
1128 if (types
.empty() == false)
1130 std::ostringstream os
;
1131 // add the special compressiontype byhash first if supported
1132 std::string
const useByHashConf
= Target
->Option(IndexTarget::BY_HASH
);
1133 bool useByHash
= false;
1134 if(useByHashConf
== "force")
1137 useByHash
= StringToBool(useByHashConf
) == true && metaBaseSupportsByHash
;
1138 if (useByHash
== true)
1140 std::copy(types
.begin(), types
.end()-1, std::ostream_iterator
<std::string
>(os
, " "));
1141 os
<< *types
.rbegin();
1142 Target
->Options
["COMPRESSIONTYPES"] = os
.str();
1145 Target
->Options
["COMPRESSIONTYPES"].clear();
1147 std::string filename
= GetFinalFileNameFromURI(Target
->URI
);
1148 if (RealFileExists(filename
) == false)
1150 if (Target
->KeepCompressed
)
1152 filename
= GetKeepCompressedFileName(filename
, *Target
);
1153 if (RealFileExists(filename
) == false)
1160 if (filename
.empty() == false)
1162 // if the Release file is a hit and we have an index it must be the current one
1163 if (TransactionManager
->IMSHit
== true)
1165 else if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1167 // see if the file changed since the last Release file
1168 // we use the uncompressed files as we might compress differently compared to the server,
1169 // so the hashes might not match, even if they contain the same data.
1170 HashStringList
const newFile
= GetExpectedHashesFromFor(TransactionManager
->MetaIndexParser
, Target
->MetaKey
);
1171 HashStringList
const oldFile
= GetExpectedHashesFromFor(TransactionManager
->LastMetaIndexParser
, Target
->MetaKey
);
1172 if (newFile
!= oldFile
)
1179 trypdiff
= false; // no file to patch
1181 if (filename
.empty() == false)
1183 new NoActionItem(Owner
, *Target
, filename
);
1184 std::string
const idxfilename
= GetFinalFileNameFromURI(Target
->URI
+ ".diff/Index");
1185 if (FileExists(idxfilename
))
1186 new NoActionItem(Owner
, *Target
, idxfilename
);
1190 // check if we have patches available
1191 trypdiff
&= TransactionManager
->MetaIndexParser
->Exists(Target
->MetaKey
+ ".diff/Index");
1195 // if we have no file to patch, no point in trying
1196 std::string filename
= GetFinalFileNameFromURI(Target
->URI
);
1197 if (RealFileExists(filename
) == false)
1199 if (Target
->KeepCompressed
)
1201 filename
= GetKeepCompressedFileName(filename
, *Target
);
1202 if (RealFileExists(filename
) == false)
1208 trypdiff
&= (filename
.empty() == false);
1211 // no point in patching from local sources
1214 std::string
const proto
= Target
->URI
.substr(0, strlen("file:/"));
1215 if (proto
== "file:/" || proto
== "copy:/" || proto
== "cdrom:")
1219 // Queue the Index file (Packages, Sources, Translation-$foo, …)
1221 new pkgAcqDiffIndex(Owner
, TransactionManager
, *Target
);
1223 new pkgAcqIndex(Owner
, TransactionManager
, *Target
);
1227 bool pkgAcqMetaBase::VerifyVendor(string
const &Message
) /*{{{*/
1229 string::size_type pos
;
1231 // check for missing sigs (that where not fatal because otherwise we had
1234 string msg
= _("There is no public key available for the "
1235 "following key IDs:\n");
1236 pos
= Message
.find("NO_PUBKEY ");
1237 if (pos
!= std::string::npos
)
1239 string::size_type start
= pos
+strlen("NO_PUBKEY ");
1240 string Fingerprint
= Message
.substr(start
, Message
.find("\n")-start
);
1241 missingkeys
+= (Fingerprint
);
1243 if(!missingkeys
.empty())
1244 _error
->Warning("%s", (msg
+ missingkeys
).c_str());
1246 string Transformed
= TransactionManager
->MetaIndexParser
->GetExpectedDist();
1248 if (Transformed
== "../project/experimental")
1250 Transformed
= "experimental";
1253 pos
= Transformed
.rfind('/');
1254 if (pos
!= string::npos
)
1256 Transformed
= Transformed
.substr(0, pos
);
1259 if (Transformed
== ".")
1264 if (TransactionManager
->MetaIndexParser
->GetValidUntil() > 0)
1266 time_t const invalid_since
= time(NULL
) - TransactionManager
->MetaIndexParser
->GetValidUntil();
1267 if (invalid_since
> 0)
1271 // TRANSLATOR: The first %s is the URL of the bad Release file, the second is
1272 // the time since then the file is invalid - formatted in the same way as in
1273 // the download progress display (e.g. 7d 3h 42min 1s)
1274 _("Release file for %s is expired (invalid since %s). "
1275 "Updates for this repository will not be applied."),
1276 Target
.URI
.c_str(), TimeToStr(invalid_since
).c_str());
1277 if (ErrorText
.empty())
1279 return _error
->Error("%s", errmsg
.c_str());
1283 /* Did we get a file older than what we have? This is a last minute IMS hit and doubles
1284 as a prevention of downgrading us to older (still valid) files */
1285 if (TransactionManager
->IMSHit
== false && TransactionManager
->LastMetaIndexParser
!= NULL
&&
1286 TransactionManager
->LastMetaIndexParser
->GetDate() > TransactionManager
->MetaIndexParser
->GetDate())
1288 TransactionManager
->IMSHit
= true;
1289 RemoveFile("VerifyVendor", DestFile
);
1290 PartialFile
= DestFile
= GetFinalFilename();
1291 // load the 'old' file in the 'new' one instead of flipping pointers as
1292 // the new one isn't owned by us, while the old one is so cleanup would be confused.
1293 TransactionManager
->MetaIndexParser
->swapLoad(TransactionManager
->LastMetaIndexParser
);
1294 delete TransactionManager
->LastMetaIndexParser
;
1295 TransactionManager
->LastMetaIndexParser
= NULL
;
1298 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1300 std::cerr
<< "Got Codename: " << TransactionManager
->MetaIndexParser
->GetCodename() << std::endl
;
1301 std::cerr
<< "Expecting Dist: " << TransactionManager
->MetaIndexParser
->GetExpectedDist() << std::endl
;
1302 std::cerr
<< "Transformed Dist: " << Transformed
<< std::endl
;
1305 if (TransactionManager
->MetaIndexParser
->CheckDist(Transformed
) == false)
1307 // This might become fatal one day
1308 // Status = StatAuthError;
1309 // ErrorText = "Conflicting distribution; expected "
1310 // + MetaIndexParser->GetExpectedDist() + " but got "
1311 // + MetaIndexParser->GetCodename();
1313 if (!Transformed
.empty())
1315 _error
->Warning(_("Conflicting distribution: %s (expected %s but got %s)"),
1316 Desc
.Description
.c_str(),
1317 Transformed
.c_str(),
1318 TransactionManager
->MetaIndexParser
->GetCodename().c_str());
1325 pkgAcqMetaBase::~pkgAcqMetaBase()
1329 pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire
* const Owner
, /*{{{*/
1330 IndexTarget
const &ClearsignedTarget
,
1331 IndexTarget
const &DetachedDataTarget
, IndexTarget
const &DetachedSigTarget
,
1332 std::vector
<IndexTarget
> const &IndexTargets
,
1333 metaIndex
* const MetaIndexParser
) :
1334 pkgAcqMetaIndex(Owner
, this, ClearsignedTarget
, DetachedSigTarget
, IndexTargets
),
1335 d(NULL
), ClearsignedTarget(ClearsignedTarget
),
1336 DetachedDataTarget(DetachedDataTarget
),
1337 MetaIndexParser(MetaIndexParser
), LastMetaIndexParser(NULL
)
1339 // index targets + (worst case:) Release/Release.gpg
1340 ExpectedAdditionalItems
= IndexTargets
.size() + 2;
1341 TransactionManager
->Add(this);
1344 pkgAcqMetaClearSig::~pkgAcqMetaClearSig() /*{{{*/
1346 if (LastMetaIndexParser
!= NULL
)
1347 delete LastMetaIndexParser
;
1350 // pkgAcqMetaClearSig::Custom600Headers - Insert custom request headers /*{{{*/
1351 string
pkgAcqMetaClearSig::Custom600Headers() const
1353 string Header
= pkgAcqMetaBase::Custom600Headers();
1354 Header
+= "\nFail-Ignore: true";
1355 std::string
const key
= TransactionManager
->MetaIndexParser
->GetSignedBy();
1356 if (key
.empty() == false)
1357 Header
+= "\nSigned-By: " + key
;
1362 bool pkgAcqMetaClearSig::VerifyDone(std::string
const &Message
, /*{{{*/
1363 pkgAcquire::MethodConfig
const * const Cnf
)
1365 Item::VerifyDone(Message
, Cnf
);
1367 if (FileExists(DestFile
) && !StartsWithGPGClearTextSignature(DestFile
))
1368 return RenameOnError(NotClearsigned
);
1373 // pkgAcqMetaClearSig::Done - We got a file /*{{{*/
1374 void pkgAcqMetaClearSig::Done(std::string
const &Message
,
1375 HashStringList
const &Hashes
,
1376 pkgAcquire::MethodConfig
const * const Cnf
)
1378 Item::Done(Message
, Hashes
, Cnf
);
1380 if(AuthPass
== false)
1382 if(CheckDownloadDone(this, Message
, Hashes
) == true)
1383 QueueForSignatureVerify(this, DestFile
, DestFile
);
1386 else if(CheckAuthDone(Message
) == true)
1388 if (TransactionManager
->IMSHit
== false)
1389 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
1390 else if (RealFileExists(GetFinalFilename()) == false)
1392 // We got an InRelease file IMSHit, but we haven't one, which means
1393 // we had a valid Release/Release.gpg combo stepping in, which we have
1394 // to 'acquire' now to ensure list cleanup isn't removing them
1395 new NoActionItem(Owner
, DetachedDataTarget
);
1396 new NoActionItem(Owner
, DetachedSigTarget
);
1401 void pkgAcqMetaClearSig::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
) /*{{{*/
1403 Item::Failed(Message
, Cnf
);
1405 // we failed, we will not get additional items from this method
1406 ExpectedAdditionalItems
= 0;
1408 if (AuthPass
== false)
1410 if (Status
== StatAuthError
|| Status
== StatTransientNetworkError
)
1412 // if we expected a ClearTextSignature (InRelease) but got a network
1413 // error or got a file, but it wasn't valid, we end up here (see VerifyDone).
1414 // As these is usually called by web-portals we do not try Release/Release.gpg
1415 // as this is gonna fail anyway and instead abort our try (LP#346386)
1416 TransactionManager
->AbortTransaction();
1420 // Queue the 'old' InRelease file for removal if we try Release.gpg
1421 // as otherwise the file will stay around and gives a false-auth
1422 // impression (CVE-2012-0214)
1423 TransactionManager
->TransactionStageRemoval(this, GetFinalFilename());
1426 new pkgAcqMetaIndex(Owner
, TransactionManager
, DetachedDataTarget
, DetachedSigTarget
, IndexTargets
);
1430 if(CheckStopAuthentication(this, Message
))
1433 // No Release file was present, or verification failed, so fall
1434 // back to queueing Packages files without verification
1435 // only allow going further if the user explicitly wants it
1436 if(AllowInsecureRepositories(_("The repository '%s' is not signed."), ClearsignedTarget
.Description
, TransactionManager
->MetaIndexParser
, TransactionManager
, this) == true)
1440 /* InRelease files become Release files, otherwise
1441 * they would be considered as trusted later on */
1442 string
const FinalRelease
= GetFinalFileNameFromURI(DetachedDataTarget
.URI
);
1443 string
const PartialRelease
= GetPartialFileNameFromURI(DetachedDataTarget
.URI
);
1444 string
const FinalReleasegpg
= GetFinalFileNameFromURI(DetachedSigTarget
.URI
);
1445 string
const FinalInRelease
= GetFinalFilename();
1446 Rename(DestFile
, PartialRelease
);
1447 TransactionManager
->TransactionStageCopy(this, PartialRelease
, FinalRelease
);
1449 if (RealFileExists(FinalReleasegpg
) || RealFileExists(FinalInRelease
))
1451 // open the last Release if we have it
1452 if (TransactionManager
->IMSHit
== false)
1454 TransactionManager
->LastMetaIndexParser
= TransactionManager
->MetaIndexParser
->UnloadedClone();
1455 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1457 _error
->PushToStack();
1458 if (RealFileExists(FinalInRelease
))
1459 TransactionManager
->LastMetaIndexParser
->Load(FinalInRelease
, NULL
);
1461 TransactionManager
->LastMetaIndexParser
->Load(FinalRelease
, NULL
);
1462 // its unlikely to happen, but if what we have is bad ignore it
1463 if (_error
->PendingError())
1465 delete TransactionManager
->LastMetaIndexParser
;
1466 TransactionManager
->LastMetaIndexParser
= NULL
;
1468 _error
->RevertToStack();
1473 // we parse the indexes here because at this point the user wanted
1474 // a repository that may potentially harm him
1475 if (TransactionManager
->MetaIndexParser
->Load(PartialRelease
, &ErrorText
) == false || VerifyVendor(Message
) == false)
1476 /* expired Release files are still a problem you need extra force for */;
1484 pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire
* const Owner
, /*{{{*/
1485 pkgAcqMetaClearSig
* const TransactionManager
,
1486 IndexTarget
const &DataTarget
,
1487 IndexTarget
const &DetachedSigTarget
,
1488 vector
<IndexTarget
> const &IndexTargets
) :
1489 pkgAcqMetaBase(Owner
, TransactionManager
, IndexTargets
, DataTarget
), d(NULL
),
1490 DetachedSigTarget(DetachedSigTarget
)
1492 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1493 std::clog
<< "New pkgAcqMetaIndex with TransactionManager "
1494 << this->TransactionManager
<< std::endl
;
1496 DestFile
= GetPartialFileNameFromURI(DataTarget
.URI
);
1499 Desc
.Description
= DataTarget
.Description
;
1501 Desc
.ShortDesc
= DataTarget
.ShortDesc
;
1502 Desc
.URI
= DataTarget
.URI
;
1504 // we expect more item
1505 ExpectedAdditionalItems
= IndexTargets
.size();
1509 void pkgAcqMetaIndex::Done(string
const &Message
, /*{{{*/
1510 HashStringList
const &Hashes
,
1511 pkgAcquire::MethodConfig
const * const Cfg
)
1513 Item::Done(Message
,Hashes
,Cfg
);
1515 if(CheckDownloadDone(this, Message
, Hashes
))
1517 // we have a Release file, now download the Signature, all further
1518 // verify/queue for additional downloads will be done in the
1519 // pkgAcqMetaSig::Done() code
1520 new pkgAcqMetaSig(Owner
, TransactionManager
, DetachedSigTarget
, this);
1524 // pkgAcqMetaIndex::Failed - no Release file present /*{{{*/
1525 void pkgAcqMetaIndex::Failed(string
const &Message
,
1526 pkgAcquire::MethodConfig
const * const Cnf
)
1528 pkgAcquire::Item::Failed(Message
, Cnf
);
1531 // No Release file was present so fall
1532 // back to queueing Packages files without verification
1533 // only allow going further if the user explicitly wants it
1534 if(AllowInsecureRepositories(_("The repository '%s' does not have a Release file."), Target
.Description
, TransactionManager
->MetaIndexParser
, TransactionManager
, this) == true)
1536 // ensure old Release files are removed
1537 TransactionManager
->TransactionStageRemoval(this, GetFinalFilename());
1539 // queue without any kind of hashsum support
1540 QueueIndexes(false);
1544 void pkgAcqMetaIndex::Finished() /*{{{*/
1546 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1547 std::clog
<< "Finished: " << DestFile
<<std::endl
;
1548 if(TransactionManager
!= NULL
&&
1549 TransactionManager
->TransactionHasError() == false)
1550 TransactionManager
->CommitTransaction();
1553 std::string
pkgAcqMetaIndex::DescURI() const /*{{{*/
1558 pkgAcqMetaIndex::~pkgAcqMetaIndex() {}
1560 // AcqMetaSig::AcqMetaSig - Constructor /*{{{*/
1561 pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire
* const Owner
,
1562 pkgAcqMetaClearSig
* const TransactionManager
,
1563 IndexTarget
const &Target
,
1564 pkgAcqMetaIndex
* const MetaIndex
) :
1565 pkgAcqTransactionItem(Owner
, TransactionManager
, Target
), d(NULL
), MetaIndex(MetaIndex
)
1567 DestFile
= GetPartialFileNameFromURI(Target
.URI
);
1569 // remove any partial downloaded sig-file in partial/.
1570 // it may confuse proxies and is too small to warrant a
1571 // partial download anyway
1572 RemoveFile("pkgAcqMetaSig", DestFile
);
1574 // set the TransactionManager
1575 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1576 std::clog
<< "New pkgAcqMetaSig with TransactionManager "
1577 << TransactionManager
<< std::endl
;
1580 Desc
.Description
= Target
.Description
;
1582 Desc
.ShortDesc
= Target
.ShortDesc
;
1583 Desc
.URI
= Target
.URI
;
1585 // If we got a hit for Release, we will get one for Release.gpg too (or obscure errors),
1586 // so we skip the download step and go instantly to verification
1587 if (TransactionManager
->IMSHit
== true && RealFileExists(GetFinalFilename()))
1591 PartialFile
= DestFile
= GetFinalFilename();
1592 MetaIndexFileSignature
= DestFile
;
1593 MetaIndex
->QueueForSignatureVerify(this, MetaIndex
->DestFile
, DestFile
);
1599 pkgAcqMetaSig::~pkgAcqMetaSig() /*{{{*/
1603 // pkgAcqMetaSig::Custom600Headers - Insert custom request headers /*{{{*/
1604 std::string
pkgAcqMetaSig::Custom600Headers() const
1606 std::string Header
= pkgAcqTransactionItem::Custom600Headers();
1607 std::string
const key
= TransactionManager
->MetaIndexParser
->GetSignedBy();
1608 if (key
.empty() == false)
1609 Header
+= "\nSigned-By: " + key
;
1613 // AcqMetaSig::Done - The signature was downloaded/verified /*{{{*/
1614 void pkgAcqMetaSig::Done(string
const &Message
, HashStringList
const &Hashes
,
1615 pkgAcquire::MethodConfig
const * const Cfg
)
1617 if (MetaIndexFileSignature
.empty() == false)
1619 DestFile
= MetaIndexFileSignature
;
1620 MetaIndexFileSignature
.clear();
1622 Item::Done(Message
, Hashes
, Cfg
);
1624 if(MetaIndex
->AuthPass
== false)
1626 if(MetaIndex
->CheckDownloadDone(this, Message
, Hashes
) == true)
1628 // destfile will be modified to point to MetaIndexFile for the
1629 // gpgv method, so we need to save it here
1630 MetaIndexFileSignature
= DestFile
;
1631 MetaIndex
->QueueForSignatureVerify(this, MetaIndex
->DestFile
, DestFile
);
1635 else if(MetaIndex
->CheckAuthDone(Message
) == true)
1637 if (TransactionManager
->IMSHit
== false)
1639 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
1640 TransactionManager
->TransactionStageCopy(MetaIndex
, MetaIndex
->DestFile
, MetaIndex
->GetFinalFilename());
1645 void pkgAcqMetaSig::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
1647 Item::Failed(Message
,Cnf
);
1649 // check if we need to fail at this point
1650 if (MetaIndex
->AuthPass
== true && MetaIndex
->CheckStopAuthentication(this, Message
))
1653 string
const FinalRelease
= MetaIndex
->GetFinalFilename();
1654 string
const FinalReleasegpg
= GetFinalFilename();
1655 string
const FinalInRelease
= TransactionManager
->GetFinalFilename();
1657 if (RealFileExists(FinalReleasegpg
) || RealFileExists(FinalInRelease
))
1659 std::string downgrade_msg
;
1660 strprintf(downgrade_msg
, _("The repository '%s' is no longer signed."),
1661 MetaIndex
->Target
.Description
.c_str());
1662 if(_config
->FindB("Acquire::AllowDowngradeToInsecureRepositories"))
1664 // meh, the users wants to take risks (we still mark the packages
1665 // from this repository as unauthenticated)
1666 _error
->Warning("%s", downgrade_msg
.c_str());
1667 _error
->Warning(_("This is normally not allowed, but the option "
1668 "Acquire::AllowDowngradeToInsecureRepositories was "
1669 "given to override it."));
1672 MessageInsecureRepository(true, downgrade_msg
);
1673 if (TransactionManager
->IMSHit
== false)
1674 Rename(MetaIndex
->DestFile
, MetaIndex
->DestFile
+ ".FAILED");
1675 Item::Failed("Message: " + downgrade_msg
, Cnf
);
1676 TransactionManager
->AbortTransaction();
1681 // ensures that a Release.gpg file in the lists/ is removed by the transaction
1682 TransactionManager
->TransactionStageRemoval(this, DestFile
);
1684 // only allow going further if the user explicitly wants it
1685 if (AllowInsecureRepositories(_("The repository '%s' is not signed."), MetaIndex
->Target
.Description
, TransactionManager
->MetaIndexParser
, TransactionManager
, this) == true)
1687 if (RealFileExists(FinalReleasegpg
) || RealFileExists(FinalInRelease
))
1689 // open the last Release if we have it
1690 if (TransactionManager
->IMSHit
== false)
1692 TransactionManager
->LastMetaIndexParser
= TransactionManager
->MetaIndexParser
->UnloadedClone();
1693 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1695 _error
->PushToStack();
1696 if (RealFileExists(FinalInRelease
))
1697 TransactionManager
->LastMetaIndexParser
->Load(FinalInRelease
, NULL
);
1699 TransactionManager
->LastMetaIndexParser
->Load(FinalRelease
, NULL
);
1700 // its unlikely to happen, but if what we have is bad ignore it
1701 if (_error
->PendingError())
1703 delete TransactionManager
->LastMetaIndexParser
;
1704 TransactionManager
->LastMetaIndexParser
= NULL
;
1706 _error
->RevertToStack();
1711 // we parse the indexes here because at this point the user wanted
1712 // a repository that may potentially harm him
1713 bool const GoodLoad
= TransactionManager
->MetaIndexParser
->Load(MetaIndex
->DestFile
, &ErrorText
);
1714 if (MetaIndex
->VerifyVendor(Message
) == false)
1715 /* expired Release files are still a problem you need extra force for */;
1717 MetaIndex
->QueueIndexes(GoodLoad
);
1719 TransactionManager
->TransactionStageCopy(MetaIndex
, MetaIndex
->DestFile
, MetaIndex
->GetFinalFilename());
1722 // FIXME: this is used often (e.g. in pkgAcqIndexTrans) so refactor
1723 if (Cnf
->LocalOnly
== true ||
1724 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1733 // AcqBaseIndex - Constructor /*{{{*/
1734 pkgAcqBaseIndex::pkgAcqBaseIndex(pkgAcquire
* const Owner
,
1735 pkgAcqMetaClearSig
* const TransactionManager
,
1736 IndexTarget
const &Target
)
1737 : pkgAcqTransactionItem(Owner
, TransactionManager
, Target
), d(NULL
)
1741 pkgAcqBaseIndex::~pkgAcqBaseIndex() {}
1743 // AcqDiffIndex::AcqDiffIndex - Constructor /*{{{*/
1744 // ---------------------------------------------------------------------
1745 /* Get the DiffIndex file first and see if there are patches available
1746 * If so, create a pkgAcqIndexDiffs fetcher that will get and apply the
1747 * patches. If anything goes wrong in that process, it will fall back to
1748 * the original packages file
1750 pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire
* const Owner
,
1751 pkgAcqMetaClearSig
* const TransactionManager
,
1752 IndexTarget
const &Target
)
1753 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
), diffs(NULL
)
1755 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
1758 Desc
.Description
= Target
.Description
+ ".diff/Index";
1759 Desc
.ShortDesc
= Target
.ShortDesc
;
1760 Desc
.URI
= Target
.URI
+ ".diff/Index";
1762 DestFile
= GetPartialFileNameFromURI(Desc
.URI
);
1765 std::clog
<< "pkgAcqDiffIndex: " << Desc
.URI
<< std::endl
;
1770 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
1771 // ---------------------------------------------------------------------
1772 /* The only header we use is the last-modified header. */
1773 string
pkgAcqDiffIndex::Custom600Headers() const
1775 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1776 return "\nIndex-File: true";
1778 string
const Final
= GetFinalFilename();
1781 std::clog
<< "Custom600Header-IMS: " << Final
<< std::endl
;
1784 if (stat(Final
.c_str(),&Buf
) != 0)
1785 return "\nIndex-File: true";
1787 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1790 void pkgAcqDiffIndex::QueueOnIMSHit() const /*{{{*/
1792 // list cleanup needs to know that this file as well as the already
1793 // present index is ours, so we create an empty diff to save it for us
1794 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
);
1797 bool pkgAcqDiffIndex::ParseDiffIndex(string
const &IndexDiffFile
) /*{{{*/
1799 // failing here is fine: our caller will take care of trying to
1800 // get the complete file if patching fails
1802 std::clog
<< "pkgAcqDiffIndex::ParseIndexDiff() " << IndexDiffFile
1805 FileFd
Fd(IndexDiffFile
,FileFd::ReadOnly
);
1807 if (Fd
.IsOpen() == false || Fd
.Failed())
1811 if(unlikely(TF
.Step(Tags
) == false))
1814 HashStringList ServerHashes
;
1815 unsigned long long ServerSize
= 0;
1817 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
1819 std::string tagname
= *type
;
1820 tagname
.append("-Current");
1821 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1822 if (tmp
.empty() == true)
1826 unsigned long long size
;
1827 std::stringstream
ss(tmp
);
1829 if (unlikely(hash
.empty() == true))
1831 if (unlikely(ServerSize
!= 0 && ServerSize
!= size
))
1833 ServerHashes
.push_back(HashString(*type
, hash
));
1837 if (ServerHashes
.usable() == false)
1840 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": Did not find a good hashsum in the index" << std::endl
;
1844 std::string
const CurrentPackagesFile
= GetFinalFileNameFromURI(Target
.URI
);
1845 HashStringList
const TargetFileHashes
= GetExpectedHashesFor(Target
.MetaKey
);
1846 if (TargetFileHashes
.usable() == false || ServerHashes
!= TargetFileHashes
)
1850 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": Index has different hashes than parser, probably older, so fail pdiffing" << std::endl
;
1851 printHashSumComparision(CurrentPackagesFile
, ServerHashes
, TargetFileHashes
);
1856 HashStringList LocalHashes
;
1857 // try avoiding calculating the hash here as this is costly
1858 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1859 LocalHashes
= GetExpectedHashesFromFor(TransactionManager
->LastMetaIndexParser
, Target
.MetaKey
);
1860 if (LocalHashes
.usable() == false)
1862 FileFd
fd(CurrentPackagesFile
, FileFd::ReadOnly
, FileFd::Auto
);
1863 Hashes
LocalHashesCalc(ServerHashes
);
1864 LocalHashesCalc
.AddFD(fd
);
1865 LocalHashes
= LocalHashesCalc
.GetHashStringList();
1868 if (ServerHashes
== LocalHashes
)
1870 // we have the same sha1 as the server so we are done here
1872 std::clog
<< "pkgAcqDiffIndex: Package file " << CurrentPackagesFile
<< " is up-to-date" << std::endl
;
1878 std::clog
<< "Server-Current: " << ServerHashes
.find(NULL
)->toStr() << " and we start at "
1879 << CurrentPackagesFile
<< " " << LocalHashes
.FileSize() << " " << LocalHashes
.find(NULL
)->toStr() << std::endl
;
1881 // historically, older hashes have more info than newer ones, so start
1882 // collecting with older ones first to avoid implementing complicated
1883 // information merging techniques… a failure is after all always
1884 // recoverable with a complete file and hashes aren't changed that often.
1885 std::vector
<char const *> types
;
1886 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
1887 types
.push_back(*type
);
1889 // parse all of (provided) history
1890 vector
<DiffInfo
> available_patches
;
1891 bool firstAcceptedHashes
= true;
1892 for (auto type
= types
.crbegin(); type
!= types
.crend(); ++type
)
1894 if (LocalHashes
.find(*type
) == NULL
)
1897 std::string tagname
= *type
;
1898 tagname
.append("-History");
1899 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1900 if (tmp
.empty() == true)
1903 string hash
, filename
;
1904 unsigned long long size
;
1905 std::stringstream
ss(tmp
);
1907 while (ss
>> hash
>> size
>> filename
)
1909 if (unlikely(hash
.empty() == true || filename
.empty() == true))
1912 // see if we have a record for this file already
1913 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
1914 for (; cur
!= available_patches
.end(); ++cur
)
1916 if (cur
->file
!= filename
)
1918 cur
->result_hashes
.push_back(HashString(*type
, hash
));
1921 if (cur
!= available_patches
.end())
1923 if (firstAcceptedHashes
== true)
1926 next
.file
= filename
;
1927 next
.result_hashes
.push_back(HashString(*type
, hash
));
1928 next
.result_hashes
.FileSize(size
);
1929 available_patches
.push_back(next
);
1934 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
1935 << " wasn't in the list for the first parsed hash! (history)" << std::endl
;
1939 firstAcceptedHashes
= false;
1942 if (unlikely(available_patches
.empty() == true))
1945 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": "
1946 << "Couldn't find any patches for the patch series." << std::endl
;
1950 for (auto type
= types
.crbegin(); type
!= types
.crend(); ++type
)
1952 if (LocalHashes
.find(*type
) == NULL
)
1955 std::string tagname
= *type
;
1956 tagname
.append("-Patches");
1957 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1958 if (tmp
.empty() == true)
1961 string hash
, filename
;
1962 unsigned long long size
;
1963 std::stringstream
ss(tmp
);
1965 while (ss
>> hash
>> size
>> filename
)
1967 if (unlikely(hash
.empty() == true || filename
.empty() == true))
1970 // see if we have a record for this file already
1971 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
1972 for (; cur
!= available_patches
.end(); ++cur
)
1974 if (cur
->file
!= filename
)
1976 if (cur
->patch_hashes
.empty())
1977 cur
->patch_hashes
.FileSize(size
);
1978 cur
->patch_hashes
.push_back(HashString(*type
, hash
));
1981 if (cur
!= available_patches
.end())
1984 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
1985 << " wasn't in the list for the first parsed hash! (patches)" << std::endl
;
1990 for (auto type
= types
.crbegin(); type
!= types
.crend(); ++type
)
1992 std::string tagname
= *type
;
1993 tagname
.append("-Download");
1994 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1995 if (tmp
.empty() == true)
1998 string hash
, filename
;
1999 unsigned long long size
;
2000 std::stringstream
ss(tmp
);
2002 // FIXME: all of pdiff supports only .gz compressed patches
2003 while (ss
>> hash
>> size
>> filename
)
2005 if (unlikely(hash
.empty() == true || filename
.empty() == true))
2007 if (unlikely(APT::String::Endswith(filename
, ".gz") == false))
2009 filename
.erase(filename
.length() - 3);
2011 // see if we have a record for this file already
2012 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
2013 for (; cur
!= available_patches
.end(); ++cur
)
2015 if (cur
->file
!= filename
)
2017 if (cur
->download_hashes
.empty())
2018 cur
->download_hashes
.FileSize(size
);
2019 cur
->download_hashes
.push_back(HashString(*type
, hash
));
2022 if (cur
!= available_patches
.end())
2025 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
2026 << " wasn't in the list for the first parsed hash! (download)" << std::endl
;
2032 bool foundStart
= false;
2033 for (std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
2034 cur
!= available_patches
.end(); ++cur
)
2036 if (LocalHashes
!= cur
->result_hashes
)
2039 available_patches
.erase(available_patches
.begin(), cur
);
2044 if (foundStart
== false || unlikely(available_patches
.empty() == true))
2047 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": "
2048 << "Couldn't find the start of the patch series." << std::endl
;
2052 // patching with too many files is rather slow compared to a fast download
2053 unsigned long const fileLimit
= _config
->FindI("Acquire::PDiffs::FileLimit", 0);
2054 if (fileLimit
!= 0 && fileLimit
< available_patches
.size())
2057 std::clog
<< "Need " << available_patches
.size() << " diffs (Limit is " << fileLimit
2058 << ") so fallback to complete download" << std::endl
;
2062 // calculate the size of all patches we have to get
2063 // note that all sizes are uncompressed, while we download compressed files
2064 unsigned long long patchesSize
= 0;
2065 for (std::vector
<DiffInfo
>::const_iterator cur
= available_patches
.begin();
2066 cur
!= available_patches
.end(); ++cur
)
2067 patchesSize
+= cur
->patch_hashes
.FileSize();
2068 unsigned long long const sizeLimit
= ServerSize
* _config
->FindI("Acquire::PDiffs::SizeLimit", 100);
2069 if (sizeLimit
> 0 && (sizeLimit
/100) < patchesSize
)
2072 std::clog
<< "Need " << patchesSize
<< " bytes (Limit is " << sizeLimit
/100
2073 << ") so fallback to complete download" << std::endl
;
2077 // we have something, queue the diffs
2078 string::size_type
const last_space
= Description
.rfind(" ");
2079 if(last_space
!= string::npos
)
2080 Description
.erase(last_space
, Description
.size()-last_space
);
2082 /* decide if we should download patches one by one or in one go:
2083 The first is good if the server merges patches, but many don't so client
2084 based merging can be attempt in which case the second is better.
2085 "bad things" will happen if patches are merged on the server,
2086 but client side merging is attempt as well */
2087 bool pdiff_merge
= _config
->FindB("Acquire::PDiffs::Merge", true);
2088 if (pdiff_merge
== true)
2090 // reprepro adds this flag if it has merged patches on the server
2091 std::string
const precedence
= Tags
.FindS("X-Patch-Precedence");
2092 pdiff_merge
= (precedence
!= "merged");
2095 if (pdiff_merge
== false)
2096 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
, available_patches
);
2099 diffs
= new std::vector
<pkgAcqIndexMergeDiffs
*>(available_patches
.size());
2100 for(size_t i
= 0; i
< available_patches
.size(); ++i
)
2101 (*diffs
)[i
] = new pkgAcqIndexMergeDiffs(Owner
, TransactionManager
,
2103 available_patches
[i
],
2113 void pkgAcqDiffIndex::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
2115 Item::Failed(Message
,Cnf
);
2119 std::clog
<< "pkgAcqDiffIndex failed: " << Desc
.URI
<< " with " << Message
<< std::endl
2120 << "Falling back to normal index file acquire" << std::endl
;
2122 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
2125 void pkgAcqDiffIndex::Done(string
const &Message
,HashStringList
const &Hashes
, /*{{{*/
2126 pkgAcquire::MethodConfig
const * const Cnf
)
2129 std::clog
<< "pkgAcqDiffIndex::Done(): " << Desc
.URI
<< std::endl
;
2131 Item::Done(Message
, Hashes
, Cnf
);
2133 string
const FinalFile
= GetFinalFilename();
2134 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false))
2135 DestFile
= FinalFile
;
2137 if(ParseDiffIndex(DestFile
) == false)
2139 Failed("Message: Couldn't parse pdiff index", Cnf
);
2140 // queue for final move - this should happen even if we fail
2141 // while parsing (e.g. on sizelimit) and download the complete file.
2142 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
2146 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
2155 pkgAcqDiffIndex::~pkgAcqDiffIndex()
2161 // AcqIndexDiffs::AcqIndexDiffs - Constructor /*{{{*/
2162 // ---------------------------------------------------------------------
2163 /* The package diff is added to the queue. one object is constructed
2164 * for each diff and the index
2166 pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire
* const Owner
,
2167 pkgAcqMetaClearSig
* const TransactionManager
,
2168 IndexTarget
const &Target
,
2169 vector
<DiffInfo
> const &diffs
)
2170 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
),
2171 available_patches(diffs
)
2173 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
2175 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
2178 Description
= Target
.Description
;
2179 Desc
.ShortDesc
= Target
.ShortDesc
;
2181 if(available_patches
.empty() == true)
2183 // we are done (yeah!), check hashes against the final file
2184 DestFile
= GetKeepCompressedFileName(GetFinalFileNameFromURI(Target
.URI
), Target
);
2189 if (BootstrapPDiffWith(GetPartialFileNameFromURI(Target
.URI
), GetFinalFilename(), Target
) == false)
2191 Failed("Bootstrapping of " + DestFile
+ " failed", NULL
);
2195 // get the next diff
2196 State
= StateFetchDiff
;
2201 void pkgAcqIndexDiffs::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
2203 Item::Failed(Message
,Cnf
);
2206 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
2208 std::clog
<< "pkgAcqIndexDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
2209 << "Falling back to normal index file acquire " << std::endl
;
2210 RenameOnError(PDiffError
);
2211 std::string
const patchname
= GetDiffsPatchFileName(DestFile
);
2212 if (RealFileExists(patchname
))
2213 rename(patchname
.c_str(), std::string(patchname
+ ".FAILED").c_str());
2214 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
2218 // Finish - helper that cleans the item out of the fetcher queue /*{{{*/
2219 void pkgAcqIndexDiffs::Finish(bool allDone
)
2222 std::clog
<< "pkgAcqIndexDiffs::Finish(): "
2224 << Desc
.URI
<< std::endl
;
2226 // we restore the original name, this is required, otherwise
2227 // the file will be cleaned
2230 std::string Final
= GetFinalFilename();
2231 if (Target
.KeepCompressed
)
2233 std::string
const ext
= flExtension(DestFile
);
2234 if (ext
.empty() == false)
2235 Final
.append(".").append(ext
);
2237 TransactionManager
->TransactionStageCopy(this, DestFile
, Final
);
2239 // this is for the "real" finish
2244 std::clog
<< "\n\nallDone: " << DestFile
<< "\n" << std::endl
;
2251 std::clog
<< "Finishing: " << Desc
.URI
<< std::endl
;
2258 bool pkgAcqIndexDiffs::QueueNextDiff() /*{{{*/
2260 // calc sha1 of the just patched file
2261 std::string
const FinalFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
2262 if(!FileExists(FinalFile
))
2264 Failed("Message: No FinalFile " + FinalFile
+ " available", NULL
);
2268 FileFd
fd(FinalFile
, FileFd::ReadOnly
, FileFd::Extension
);
2269 Hashes LocalHashesCalc
;
2270 LocalHashesCalc
.AddFD(fd
);
2271 HashStringList
const LocalHashes
= LocalHashesCalc
.GetHashStringList();
2274 std::clog
<< "QueueNextDiff: " << FinalFile
<< " (" << LocalHashes
.find(NULL
)->toStr() << ")" << std::endl
;
2276 HashStringList
const TargetFileHashes
= GetExpectedHashesFor(Target
.MetaKey
);
2277 if (unlikely(LocalHashes
.usable() == false || TargetFileHashes
.usable() == false))
2279 Failed("Local/Expected hashes are not usable", NULL
);
2284 // final file reached before all patches are applied
2285 if(LocalHashes
== TargetFileHashes
)
2291 // remove all patches until the next matching patch is found
2292 // this requires the Index file to be ordered
2293 available_patches
.erase(available_patches
.begin(),
2294 std::find_if(available_patches
.begin(), available_patches
.end(), [&](DiffInfo
const &I
) {
2295 return I
.result_hashes
== LocalHashes
;
2298 // error checking and falling back if no patch was found
2299 if(available_patches
.empty() == true)
2301 Failed("No patches left to reach target", NULL
);
2305 // queue the right diff
2306 Desc
.URI
= Target
.URI
+ ".diff/" + available_patches
[0].file
+ ".gz";
2307 Desc
.Description
= Description
+ " " + available_patches
[0].file
+ string(".pdiff");
2308 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
+ ".diff/" + available_patches
[0].file
), Target
);
2311 std::clog
<< "pkgAcqIndexDiffs::QueueNextDiff(): " << Desc
.URI
<< std::endl
;
2318 void pkgAcqIndexDiffs::Done(string
const &Message
, HashStringList
const &Hashes
, /*{{{*/
2319 pkgAcquire::MethodConfig
const * const Cnf
)
2322 std::clog
<< "pkgAcqIndexDiffs::Done(): " << Desc
.URI
<< std::endl
;
2324 Item::Done(Message
, Hashes
, Cnf
);
2326 std::string
const FinalFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
2327 std::string
const PatchFile
= GetDiffsPatchFileName(FinalFile
);
2329 // success in downloading a diff, enter ApplyDiff state
2330 if(State
== StateFetchDiff
)
2332 Rename(DestFile
, PatchFile
);
2335 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
2337 State
= StateApplyDiff
;
2339 Desc
.URI
= "rred:" + FinalFile
;
2341 SetActiveSubprocess("rred");
2345 // success in download/apply a diff, queue next (if needed)
2346 if(State
== StateApplyDiff
)
2348 // remove the just applied patch
2349 available_patches
.erase(available_patches
.begin());
2350 RemoveFile("pkgAcqIndexDiffs::Done", PatchFile
);
2355 std::clog
<< "Moving patched file in place: " << std::endl
2356 << DestFile
<< " -> " << FinalFile
<< std::endl
;
2358 Rename(DestFile
,FinalFile
);
2359 chmod(FinalFile
.c_str(),0644);
2361 // see if there is more to download
2362 if(available_patches
.empty() == false) {
2363 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
,
2368 DestFile
= FinalFile
;
2369 return Finish(true);
2373 std::string
pkgAcqIndexDiffs::Custom600Headers() const /*{{{*/
2375 if(State
!= StateApplyDiff
)
2376 return pkgAcqBaseIndex::Custom600Headers();
2377 std::ostringstream patchhashes
;
2378 HashStringList
const ExpectedHashes
= available_patches
[0].patch_hashes
;
2379 for (HashStringList::const_iterator hs
= ExpectedHashes
.begin(); hs
!= ExpectedHashes
.end(); ++hs
)
2380 patchhashes
<< "\nPatch-0-" << hs
->HashType() << "-Hash: " << hs
->HashValue();
2381 patchhashes
<< pkgAcqBaseIndex::Custom600Headers();
2382 return patchhashes
.str();
2385 pkgAcqIndexDiffs::~pkgAcqIndexDiffs() {}
2387 // AcqIndexMergeDiffs::AcqIndexMergeDiffs - Constructor /*{{{*/
2388 pkgAcqIndexMergeDiffs::pkgAcqIndexMergeDiffs(pkgAcquire
* const Owner
,
2389 pkgAcqMetaClearSig
* const TransactionManager
,
2390 IndexTarget
const &Target
,
2391 DiffInfo
const &patch
,
2392 std::vector
<pkgAcqIndexMergeDiffs
*> const * const allPatches
)
2393 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
),
2394 patch(patch
), allPatches(allPatches
), State(StateFetchDiff
)
2396 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
2399 Description
= Target
.Description
;
2400 Desc
.ShortDesc
= Target
.ShortDesc
;
2402 Desc
.URI
= Target
.URI
+ ".diff/" + patch
.file
+ ".gz";
2403 Desc
.Description
= Description
+ " " + patch
.file
+ string(".pdiff");
2405 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
+ ".diff/" + patch
.file
), Target
);
2408 std::clog
<< "pkgAcqIndexMergeDiffs: " << Desc
.URI
<< std::endl
;
2413 void pkgAcqIndexMergeDiffs::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
2416 std::clog
<< "pkgAcqIndexMergeDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
;
2418 Item::Failed(Message
,Cnf
);
2421 // check if we are the first to fail, otherwise we are done here
2422 State
= StateDoneDiff
;
2423 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2424 I
!= allPatches
->end(); ++I
)
2425 if ((*I
)->State
== StateErrorDiff
)
2428 // first failure means we should fallback
2429 State
= StateErrorDiff
;
2431 std::clog
<< "Falling back to normal index file acquire" << std::endl
;
2432 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
2433 RenameOnError(PDiffError
);
2434 std::string
const patchname
= GetMergeDiffsPatchFileName(DestFile
, patch
.file
);
2435 if (RealFileExists(patchname
))
2436 rename(patchname
.c_str(), std::string(patchname
+ ".FAILED").c_str());
2437 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
2441 void pkgAcqIndexMergeDiffs::Done(string
const &Message
, HashStringList
const &Hashes
, /*{{{*/
2442 pkgAcquire::MethodConfig
const * const Cnf
)
2445 std::clog
<< "pkgAcqIndexMergeDiffs::Done(): " << Desc
.URI
<< std::endl
;
2447 Item::Done(Message
, Hashes
, Cnf
);
2449 std::string
const UncompressedFinalFile
= GetPartialFileNameFromURI(Target
.URI
);
2450 std::string
const FinalFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
2451 if (State
== StateFetchDiff
)
2453 Rename(DestFile
, GetMergeDiffsPatchFileName(FinalFile
, patch
.file
));
2455 // check if this is the last completed diff
2456 State
= StateDoneDiff
;
2457 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2458 I
!= allPatches
->end(); ++I
)
2459 if ((*I
)->State
!= StateDoneDiff
)
2462 std::clog
<< "Not the last done diff in the batch: " << Desc
.URI
<< std::endl
;
2466 // this is the last completed diff, so we are ready to apply now
2467 State
= StateApplyDiff
;
2469 if (BootstrapPDiffWith(UncompressedFinalFile
, GetFinalFilename(), Target
) == false)
2471 Failed("Bootstrapping of " + DestFile
+ " failed", NULL
);
2476 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
2479 Desc
.URI
= "rred:" + FinalFile
;
2481 SetActiveSubprocess("rred");
2484 // success in download/apply all diffs, clean up
2485 else if (State
== StateApplyDiff
)
2487 // move the result into place
2488 std::string
const Final
= GetKeepCompressedFileName(GetFinalFilename(), Target
);
2490 std::clog
<< "Queue patched file in place: " << std::endl
2491 << DestFile
<< " -> " << Final
<< std::endl
;
2493 // queue for copy by the transaction manager
2494 TransactionManager
->TransactionStageCopy(this, DestFile
, Final
);
2496 // ensure the ed's are gone regardless of list-cleanup
2497 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2498 I
!= allPatches
->end(); ++I
)
2500 std::string
const PartialFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
2501 std::string
const patch
= GetMergeDiffsPatchFileName(PartialFile
, (*I
)->patch
.file
);
2502 RemoveFile("pkgAcqIndexMergeDiffs::Done", patch
);
2504 RemoveFile("pkgAcqIndexMergeDiffs::Done", FinalFile
);
2509 std::clog
<< "allDone: " << DestFile
<< "\n" << std::endl
;
2513 std::string
pkgAcqIndexMergeDiffs::Custom600Headers() const /*{{{*/
2515 if(State
!= StateApplyDiff
)
2516 return pkgAcqBaseIndex::Custom600Headers();
2517 std::ostringstream patchhashes
;
2518 unsigned int seen_patches
= 0;
2519 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2520 I
!= allPatches
->end(); ++I
)
2522 HashStringList
const ExpectedHashes
= (*I
)->patch
.patch_hashes
;
2523 for (HashStringList::const_iterator hs
= ExpectedHashes
.begin(); hs
!= ExpectedHashes
.end(); ++hs
)
2524 patchhashes
<< "\nPatch-" << seen_patches
<< "-" << hs
->HashType() << "-Hash: " << hs
->HashValue();
2527 patchhashes
<< pkgAcqBaseIndex::Custom600Headers();
2528 return patchhashes
.str();
2531 pkgAcqIndexMergeDiffs::~pkgAcqIndexMergeDiffs() {}
2533 // AcqIndex::AcqIndex - Constructor /*{{{*/
2534 pkgAcqIndex::pkgAcqIndex(pkgAcquire
* const Owner
,
2535 pkgAcqMetaClearSig
* const TransactionManager
,
2536 IndexTarget
const &Target
)
2537 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
), Stage(STAGE_DOWNLOAD
),
2538 CompressionExtensions(Target
.Option(IndexTarget::COMPRESSIONTYPES
))
2540 Init(Target
.URI
, Target
.Description
, Target
.ShortDesc
);
2542 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
2543 std::clog
<< "New pkgIndex with TransactionManager "
2544 << TransactionManager
<< std::endl
;
2547 // AcqIndex::Init - defered Constructor /*{{{*/
2548 static void NextCompressionExtension(std::string
&CurrentCompressionExtension
, std::string
&CompressionExtensions
, bool const preview
)
2550 size_t const nextExt
= CompressionExtensions
.find(' ');
2551 if (nextExt
== std::string::npos
)
2553 CurrentCompressionExtension
= CompressionExtensions
;
2554 if (preview
== false)
2555 CompressionExtensions
.clear();
2559 CurrentCompressionExtension
= CompressionExtensions
.substr(0, nextExt
);
2560 if (preview
== false)
2561 CompressionExtensions
= CompressionExtensions
.substr(nextExt
+1);
2564 void pkgAcqIndex::Init(string
const &URI
, string
const &URIDesc
,
2565 string
const &ShortDesc
)
2567 Stage
= STAGE_DOWNLOAD
;
2569 DestFile
= GetPartialFileNameFromURI(URI
);
2570 NextCompressionExtension(CurrentCompressionExtension
, CompressionExtensions
, false);
2572 if (CurrentCompressionExtension
== "uncompressed")
2576 else if (CurrentCompressionExtension
== "by-hash")
2578 NextCompressionExtension(CurrentCompressionExtension
, CompressionExtensions
, true);
2579 if(unlikely(TransactionManager
->MetaIndexParser
== NULL
|| CurrentCompressionExtension
.empty()))
2581 if (CurrentCompressionExtension
!= "uncompressed")
2583 Desc
.URI
= URI
+ '.' + CurrentCompressionExtension
;
2584 DestFile
= DestFile
+ '.' + CurrentCompressionExtension
;
2587 HashStringList
const Hashes
= GetExpectedHashes();
2588 HashString
const * const TargetHash
= Hashes
.find(NULL
);
2589 if (unlikely(TargetHash
== nullptr))
2591 std::string
const ByHash
= "/by-hash/" + TargetHash
->HashType() + "/" + TargetHash
->HashValue();
2592 size_t const trailing_slash
= Desc
.URI
.find_last_of("/");
2593 if (unlikely(trailing_slash
== std::string::npos
))
2595 Desc
.URI
= Desc
.URI
.replace(
2597 Desc
.URI
.substr(trailing_slash
+1).size()+1,
2600 else if (unlikely(CurrentCompressionExtension
.empty()))
2604 Desc
.URI
= URI
+ '.' + CurrentCompressionExtension
;
2605 DestFile
= DestFile
+ '.' + CurrentCompressionExtension
;
2609 Desc
.Description
= URIDesc
;
2611 Desc
.ShortDesc
= ShortDesc
;
2616 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
2617 // ---------------------------------------------------------------------
2618 /* The only header we use is the last-modified header. */
2619 string
pkgAcqIndex::Custom600Headers() const
2622 string msg
= "\nIndex-File: true";
2624 if (TransactionManager
->LastMetaIndexParser
== NULL
)
2626 std::string
const Final
= GetFinalFilename();
2629 if (stat(Final
.c_str(),&Buf
) == 0)
2630 msg
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
2633 if(Target
.IsOptional
)
2634 msg
+= "\nFail-Ignore: true";
2639 // AcqIndex::Failed - getting the indexfile failed /*{{{*/
2640 void pkgAcqIndex::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)
2642 Item::Failed(Message
,Cnf
);
2644 // authorisation matches will not be fixed by other compression types
2645 if (Status
!= StatAuthError
)
2647 if (CompressionExtensions
.empty() == false)
2649 Init(Target
.URI
, Desc
.Description
, Desc
.ShortDesc
);
2655 if(Target
.IsOptional
&& GetExpectedHashes().empty() && Stage
== STAGE_DOWNLOAD
)
2658 TransactionManager
->AbortTransaction();
2661 // AcqIndex::ReverifyAfterIMS - Reverify index after an ims-hit /*{{{*/
2662 void pkgAcqIndex::ReverifyAfterIMS()
2664 // update destfile to *not* include the compression extension when doing
2665 // a reverify (as its uncompressed on disk already)
2666 DestFile
= GetCompressedFileName(Target
, GetPartialFileNameFromURI(Target
.URI
), CurrentCompressionExtension
);
2668 // copy FinalFile into partial/ so that we check the hash again
2669 string FinalFile
= GetFinalFilename();
2670 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
2671 Desc
.URI
= "copy:" + FinalFile
;
2675 // AcqIndex::Done - Finished a fetch /*{{{*/
2676 // ---------------------------------------------------------------------
2677 /* This goes through a number of states.. On the initial fetch the
2678 method could possibly return an alternate filename which points
2679 to the uncompressed version of the file. If this is so the file
2680 is copied into the partial directory. In all other cases the file
2681 is decompressed with a compressed uri. */
2682 void pkgAcqIndex::Done(string
const &Message
,
2683 HashStringList
const &Hashes
,
2684 pkgAcquire::MethodConfig
const * const Cfg
)
2686 Item::Done(Message
,Hashes
,Cfg
);
2690 case STAGE_DOWNLOAD
:
2691 StageDownloadDone(Message
, Hashes
, Cfg
);
2693 case STAGE_DECOMPRESS_AND_VERIFY
:
2694 StageDecompressDone(Message
, Hashes
, Cfg
);
2699 // AcqIndex::StageDownloadDone - Queue for decompress and verify /*{{{*/
2700 void pkgAcqIndex::StageDownloadDone(string
const &Message
, HashStringList
const &,
2701 pkgAcquire::MethodConfig
const * const)
2705 // Handle the unzipd case
2706 std::string FileName
= LookupTag(Message
,"Alt-Filename");
2707 if (FileName
.empty() == false)
2709 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
2711 if (CurrentCompressionExtension
!= "uncompressed")
2712 DestFile
.erase(DestFile
.length() - (CurrentCompressionExtension
.length() + 1));
2713 Desc
.URI
= "copy:" + FileName
;
2715 SetActiveSubprocess("copy");
2718 FileName
= LookupTag(Message
,"Filename");
2720 // Methods like e.g. "file:" will give us a (compressed) FileName that is
2721 // not the "DestFile" we set, in this case we uncompress from the local file
2722 if (FileName
!= DestFile
&& RealFileExists(DestFile
) == false)
2725 if (Target
.KeepCompressed
== true)
2727 // but if we don't keep the uncompress we copy the compressed file first
2728 Stage
= STAGE_DOWNLOAD
;
2729 Desc
.URI
= "copy:" + FileName
;
2731 SetActiveSubprocess("copy");
2736 // symlinking ensures that the filename can be used for compression detection
2737 // that is e.g. needed for by-hash over file
2738 if (symlink(FileName
.c_str(),DestFile
.c_str()) != 0)
2739 _error
->WarningE("pkgAcqIndex::StageDownloadDone", "Symlinking file %s to %s failed", FileName
.c_str(), DestFile
.c_str());
2742 EraseFileName
= DestFile
;
2743 FileName
= DestFile
;
2748 EraseFileName
= FileName
;
2750 // we need to verify the file against the current Release file again
2751 // on if-modfied-since hit to avoid a stale attack against us
2752 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
2754 // The files timestamp matches, reverify by copy into partial/
2760 string decompProg
= "store";
2761 if (Target
.KeepCompressed
== true)
2763 DestFile
= "/dev/null";
2764 EraseFileName
.clear();
2768 if (CurrentCompressionExtension
== "uncompressed")
2769 decompProg
= "copy";
2771 DestFile
.erase(DestFile
.length() - (CurrentCompressionExtension
.length() + 1));
2774 // queue uri for the next stage
2775 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
2776 Desc
.URI
= decompProg
+ ":" + FileName
;
2778 SetActiveSubprocess(decompProg
);
2781 // AcqIndex::StageDecompressDone - Final verification /*{{{*/
2782 void pkgAcqIndex::StageDecompressDone(string
const &,
2783 HashStringList
const &,
2784 pkgAcquire::MethodConfig
const * const)
2786 if (Target
.KeepCompressed
== true && DestFile
== "/dev/null")
2787 DestFile
= GetPartialFileNameFromURI(Target
.URI
+ '.' + CurrentCompressionExtension
);
2789 // Done, queue for rename on transaction finished
2790 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
2794 pkgAcqIndex::~pkgAcqIndex() {}
2797 // AcqArchive::AcqArchive - Constructor /*{{{*/
2798 // ---------------------------------------------------------------------
2799 /* This just sets up the initial fetch environment and queues the first
2801 pkgAcqArchive::pkgAcqArchive(pkgAcquire
* const Owner
,pkgSourceList
* const Sources
,
2802 pkgRecords
* const Recs
,pkgCache::VerIterator
const &Version
,
2803 string
&StoreFilename
) :
2804 Item(Owner
), d(NULL
), LocalSource(false), Version(Version
), Sources(Sources
), Recs(Recs
),
2805 StoreFilename(StoreFilename
), Vf(Version
.FileList()),
2808 Retries
= _config
->FindI("Acquire::Retries",0);
2810 if (Version
.Arch() == 0)
2812 _error
->Error(_("I wasn't able to locate a file for the %s package. "
2813 "This might mean you need to manually fix this package. "
2814 "(due to missing arch)"),
2815 Version
.ParentPkg().FullName().c_str());
2819 /* We need to find a filename to determine the extension. We make the
2820 assumption here that all the available sources for this version share
2821 the same extension.. */
2822 // Skip not source sources, they do not have file fields.
2823 for (; Vf
.end() == false; ++Vf
)
2825 if (Vf
.File().Flagged(pkgCache::Flag::NotSource
))
2830 // Does not really matter here.. we are going to fail out below
2831 if (Vf
.end() != true)
2833 // If this fails to get a file name we will bomb out below.
2834 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2835 if (_error
->PendingError() == true)
2838 // Generate the final file name as: package_version_arch.foo
2839 StoreFilename
= QuoteString(Version
.ParentPkg().Name(),"_:") + '_' +
2840 QuoteString(Version
.VerStr(),"_:") + '_' +
2841 QuoteString(Version
.Arch(),"_:.") +
2842 "." + flExtension(Parse
.FileName());
2845 // check if we have one trusted source for the package. if so, switch
2846 // to "TrustedOnly" mode - but only if not in AllowUnauthenticated mode
2847 bool const allowUnauth
= _config
->FindB("APT::Get::AllowUnauthenticated", false);
2848 bool const debugAuth
= _config
->FindB("Debug::pkgAcquire::Auth", false);
2849 bool seenUntrusted
= false;
2850 for (pkgCache::VerFileIterator i
= Version
.FileList(); i
.end() == false; ++i
)
2852 pkgIndexFile
*Index
;
2853 if (Sources
->FindIndex(i
.File(),Index
) == false)
2856 if (debugAuth
== true)
2857 std::cerr
<< "Checking index: " << Index
->Describe()
2858 << "(Trusted=" << Index
->IsTrusted() << ")" << std::endl
;
2860 if (Index
->IsTrusted() == true)
2863 if (allowUnauth
== false)
2867 seenUntrusted
= true;
2870 // "allow-unauthenticated" restores apts old fetching behaviour
2871 // that means that e.g. unauthenticated file:// uris are higher
2872 // priority than authenticated http:// uris
2873 if (allowUnauth
== true && seenUntrusted
== true)
2877 if (QueueNext() == false && _error
->PendingError() == false)
2878 _error
->Error(_("Can't find a source to download version '%s' of '%s'"),
2879 Version
.VerStr(), Version
.ParentPkg().FullName(false).c_str());
2882 // AcqArchive::QueueNext - Queue the next file source /*{{{*/
2883 // ---------------------------------------------------------------------
2884 /* This queues the next available file version for download. It checks if
2885 the archive is already available in the cache and stashs the MD5 for
2887 bool pkgAcqArchive::QueueNext()
2889 for (; Vf
.end() == false; ++Vf
)
2891 pkgCache::PkgFileIterator
const PkgF
= Vf
.File();
2892 // Ignore not source sources
2893 if (PkgF
.Flagged(pkgCache::Flag::NotSource
))
2896 // Try to cross match against the source list
2897 pkgIndexFile
*Index
;
2898 if (Sources
->FindIndex(PkgF
, Index
) == false)
2900 LocalSource
= PkgF
.Flagged(pkgCache::Flag::LocalSource
);
2902 // only try to get a trusted package from another source if that source
2904 if(Trusted
&& !Index
->IsTrusted())
2907 // Grab the text package record
2908 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2909 if (_error
->PendingError() == true)
2912 string PkgFile
= Parse
.FileName();
2913 ExpectedHashes
= Parse
.Hashes();
2915 if (PkgFile
.empty() == true)
2916 return _error
->Error(_("The package index files are corrupted. No Filename: "
2917 "field for package %s."),
2918 Version
.ParentPkg().Name());
2920 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
2921 Desc
.Description
= Index
->ArchiveInfo(Version
);
2923 Desc
.ShortDesc
= Version
.ParentPkg().FullName(true);
2925 // See if we already have the file. (Legacy filenames)
2926 FileSize
= Version
->Size
;
2927 string FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile
);
2929 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2931 // Make sure the size matches
2932 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2937 StoreFilename
= DestFile
= FinalFile
;
2941 /* Hmm, we have a file and its size does not match, this means it is
2942 an old style mismatched arch */
2943 RemoveFile("pkgAcqArchive::QueueNext", FinalFile
);
2946 // Check it again using the new style output filenames
2947 FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
2948 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2950 // Make sure the size matches
2951 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2956 StoreFilename
= DestFile
= FinalFile
;
2960 /* Hmm, we have a file and its size does not match, this shouldn't
2962 RemoveFile("pkgAcqArchive::QueueNext", FinalFile
);
2965 DestFile
= _config
->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename
);
2967 // Check the destination file
2968 if (stat(DestFile
.c_str(),&Buf
) == 0)
2970 // Hmm, the partial file is too big, erase it
2971 if ((unsigned long long)Buf
.st_size
> Version
->Size
)
2972 RemoveFile("pkgAcqArchive::QueueNext", DestFile
);
2974 PartialSize
= Buf
.st_size
;
2977 // Disables download of archives - useful if no real installation follows,
2978 // e.g. if we are just interested in proposed installation order
2979 if (_config
->FindB("Debug::pkgAcqArchive::NoQueue", false) == true)
2984 StoreFilename
= DestFile
= FinalFile
;
2998 // AcqArchive::Done - Finished fetching /*{{{*/
2999 // ---------------------------------------------------------------------
3001 void pkgAcqArchive::Done(string
const &Message
, HashStringList
const &Hashes
,
3002 pkgAcquire::MethodConfig
const * const Cfg
)
3004 Item::Done(Message
, Hashes
, Cfg
);
3006 // Grab the output filename
3007 std::string
const FileName
= LookupTag(Message
,"Filename");
3008 if (DestFile
!= FileName
&& RealFileExists(DestFile
) == false)
3010 StoreFilename
= DestFile
= FileName
;
3016 // Done, move it into position
3017 string
const FinalFile
= GetFinalFilename();
3018 Rename(DestFile
,FinalFile
);
3019 StoreFilename
= DestFile
= FinalFile
;
3023 // AcqArchive::Failed - Failure handler /*{{{*/
3024 // ---------------------------------------------------------------------
3025 /* Here we try other sources */
3026 void pkgAcqArchive::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)
3028 Item::Failed(Message
,Cnf
);
3030 /* We don't really want to retry on failed media swaps, this prevents
3031 that. An interesting observation is that permanent failures are not
3033 if (Cnf
->Removable
== true &&
3034 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
3036 // Vf = Version.FileList();
3037 while (Vf
.end() == false) ++Vf
;
3038 StoreFilename
= string();
3043 if (QueueNext() == false)
3045 // This is the retry counter
3047 Cnf
->LocalOnly
== false &&
3048 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
3051 Vf
= Version
.FileList();
3052 if (QueueNext() == true)
3056 StoreFilename
= string();
3061 APT_PURE
bool pkgAcqArchive::IsTrusted() const /*{{{*/
3066 void pkgAcqArchive::Finished() /*{{{*/
3068 if (Status
== pkgAcquire::Item::StatDone
&&
3071 StoreFilename
= string();
3074 std::string
pkgAcqArchive::DescURI() const /*{{{*/
3079 std::string
pkgAcqArchive::ShortDesc() const /*{{{*/
3081 return Desc
.ShortDesc
;
3084 pkgAcqArchive::~pkgAcqArchive() {}
3086 // AcqChangelog::pkgAcqChangelog - Constructors /*{{{*/
3087 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire
* const Owner
, pkgCache::VerIterator
const &Ver
,
3088 std::string
const &DestDir
, std::string
const &DestFilename
) :
3089 pkgAcquire::Item(Owner
), d(NULL
), SrcName(Ver
.SourcePkgName()), SrcVersion(Ver
.SourceVerStr())
3091 Desc
.URI
= URI(Ver
);
3092 Init(DestDir
, DestFilename
);
3094 // some parameters are char* here as they come likely from char* interfaces – which can also return NULL
3095 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire
* const Owner
, pkgCache::RlsFileIterator
const &RlsFile
,
3096 char const * const Component
, char const * const SrcName
, char const * const SrcVersion
,
3097 const string
&DestDir
, const string
&DestFilename
) :
3098 pkgAcquire::Item(Owner
), d(NULL
), SrcName(SrcName
), SrcVersion(SrcVersion
)
3100 Desc
.URI
= URI(RlsFile
, Component
, SrcName
, SrcVersion
);
3101 Init(DestDir
, DestFilename
);
3103 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire
* const Owner
,
3104 std::string
const &URI
, char const * const SrcName
, char const * const SrcVersion
,
3105 const string
&DestDir
, const string
&DestFilename
) :
3106 pkgAcquire::Item(Owner
), d(NULL
), SrcName(SrcName
), SrcVersion(SrcVersion
)
3109 Init(DestDir
, DestFilename
);
3111 void pkgAcqChangelog::Init(std::string
const &DestDir
, std::string
const &DestFilename
)
3113 if (Desc
.URI
.empty())
3116 // TRANSLATOR: %s=%s is sourcename=sourceversion, e.g. apt=1.1
3117 strprintf(ErrorText
, _("Changelog unavailable for %s=%s"), SrcName
.c_str(), SrcVersion
.c_str());
3118 // Let the error message print something sensible rather than "Failed to fetch /"
3119 if (DestFilename
.empty())
3120 DestFile
= SrcName
+ ".changelog";
3122 DestFile
= DestFilename
;
3123 Desc
.URI
= "changelog:/" + DestFile
;
3127 if (DestDir
.empty())
3129 std::string
const SandboxUser
= _config
->Find("APT::Sandbox::User");
3130 std::string
const systemTemp
= GetTempDir(SandboxUser
);
3132 snprintf(tmpname
, sizeof(tmpname
), "%s/apt-changelog-XXXXXX", systemTemp
.c_str());
3133 if (NULL
== mkdtemp(tmpname
))
3135 _error
->Errno("mkdtemp", "mkdtemp failed in changelog acquire of %s %s", SrcName
.c_str(), SrcVersion
.c_str());
3139 DestFile
= TemporaryDirectory
= tmpname
;
3141 ChangeOwnerAndPermissionOfFile("Item::QueueURI", DestFile
.c_str(),
3142 SandboxUser
.c_str(), "root", 0700);
3147 if (DestFilename
.empty())
3148 DestFile
= flCombine(DestFile
, SrcName
+ ".changelog");
3150 DestFile
= flCombine(DestFile
, DestFilename
);
3152 Desc
.ShortDesc
= "Changelog";
3153 strprintf(Desc
.Description
, "%s %s %s Changelog", URI::SiteOnly(Desc
.URI
).c_str(), SrcName
.c_str(), SrcVersion
.c_str());
3158 std::string
pkgAcqChangelog::URI(pkgCache::VerIterator
const &Ver
) /*{{{*/
3160 char const * const SrcName
= Ver
.SourcePkgName();
3161 char const * const SrcVersion
= Ver
.SourceVerStr();
3162 pkgCache::PkgFileIterator PkgFile
;
3163 // find the first source for this version which promises a changelog
3164 for (pkgCache::VerFileIterator VF
= Ver
.FileList(); VF
.end() == false; ++VF
)
3166 pkgCache::PkgFileIterator
const PF
= VF
.File();
3167 if (PF
.Flagged(pkgCache::Flag::NotSource
) || PF
->Release
== 0)
3170 pkgCache::RlsFileIterator
const RF
= PF
.ReleaseFile();
3171 std::string
const uri
= URI(RF
, PF
.Component(), SrcName
, SrcVersion
);
3178 std::string
pkgAcqChangelog::URITemplate(pkgCache::RlsFileIterator
const &Rls
)
3180 if (Rls
.end() == true || (Rls
->Label
== 0 && Rls
->Origin
== 0))
3182 std::string
const serverConfig
= "Acquire::Changelogs::URI";
3184 #define APT_EMPTY_SERVER \
3185 if (server.empty() == false) \
3187 if (server != "no") \
3191 #define APT_CHECK_SERVER(X, Y) \
3194 std::string const specialServerConfig = serverConfig + "::" + Y + #X + "::" + Rls.X(); \
3195 server = _config->Find(specialServerConfig); \
3198 // this way e.g. Debian-Security can fallback to Debian
3199 APT_CHECK_SERVER(Label
, "Override::")
3200 APT_CHECK_SERVER(Origin
, "Override::")
3202 if (RealFileExists(Rls
.FileName()))
3204 _error
->PushToStack();
3206 /* This can be costly. A caller wanting to get millions of URIs might
3207 want to do this on its own once and use Override settings.
3208 We don't do this here as Origin/Label are not as unique as they
3209 should be so this could produce request order-dependent anomalies */
3210 if (OpenMaybeClearSignedFile(Rls
.FileName(), rf
) == true)
3212 pkgTagFile
TagFile(&rf
, rf
.Size());
3213 pkgTagSection Section
;
3214 if (TagFile
.Step(Section
) == true)
3215 server
= Section
.FindS("Changelogs");
3217 _error
->RevertToStack();
3221 APT_CHECK_SERVER(Label
, "")
3222 APT_CHECK_SERVER(Origin
, "")
3223 #undef APT_CHECK_SERVER
3224 #undef APT_EMPTY_SERVER
3227 std::string
pkgAcqChangelog::URI(pkgCache::RlsFileIterator
const &Rls
,
3228 char const * const Component
, char const * const SrcName
,
3229 char const * const SrcVersion
)
3231 return URI(URITemplate(Rls
), Component
, SrcName
, SrcVersion
);
3233 std::string
pkgAcqChangelog::URI(std::string
const &Template
,
3234 char const * const Component
, char const * const SrcName
,
3235 char const * const SrcVersion
)
3237 if (Template
.find("@CHANGEPATH@") == std::string::npos
)
3240 // the path is: COMPONENT/SRC/SRCNAME/SRCNAME_SRCVER, e.g. main/a/apt/1.1 or contrib/liba/libapt/2.0
3241 std::string Src
= SrcName
;
3242 std::string path
= APT::String::Startswith(SrcName
, "lib") ? Src
.substr(0, 4) : Src
.substr(0,1);
3243 path
.append("/").append(Src
).append("/");
3244 path
.append(Src
).append("_").append(StripEpoch(SrcVersion
));
3245 // we omit component for releases without one (= flat-style repositories)
3246 if (Component
!= NULL
&& strlen(Component
) != 0)
3247 path
= std::string(Component
) + "/" + path
;
3249 return SubstVar(Template
, "@CHANGEPATH@", path
);
3252 // AcqChangelog::Failed - Failure handler /*{{{*/
3253 void pkgAcqChangelog::Failed(string
const &Message
, pkgAcquire::MethodConfig
const * const Cnf
)
3255 Item::Failed(Message
,Cnf
);
3257 std::string errText
;
3258 // TRANSLATOR: %s=%s is sourcename=sourceversion, e.g. apt=1.1
3259 strprintf(errText
, _("Changelog unavailable for %s=%s"), SrcName
.c_str(), SrcVersion
.c_str());
3261 // Error is probably something techy like 404 Not Found
3262 if (ErrorText
.empty())
3263 ErrorText
= errText
;
3265 ErrorText
= errText
+ " (" + ErrorText
+ ")";
3269 // AcqChangelog::Done - Item downloaded OK /*{{{*/
3270 void pkgAcqChangelog::Done(string
const &Message
,HashStringList
const &CalcHashes
,
3271 pkgAcquire::MethodConfig
const * const Cnf
)
3273 Item::Done(Message
,CalcHashes
,Cnf
);
3278 pkgAcqChangelog::~pkgAcqChangelog() /*{{{*/
3280 if (TemporaryDirectory
.empty() == false)
3282 RemoveFile("~pkgAcqChangelog", DestFile
);
3283 rmdir(TemporaryDirectory
.c_str());
3288 // AcqFile::pkgAcqFile - Constructor /*{{{*/
3289 pkgAcqFile::pkgAcqFile(pkgAcquire
* const Owner
,string
const &URI
, HashStringList
const &Hashes
,
3290 unsigned long long const Size
,string
const &Dsc
,string
const &ShortDesc
,
3291 const string
&DestDir
, const string
&DestFilename
,
3292 bool const IsIndexFile
) :
3293 Item(Owner
), d(NULL
), IsIndexFile(IsIndexFile
), ExpectedHashes(Hashes
)
3295 Retries
= _config
->FindI("Acquire::Retries",0);
3297 if(!DestFilename
.empty())
3298 DestFile
= DestFilename
;
3299 else if(!DestDir
.empty())
3300 DestFile
= DestDir
+ "/" + flNotDir(URI
);
3302 DestFile
= flNotDir(URI
);
3306 Desc
.Description
= Dsc
;
3309 // Set the short description to the archive component
3310 Desc
.ShortDesc
= ShortDesc
;
3312 // Get the transfer sizes
3315 if (stat(DestFile
.c_str(),&Buf
) == 0)
3317 // Hmm, the partial file is too big, erase it
3318 if ((Size
> 0) && (unsigned long long)Buf
.st_size
> Size
)
3319 RemoveFile("pkgAcqFile", DestFile
);
3321 PartialSize
= Buf
.st_size
;
3327 // AcqFile::Done - Item downloaded OK /*{{{*/
3328 void pkgAcqFile::Done(string
const &Message
,HashStringList
const &CalcHashes
,
3329 pkgAcquire::MethodConfig
const * const Cnf
)
3331 Item::Done(Message
,CalcHashes
,Cnf
);
3333 std::string
const FileName
= LookupTag(Message
,"Filename");
3336 // The files timestamp matches
3337 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
3340 // We have to copy it into place
3341 if (RealFileExists(DestFile
.c_str()) == false)
3344 if (_config
->FindB("Acquire::Source-Symlinks",true) == false ||
3345 Cnf
->Removable
== true)
3347 Desc
.URI
= "copy:" + FileName
;
3352 // Erase the file if it is a symlink so we can overwrite it
3354 if (lstat(DestFile
.c_str(),&St
) == 0)
3356 if (S_ISLNK(St
.st_mode
) != 0)
3357 RemoveFile("pkgAcqFile::Done", DestFile
);
3361 if (symlink(FileName
.c_str(),DestFile
.c_str()) != 0)
3363 _error
->PushToStack();
3364 _error
->Errno("pkgAcqFile::Done", "Symlinking file %s failed", DestFile
.c_str());
3365 std::stringstream msg
;
3366 _error
->DumpErrors(msg
, GlobalError::DEBUG
, false);
3367 _error
->RevertToStack();
3368 ErrorText
= msg
.str();
3375 // AcqFile::Failed - Failure handler /*{{{*/
3376 // ---------------------------------------------------------------------
3377 /* Here we try other sources */
3378 void pkgAcqFile::Failed(string
const &Message
, pkgAcquire::MethodConfig
const * const Cnf
)
3380 Item::Failed(Message
,Cnf
);
3382 // This is the retry counter
3384 Cnf
->LocalOnly
== false &&
3385 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
3395 string
pkgAcqFile::Custom600Headers() const /*{{{*/
3398 return "\nIndex-File: true";
3402 pkgAcqFile::~pkgAcqFile() {}