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();
150 static bool RemoveFile(char const * const Function
, std::string
const &FileName
)/*{{{*/
152 if (FileName
== "/dev/null")
155 if (unlink(FileName
.c_str()) != 0)
159 return _error
->WarningE(Function
, "Removal of file %s failed", FileName
.c_str());
165 static bool MessageInsecureRepository(bool const isError
, std::string
const &msg
)/*{{{*/
169 _error
->Error("%s", msg
.c_str());
170 _error
->Notice("%s", _("Updating such a repository securily is impossible and therefore disabled by default."));
174 _error
->Warning("%s", msg
.c_str());
175 _error
->Notice("%s", _("Data from such a repository can not be authenticated and is therefore potentially dangerous to use."));
177 _error
->Notice("%s", _("See apt-secure(8) manpage for repository creation and user configuration details."));
180 static bool MessageInsecureRepository(bool const isError
, char const * const msg
, std::string
const &repo
)
183 strprintf(m
, msg
, repo
.c_str());
184 return MessageInsecureRepository(isError
, m
);
187 static bool AllowInsecureRepositories(char const * const msg
, std::string
const &repo
,/*{{{*/
188 metaIndex
const * const MetaIndexParser
, pkgAcqMetaClearSig
* const TransactionManager
, pkgAcquire::Item
* const I
)
190 if(MetaIndexParser
->GetTrusted() == metaIndex::TRI_YES
)
193 if (_config
->FindB("Acquire::AllowInsecureRepositories") == true)
195 MessageInsecureRepository(false, msg
, repo
);
199 MessageInsecureRepository(true, msg
, repo
);
200 TransactionManager
->AbortTransaction();
201 I
->Status
= pkgAcquire::Item::StatError
;
205 static HashStringList
GetExpectedHashesFromFor(metaIndex
* const Parser
, std::string
const &MetaKey
)/*{{{*/
208 return HashStringList();
209 metaIndex::checkSum
* const R
= Parser
->Lookup(MetaKey
);
211 return HashStringList();
216 // all ::HashesRequired and ::GetExpectedHashes implementations /*{{{*/
217 /* ::GetExpectedHashes is abstract and has to be implemented by all subclasses.
218 It is best to implement it as broadly as possible, while ::HashesRequired defaults
219 to true and should be as restrictive as possible for false cases. Note that if
220 a hash is returned by ::GetExpectedHashes it must match. Only if it doesn't
221 ::HashesRequired is called to evaluate if its okay to have no hashes. */
222 APT_CONST
bool pkgAcqTransactionItem::HashesRequired() const
224 /* signed repositories obviously have a parser and good hashes.
225 unsigned repositories, too, as even if we can't trust them for security,
226 we can at least trust them for integrity of the download itself.
227 Only repositories without a Release file can (obviously) not have
228 hashes – and they are very uncommon and strongly discouraged */
229 return TransactionManager
->MetaIndexParser
!= NULL
&&
230 TransactionManager
->MetaIndexParser
->GetLoadedSuccessfully() != metaIndex::TRI_UNSET
;
232 HashStringList
pkgAcqTransactionItem::GetExpectedHashes() const
234 return GetExpectedHashesFor(GetMetaKey());
237 APT_CONST
bool pkgAcqMetaBase::HashesRequired() const
239 // Release and co have no hashes 'by design'.
242 HashStringList
pkgAcqMetaBase::GetExpectedHashes() const
244 return HashStringList();
247 APT_CONST
bool pkgAcqIndexDiffs::HashesRequired() const
249 /* We don't always have the diff of the downloaded pdiff file.
250 What we have for sure is hashes for the uncompressed file,
251 but rred uncompresses them on the fly while parsing, so not handled here.
252 Hashes are (also) checked while searching for (next) patch to apply. */
253 if (State
== StateFetchDiff
)
254 return available_patches
[0].download_hashes
.empty() == false;
257 HashStringList
pkgAcqIndexDiffs::GetExpectedHashes() const
259 if (State
== StateFetchDiff
)
260 return available_patches
[0].download_hashes
;
261 return HashStringList();
264 APT_CONST
bool pkgAcqIndexMergeDiffs::HashesRequired() const
266 /* @see #pkgAcqIndexDiffs::HashesRequired, with the difference that
267 we can check the rred result after all patches are applied as
268 we know the expected result rather than potentially apply more patches */
269 if (State
== StateFetchDiff
)
270 return patch
.download_hashes
.empty() == false;
271 return State
== StateApplyDiff
;
273 HashStringList
pkgAcqIndexMergeDiffs::GetExpectedHashes() const
275 if (State
== StateFetchDiff
)
276 return patch
.download_hashes
;
277 else if (State
== StateApplyDiff
)
278 return GetExpectedHashesFor(Target
.MetaKey
);
279 return HashStringList();
282 APT_CONST
bool pkgAcqArchive::HashesRequired() const
284 return LocalSource
== false;
286 HashStringList
pkgAcqArchive::GetExpectedHashes() const
288 // figured out while parsing the records
289 return ExpectedHashes
;
292 APT_CONST
bool pkgAcqFile::HashesRequired() const
294 // supplied as parameter at creation time, so the caller decides
295 return ExpectedHashes
.usable();
297 HashStringList
pkgAcqFile::GetExpectedHashes() const
299 return ExpectedHashes
;
302 // Acquire::Item::QueueURI and specialisations from child classes /*{{{*/
303 bool pkgAcquire::Item::QueueURI(pkgAcquire::ItemDesc
&Item
)
305 Owner
->Enqueue(Item
);
308 /* The idea here is that an item isn't queued if it exists on disk and the
309 transition manager was a hit as this means that the files it contains
310 the checksums for can't be updated either (or they are and we are asking
311 for a hashsum mismatch to happen which helps nobody) */
312 bool pkgAcqTransactionItem::QueueURI(pkgAcquire::ItemDesc
&Item
)
314 std::string
const FinalFile
= GetFinalFilename();
315 if (TransactionManager
!= NULL
&& TransactionManager
->IMSHit
== true &&
316 FileExists(FinalFile
) == true)
318 PartialFile
= DestFile
= FinalFile
;
322 return pkgAcquire::Item::QueueURI(Item
);
324 /* The transition manager InRelease itself (or its older sisters-in-law
325 Release & Release.gpg) is always queued as this allows us to rerun gpgv
326 on it to verify that we aren't stalled with old files */
327 bool pkgAcqMetaBase::QueueURI(pkgAcquire::ItemDesc
&Item
)
329 return pkgAcquire::Item::QueueURI(Item
);
331 /* the Diff/Index needs to queue also the up-to-date complete index file
332 to ensure that the list cleaner isn't eating it */
333 bool pkgAcqDiffIndex::QueueURI(pkgAcquire::ItemDesc
&Item
)
335 if (pkgAcqTransactionItem::QueueURI(Item
) == true)
341 // Acquire::Item::GetFinalFilename and specialisations for child classes /*{{{*/
342 std::string
pkgAcquire::Item::GetFinalFilename() const
344 return GetFinalFileNameFromURI(Desc
.URI
);
346 std::string
pkgAcqDiffIndex::GetFinalFilename() const
348 // the logic we inherent from pkgAcqBaseIndex isn't what we need here
349 return pkgAcquire::Item::GetFinalFilename();
351 std::string
pkgAcqIndex::GetFinalFilename() const
353 std::string
const FinalFile
= GetFinalFileNameFromURI(Target
.URI
);
354 return GetCompressedFileName(Target
, FinalFile
, CurrentCompressionExtension
);
356 std::string
pkgAcqMetaSig::GetFinalFilename() const
358 return GetFinalFileNameFromURI(Target
.URI
);
360 std::string
pkgAcqBaseIndex::GetFinalFilename() const
362 return GetFinalFileNameFromURI(Target
.URI
);
364 std::string
pkgAcqMetaBase::GetFinalFilename() const
366 return GetFinalFileNameFromURI(Target
.URI
);
368 std::string
pkgAcqArchive::GetFinalFilename() const
370 return _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
373 // pkgAcqTransactionItem::GetMetaKey and specialisations for child classes /*{{{*/
374 std::string
pkgAcqTransactionItem::GetMetaKey() const
376 return Target
.MetaKey
;
378 std::string
pkgAcqIndex::GetMetaKey() const
380 if (Stage
== STAGE_DECOMPRESS_AND_VERIFY
|| CurrentCompressionExtension
== "uncompressed")
381 return Target
.MetaKey
;
382 return Target
.MetaKey
+ "." + CurrentCompressionExtension
;
384 std::string
pkgAcqDiffIndex::GetMetaKey() const
386 return Target
.MetaKey
+ ".diff/Index";
389 //pkgAcqTransactionItem::TransactionState and specialisations for child classes /*{{{*/
390 bool pkgAcqTransactionItem::TransactionState(TransactionStates
const state
)
392 bool const Debug
= _config
->FindB("Debug::Acquire::Transaction", false);
395 case TransactionAbort
:
397 std::clog
<< " Cancel: " << DestFile
<< std::endl
;
398 if (Status
== pkgAcquire::Item::StatIdle
)
400 Status
= pkgAcquire::Item::StatDone
;
404 case TransactionCommit
:
405 if(PartialFile
!= "")
408 std::clog
<< "mv " << PartialFile
<< " -> "<< DestFile
<< " # " << DescURI() << std::endl
;
410 Rename(PartialFile
, DestFile
);
413 std::clog
<< "rm " << DestFile
<< " # " << DescURI() << std::endl
;
414 RemoveFile("TransactionCommit", DestFile
);
420 bool pkgAcqMetaBase::TransactionState(TransactionStates
const state
)
422 // Do not remove InRelease on IMSHit of Release.gpg [yes, this is very edgecasey]
423 if (TransactionManager
->IMSHit
== false)
424 return pkgAcqTransactionItem::TransactionState(state
);
427 bool pkgAcqIndex::TransactionState(TransactionStates
const state
)
429 if (pkgAcqTransactionItem::TransactionState(state
) == false)
434 case TransactionAbort
:
435 if (Stage
== STAGE_DECOMPRESS_AND_VERIFY
)
437 // keep the compressed file, but drop the decompressed
438 EraseFileName
.clear();
439 if (PartialFile
.empty() == false && flExtension(PartialFile
) == "decomp")
440 RemoveFile("TransactionAbort", PartialFile
);
443 case TransactionCommit
:
444 if (EraseFileName
.empty() == false)
445 RemoveFile("TransactionCommit", EraseFileName
);
450 bool pkgAcqDiffIndex::TransactionState(TransactionStates
const state
)
452 if (pkgAcqTransactionItem::TransactionState(state
) == false)
457 case TransactionCommit
:
459 case TransactionAbort
:
460 std::string
const Partial
= GetPartialFileNameFromURI(Target
.URI
);
461 RemoveFile("TransactionAbort", Partial
);
469 class APT_HIDDEN NoActionItem
: public pkgAcquire::Item
/*{{{*/
470 /* The sole purpose of this class is having an item which does nothing to
471 reach its done state to prevent cleanup deleting the mentioned file.
472 Handy in cases in which we know we have the file already, like IMS-Hits. */
474 IndexTarget
const Target
;
476 virtual std::string
DescURI() const APT_OVERRIDE
{return Target
.URI
;};
477 virtual HashStringList
GetExpectedHashes() const APT_OVERRIDE
{return HashStringList();};
479 NoActionItem(pkgAcquire
* const Owner
, IndexTarget
const &Target
) :
480 pkgAcquire::Item(Owner
), Target(Target
)
483 DestFile
= GetFinalFileNameFromURI(Target
.URI
);
485 NoActionItem(pkgAcquire
* const Owner
, IndexTarget
const &Target
, std::string
const &FinalFile
) :
486 pkgAcquire::Item(Owner
), Target(Target
)
489 DestFile
= FinalFile
;
494 // Acquire::Item::Item - Constructor /*{{{*/
495 APT_IGNORE_DEPRECATED_PUSH
496 pkgAcquire::Item::Item(pkgAcquire
* const owner
) :
497 FileSize(0), PartialSize(0), Mode(0), ID(0), Complete(false), Local(false),
498 QueueCounter(0), ExpectedAdditionalItems(0), Owner(owner
), d(NULL
)
503 APT_IGNORE_DEPRECATED_POP
505 // Acquire::Item::~Item - Destructor /*{{{*/
506 pkgAcquire::Item::~Item()
511 std::string
pkgAcquire::Item::Custom600Headers() const /*{{{*/
513 return std::string();
516 std::string
pkgAcquire::Item::ShortDesc() const /*{{{*/
521 APT_CONST
void pkgAcquire::Item::Finished() /*{{{*/
525 APT_PURE pkgAcquire
* pkgAcquire::Item::GetOwner() const /*{{{*/
530 APT_CONST
pkgAcquire::ItemDesc
&pkgAcquire::Item::GetItemDesc() /*{{{*/
535 APT_CONST
bool pkgAcquire::Item::IsTrusted() const /*{{{*/
540 // Acquire::Item::Failed - Item failed to download /*{{{*/
541 // ---------------------------------------------------------------------
542 /* We return to an idle state if there are still other queues that could
544 void pkgAcquire::Item::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)
546 if(ErrorText
.empty())
547 ErrorText
= LookupTag(Message
,"Message");
548 if (QueueCounter
<= 1)
550 /* This indicates that the file is not available right now but might
551 be sometime later. If we do a retry cycle then this should be
553 if (Cnf
!= NULL
&& Cnf
->LocalOnly
== true &&
554 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
570 case StatTransientNetworkError
:
577 string
const FailReason
= LookupTag(Message
, "FailReason");
578 if (FailReason
== "MaximumSizeExceeded")
579 RenameOnError(MaximumSizeExceeded
);
580 else if (Status
== StatAuthError
)
581 RenameOnError(HashSumMismatch
);
583 // report mirror failure back to LP if we actually use a mirror
584 if (FailReason
.empty() == false)
585 ReportMirrorFailure(FailReason
);
587 ReportMirrorFailure(ErrorText
);
589 if (QueueCounter
> 1)
593 // Acquire::Item::Start - Item has begun to download /*{{{*/
594 // ---------------------------------------------------------------------
595 /* Stash status and the file size. Note that setting Complete means
596 sub-phases of the acquire process such as decompresion are operating */
597 void pkgAcquire::Item::Start(string
const &/*Message*/, unsigned long long const Size
)
599 Status
= StatFetching
;
601 if (FileSize
== 0 && Complete
== false)
605 // Acquire::Item::VerifyDone - check if Item was downloaded OK /*{{{*/
606 /* Note that hash-verification is 'hardcoded' in acquire-worker and has
607 * already passed if this method is called. */
608 bool pkgAcquire::Item::VerifyDone(std::string
const &Message
,
609 pkgAcquire::MethodConfig
const * const /*Cnf*/)
611 std::string
const FileName
= LookupTag(Message
,"Filename");
612 if (FileName
.empty() == true)
615 ErrorText
= "Method gave a blank filename";
622 // Acquire::Item::Done - Item downloaded OK /*{{{*/
623 void pkgAcquire::Item::Done(string
const &/*Message*/, HashStringList
const &Hashes
,
624 pkgAcquire::MethodConfig
const * const /*Cnf*/)
626 // We just downloaded something..
629 unsigned long long const downloadedSize
= Hashes
.FileSize();
630 if (downloadedSize
!= 0)
632 FileSize
= downloadedSize
;
636 ErrorText
= string();
637 Owner
->Dequeue(this);
640 // Acquire::Item::Rename - Rename a file /*{{{*/
641 // ---------------------------------------------------------------------
642 /* This helper function is used by a lot of item methods as their final
644 bool pkgAcquire::Item::Rename(string
const &From
,string
const &To
)
646 if (From
== To
|| rename(From
.c_str(),To
.c_str()) == 0)
650 strprintf(S
, _("rename failed, %s (%s -> %s)."), strerror(errno
),
651 From
.c_str(),To
.c_str());
653 if (ErrorText
.empty())
656 ErrorText
= ErrorText
+ ": " + S
;
660 void pkgAcquire::Item::Dequeue() /*{{{*/
662 Owner
->Dequeue(this);
665 bool pkgAcquire::Item::RenameOnError(pkgAcquire::Item::RenameOnErrorState
const error
)/*{{{*/
667 if (RealFileExists(DestFile
))
668 Rename(DestFile
, DestFile
+ ".FAILED");
673 case HashSumMismatch
:
674 errtext
= _("Hash Sum mismatch");
675 Status
= StatAuthError
;
676 ReportMirrorFailure("HashChecksumFailure");
679 errtext
= _("Size mismatch");
680 Status
= StatAuthError
;
681 ReportMirrorFailure("SizeFailure");
684 errtext
= _("Invalid file format");
686 // do not report as usually its not the mirrors fault, but Portal/Proxy
689 errtext
= _("Signature error");
693 strprintf(errtext
, _("Clearsigned file isn't valid, got '%s' (does the network require authentication?)"), "NOSPLIT");
694 Status
= StatAuthError
;
696 case MaximumSizeExceeded
:
697 // the method is expected to report a good error for this
701 // no handling here, done by callers
704 if (ErrorText
.empty())
709 void pkgAcquire::Item::SetActiveSubprocess(const std::string
&subprocess
)/*{{{*/
711 ActiveSubprocess
= subprocess
;
712 APT_IGNORE_DEPRECATED(Mode
= ActiveSubprocess
.c_str();)
715 // Acquire::Item::ReportMirrorFailure /*{{{*/
716 void pkgAcquire::Item::ReportMirrorFailure(string
const &FailCode
)
718 // we only act if a mirror was used at all
719 if(UsedMirror
.empty())
722 std::cerr
<< "\nReportMirrorFailure: "
724 << " Uri: " << DescURI()
726 << FailCode
<< std::endl
;
728 string report
= _config
->Find("Methods::Mirror::ProblemReporting",
729 "/usr/lib/apt/apt-report-mirror-failure");
730 if(!FileExists(report
))
733 std::vector
<char const*> Args
;
734 Args
.push_back(report
.c_str());
735 Args
.push_back(UsedMirror
.c_str());
736 Args
.push_back(DescURI().c_str());
737 Args
.push_back(FailCode
.c_str());
738 Args
.push_back(NULL
);
740 pid_t pid
= ExecFork();
743 _error
->Error("ReportMirrorFailure Fork failed");
748 execvp(Args
[0], (char**)Args
.data());
749 std::cerr
<< "Could not exec " << Args
[0] << std::endl
;
752 if(!ExecWait(pid
, "report-mirror-failure"))
754 _error
->Warning("Couldn't report problem to '%s'",
755 _config
->Find("Methods::Mirror::ProblemReporting").c_str());
759 std::string
pkgAcquire::Item::HashSum() const /*{{{*/
761 HashStringList
const hashes
= GetExpectedHashes();
762 HashString
const * const hs
= hashes
.find(NULL
);
763 return hs
!= NULL
? hs
->toStr() : "";
767 pkgAcqTransactionItem::pkgAcqTransactionItem(pkgAcquire
* const Owner
, /*{{{*/
768 pkgAcqMetaClearSig
* const transactionManager
, IndexTarget
const &target
) :
769 pkgAcquire::Item(Owner
), d(NULL
), Target(target
), TransactionManager(transactionManager
)
771 if (TransactionManager
!= this)
772 TransactionManager
->Add(this);
775 pkgAcqTransactionItem::~pkgAcqTransactionItem() /*{{{*/
779 HashStringList
pkgAcqTransactionItem::GetExpectedHashesFor(std::string
const &MetaKey
) const /*{{{*/
781 return GetExpectedHashesFromFor(TransactionManager
->MetaIndexParser
, MetaKey
);
785 // AcqMetaBase - Constructor /*{{{*/
786 pkgAcqMetaBase::pkgAcqMetaBase(pkgAcquire
* const Owner
,
787 pkgAcqMetaClearSig
* const TransactionManager
,
788 std::vector
<IndexTarget
> const &IndexTargets
,
789 IndexTarget
const &DataTarget
)
790 : pkgAcqTransactionItem(Owner
, TransactionManager
, DataTarget
), d(NULL
),
791 IndexTargets(IndexTargets
),
792 AuthPass(false), IMSHit(false)
796 // AcqMetaBase::Add - Add a item to the current Transaction /*{{{*/
797 void pkgAcqMetaBase::Add(pkgAcqTransactionItem
* const I
)
799 Transaction
.push_back(I
);
802 // AcqMetaBase::AbortTransaction - Abort the current Transaction /*{{{*/
803 void pkgAcqMetaBase::AbortTransaction()
805 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
806 std::clog
<< "AbortTransaction: " << TransactionManager
<< std::endl
;
808 // ensure the toplevel is in error state too
809 for (std::vector
<pkgAcqTransactionItem
*>::iterator I
= Transaction
.begin();
810 I
!= Transaction
.end(); ++I
)
812 (*I
)->TransactionState(TransactionAbort
);
817 // AcqMetaBase::TransactionHasError - Check for errors in Transaction /*{{{*/
818 APT_PURE
bool pkgAcqMetaBase::TransactionHasError() const
820 for (std::vector
<pkgAcqTransactionItem
*>::const_iterator I
= Transaction
.begin();
821 I
!= Transaction
.end(); ++I
)
823 switch((*I
)->Status
) {
824 case StatDone
: break;
825 case StatIdle
: break;
826 case StatAuthError
: return true;
827 case StatError
: return true;
828 case StatTransientNetworkError
: return true;
829 case StatFetching
: break;
835 // AcqMetaBase::CommitTransaction - Commit a transaction /*{{{*/
836 void pkgAcqMetaBase::CommitTransaction()
838 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
839 std::clog
<< "CommitTransaction: " << this << std::endl
;
841 // move new files into place *and* remove files that are not
842 // part of the transaction but are still on disk
843 for (std::vector
<pkgAcqTransactionItem
*>::iterator I
= Transaction
.begin();
844 I
!= Transaction
.end(); ++I
)
846 (*I
)->TransactionState(TransactionCommit
);
851 // AcqMetaBase::TransactionStageCopy - Stage a file for copying /*{{{*/
852 void pkgAcqMetaBase::TransactionStageCopy(pkgAcqTransactionItem
* const I
,
853 const std::string
&From
,
854 const std::string
&To
)
856 I
->PartialFile
= From
;
860 // AcqMetaBase::TransactionStageRemoval - Stage a file for removal /*{{{*/
861 void pkgAcqMetaBase::TransactionStageRemoval(pkgAcqTransactionItem
* const I
,
862 const std::string
&FinalFile
)
865 I
->DestFile
= FinalFile
;
868 // AcqMetaBase::GenerateAuthWarning - Check gpg authentication error /*{{{*/
869 bool pkgAcqMetaBase::CheckStopAuthentication(pkgAcquire::Item
* const I
, const std::string
&Message
)
871 // FIXME: this entire function can do now that we disallow going to
872 // a unauthenticated state and can cleanly rollback
874 string
const Final
= I
->GetFinalFilename();
875 if(FileExists(Final
))
877 I
->Status
= StatTransientNetworkError
;
878 _error
->Warning(_("An error occurred during the signature "
879 "verification. The repository is not updated "
880 "and the previous index files will be used. "
881 "GPG error: %s: %s"),
882 Desc
.Description
.c_str(),
883 LookupTag(Message
,"Message").c_str());
884 RunScripts("APT::Update::Auth-Failure");
886 } else if (LookupTag(Message
,"Message").find("NODATA") != string::npos
) {
887 /* Invalid signature file, reject (LP: #346386) (Closes: #627642) */
888 _error
->Error(_("GPG error: %s: %s"),
889 Desc
.Description
.c_str(),
890 LookupTag(Message
,"Message").c_str());
891 I
->Status
= StatAuthError
;
894 _error
->Warning(_("GPG error: %s: %s"),
895 Desc
.Description
.c_str(),
896 LookupTag(Message
,"Message").c_str());
898 // gpgv method failed
899 ReportMirrorFailure("GPGFailure");
903 // AcqMetaBase::Custom600Headers - Get header for AcqMetaBase /*{{{*/
904 // ---------------------------------------------------------------------
905 string
pkgAcqMetaBase::Custom600Headers() const
907 std::string Header
= "\nIndex-File: true";
908 std::string MaximumSize
;
909 strprintf(MaximumSize
, "\nMaximum-Size: %i",
910 _config
->FindI("Acquire::MaxReleaseFileSize", 10*1000*1000));
911 Header
+= MaximumSize
;
913 string
const FinalFile
= GetFinalFilename();
915 if (stat(FinalFile
.c_str(),&Buf
) == 0)
916 Header
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
921 // AcqMetaBase::QueueForSignatureVerify /*{{{*/
922 void pkgAcqMetaBase::QueueForSignatureVerify(pkgAcqTransactionItem
* const I
, std::string
const &File
, std::string
const &Signature
)
925 I
->Desc
.URI
= "gpgv:" + Signature
;
928 I
->SetActiveSubprocess("gpgv");
931 // AcqMetaBase::CheckDownloadDone /*{{{*/
932 bool pkgAcqMetaBase::CheckDownloadDone(pkgAcqTransactionItem
* const I
, const std::string
&Message
, HashStringList
const &Hashes
) const
934 // We have just finished downloading a Release file (it is not
937 std::string
const FileName
= LookupTag(Message
,"Filename");
938 if (FileName
!= I
->DestFile
&& RealFileExists(I
->DestFile
) == false)
941 I
->Desc
.URI
= "copy:" + FileName
;
942 I
->QueueURI(I
->Desc
);
946 // make sure to verify against the right file on I-M-S hit
947 bool IMSHit
= StringToBool(LookupTag(Message
,"IMS-Hit"), false);
948 if (IMSHit
== false && Hashes
.usable())
950 // detect IMS-Hits servers haven't detected by Hash comparison
951 std::string
const FinalFile
= I
->GetFinalFilename();
952 if (RealFileExists(FinalFile
) && Hashes
.VerifyFile(FinalFile
) == true)
955 RemoveFile("CheckDownloadDone", I
->DestFile
);
961 // for simplicity, the transaction manager is always InRelease
962 // even if it doesn't exist.
963 if (TransactionManager
!= NULL
)
964 TransactionManager
->IMSHit
= true;
965 I
->PartialFile
= I
->DestFile
= I
->GetFinalFilename();
968 // set Item to complete as the remaining work is all local (verify etc)
974 bool pkgAcqMetaBase::CheckAuthDone(string
const &Message
) /*{{{*/
976 // At this point, the gpgv method has succeeded, so there is a
977 // valid signature from a key in the trusted keyring. We
978 // perform additional verification of its contents, and use them
979 // to verify the indexes we are about to download
981 if (TransactionManager
->IMSHit
== false)
983 // open the last (In)Release if we have it
984 std::string
const FinalFile
= GetFinalFilename();
985 std::string FinalRelease
;
986 std::string FinalInRelease
;
987 if (APT::String::Endswith(FinalFile
, "InRelease"))
989 FinalInRelease
= FinalFile
;
990 FinalRelease
= FinalFile
.substr(0, FinalFile
.length() - strlen("InRelease")) + "Release";
994 FinalInRelease
= FinalFile
.substr(0, FinalFile
.length() - strlen("Release")) + "InRelease";
995 FinalRelease
= FinalFile
;
997 if (RealFileExists(FinalInRelease
) || RealFileExists(FinalRelease
))
999 TransactionManager
->LastMetaIndexParser
= TransactionManager
->MetaIndexParser
->UnloadedClone();
1000 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1002 _error
->PushToStack();
1003 if (RealFileExists(FinalInRelease
))
1004 TransactionManager
->LastMetaIndexParser
->Load(FinalInRelease
, NULL
);
1006 TransactionManager
->LastMetaIndexParser
->Load(FinalRelease
, NULL
);
1007 // its unlikely to happen, but if what we have is bad ignore it
1008 if (_error
->PendingError())
1010 delete TransactionManager
->LastMetaIndexParser
;
1011 TransactionManager
->LastMetaIndexParser
= NULL
;
1013 _error
->RevertToStack();
1018 if (TransactionManager
->MetaIndexParser
->Load(DestFile
, &ErrorText
) == false)
1020 Status
= StatAuthError
;
1024 if (!VerifyVendor(Message
))
1026 Status
= StatAuthError
;
1030 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1031 std::cerr
<< "Signature verification succeeded: "
1032 << DestFile
<< std::endl
;
1034 // Download further indexes with verification
1040 void pkgAcqMetaBase::QueueIndexes(bool const verify
) /*{{{*/
1042 // at this point the real Items are loaded in the fetcher
1043 ExpectedAdditionalItems
= 0;
1045 bool metaBaseSupportsByHash
= false;
1046 if (TransactionManager
!= NULL
&& TransactionManager
->MetaIndexParser
!= NULL
)
1047 metaBaseSupportsByHash
= TransactionManager
->MetaIndexParser
->GetSupportsAcquireByHash();
1049 for (std::vector
<IndexTarget
>::iterator Target
= IndexTargets
.begin();
1050 Target
!= IndexTargets
.end();
1053 bool trypdiff
= Target
->OptionBool(IndexTarget::PDIFFS
);
1056 if (TransactionManager
->MetaIndexParser
->Exists(Target
->MetaKey
) == false)
1058 // optional targets that we do not have in the Release file are skipped
1059 if (Target
->IsOptional
)
1062 Status
= StatAuthError
;
1063 strprintf(ErrorText
, _("Unable to find expected entry '%s' in Release file (Wrong sources.list entry or malformed file)"), Target
->MetaKey
.c_str());
1067 // autoselect the compression method
1068 std::vector
<std::string
> types
= VectorizeString(Target
->Option(IndexTarget::COMPRESSIONTYPES
), ' ');
1069 types
.erase(std::remove_if(types
.begin(), types
.end(), [&](std::string
const &t
) {
1070 if (t
== "uncompressed")
1071 return TransactionManager
->MetaIndexParser
->Exists(Target
->MetaKey
) == false;
1072 std::string
const MetaKey
= Target
->MetaKey
+ "." + t
;
1073 return TransactionManager
->MetaIndexParser
->Exists(MetaKey
) == false;
1075 if (types
.empty() == false)
1077 std::ostringstream os
;
1078 // add the special compressiontype byhash first if supported
1079 std::string
const useByHashConf
= Target
->Option(IndexTarget::BY_HASH
);
1080 bool useByHash
= false;
1081 if(useByHashConf
== "force")
1084 useByHash
= StringToBool(useByHashConf
) == true && metaBaseSupportsByHash
;
1085 if (useByHash
== true)
1087 std::copy(types
.begin(), types
.end()-1, std::ostream_iterator
<std::string
>(os
, " "));
1088 os
<< *types
.rbegin();
1089 Target
->Options
["COMPRESSIONTYPES"] = os
.str();
1092 Target
->Options
["COMPRESSIONTYPES"].clear();
1094 std::string filename
= GetFinalFileNameFromURI(Target
->URI
);
1095 if (RealFileExists(filename
) == false)
1097 if (Target
->KeepCompressed
)
1099 filename
= GetKeepCompressedFileName(filename
, *Target
);
1100 if (RealFileExists(filename
) == false)
1107 if (filename
.empty() == false)
1109 // if the Release file is a hit and we have an index it must be the current one
1110 if (TransactionManager
->IMSHit
== true)
1112 else if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1114 // see if the file changed since the last Release file
1115 // we use the uncompressed files as we might compress differently compared to the server,
1116 // so the hashes might not match, even if they contain the same data.
1117 HashStringList
const newFile
= GetExpectedHashesFromFor(TransactionManager
->MetaIndexParser
, Target
->MetaKey
);
1118 HashStringList
const oldFile
= GetExpectedHashesFromFor(TransactionManager
->LastMetaIndexParser
, Target
->MetaKey
);
1119 if (newFile
!= oldFile
)
1126 trypdiff
= false; // no file to patch
1128 if (filename
.empty() == false)
1130 new NoActionItem(Owner
, *Target
, filename
);
1131 std::string
const idxfilename
= GetFinalFileNameFromURI(Target
->URI
+ ".diff/Index");
1132 if (FileExists(idxfilename
))
1133 new NoActionItem(Owner
, *Target
, idxfilename
);
1137 // check if we have patches available
1138 trypdiff
&= TransactionManager
->MetaIndexParser
->Exists(Target
->MetaKey
+ ".diff/Index");
1142 // if we have no file to patch, no point in trying
1143 std::string filename
= GetFinalFileNameFromURI(Target
->URI
);
1144 if (RealFileExists(filename
) == false)
1146 if (Target
->KeepCompressed
)
1148 filename
= GetKeepCompressedFileName(filename
, *Target
);
1149 if (RealFileExists(filename
) == false)
1155 trypdiff
&= (filename
.empty() == false);
1158 // no point in patching from local sources
1161 std::string
const proto
= Target
->URI
.substr(0, strlen("file:/"));
1162 if (proto
== "file:/" || proto
== "copy:/" || proto
== "cdrom:")
1166 // Queue the Index file (Packages, Sources, Translation-$foo, …)
1168 new pkgAcqDiffIndex(Owner
, TransactionManager
, *Target
);
1170 new pkgAcqIndex(Owner
, TransactionManager
, *Target
);
1174 bool pkgAcqMetaBase::VerifyVendor(string
const &Message
) /*{{{*/
1176 string::size_type pos
;
1178 // check for missing sigs (that where not fatal because otherwise we had
1181 string msg
= _("There is no public key available for the "
1182 "following key IDs:\n");
1183 pos
= Message
.find("NO_PUBKEY ");
1184 if (pos
!= std::string::npos
)
1186 string::size_type start
= pos
+strlen("NO_PUBKEY ");
1187 string Fingerprint
= Message
.substr(start
, Message
.find("\n")-start
);
1188 missingkeys
+= (Fingerprint
);
1190 if(!missingkeys
.empty())
1191 _error
->Warning("%s", (msg
+ missingkeys
).c_str());
1193 string Transformed
= TransactionManager
->MetaIndexParser
->GetExpectedDist();
1195 if (Transformed
== "../project/experimental")
1197 Transformed
= "experimental";
1200 pos
= Transformed
.rfind('/');
1201 if (pos
!= string::npos
)
1203 Transformed
= Transformed
.substr(0, pos
);
1206 if (Transformed
== ".")
1211 if (TransactionManager
->MetaIndexParser
->GetValidUntil() > 0)
1213 time_t const invalid_since
= time(NULL
) - TransactionManager
->MetaIndexParser
->GetValidUntil();
1214 if (invalid_since
> 0)
1218 // TRANSLATOR: The first %s is the URL of the bad Release file, the second is
1219 // the time since then the file is invalid - formatted in the same way as in
1220 // the download progress display (e.g. 7d 3h 42min 1s)
1221 _("Release file for %s is expired (invalid since %s). "
1222 "Updates for this repository will not be applied."),
1223 Target
.URI
.c_str(), TimeToStr(invalid_since
).c_str());
1224 if (ErrorText
.empty())
1226 return _error
->Error("%s", errmsg
.c_str());
1230 /* Did we get a file older than what we have? This is a last minute IMS hit and doubles
1231 as a prevention of downgrading us to older (still valid) files */
1232 if (TransactionManager
->IMSHit
== false && TransactionManager
->LastMetaIndexParser
!= NULL
&&
1233 TransactionManager
->LastMetaIndexParser
->GetDate() > TransactionManager
->MetaIndexParser
->GetDate())
1235 TransactionManager
->IMSHit
= true;
1236 RemoveFile("VerifyVendor", DestFile
);
1237 PartialFile
= DestFile
= GetFinalFilename();
1238 // load the 'old' file in the 'new' one instead of flipping pointers as
1239 // the new one isn't owned by us, while the old one is so cleanup would be confused.
1240 TransactionManager
->MetaIndexParser
->swapLoad(TransactionManager
->LastMetaIndexParser
);
1241 delete TransactionManager
->LastMetaIndexParser
;
1242 TransactionManager
->LastMetaIndexParser
= NULL
;
1245 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1247 std::cerr
<< "Got Codename: " << TransactionManager
->MetaIndexParser
->GetCodename() << std::endl
;
1248 std::cerr
<< "Expecting Dist: " << TransactionManager
->MetaIndexParser
->GetExpectedDist() << std::endl
;
1249 std::cerr
<< "Transformed Dist: " << Transformed
<< std::endl
;
1252 if (TransactionManager
->MetaIndexParser
->CheckDist(Transformed
) == false)
1254 // This might become fatal one day
1255 // Status = StatAuthError;
1256 // ErrorText = "Conflicting distribution; expected "
1257 // + MetaIndexParser->GetExpectedDist() + " but got "
1258 // + MetaIndexParser->GetCodename();
1260 if (!Transformed
.empty())
1262 _error
->Warning(_("Conflicting distribution: %s (expected %s but got %s)"),
1263 Desc
.Description
.c_str(),
1264 Transformed
.c_str(),
1265 TransactionManager
->MetaIndexParser
->GetCodename().c_str());
1272 pkgAcqMetaBase::~pkgAcqMetaBase()
1276 pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire
* const Owner
, /*{{{*/
1277 IndexTarget
const &ClearsignedTarget
,
1278 IndexTarget
const &DetachedDataTarget
, IndexTarget
const &DetachedSigTarget
,
1279 std::vector
<IndexTarget
> const &IndexTargets
,
1280 metaIndex
* const MetaIndexParser
) :
1281 pkgAcqMetaIndex(Owner
, this, ClearsignedTarget
, DetachedSigTarget
, IndexTargets
),
1282 d(NULL
), ClearsignedTarget(ClearsignedTarget
),
1283 DetachedDataTarget(DetachedDataTarget
),
1284 MetaIndexParser(MetaIndexParser
), LastMetaIndexParser(NULL
)
1286 // index targets + (worst case:) Release/Release.gpg
1287 ExpectedAdditionalItems
= IndexTargets
.size() + 2;
1288 TransactionManager
->Add(this);
1291 pkgAcqMetaClearSig::~pkgAcqMetaClearSig() /*{{{*/
1293 if (LastMetaIndexParser
!= NULL
)
1294 delete LastMetaIndexParser
;
1297 // pkgAcqMetaClearSig::Custom600Headers - Insert custom request headers /*{{{*/
1298 string
pkgAcqMetaClearSig::Custom600Headers() const
1300 string Header
= pkgAcqMetaBase::Custom600Headers();
1301 Header
+= "\nFail-Ignore: true";
1302 std::string
const key
= TransactionManager
->MetaIndexParser
->GetSignedBy();
1303 if (key
.empty() == false)
1304 Header
+= "\nSigned-By: " + key
;
1309 bool pkgAcqMetaClearSig::VerifyDone(std::string
const &Message
, /*{{{*/
1310 pkgAcquire::MethodConfig
const * const Cnf
)
1312 Item::VerifyDone(Message
, Cnf
);
1314 if (FileExists(DestFile
) && !StartsWithGPGClearTextSignature(DestFile
))
1315 return RenameOnError(NotClearsigned
);
1320 // pkgAcqMetaClearSig::Done - We got a file /*{{{*/
1321 void pkgAcqMetaClearSig::Done(std::string
const &Message
,
1322 HashStringList
const &Hashes
,
1323 pkgAcquire::MethodConfig
const * const Cnf
)
1325 Item::Done(Message
, Hashes
, Cnf
);
1327 if(AuthPass
== false)
1329 if(CheckDownloadDone(this, Message
, Hashes
) == true)
1330 QueueForSignatureVerify(this, DestFile
, DestFile
);
1333 else if(CheckAuthDone(Message
) == true)
1335 if (TransactionManager
->IMSHit
== false)
1336 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
1337 else if (RealFileExists(GetFinalFilename()) == false)
1339 // We got an InRelease file IMSHit, but we haven't one, which means
1340 // we had a valid Release/Release.gpg combo stepping in, which we have
1341 // to 'acquire' now to ensure list cleanup isn't removing them
1342 new NoActionItem(Owner
, DetachedDataTarget
);
1343 new NoActionItem(Owner
, DetachedSigTarget
);
1348 void pkgAcqMetaClearSig::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
) /*{{{*/
1350 Item::Failed(Message
, Cnf
);
1352 // we failed, we will not get additional items from this method
1353 ExpectedAdditionalItems
= 0;
1355 if (AuthPass
== false)
1357 if (Status
== StatAuthError
|| Status
== StatTransientNetworkError
)
1359 // if we expected a ClearTextSignature (InRelease) but got a network
1360 // error or got a file, but it wasn't valid, we end up here (see VerifyDone).
1361 // As these is usually called by web-portals we do not try Release/Release.gpg
1362 // as this is gonna fail anyway and instead abort our try (LP#346386)
1363 TransactionManager
->AbortTransaction();
1367 // Queue the 'old' InRelease file for removal if we try Release.gpg
1368 // as otherwise the file will stay around and gives a false-auth
1369 // impression (CVE-2012-0214)
1370 TransactionManager
->TransactionStageRemoval(this, GetFinalFilename());
1373 new pkgAcqMetaIndex(Owner
, TransactionManager
, DetachedDataTarget
, DetachedSigTarget
, IndexTargets
);
1377 if(CheckStopAuthentication(this, Message
))
1380 // No Release file was present, or verification failed, so fall
1381 // back to queueing Packages files without verification
1382 // only allow going further if the users explicitely wants it
1383 if(AllowInsecureRepositories(_("The repository '%s' is not signed."), ClearsignedTarget
.Description
, TransactionManager
->MetaIndexParser
, TransactionManager
, this) == true)
1387 /* InRelease files become Release files, otherwise
1388 * they would be considered as trusted later on */
1389 string
const FinalRelease
= GetFinalFileNameFromURI(DetachedDataTarget
.URI
);
1390 string
const PartialRelease
= GetPartialFileNameFromURI(DetachedDataTarget
.URI
);
1391 string
const FinalReleasegpg
= GetFinalFileNameFromURI(DetachedSigTarget
.URI
);
1392 string
const FinalInRelease
= GetFinalFilename();
1393 Rename(DestFile
, PartialRelease
);
1394 TransactionManager
->TransactionStageCopy(this, PartialRelease
, FinalRelease
);
1396 if (RealFileExists(FinalReleasegpg
) || RealFileExists(FinalInRelease
))
1398 // open the last Release if we have it
1399 if (TransactionManager
->IMSHit
== false)
1401 TransactionManager
->LastMetaIndexParser
= TransactionManager
->MetaIndexParser
->UnloadedClone();
1402 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1404 _error
->PushToStack();
1405 if (RealFileExists(FinalInRelease
))
1406 TransactionManager
->LastMetaIndexParser
->Load(FinalInRelease
, NULL
);
1408 TransactionManager
->LastMetaIndexParser
->Load(FinalRelease
, NULL
);
1409 // its unlikely to happen, but if what we have is bad ignore it
1410 if (_error
->PendingError())
1412 delete TransactionManager
->LastMetaIndexParser
;
1413 TransactionManager
->LastMetaIndexParser
= NULL
;
1415 _error
->RevertToStack();
1420 // we parse the indexes here because at this point the user wanted
1421 // a repository that may potentially harm him
1422 if (TransactionManager
->MetaIndexParser
->Load(PartialRelease
, &ErrorText
) == false || VerifyVendor(Message
) == false)
1423 /* expired Release files are still a problem you need extra force for */;
1431 pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire
* const Owner
, /*{{{*/
1432 pkgAcqMetaClearSig
* const TransactionManager
,
1433 IndexTarget
const &DataTarget
,
1434 IndexTarget
const &DetachedSigTarget
,
1435 vector
<IndexTarget
> const &IndexTargets
) :
1436 pkgAcqMetaBase(Owner
, TransactionManager
, IndexTargets
, DataTarget
), d(NULL
),
1437 DetachedSigTarget(DetachedSigTarget
)
1439 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1440 std::clog
<< "New pkgAcqMetaIndex with TransactionManager "
1441 << this->TransactionManager
<< std::endl
;
1443 DestFile
= GetPartialFileNameFromURI(DataTarget
.URI
);
1446 Desc
.Description
= DataTarget
.Description
;
1448 Desc
.ShortDesc
= DataTarget
.ShortDesc
;
1449 Desc
.URI
= DataTarget
.URI
;
1451 // we expect more item
1452 ExpectedAdditionalItems
= IndexTargets
.size();
1456 void pkgAcqMetaIndex::Done(string
const &Message
, /*{{{*/
1457 HashStringList
const &Hashes
,
1458 pkgAcquire::MethodConfig
const * const Cfg
)
1460 Item::Done(Message
,Hashes
,Cfg
);
1462 if(CheckDownloadDone(this, Message
, Hashes
))
1464 // we have a Release file, now download the Signature, all further
1465 // verify/queue for additional downloads will be done in the
1466 // pkgAcqMetaSig::Done() code
1467 new pkgAcqMetaSig(Owner
, TransactionManager
, DetachedSigTarget
, this);
1471 // pkgAcqMetaIndex::Failed - no Release file present /*{{{*/
1472 void pkgAcqMetaIndex::Failed(string
const &Message
,
1473 pkgAcquire::MethodConfig
const * const Cnf
)
1475 pkgAcquire::Item::Failed(Message
, Cnf
);
1478 // No Release file was present so fall
1479 // back to queueing Packages files without verification
1480 // only allow going further if the users explicitely wants it
1481 if(AllowInsecureRepositories(_("The repository '%s' does not have a Release file."), Target
.Description
, TransactionManager
->MetaIndexParser
, TransactionManager
, this) == true)
1483 // ensure old Release files are removed
1484 TransactionManager
->TransactionStageRemoval(this, GetFinalFilename());
1486 // queue without any kind of hashsum support
1487 QueueIndexes(false);
1491 void pkgAcqMetaIndex::Finished() /*{{{*/
1493 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1494 std::clog
<< "Finished: " << DestFile
<<std::endl
;
1495 if(TransactionManager
!= NULL
&&
1496 TransactionManager
->TransactionHasError() == false)
1497 TransactionManager
->CommitTransaction();
1500 std::string
pkgAcqMetaIndex::DescURI() const /*{{{*/
1505 pkgAcqMetaIndex::~pkgAcqMetaIndex() {}
1507 // AcqMetaSig::AcqMetaSig - Constructor /*{{{*/
1508 pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire
* const Owner
,
1509 pkgAcqMetaClearSig
* const TransactionManager
,
1510 IndexTarget
const &Target
,
1511 pkgAcqMetaIndex
* const MetaIndex
) :
1512 pkgAcqTransactionItem(Owner
, TransactionManager
, Target
), d(NULL
), MetaIndex(MetaIndex
)
1514 DestFile
= GetPartialFileNameFromURI(Target
.URI
);
1516 // remove any partial downloaded sig-file in partial/.
1517 // it may confuse proxies and is too small to warrant a
1518 // partial download anyway
1519 RemoveFile("pkgAcqMetaSig", DestFile
);
1521 // set the TransactionManager
1522 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1523 std::clog
<< "New pkgAcqMetaSig with TransactionManager "
1524 << TransactionManager
<< std::endl
;
1527 Desc
.Description
= Target
.Description
;
1529 Desc
.ShortDesc
= Target
.ShortDesc
;
1530 Desc
.URI
= Target
.URI
;
1532 // If we got a hit for Release, we will get one for Release.gpg too (or obscure errors),
1533 // so we skip the download step and go instantly to verification
1534 if (TransactionManager
->IMSHit
== true && RealFileExists(GetFinalFilename()))
1538 PartialFile
= DestFile
= GetFinalFilename();
1539 MetaIndexFileSignature
= DestFile
;
1540 MetaIndex
->QueueForSignatureVerify(this, MetaIndex
->DestFile
, DestFile
);
1546 pkgAcqMetaSig::~pkgAcqMetaSig() /*{{{*/
1550 // pkgAcqMetaSig::Custom600Headers - Insert custom request headers /*{{{*/
1551 std::string
pkgAcqMetaSig::Custom600Headers() const
1553 std::string Header
= pkgAcqTransactionItem::Custom600Headers();
1554 std::string
const key
= TransactionManager
->MetaIndexParser
->GetSignedBy();
1555 if (key
.empty() == false)
1556 Header
+= "\nSigned-By: " + key
;
1560 // AcqMetaSig::Done - The signature was downloaded/verified /*{{{*/
1561 void pkgAcqMetaSig::Done(string
const &Message
, HashStringList
const &Hashes
,
1562 pkgAcquire::MethodConfig
const * const Cfg
)
1564 if (MetaIndexFileSignature
.empty() == false)
1566 DestFile
= MetaIndexFileSignature
;
1567 MetaIndexFileSignature
.clear();
1569 Item::Done(Message
, Hashes
, Cfg
);
1571 if(MetaIndex
->AuthPass
== false)
1573 if(MetaIndex
->CheckDownloadDone(this, Message
, Hashes
) == true)
1575 // destfile will be modified to point to MetaIndexFile for the
1576 // gpgv method, so we need to save it here
1577 MetaIndexFileSignature
= DestFile
;
1578 MetaIndex
->QueueForSignatureVerify(this, MetaIndex
->DestFile
, DestFile
);
1582 else if(MetaIndex
->CheckAuthDone(Message
) == true)
1584 if (TransactionManager
->IMSHit
== false)
1586 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
1587 TransactionManager
->TransactionStageCopy(MetaIndex
, MetaIndex
->DestFile
, MetaIndex
->GetFinalFilename());
1592 void pkgAcqMetaSig::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
1594 Item::Failed(Message
,Cnf
);
1596 // check if we need to fail at this point
1597 if (MetaIndex
->AuthPass
== true && MetaIndex
->CheckStopAuthentication(this, Message
))
1600 string
const FinalRelease
= MetaIndex
->GetFinalFilename();
1601 string
const FinalReleasegpg
= GetFinalFilename();
1602 string
const FinalInRelease
= TransactionManager
->GetFinalFilename();
1604 if (RealFileExists(FinalReleasegpg
) || RealFileExists(FinalInRelease
))
1606 std::string downgrade_msg
;
1607 strprintf(downgrade_msg
, _("The repository '%s' is no longer signed."),
1608 MetaIndex
->Target
.Description
.c_str());
1609 if(_config
->FindB("Acquire::AllowDowngradeToInsecureRepositories"))
1611 // meh, the users wants to take risks (we still mark the packages
1612 // from this repository as unauthenticated)
1613 _error
->Warning("%s", downgrade_msg
.c_str());
1614 _error
->Warning(_("This is normally not allowed, but the option "
1615 "Acquire::AllowDowngradeToInsecureRepositories was "
1616 "given to override it."));
1619 MessageInsecureRepository(true, downgrade_msg
);
1620 if (TransactionManager
->IMSHit
== false)
1621 Rename(MetaIndex
->DestFile
, MetaIndex
->DestFile
+ ".FAILED");
1622 Item::Failed("Message: " + downgrade_msg
, Cnf
);
1623 TransactionManager
->AbortTransaction();
1628 // ensures that a Release.gpg file in the lists/ is removed by the transaction
1629 TransactionManager
->TransactionStageRemoval(this, DestFile
);
1631 // only allow going further if the users explicitely wants it
1632 if (AllowInsecureRepositories(_("The repository '%s' is not signed."), MetaIndex
->Target
.Description
, TransactionManager
->MetaIndexParser
, TransactionManager
, this) == true)
1634 if (RealFileExists(FinalReleasegpg
) || RealFileExists(FinalInRelease
))
1636 // open the last Release if we have it
1637 if (TransactionManager
->IMSHit
== false)
1639 TransactionManager
->LastMetaIndexParser
= TransactionManager
->MetaIndexParser
->UnloadedClone();
1640 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1642 _error
->PushToStack();
1643 if (RealFileExists(FinalInRelease
))
1644 TransactionManager
->LastMetaIndexParser
->Load(FinalInRelease
, NULL
);
1646 TransactionManager
->LastMetaIndexParser
->Load(FinalRelease
, NULL
);
1647 // its unlikely to happen, but if what we have is bad ignore it
1648 if (_error
->PendingError())
1650 delete TransactionManager
->LastMetaIndexParser
;
1651 TransactionManager
->LastMetaIndexParser
= NULL
;
1653 _error
->RevertToStack();
1658 // we parse the indexes here because at this point the user wanted
1659 // a repository that may potentially harm him
1660 if (TransactionManager
->MetaIndexParser
->Load(MetaIndex
->DestFile
, &ErrorText
) == false || MetaIndex
->VerifyVendor(Message
) == false)
1661 /* expired Release files are still a problem you need extra force for */;
1663 MetaIndex
->QueueIndexes(true);
1665 TransactionManager
->TransactionStageCopy(MetaIndex
, MetaIndex
->DestFile
, MetaIndex
->GetFinalFilename());
1668 // FIXME: this is used often (e.g. in pkgAcqIndexTrans) so refactor
1669 if (Cnf
->LocalOnly
== true ||
1670 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1679 // AcqBaseIndex - Constructor /*{{{*/
1680 pkgAcqBaseIndex::pkgAcqBaseIndex(pkgAcquire
* const Owner
,
1681 pkgAcqMetaClearSig
* const TransactionManager
,
1682 IndexTarget
const &Target
)
1683 : pkgAcqTransactionItem(Owner
, TransactionManager
, Target
), d(NULL
)
1687 pkgAcqBaseIndex::~pkgAcqBaseIndex() {}
1689 // AcqDiffIndex::AcqDiffIndex - Constructor /*{{{*/
1690 // ---------------------------------------------------------------------
1691 /* Get the DiffIndex file first and see if there are patches available
1692 * If so, create a pkgAcqIndexDiffs fetcher that will get and apply the
1693 * patches. If anything goes wrong in that process, it will fall back to
1694 * the original packages file
1696 pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire
* const Owner
,
1697 pkgAcqMetaClearSig
* const TransactionManager
,
1698 IndexTarget
const &Target
)
1699 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
), diffs(NULL
)
1701 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
1704 Desc
.Description
= Target
.Description
+ ".diff/Index";
1705 Desc
.ShortDesc
= Target
.ShortDesc
;
1706 Desc
.URI
= Target
.URI
+ ".diff/Index";
1708 DestFile
= GetPartialFileNameFromURI(Desc
.URI
);
1711 std::clog
<< "pkgAcqDiffIndex: " << Desc
.URI
<< std::endl
;
1716 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
1717 // ---------------------------------------------------------------------
1718 /* The only header we use is the last-modified header. */
1719 string
pkgAcqDiffIndex::Custom600Headers() const
1721 string
const Final
= GetFinalFilename();
1724 std::clog
<< "Custom600Header-IMS: " << Final
<< std::endl
;
1727 if (stat(Final
.c_str(),&Buf
) != 0)
1728 return "\nIndex-File: true";
1730 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1733 void pkgAcqDiffIndex::QueueOnIMSHit() const /*{{{*/
1735 // list cleanup needs to know that this file as well as the already
1736 // present index is ours, so we create an empty diff to save it for us
1737 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
);
1740 bool pkgAcqDiffIndex::ParseDiffIndex(string
const &IndexDiffFile
) /*{{{*/
1742 // failing here is fine: our caller will take care of trying to
1743 // get the complete file if patching fails
1745 std::clog
<< "pkgAcqDiffIndex::ParseIndexDiff() " << IndexDiffFile
1748 FileFd
Fd(IndexDiffFile
,FileFd::ReadOnly
);
1750 if (Fd
.IsOpen() == false || Fd
.Failed())
1754 if(unlikely(TF
.Step(Tags
) == false))
1757 HashStringList ServerHashes
;
1758 unsigned long long ServerSize
= 0;
1760 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
1762 std::string tagname
= *type
;
1763 tagname
.append("-Current");
1764 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1765 if (tmp
.empty() == true)
1769 unsigned long long size
;
1770 std::stringstream
ss(tmp
);
1772 if (unlikely(hash
.empty() == true))
1774 if (unlikely(ServerSize
!= 0 && ServerSize
!= size
))
1776 ServerHashes
.push_back(HashString(*type
, hash
));
1780 if (ServerHashes
.usable() == false)
1783 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": Did not find a good hashsum in the index" << std::endl
;
1787 std::string
const CurrentPackagesFile
= GetFinalFileNameFromURI(Target
.URI
);
1788 HashStringList
const TargetFileHashes
= GetExpectedHashesFor(Target
.MetaKey
);
1789 if (TargetFileHashes
.usable() == false || ServerHashes
!= TargetFileHashes
)
1793 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": Index has different hashes than parser, probably older, so fail pdiffing" << std::endl
;
1794 printHashSumComparision(CurrentPackagesFile
, ServerHashes
, TargetFileHashes
);
1799 HashStringList LocalHashes
;
1800 // try avoiding calculating the hash here as this is costly
1801 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1802 LocalHashes
= GetExpectedHashesFromFor(TransactionManager
->LastMetaIndexParser
, Target
.MetaKey
);
1803 if (LocalHashes
.usable() == false)
1805 FileFd
fd(CurrentPackagesFile
, FileFd::ReadOnly
, FileFd::Auto
);
1806 Hashes
LocalHashesCalc(ServerHashes
);
1807 LocalHashesCalc
.AddFD(fd
);
1808 LocalHashes
= LocalHashesCalc
.GetHashStringList();
1811 if (ServerHashes
== LocalHashes
)
1813 // we have the same sha1 as the server so we are done here
1815 std::clog
<< "pkgAcqDiffIndex: Package file " << CurrentPackagesFile
<< " is up-to-date" << std::endl
;
1821 std::clog
<< "Server-Current: " << ServerHashes
.find(NULL
)->toStr() << " and we start at "
1822 << CurrentPackagesFile
<< " " << LocalHashes
.FileSize() << " " << LocalHashes
.find(NULL
)->toStr() << std::endl
;
1824 // parse all of (provided) history
1825 vector
<DiffInfo
> available_patches
;
1826 bool firstAcceptedHashes
= true;
1827 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
1829 if (LocalHashes
.find(*type
) == NULL
)
1832 std::string tagname
= *type
;
1833 tagname
.append("-History");
1834 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1835 if (tmp
.empty() == true)
1838 string hash
, filename
;
1839 unsigned long long size
;
1840 std::stringstream
ss(tmp
);
1842 while (ss
>> hash
>> size
>> filename
)
1844 if (unlikely(hash
.empty() == true || filename
.empty() == true))
1847 // see if we have a record for this file already
1848 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
1849 for (; cur
!= available_patches
.end(); ++cur
)
1851 if (cur
->file
!= filename
)
1853 cur
->result_hashes
.push_back(HashString(*type
, hash
));
1856 if (cur
!= available_patches
.end())
1858 if (firstAcceptedHashes
== true)
1861 next
.file
= filename
;
1862 next
.result_hashes
.push_back(HashString(*type
, hash
));
1863 next
.result_hashes
.FileSize(size
);
1864 available_patches
.push_back(next
);
1869 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
1870 << " wasn't in the list for the first parsed hash! (history)" << std::endl
;
1874 firstAcceptedHashes
= false;
1877 if (unlikely(available_patches
.empty() == true))
1880 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": "
1881 << "Couldn't find any patches for the patch series." << std::endl
;
1885 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
1887 if (LocalHashes
.find(*type
) == NULL
)
1890 std::string tagname
= *type
;
1891 tagname
.append("-Patches");
1892 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1893 if (tmp
.empty() == true)
1896 string hash
, filename
;
1897 unsigned long long size
;
1898 std::stringstream
ss(tmp
);
1900 while (ss
>> hash
>> size
>> filename
)
1902 if (unlikely(hash
.empty() == true || filename
.empty() == true))
1905 // see if we have a record for this file already
1906 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
1907 for (; cur
!= available_patches
.end(); ++cur
)
1909 if (cur
->file
!= filename
)
1911 if (cur
->patch_hashes
.empty())
1912 cur
->patch_hashes
.FileSize(size
);
1913 cur
->patch_hashes
.push_back(HashString(*type
, hash
));
1916 if (cur
!= available_patches
.end())
1919 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
1920 << " wasn't in the list for the first parsed hash! (patches)" << std::endl
;
1925 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
1927 std::string tagname
= *type
;
1928 tagname
.append("-Download");
1929 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1930 if (tmp
.empty() == true)
1933 string hash
, filename
;
1934 unsigned long long size
;
1935 std::stringstream
ss(tmp
);
1937 // FIXME: all of pdiff supports only .gz compressed patches
1938 while (ss
>> hash
>> size
>> filename
)
1940 if (unlikely(hash
.empty() == true || filename
.empty() == true))
1942 if (unlikely(APT::String::Endswith(filename
, ".gz") == false))
1944 filename
.erase(filename
.length() - 3);
1946 // see if we have a record for this file already
1947 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
1948 for (; cur
!= available_patches
.end(); ++cur
)
1950 if (cur
->file
!= filename
)
1952 if (cur
->download_hashes
.empty())
1953 cur
->download_hashes
.FileSize(size
);
1954 cur
->download_hashes
.push_back(HashString(*type
, hash
));
1957 if (cur
!= available_patches
.end())
1960 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
1961 << " wasn't in the list for the first parsed hash! (download)" << std::endl
;
1967 bool foundStart
= false;
1968 for (std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
1969 cur
!= available_patches
.end(); ++cur
)
1971 if (LocalHashes
!= cur
->result_hashes
)
1974 available_patches
.erase(available_patches
.begin(), cur
);
1979 if (foundStart
== false || unlikely(available_patches
.empty() == true))
1982 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": "
1983 << "Couldn't find the start of the patch series." << std::endl
;
1987 // patching with too many files is rather slow compared to a fast download
1988 unsigned long const fileLimit
= _config
->FindI("Acquire::PDiffs::FileLimit", 0);
1989 if (fileLimit
!= 0 && fileLimit
< available_patches
.size())
1992 std::clog
<< "Need " << available_patches
.size() << " diffs (Limit is " << fileLimit
1993 << ") so fallback to complete download" << std::endl
;
1997 // calculate the size of all patches we have to get
1998 // note that all sizes are uncompressed, while we download compressed files
1999 unsigned long long patchesSize
= 0;
2000 for (std::vector
<DiffInfo
>::const_iterator cur
= available_patches
.begin();
2001 cur
!= available_patches
.end(); ++cur
)
2002 patchesSize
+= cur
->patch_hashes
.FileSize();
2003 unsigned long long const sizeLimit
= ServerSize
* _config
->FindI("Acquire::PDiffs::SizeLimit", 100);
2004 if (sizeLimit
> 0 && (sizeLimit
/100) < patchesSize
)
2007 std::clog
<< "Need " << patchesSize
<< " bytes (Limit is " << sizeLimit
/100
2008 << ") so fallback to complete download" << std::endl
;
2012 // we have something, queue the diffs
2013 string::size_type
const last_space
= Description
.rfind(" ");
2014 if(last_space
!= string::npos
)
2015 Description
.erase(last_space
, Description
.size()-last_space
);
2017 /* decide if we should download patches one by one or in one go:
2018 The first is good if the server merges patches, but many don't so client
2019 based merging can be attempt in which case the second is better.
2020 "bad things" will happen if patches are merged on the server,
2021 but client side merging is attempt as well */
2022 bool pdiff_merge
= _config
->FindB("Acquire::PDiffs::Merge", true);
2023 if (pdiff_merge
== true)
2025 // reprepro adds this flag if it has merged patches on the server
2026 std::string
const precedence
= Tags
.FindS("X-Patch-Precedence");
2027 pdiff_merge
= (precedence
!= "merged");
2030 if (pdiff_merge
== false)
2031 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
, available_patches
);
2034 diffs
= new std::vector
<pkgAcqIndexMergeDiffs
*>(available_patches
.size());
2035 for(size_t i
= 0; i
< available_patches
.size(); ++i
)
2036 (*diffs
)[i
] = new pkgAcqIndexMergeDiffs(Owner
, TransactionManager
,
2038 available_patches
[i
],
2048 void pkgAcqDiffIndex::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
2050 Item::Failed(Message
,Cnf
);
2054 std::clog
<< "pkgAcqDiffIndex failed: " << Desc
.URI
<< " with " << Message
<< std::endl
2055 << "Falling back to normal index file acquire" << std::endl
;
2057 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
2060 void pkgAcqDiffIndex::Done(string
const &Message
,HashStringList
const &Hashes
, /*{{{*/
2061 pkgAcquire::MethodConfig
const * const Cnf
)
2064 std::clog
<< "pkgAcqDiffIndex::Done(): " << Desc
.URI
<< std::endl
;
2066 Item::Done(Message
, Hashes
, Cnf
);
2068 string
const FinalFile
= GetFinalFilename();
2069 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false))
2070 DestFile
= FinalFile
;
2072 if(ParseDiffIndex(DestFile
) == false)
2074 Failed("Message: Couldn't parse pdiff index", Cnf
);
2075 // queue for final move - this should happen even if we fail
2076 // while parsing (e.g. on sizelimit) and download the complete file.
2077 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
2081 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
2090 pkgAcqDiffIndex::~pkgAcqDiffIndex()
2096 // AcqIndexDiffs::AcqIndexDiffs - Constructor /*{{{*/
2097 // ---------------------------------------------------------------------
2098 /* The package diff is added to the queue. one object is constructed
2099 * for each diff and the index
2101 pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire
* const Owner
,
2102 pkgAcqMetaClearSig
* const TransactionManager
,
2103 IndexTarget
const &Target
,
2104 vector
<DiffInfo
> const &diffs
)
2105 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
),
2106 available_patches(diffs
)
2108 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
2110 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
2113 Description
= Target
.Description
;
2114 Desc
.ShortDesc
= Target
.ShortDesc
;
2116 if(available_patches
.empty() == true)
2118 // we are done (yeah!), check hashes against the final file
2119 DestFile
= GetKeepCompressedFileName(GetFinalFileNameFromURI(Target
.URI
), Target
);
2124 if (BootstrapPDiffWith(GetPartialFileNameFromURI(Target
.URI
), GetFinalFilename(), Target
) == false)
2126 Failed("Bootstrapping of " + DestFile
+ " failed", NULL
);
2130 // get the next diff
2131 State
= StateFetchDiff
;
2136 void pkgAcqIndexDiffs::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
2138 Item::Failed(Message
,Cnf
);
2141 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
2143 std::clog
<< "pkgAcqIndexDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
2144 << "Falling back to normal index file acquire " << std::endl
;
2145 RenameOnError(PDiffError
);
2146 std::string
const patchname
= GetDiffsPatchFileName(DestFile
);
2147 if (RealFileExists(patchname
))
2148 rename(patchname
.c_str(), std::string(patchname
+ ".FAILED").c_str());
2149 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
2153 // Finish - helper that cleans the item out of the fetcher queue /*{{{*/
2154 void pkgAcqIndexDiffs::Finish(bool allDone
)
2157 std::clog
<< "pkgAcqIndexDiffs::Finish(): "
2159 << Desc
.URI
<< std::endl
;
2161 // we restore the original name, this is required, otherwise
2162 // the file will be cleaned
2165 std::string Final
= GetFinalFilename();
2166 if (Target
.KeepCompressed
)
2168 std::string
const ext
= flExtension(DestFile
);
2169 if (ext
.empty() == false)
2170 Final
.append(".").append(ext
);
2172 TransactionManager
->TransactionStageCopy(this, DestFile
, Final
);
2174 // this is for the "real" finish
2179 std::clog
<< "\n\nallDone: " << DestFile
<< "\n" << std::endl
;
2186 std::clog
<< "Finishing: " << Desc
.URI
<< std::endl
;
2193 bool pkgAcqIndexDiffs::QueueNextDiff() /*{{{*/
2195 // calc sha1 of the just patched file
2196 std::string
const FinalFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
2197 if(!FileExists(FinalFile
))
2199 Failed("Message: No FinalFile " + FinalFile
+ " available", NULL
);
2203 FileFd
fd(FinalFile
, FileFd::ReadOnly
, FileFd::Extension
);
2204 Hashes LocalHashesCalc
;
2205 LocalHashesCalc
.AddFD(fd
);
2206 HashStringList
const LocalHashes
= LocalHashesCalc
.GetHashStringList();
2209 std::clog
<< "QueueNextDiff: " << FinalFile
<< " (" << LocalHashes
.find(NULL
)->toStr() << ")" << std::endl
;
2211 HashStringList
const TargetFileHashes
= GetExpectedHashesFor(Target
.MetaKey
);
2212 if (unlikely(LocalHashes
.usable() == false || TargetFileHashes
.usable() == false))
2214 Failed("Local/Expected hashes are not usable", NULL
);
2219 // final file reached before all patches are applied
2220 if(LocalHashes
== TargetFileHashes
)
2226 // remove all patches until the next matching patch is found
2227 // this requires the Index file to be ordered
2228 for(vector
<DiffInfo
>::iterator I
= available_patches
.begin();
2229 available_patches
.empty() == false &&
2230 I
!= available_patches
.end() &&
2231 I
->result_hashes
!= LocalHashes
;
2234 available_patches
.erase(I
);
2237 // error checking and falling back if no patch was found
2238 if(available_patches
.empty() == true)
2240 Failed("No patches left to reach target", NULL
);
2244 // queue the right diff
2245 Desc
.URI
= Target
.URI
+ ".diff/" + available_patches
[0].file
+ ".gz";
2246 Desc
.Description
= Description
+ " " + available_patches
[0].file
+ string(".pdiff");
2247 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
+ ".diff/" + available_patches
[0].file
), Target
);
2250 std::clog
<< "pkgAcqIndexDiffs::QueueNextDiff(): " << Desc
.URI
<< std::endl
;
2257 void pkgAcqIndexDiffs::Done(string
const &Message
, HashStringList
const &Hashes
, /*{{{*/
2258 pkgAcquire::MethodConfig
const * const Cnf
)
2261 std::clog
<< "pkgAcqIndexDiffs::Done(): " << Desc
.URI
<< std::endl
;
2263 Item::Done(Message
, Hashes
, Cnf
);
2265 std::string
const FinalFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
2266 std::string
const PatchFile
= GetDiffsPatchFileName(FinalFile
);
2268 // success in downloading a diff, enter ApplyDiff state
2269 if(State
== StateFetchDiff
)
2271 Rename(DestFile
, PatchFile
);
2274 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
2276 State
= StateApplyDiff
;
2278 Desc
.URI
= "rred:" + FinalFile
;
2280 SetActiveSubprocess("rred");
2284 // success in download/apply a diff, queue next (if needed)
2285 if(State
== StateApplyDiff
)
2287 // remove the just applied patch
2288 available_patches
.erase(available_patches
.begin());
2289 RemoveFile("pkgAcqIndexDiffs::Done", PatchFile
);
2294 std::clog
<< "Moving patched file in place: " << std::endl
2295 << DestFile
<< " -> " << FinalFile
<< std::endl
;
2297 Rename(DestFile
,FinalFile
);
2298 chmod(FinalFile
.c_str(),0644);
2300 // see if there is more to download
2301 if(available_patches
.empty() == false) {
2302 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
,
2307 DestFile
= FinalFile
;
2308 return Finish(true);
2312 std::string
pkgAcqIndexDiffs::Custom600Headers() const /*{{{*/
2314 if(State
!= StateApplyDiff
)
2315 return pkgAcqBaseIndex::Custom600Headers();
2316 std::ostringstream patchhashes
;
2317 HashStringList
const ExpectedHashes
= available_patches
[0].patch_hashes
;
2318 for (HashStringList::const_iterator hs
= ExpectedHashes
.begin(); hs
!= ExpectedHashes
.end(); ++hs
)
2319 patchhashes
<< "\nPatch-0-" << hs
->HashType() << "-Hash: " << hs
->HashValue();
2320 patchhashes
<< pkgAcqBaseIndex::Custom600Headers();
2321 return patchhashes
.str();
2324 pkgAcqIndexDiffs::~pkgAcqIndexDiffs() {}
2326 // AcqIndexMergeDiffs::AcqIndexMergeDiffs - Constructor /*{{{*/
2327 pkgAcqIndexMergeDiffs::pkgAcqIndexMergeDiffs(pkgAcquire
* const Owner
,
2328 pkgAcqMetaClearSig
* const TransactionManager
,
2329 IndexTarget
const &Target
,
2330 DiffInfo
const &patch
,
2331 std::vector
<pkgAcqIndexMergeDiffs
*> const * const allPatches
)
2332 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
),
2333 patch(patch
), allPatches(allPatches
), State(StateFetchDiff
)
2335 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
2338 Description
= Target
.Description
;
2339 Desc
.ShortDesc
= Target
.ShortDesc
;
2341 Desc
.URI
= Target
.URI
+ ".diff/" + patch
.file
+ ".gz";
2342 Desc
.Description
= Description
+ " " + patch
.file
+ string(".pdiff");
2344 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
+ ".diff/" + patch
.file
), Target
);
2347 std::clog
<< "pkgAcqIndexMergeDiffs: " << Desc
.URI
<< std::endl
;
2352 void pkgAcqIndexMergeDiffs::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
2355 std::clog
<< "pkgAcqIndexMergeDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
;
2357 Item::Failed(Message
,Cnf
);
2360 // check if we are the first to fail, otherwise we are done here
2361 State
= StateDoneDiff
;
2362 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2363 I
!= allPatches
->end(); ++I
)
2364 if ((*I
)->State
== StateErrorDiff
)
2367 // first failure means we should fallback
2368 State
= StateErrorDiff
;
2370 std::clog
<< "Falling back to normal index file acquire" << std::endl
;
2371 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
2372 RenameOnError(PDiffError
);
2373 std::string
const patchname
= GetMergeDiffsPatchFileName(DestFile
, patch
.file
);
2374 if (RealFileExists(patchname
))
2375 rename(patchname
.c_str(), std::string(patchname
+ ".FAILED").c_str());
2376 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
2380 void pkgAcqIndexMergeDiffs::Done(string
const &Message
, HashStringList
const &Hashes
, /*{{{*/
2381 pkgAcquire::MethodConfig
const * const Cnf
)
2384 std::clog
<< "pkgAcqIndexMergeDiffs::Done(): " << Desc
.URI
<< std::endl
;
2386 Item::Done(Message
, Hashes
, Cnf
);
2388 std::string
const UncompressedFinalFile
= GetPartialFileNameFromURI(Target
.URI
);
2389 std::string
const FinalFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
2390 if (State
== StateFetchDiff
)
2392 Rename(DestFile
, GetMergeDiffsPatchFileName(FinalFile
, patch
.file
));
2394 // check if this is the last completed diff
2395 State
= StateDoneDiff
;
2396 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2397 I
!= allPatches
->end(); ++I
)
2398 if ((*I
)->State
!= StateDoneDiff
)
2401 std::clog
<< "Not the last done diff in the batch: " << Desc
.URI
<< std::endl
;
2405 // this is the last completed diff, so we are ready to apply now
2406 State
= StateApplyDiff
;
2408 if (BootstrapPDiffWith(UncompressedFinalFile
, GetFinalFilename(), Target
) == false)
2410 Failed("Bootstrapping of " + DestFile
+ " failed", NULL
);
2415 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
2418 Desc
.URI
= "rred:" + FinalFile
;
2420 SetActiveSubprocess("rred");
2423 // success in download/apply all diffs, clean up
2424 else if (State
== StateApplyDiff
)
2426 // move the result into place
2427 std::string
const Final
= GetKeepCompressedFileName(GetFinalFilename(), Target
);
2429 std::clog
<< "Queue patched file in place: " << std::endl
2430 << DestFile
<< " -> " << Final
<< std::endl
;
2432 // queue for copy by the transaction manager
2433 TransactionManager
->TransactionStageCopy(this, DestFile
, Final
);
2435 // ensure the ed's are gone regardless of list-cleanup
2436 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2437 I
!= allPatches
->end(); ++I
)
2439 std::string
const PartialFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
2440 std::string
const patch
= GetMergeDiffsPatchFileName(PartialFile
, (*I
)->patch
.file
);
2441 RemoveFile("pkgAcqIndexMergeDiffs::Done", patch
);
2443 RemoveFile("pkgAcqIndexMergeDiffs::Done", FinalFile
);
2448 std::clog
<< "allDone: " << DestFile
<< "\n" << std::endl
;
2452 std::string
pkgAcqIndexMergeDiffs::Custom600Headers() const /*{{{*/
2454 if(State
!= StateApplyDiff
)
2455 return pkgAcqBaseIndex::Custom600Headers();
2456 std::ostringstream patchhashes
;
2457 unsigned int seen_patches
= 0;
2458 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2459 I
!= allPatches
->end(); ++I
)
2461 HashStringList
const ExpectedHashes
= (*I
)->patch
.patch_hashes
;
2462 for (HashStringList::const_iterator hs
= ExpectedHashes
.begin(); hs
!= ExpectedHashes
.end(); ++hs
)
2463 patchhashes
<< "\nPatch-" << seen_patches
<< "-" << hs
->HashType() << "-Hash: " << hs
->HashValue();
2466 patchhashes
<< pkgAcqBaseIndex::Custom600Headers();
2467 return patchhashes
.str();
2470 pkgAcqIndexMergeDiffs::~pkgAcqIndexMergeDiffs() {}
2472 // AcqIndex::AcqIndex - Constructor /*{{{*/
2473 pkgAcqIndex::pkgAcqIndex(pkgAcquire
* const Owner
,
2474 pkgAcqMetaClearSig
* const TransactionManager
,
2475 IndexTarget
const &Target
)
2476 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
), Stage(STAGE_DOWNLOAD
),
2477 CompressionExtensions(Target
.Option(IndexTarget::COMPRESSIONTYPES
))
2479 Init(Target
.URI
, Target
.Description
, Target
.ShortDesc
);
2481 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
2482 std::clog
<< "New pkgIndex with TransactionManager "
2483 << TransactionManager
<< std::endl
;
2486 // AcqIndex::Init - defered Constructor /*{{{*/
2487 static void NextCompressionExtension(std::string
&CurrentCompressionExtension
, std::string
&CompressionExtensions
, bool const preview
)
2489 size_t const nextExt
= CompressionExtensions
.find(' ');
2490 if (nextExt
== std::string::npos
)
2492 CurrentCompressionExtension
= CompressionExtensions
;
2493 if (preview
== false)
2494 CompressionExtensions
.clear();
2498 CurrentCompressionExtension
= CompressionExtensions
.substr(0, nextExt
);
2499 if (preview
== false)
2500 CompressionExtensions
= CompressionExtensions
.substr(nextExt
+1);
2503 void pkgAcqIndex::Init(string
const &URI
, string
const &URIDesc
,
2504 string
const &ShortDesc
)
2506 Stage
= STAGE_DOWNLOAD
;
2508 DestFile
= GetPartialFileNameFromURI(URI
);
2509 NextCompressionExtension(CurrentCompressionExtension
, CompressionExtensions
, false);
2511 if (CurrentCompressionExtension
== "uncompressed")
2515 else if (CurrentCompressionExtension
== "by-hash")
2517 NextCompressionExtension(CurrentCompressionExtension
, CompressionExtensions
, true);
2518 if(unlikely(TransactionManager
->MetaIndexParser
== NULL
|| CurrentCompressionExtension
.empty()))
2520 if (CurrentCompressionExtension
!= "uncompressed")
2522 Desc
.URI
= URI
+ '.' + CurrentCompressionExtension
;
2523 DestFile
= DestFile
+ '.' + CurrentCompressionExtension
;
2526 HashStringList
const Hashes
= GetExpectedHashes();
2527 HashString
const * const TargetHash
= Hashes
.find(NULL
);
2528 if (unlikely(TargetHash
== nullptr))
2530 std::string
const ByHash
= "/by-hash/" + TargetHash
->HashType() + "/" + TargetHash
->HashValue();
2531 size_t const trailing_slash
= Desc
.URI
.find_last_of("/");
2532 if (unlikely(trailing_slash
== std::string::npos
))
2534 Desc
.URI
= Desc
.URI
.replace(
2536 Desc
.URI
.substr(trailing_slash
+1).size()+1,
2539 else if (unlikely(CurrentCompressionExtension
.empty()))
2543 Desc
.URI
= URI
+ '.' + CurrentCompressionExtension
;
2544 DestFile
= DestFile
+ '.' + CurrentCompressionExtension
;
2548 Desc
.Description
= URIDesc
;
2550 Desc
.ShortDesc
= ShortDesc
;
2555 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
2556 // ---------------------------------------------------------------------
2557 /* The only header we use is the last-modified header. */
2558 string
pkgAcqIndex::Custom600Headers() const
2560 string Final
= GetFinalFilename();
2562 string msg
= "\nIndex-File: true";
2564 if (stat(Final
.c_str(),&Buf
) == 0)
2565 msg
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
2567 if(Target
.IsOptional
)
2568 msg
+= "\nFail-Ignore: true";
2573 // AcqIndex::Failed - getting the indexfile failed /*{{{*/
2574 void pkgAcqIndex::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)
2576 Item::Failed(Message
,Cnf
);
2578 // authorisation matches will not be fixed by other compression types
2579 if (Status
!= StatAuthError
)
2581 if (CompressionExtensions
.empty() == false)
2583 Init(Target
.URI
, Desc
.Description
, Desc
.ShortDesc
);
2589 if(Target
.IsOptional
&& GetExpectedHashes().empty() && Stage
== STAGE_DOWNLOAD
)
2592 TransactionManager
->AbortTransaction();
2595 // AcqIndex::ReverifyAfterIMS - Reverify index after an ims-hit /*{{{*/
2596 void pkgAcqIndex::ReverifyAfterIMS()
2598 // update destfile to *not* include the compression extension when doing
2599 // a reverify (as its uncompressed on disk already)
2600 DestFile
= GetCompressedFileName(Target
, GetPartialFileNameFromURI(Target
.URI
), CurrentCompressionExtension
);
2602 // copy FinalFile into partial/ so that we check the hash again
2603 string FinalFile
= GetFinalFilename();
2604 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
2605 Desc
.URI
= "copy:" + FinalFile
;
2609 // AcqIndex::Done - Finished a fetch /*{{{*/
2610 // ---------------------------------------------------------------------
2611 /* This goes through a number of states.. On the initial fetch the
2612 method could possibly return an alternate filename which points
2613 to the uncompressed version of the file. If this is so the file
2614 is copied into the partial directory. In all other cases the file
2615 is decompressed with a compressed uri. */
2616 void pkgAcqIndex::Done(string
const &Message
,
2617 HashStringList
const &Hashes
,
2618 pkgAcquire::MethodConfig
const * const Cfg
)
2620 Item::Done(Message
,Hashes
,Cfg
);
2624 case STAGE_DOWNLOAD
:
2625 StageDownloadDone(Message
, Hashes
, Cfg
);
2627 case STAGE_DECOMPRESS_AND_VERIFY
:
2628 StageDecompressDone(Message
, Hashes
, Cfg
);
2633 // AcqIndex::StageDownloadDone - Queue for decompress and verify /*{{{*/
2634 void pkgAcqIndex::StageDownloadDone(string
const &Message
, HashStringList
const &,
2635 pkgAcquire::MethodConfig
const * const)
2639 // Handle the unzipd case
2640 std::string FileName
= LookupTag(Message
,"Alt-Filename");
2641 if (FileName
.empty() == false)
2643 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
2645 DestFile
+= ".decomp";
2646 Desc
.URI
= "copy:" + FileName
;
2648 SetActiveSubprocess("copy");
2651 FileName
= LookupTag(Message
,"Filename");
2653 // Methods like e.g. "file:" will give us a (compressed) FileName that is
2654 // not the "DestFile" we set, in this case we uncompress from the local file
2655 if (FileName
!= DestFile
&& RealFileExists(DestFile
) == false)
2658 if (Target
.KeepCompressed
== true)
2660 // but if we don't keep the uncompress we copy the compressed file first
2661 Stage
= STAGE_DOWNLOAD
;
2662 Desc
.URI
= "copy:" + FileName
;
2664 SetActiveSubprocess("copy");
2669 EraseFileName
= FileName
;
2671 // we need to verify the file against the current Release file again
2672 // on if-modfied-since hit to avoid a stale attack against us
2673 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
2675 // The files timestamp matches, reverify by copy into partial/
2681 // get the binary name for your used compression type
2683 if(CurrentCompressionExtension
== "uncompressed")
2684 decompProg
= "copy";
2686 decompProg
= _config
->Find(string("Acquire::CompressionTypes::").append(CurrentCompressionExtension
),"");
2687 if(decompProg
.empty() == true)
2689 _error
->Error("Unsupported extension: %s", CurrentCompressionExtension
.c_str());
2693 if (Target
.KeepCompressed
== true)
2695 DestFile
= "/dev/null";
2696 EraseFileName
.clear();
2699 DestFile
+= ".decomp";
2701 // queue uri for the next stage
2702 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
2703 Desc
.URI
= decompProg
+ ":" + FileName
;
2705 SetActiveSubprocess(decompProg
);
2708 // AcqIndex::StageDecompressDone - Final verification /*{{{*/
2709 void pkgAcqIndex::StageDecompressDone(string
const &,
2710 HashStringList
const &,
2711 pkgAcquire::MethodConfig
const * const)
2713 if (Target
.KeepCompressed
== true && DestFile
== "/dev/null")
2714 DestFile
= GetPartialFileNameFromURI(Target
.URI
+ '.' + CurrentCompressionExtension
);
2716 // Done, queue for rename on transaction finished
2717 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
2721 pkgAcqIndex::~pkgAcqIndex() {}
2724 // AcqArchive::AcqArchive - Constructor /*{{{*/
2725 // ---------------------------------------------------------------------
2726 /* This just sets up the initial fetch environment and queues the first
2728 pkgAcqArchive::pkgAcqArchive(pkgAcquire
* const Owner
,pkgSourceList
* const Sources
,
2729 pkgRecords
* const Recs
,pkgCache::VerIterator
const &Version
,
2730 string
&StoreFilename
) :
2731 Item(Owner
), d(NULL
), LocalSource(false), Version(Version
), Sources(Sources
), Recs(Recs
),
2732 StoreFilename(StoreFilename
), Vf(Version
.FileList()),
2735 Retries
= _config
->FindI("Acquire::Retries",0);
2737 if (Version
.Arch() == 0)
2739 _error
->Error(_("I wasn't able to locate a file for the %s package. "
2740 "This might mean you need to manually fix this package. "
2741 "(due to missing arch)"),
2742 Version
.ParentPkg().FullName().c_str());
2746 /* We need to find a filename to determine the extension. We make the
2747 assumption here that all the available sources for this version share
2748 the same extension.. */
2749 // Skip not source sources, they do not have file fields.
2750 for (; Vf
.end() == false; ++Vf
)
2752 if (Vf
.File().Flagged(pkgCache::Flag::NotSource
))
2757 // Does not really matter here.. we are going to fail out below
2758 if (Vf
.end() != true)
2760 // If this fails to get a file name we will bomb out below.
2761 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2762 if (_error
->PendingError() == true)
2765 // Generate the final file name as: package_version_arch.foo
2766 StoreFilename
= QuoteString(Version
.ParentPkg().Name(),"_:") + '_' +
2767 QuoteString(Version
.VerStr(),"_:") + '_' +
2768 QuoteString(Version
.Arch(),"_:.") +
2769 "." + flExtension(Parse
.FileName());
2772 // check if we have one trusted source for the package. if so, switch
2773 // to "TrustedOnly" mode - but only if not in AllowUnauthenticated mode
2774 bool const allowUnauth
= _config
->FindB("APT::Get::AllowUnauthenticated", false);
2775 bool const debugAuth
= _config
->FindB("Debug::pkgAcquire::Auth", false);
2776 bool seenUntrusted
= false;
2777 for (pkgCache::VerFileIterator i
= Version
.FileList(); i
.end() == false; ++i
)
2779 pkgIndexFile
*Index
;
2780 if (Sources
->FindIndex(i
.File(),Index
) == false)
2783 if (debugAuth
== true)
2784 std::cerr
<< "Checking index: " << Index
->Describe()
2785 << "(Trusted=" << Index
->IsTrusted() << ")" << std::endl
;
2787 if (Index
->IsTrusted() == true)
2790 if (allowUnauth
== false)
2794 seenUntrusted
= true;
2797 // "allow-unauthenticated" restores apts old fetching behaviour
2798 // that means that e.g. unauthenticated file:// uris are higher
2799 // priority than authenticated http:// uris
2800 if (allowUnauth
== true && seenUntrusted
== true)
2804 if (QueueNext() == false && _error
->PendingError() == false)
2805 _error
->Error(_("Can't find a source to download version '%s' of '%s'"),
2806 Version
.VerStr(), Version
.ParentPkg().FullName(false).c_str());
2809 // AcqArchive::QueueNext - Queue the next file source /*{{{*/
2810 // ---------------------------------------------------------------------
2811 /* This queues the next available file version for download. It checks if
2812 the archive is already available in the cache and stashs the MD5 for
2814 bool pkgAcqArchive::QueueNext()
2816 for (; Vf
.end() == false; ++Vf
)
2818 pkgCache::PkgFileIterator
const PkgF
= Vf
.File();
2819 // Ignore not source sources
2820 if (PkgF
.Flagged(pkgCache::Flag::NotSource
))
2823 // Try to cross match against the source list
2824 pkgIndexFile
*Index
;
2825 if (Sources
->FindIndex(PkgF
, Index
) == false)
2827 LocalSource
= PkgF
.Flagged(pkgCache::Flag::LocalSource
);
2829 // only try to get a trusted package from another source if that source
2831 if(Trusted
&& !Index
->IsTrusted())
2834 // Grab the text package record
2835 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2836 if (_error
->PendingError() == true)
2839 string PkgFile
= Parse
.FileName();
2840 ExpectedHashes
= Parse
.Hashes();
2842 if (PkgFile
.empty() == true)
2843 return _error
->Error(_("The package index files are corrupted. No Filename: "
2844 "field for package %s."),
2845 Version
.ParentPkg().Name());
2847 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
2848 Desc
.Description
= Index
->ArchiveInfo(Version
);
2850 Desc
.ShortDesc
= Version
.ParentPkg().FullName(true);
2852 // See if we already have the file. (Legacy filenames)
2853 FileSize
= Version
->Size
;
2854 string FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile
);
2856 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2858 // Make sure the size matches
2859 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2864 StoreFilename
= DestFile
= FinalFile
;
2868 /* Hmm, we have a file and its size does not match, this means it is
2869 an old style mismatched arch */
2870 RemoveFile("pkgAcqArchive::QueueNext", FinalFile
);
2873 // Check it again using the new style output filenames
2874 FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
2875 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2877 // Make sure the size matches
2878 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2883 StoreFilename
= DestFile
= FinalFile
;
2887 /* Hmm, we have a file and its size does not match, this shouldn't
2889 RemoveFile("pkgAcqArchive::QueueNext", FinalFile
);
2892 DestFile
= _config
->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename
);
2894 // Check the destination file
2895 if (stat(DestFile
.c_str(),&Buf
) == 0)
2897 // Hmm, the partial file is too big, erase it
2898 if ((unsigned long long)Buf
.st_size
> Version
->Size
)
2899 RemoveFile("pkgAcqArchive::QueueNext", DestFile
);
2901 PartialSize
= Buf
.st_size
;
2904 // Disables download of archives - useful if no real installation follows,
2905 // e.g. if we are just interested in proposed installation order
2906 if (_config
->FindB("Debug::pkgAcqArchive::NoQueue", false) == true)
2911 StoreFilename
= DestFile
= FinalFile
;
2925 // AcqArchive::Done - Finished fetching /*{{{*/
2926 // ---------------------------------------------------------------------
2928 void pkgAcqArchive::Done(string
const &Message
, HashStringList
const &Hashes
,
2929 pkgAcquire::MethodConfig
const * const Cfg
)
2931 Item::Done(Message
, Hashes
, Cfg
);
2933 // Grab the output filename
2934 std::string
const FileName
= LookupTag(Message
,"Filename");
2935 if (DestFile
!= FileName
&& RealFileExists(DestFile
) == false)
2937 StoreFilename
= DestFile
= FileName
;
2943 // Done, move it into position
2944 string
const FinalFile
= GetFinalFilename();
2945 Rename(DestFile
,FinalFile
);
2946 StoreFilename
= DestFile
= FinalFile
;
2950 // AcqArchive::Failed - Failure handler /*{{{*/
2951 // ---------------------------------------------------------------------
2952 /* Here we try other sources */
2953 void pkgAcqArchive::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)
2955 Item::Failed(Message
,Cnf
);
2957 /* We don't really want to retry on failed media swaps, this prevents
2958 that. An interesting observation is that permanent failures are not
2960 if (Cnf
->Removable
== true &&
2961 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2963 // Vf = Version.FileList();
2964 while (Vf
.end() == false) ++Vf
;
2965 StoreFilename
= string();
2970 if (QueueNext() == false)
2972 // This is the retry counter
2974 Cnf
->LocalOnly
== false &&
2975 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2978 Vf
= Version
.FileList();
2979 if (QueueNext() == true)
2983 StoreFilename
= string();
2988 APT_PURE
bool pkgAcqArchive::IsTrusted() const /*{{{*/
2993 void pkgAcqArchive::Finished() /*{{{*/
2995 if (Status
== pkgAcquire::Item::StatDone
&&
2998 StoreFilename
= string();
3001 std::string
pkgAcqArchive::DescURI() const /*{{{*/
3006 std::string
pkgAcqArchive::ShortDesc() const /*{{{*/
3008 return Desc
.ShortDesc
;
3011 pkgAcqArchive::~pkgAcqArchive() {}
3013 // AcqChangelog::pkgAcqChangelog - Constructors /*{{{*/
3014 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire
* const Owner
, pkgCache::VerIterator
const &Ver
,
3015 std::string
const &DestDir
, std::string
const &DestFilename
) :
3016 pkgAcquire::Item(Owner
), d(NULL
), SrcName(Ver
.SourcePkgName()), SrcVersion(Ver
.SourceVerStr())
3018 Desc
.URI
= URI(Ver
);
3019 Init(DestDir
, DestFilename
);
3021 // some parameters are char* here as they come likely from char* interfaces – which can also return NULL
3022 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire
* const Owner
, pkgCache::RlsFileIterator
const &RlsFile
,
3023 char const * const Component
, char const * const SrcName
, char const * const SrcVersion
,
3024 const string
&DestDir
, const string
&DestFilename
) :
3025 pkgAcquire::Item(Owner
), d(NULL
), SrcName(SrcName
), SrcVersion(SrcVersion
)
3027 Desc
.URI
= URI(RlsFile
, Component
, SrcName
, SrcVersion
);
3028 Init(DestDir
, DestFilename
);
3030 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire
* const Owner
,
3031 std::string
const &URI
, char const * const SrcName
, char const * const SrcVersion
,
3032 const string
&DestDir
, const string
&DestFilename
) :
3033 pkgAcquire::Item(Owner
), d(NULL
), SrcName(SrcName
), SrcVersion(SrcVersion
)
3036 Init(DestDir
, DestFilename
);
3038 void pkgAcqChangelog::Init(std::string
const &DestDir
, std::string
const &DestFilename
)
3040 if (Desc
.URI
.empty())
3043 // TRANSLATOR: %s=%s is sourcename=sourceversion, e.g. apt=1.1
3044 strprintf(ErrorText
, _("Changelog unavailable for %s=%s"), SrcName
.c_str(), SrcVersion
.c_str());
3045 // Let the error message print something sensible rather than "Failed to fetch /"
3046 if (DestFilename
.empty())
3047 DestFile
= SrcName
+ ".changelog";
3049 DestFile
= DestFilename
;
3050 Desc
.URI
= "changelog:/" + DestFile
;
3054 if (DestDir
.empty())
3056 std::string
const SandboxUser
= _config
->Find("APT::Sandbox::User");
3057 std::string
const systemTemp
= GetTempDir(SandboxUser
);
3059 snprintf(tmpname
, sizeof(tmpname
), "%s/apt-changelog-XXXXXX", systemTemp
.c_str());
3060 if (NULL
== mkdtemp(tmpname
))
3062 _error
->Errno("mkdtemp", "mkdtemp failed in changelog acquire of %s %s", SrcName
.c_str(), SrcVersion
.c_str());
3066 DestFile
= TemporaryDirectory
= tmpname
;
3068 ChangeOwnerAndPermissionOfFile("Item::QueueURI", DestFile
.c_str(),
3069 SandboxUser
.c_str(), "root", 0700);
3074 if (DestFilename
.empty())
3075 DestFile
= flCombine(DestFile
, SrcName
+ ".changelog");
3077 DestFile
= flCombine(DestFile
, DestFilename
);
3079 Desc
.ShortDesc
= "Changelog";
3080 strprintf(Desc
.Description
, "%s %s %s Changelog", URI::SiteOnly(Desc
.URI
).c_str(), SrcName
.c_str(), SrcVersion
.c_str());
3085 std::string
pkgAcqChangelog::URI(pkgCache::VerIterator
const &Ver
) /*{{{*/
3087 char const * const SrcName
= Ver
.SourcePkgName();
3088 char const * const SrcVersion
= Ver
.SourceVerStr();
3089 pkgCache::PkgFileIterator PkgFile
;
3090 // find the first source for this version which promises a changelog
3091 for (pkgCache::VerFileIterator VF
= Ver
.FileList(); VF
.end() == false; ++VF
)
3093 pkgCache::PkgFileIterator
const PF
= VF
.File();
3094 if (PF
.Flagged(pkgCache::Flag::NotSource
) || PF
->Release
== 0)
3097 pkgCache::RlsFileIterator
const RF
= PF
.ReleaseFile();
3098 std::string
const uri
= URI(RF
, PF
.Component(), SrcName
, SrcVersion
);
3105 std::string
pkgAcqChangelog::URITemplate(pkgCache::RlsFileIterator
const &Rls
)
3107 if (Rls
.end() == true || (Rls
->Label
== 0 && Rls
->Origin
== 0))
3109 std::string
const serverConfig
= "Acquire::Changelogs::URI";
3111 #define APT_EMPTY_SERVER \
3112 if (server.empty() == false) \
3114 if (server != "no") \
3118 #define APT_CHECK_SERVER(X, Y) \
3121 std::string const specialServerConfig = serverConfig + "::" + Y + #X + "::" + Rls.X(); \
3122 server = _config->Find(specialServerConfig); \
3125 // this way e.g. Debian-Security can fallback to Debian
3126 APT_CHECK_SERVER(Label
, "Override::")
3127 APT_CHECK_SERVER(Origin
, "Override::")
3129 if (RealFileExists(Rls
.FileName()))
3131 _error
->PushToStack();
3133 /* This can be costly. A caller wanting to get millions of URIs might
3134 want to do this on its own once and use Override settings.
3135 We don't do this here as Origin/Label are not as unique as they
3136 should be so this could produce request order-dependent anomalies */
3137 if (OpenMaybeClearSignedFile(Rls
.FileName(), rf
) == true)
3139 pkgTagFile
TagFile(&rf
, rf
.Size());
3140 pkgTagSection Section
;
3141 if (TagFile
.Step(Section
) == true)
3142 server
= Section
.FindS("Changelogs");
3144 _error
->RevertToStack();
3148 APT_CHECK_SERVER(Label
, "")
3149 APT_CHECK_SERVER(Origin
, "")
3150 #undef APT_CHECK_SERVER
3151 #undef APT_EMPTY_SERVER
3154 std::string
pkgAcqChangelog::URI(pkgCache::RlsFileIterator
const &Rls
,
3155 char const * const Component
, char const * const SrcName
,
3156 char const * const SrcVersion
)
3158 return URI(URITemplate(Rls
), Component
, SrcName
, SrcVersion
);
3160 std::string
pkgAcqChangelog::URI(std::string
const &Template
,
3161 char const * const Component
, char const * const SrcName
,
3162 char const * const SrcVersion
)
3164 if (Template
.find("CHANGEPATH") == std::string::npos
)
3167 // the path is: COMPONENT/SRC/SRCNAME/SRCNAME_SRCVER, e.g. main/a/apt/1.1 or contrib/liba/libapt/2.0
3168 std::string Src
= SrcName
;
3169 std::string path
= APT::String::Startswith(SrcName
, "lib") ? Src
.substr(0, 4) : Src
.substr(0,1);
3170 path
.append("/").append(Src
).append("/");
3171 path
.append(Src
).append("_").append(StripEpoch(SrcVersion
));
3172 // we omit component for releases without one (= flat-style repositories)
3173 if (Component
!= NULL
&& strlen(Component
) != 0)
3174 path
= std::string(Component
) + "/" + path
;
3176 return SubstVar(Template
, "CHANGEPATH", path
);
3179 // AcqChangelog::Failed - Failure handler /*{{{*/
3180 void pkgAcqChangelog::Failed(string
const &Message
, pkgAcquire::MethodConfig
const * const Cnf
)
3182 Item::Failed(Message
,Cnf
);
3184 std::string errText
;
3185 // TRANSLATOR: %s=%s is sourcename=sourceversion, e.g. apt=1.1
3186 strprintf(errText
, _("Changelog unavailable for %s=%s"), SrcName
.c_str(), SrcVersion
.c_str());
3188 // Error is probably something techy like 404 Not Found
3189 if (ErrorText
.empty())
3190 ErrorText
= errText
;
3192 ErrorText
= errText
+ " (" + ErrorText
+ ")";
3196 // AcqChangelog::Done - Item downloaded OK /*{{{*/
3197 void pkgAcqChangelog::Done(string
const &Message
,HashStringList
const &CalcHashes
,
3198 pkgAcquire::MethodConfig
const * const Cnf
)
3200 Item::Done(Message
,CalcHashes
,Cnf
);
3205 pkgAcqChangelog::~pkgAcqChangelog() /*{{{*/
3207 if (TemporaryDirectory
.empty() == false)
3209 RemoveFile("~pkgAcqChangelog", DestFile
);
3210 rmdir(TemporaryDirectory
.c_str());
3215 // AcqFile::pkgAcqFile - Constructor /*{{{*/
3216 pkgAcqFile::pkgAcqFile(pkgAcquire
* const Owner
,string
const &URI
, HashStringList
const &Hashes
,
3217 unsigned long long const Size
,string
const &Dsc
,string
const &ShortDesc
,
3218 const string
&DestDir
, const string
&DestFilename
,
3219 bool const IsIndexFile
) :
3220 Item(Owner
), d(NULL
), IsIndexFile(IsIndexFile
), ExpectedHashes(Hashes
)
3222 Retries
= _config
->FindI("Acquire::Retries",0);
3224 if(!DestFilename
.empty())
3225 DestFile
= DestFilename
;
3226 else if(!DestDir
.empty())
3227 DestFile
= DestDir
+ "/" + flNotDir(URI
);
3229 DestFile
= flNotDir(URI
);
3233 Desc
.Description
= Dsc
;
3236 // Set the short description to the archive component
3237 Desc
.ShortDesc
= ShortDesc
;
3239 // Get the transfer sizes
3242 if (stat(DestFile
.c_str(),&Buf
) == 0)
3244 // Hmm, the partial file is too big, erase it
3245 if ((Size
> 0) && (unsigned long long)Buf
.st_size
> Size
)
3246 RemoveFile("pkgAcqFile", DestFile
);
3248 PartialSize
= Buf
.st_size
;
3254 // AcqFile::Done - Item downloaded OK /*{{{*/
3255 void pkgAcqFile::Done(string
const &Message
,HashStringList
const &CalcHashes
,
3256 pkgAcquire::MethodConfig
const * const Cnf
)
3258 Item::Done(Message
,CalcHashes
,Cnf
);
3260 std::string
const FileName
= LookupTag(Message
,"Filename");
3263 // The files timestamp matches
3264 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
3267 // We have to copy it into place
3268 if (RealFileExists(DestFile
.c_str()) == false)
3271 if (_config
->FindB("Acquire::Source-Symlinks",true) == false ||
3272 Cnf
->Removable
== true)
3274 Desc
.URI
= "copy:" + FileName
;
3279 // Erase the file if it is a symlink so we can overwrite it
3281 if (lstat(DestFile
.c_str(),&St
) == 0)
3283 if (S_ISLNK(St
.st_mode
) != 0)
3284 RemoveFile("pkgAcqFile::Done", DestFile
);
3288 if (symlink(FileName
.c_str(),DestFile
.c_str()) != 0)
3290 _error
->PushToStack();
3291 _error
->Errno("pkgAcqFile::Done", "Symlinking file %s failed", DestFile
.c_str());
3292 std::stringstream msg
;
3293 _error
->DumpErrors(msg
, GlobalError::DEBUG
, false);
3294 _error
->RevertToStack();
3295 ErrorText
= msg
.str();
3302 // AcqFile::Failed - Failure handler /*{{{*/
3303 // ---------------------------------------------------------------------
3304 /* Here we try other sources */
3305 void pkgAcqFile::Failed(string
const &Message
, pkgAcquire::MethodConfig
const * const Cnf
)
3307 Item::Failed(Message
,Cnf
);
3309 // This is the retry counter
3311 Cnf
->LocalOnly
== false &&
3312 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
3322 string
pkgAcqFile::Custom600Headers() const /*{{{*/
3325 return "\nIndex-File: true";
3329 pkgAcqFile::~pkgAcqFile() {}