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/sha1.h>
26 #include <apt-pkg/tagfile.h>
27 #include <apt-pkg/metaindex.h>
28 #include <apt-pkg/acquire.h>
29 #include <apt-pkg/hashes.h>
30 #include <apt-pkg/indexfile.h>
31 #include <apt-pkg/pkgcache.h>
32 #include <apt-pkg/cacheiterators.h>
33 #include <apt-pkg/pkgrecords.h>
34 #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
GetCompressedFileName(IndexTarget
const &Target
, std::string
const &Name
, std::string
const &Ext
) /*{{{*/
85 if (Ext
.empty() || Ext
== "uncompressed")
88 // do not reverify cdrom sources as apt-cdrom may rewrite the Packages
89 // file when its doing the indexcopy
90 if (Target
.URI
.substr(0,6) == "cdrom:")
93 // adjust DestFile if its compressed on disk
94 if (Target
.KeepCompressed
== true)
95 return Name
+ '.' + Ext
;
99 static std::string
GetMergeDiffsPatchFileName(std::string
const &Final
, std::string
const &Patch
)/*{{{*/
101 // rred expects the patch as $FinalFile.ed.$patchname.gz
102 return Final
+ ".ed." + Patch
+ ".gz";
105 static std::string
GetDiffsPatchFileName(std::string
const &Final
) /*{{{*/
107 // rred expects the patch as $FinalFile.ed
108 return Final
+ ".ed";
112 static bool AllowInsecureRepositories(metaIndex
const * const MetaIndexParser
, pkgAcqMetaClearSig
* const TransactionManager
, pkgAcquire::Item
* const I
) /*{{{*/
114 if(MetaIndexParser
->GetTrusted() == metaIndex::TRI_YES
|| _config
->FindB("Acquire::AllowInsecureRepositories") == true)
117 _error
->Error(_("Use --allow-insecure-repositories to force the update"));
118 TransactionManager
->AbortTransaction();
119 I
->Status
= pkgAcquire::Item::StatError
;
123 static HashStringList
GetExpectedHashesFromFor(metaIndex
* const Parser
, std::string
const &MetaKey
)/*{{{*/
126 return HashStringList();
127 metaIndex::checkSum
* const R
= Parser
->Lookup(MetaKey
);
129 return HashStringList();
134 // all ::HashesRequired and ::GetExpectedHashes implementations /*{{{*/
135 /* ::GetExpectedHashes is abstract and has to be implemented by all subclasses.
136 It is best to implement it as broadly as possible, while ::HashesRequired defaults
137 to true and should be as restrictive as possible for false cases. Note that if
138 a hash is returned by ::GetExpectedHashes it must match. Only if it doesn't
139 ::HashesRequired is called to evaluate if its okay to have no hashes. */
140 APT_CONST
bool pkgAcqTransactionItem::HashesRequired() const
142 /* signed repositories obviously have a parser and good hashes.
143 unsigned repositories, too, as even if we can't trust them for security,
144 we can at least trust them for integrity of the download itself.
145 Only repositories without a Release file can (obviously) not have
146 hashes – and they are very uncommon and strongly discouraged */
147 return TransactionManager
->MetaIndexParser
!= NULL
&&
148 TransactionManager
->MetaIndexParser
->GetLoadedSuccessfully() != metaIndex::TRI_UNSET
;
150 HashStringList
pkgAcqTransactionItem::GetExpectedHashes() const
152 return GetExpectedHashesFor(GetMetaKey());
155 APT_CONST
bool pkgAcqMetaBase::HashesRequired() const
157 // Release and co have no hashes 'by design'.
160 HashStringList
pkgAcqMetaBase::GetExpectedHashes() const
162 return HashStringList();
165 APT_CONST
bool pkgAcqIndexDiffs::HashesRequired() const
167 /* We don't always have the diff of the downloaded pdiff file.
168 What we have for sure is hashes for the uncompressed file,
169 but rred uncompresses them on the fly while parsing, so not handled here.
170 Hashes are (also) checked while searching for (next) patch to apply. */
171 if (State
== StateFetchDiff
)
172 return available_patches
[0].download_hashes
.empty() == false;
175 HashStringList
pkgAcqIndexDiffs::GetExpectedHashes() const
177 if (State
== StateFetchDiff
)
178 return available_patches
[0].download_hashes
;
179 return HashStringList();
182 APT_CONST
bool pkgAcqIndexMergeDiffs::HashesRequired() const
184 /* @see #pkgAcqIndexDiffs::HashesRequired, with the difference that
185 we can check the rred result after all patches are applied as
186 we know the expected result rather than potentially apply more patches */
187 if (State
== StateFetchDiff
)
188 return patch
.download_hashes
.empty() == false;
189 return State
== StateApplyDiff
;
191 HashStringList
pkgAcqIndexMergeDiffs::GetExpectedHashes() const
193 if (State
== StateFetchDiff
)
194 return patch
.download_hashes
;
195 else if (State
== StateApplyDiff
)
196 return GetExpectedHashesFor(Target
.MetaKey
);
197 return HashStringList();
200 APT_CONST
bool pkgAcqArchive::HashesRequired() const
202 return LocalSource
== false;
204 HashStringList
pkgAcqArchive::GetExpectedHashes() const
206 // figured out while parsing the records
207 return ExpectedHashes
;
210 APT_CONST
bool pkgAcqFile::HashesRequired() const
212 // supplied as parameter at creation time, so the caller decides
213 return ExpectedHashes
.usable();
215 HashStringList
pkgAcqFile::GetExpectedHashes() const
217 return ExpectedHashes
;
220 // Acquire::Item::QueueURI and specialisations from child classes /*{{{*/
221 bool pkgAcquire::Item::QueueURI(pkgAcquire::ItemDesc
&Item
)
223 Owner
->Enqueue(Item
);
226 /* The idea here is that an item isn't queued if it exists on disk and the
227 transition manager was a hit as this means that the files it contains
228 the checksums for can't be updated either (or they are and we are asking
229 for a hashsum mismatch to happen which helps nobody) */
230 bool pkgAcqTransactionItem::QueueURI(pkgAcquire::ItemDesc
&Item
)
232 std::string
const FinalFile
= GetFinalFilename();
233 if (TransactionManager
!= NULL
&& TransactionManager
->IMSHit
== true &&
234 FileExists(FinalFile
) == true)
236 PartialFile
= DestFile
= FinalFile
;
240 return pkgAcquire::Item::QueueURI(Item
);
242 /* The transition manager InRelease itself (or its older sisters-in-law
243 Release & Release.gpg) is always queued as this allows us to rerun gpgv
244 on it to verify that we aren't stalled with old files */
245 bool pkgAcqMetaBase::QueueURI(pkgAcquire::ItemDesc
&Item
)
247 return pkgAcquire::Item::QueueURI(Item
);
249 /* the Diff/Index needs to queue also the up-to-date complete index file
250 to ensure that the list cleaner isn't eating it */
251 bool pkgAcqDiffIndex::QueueURI(pkgAcquire::ItemDesc
&Item
)
253 if (pkgAcqTransactionItem::QueueURI(Item
) == true)
259 // Acquire::Item::GetFinalFilename and specialisations for child classes /*{{{*/
260 std::string
pkgAcquire::Item::GetFinalFilename() const
262 return GetFinalFileNameFromURI(Desc
.URI
);
264 std::string
pkgAcqDiffIndex::GetFinalFilename() const
266 // the logic we inherent from pkgAcqBaseIndex isn't what we need here
267 return pkgAcquire::Item::GetFinalFilename();
269 std::string
pkgAcqIndex::GetFinalFilename() const
271 std::string
const FinalFile
= GetFinalFileNameFromURI(Target
.URI
);
272 return GetCompressedFileName(Target
, FinalFile
, CurrentCompressionExtension
);
274 std::string
pkgAcqMetaSig::GetFinalFilename() const
276 return GetFinalFileNameFromURI(Target
.URI
);
278 std::string
pkgAcqBaseIndex::GetFinalFilename() const
280 return GetFinalFileNameFromURI(Target
.URI
);
282 std::string
pkgAcqMetaBase::GetFinalFilename() const
284 return GetFinalFileNameFromURI(Target
.URI
);
286 std::string
pkgAcqArchive::GetFinalFilename() const
288 return _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
291 // pkgAcqTransactionItem::GetMetaKey and specialisations for child classes /*{{{*/
292 std::string
pkgAcqTransactionItem::GetMetaKey() const
294 return Target
.MetaKey
;
296 std::string
pkgAcqIndex::GetMetaKey() const
298 if (Stage
== STAGE_DECOMPRESS_AND_VERIFY
|| CurrentCompressionExtension
== "uncompressed")
299 return Target
.MetaKey
;
300 return Target
.MetaKey
+ "." + CurrentCompressionExtension
;
302 std::string
pkgAcqDiffIndex::GetMetaKey() const
304 return Target
.MetaKey
+ ".diff/Index";
307 //pkgAcqTransactionItem::TransactionState and specialisations for child classes /*{{{*/
308 bool pkgAcqTransactionItem::TransactionState(TransactionStates
const state
)
310 bool const Debug
= _config
->FindB("Debug::Acquire::Transaction", false);
313 case TransactionAbort
:
315 std::clog
<< " Cancel: " << DestFile
<< std::endl
;
316 if (Status
== pkgAcquire::Item::StatIdle
)
318 Status
= pkgAcquire::Item::StatDone
;
322 case TransactionCommit
:
323 if(PartialFile
!= "")
326 std::clog
<< "mv " << PartialFile
<< " -> "<< DestFile
<< " # " << DescURI() << std::endl
;
328 Rename(PartialFile
, DestFile
);
331 std::clog
<< "rm " << DestFile
<< " # " << DescURI() << std::endl
;
332 unlink(DestFile
.c_str());
338 bool pkgAcqMetaBase::TransactionState(TransactionStates
const state
)
340 // Do not remove InRelease on IMSHit of Release.gpg [yes, this is very edgecasey]
341 if (TransactionManager
->IMSHit
== false)
342 return pkgAcqTransactionItem::TransactionState(state
);
345 bool pkgAcqIndex::TransactionState(TransactionStates
const state
)
347 if (pkgAcqTransactionItem::TransactionState(state
) == false)
352 case TransactionAbort
:
353 if (Stage
== STAGE_DECOMPRESS_AND_VERIFY
)
355 // keep the compressed file, but drop the decompressed
356 EraseFileName
.clear();
357 if (PartialFile
.empty() == false && flExtension(PartialFile
) == "decomp")
358 unlink(PartialFile
.c_str());
361 case TransactionCommit
:
362 if (EraseFileName
.empty() == false)
363 unlink(EraseFileName
.c_str());
368 bool pkgAcqDiffIndex::TransactionState(TransactionStates
const state
)
370 if (pkgAcqTransactionItem::TransactionState(state
) == false)
375 case TransactionCommit
:
377 case TransactionAbort
:
378 std::string
const Partial
= GetPartialFileNameFromURI(Target
.URI
);
379 unlink(Partial
.c_str());
387 class APT_HIDDEN NoActionItem
: public pkgAcquire::Item
/*{{{*/
388 /* The sole purpose of this class is having an item which does nothing to
389 reach its done state to prevent cleanup deleting the mentioned file.
390 Handy in cases in which we know we have the file already, like IMS-Hits. */
392 IndexTarget
const Target
;
394 virtual std::string
DescURI() const APT_OVERRIDE
{return Target
.URI
;};
395 virtual HashStringList
GetExpectedHashes() const APT_OVERRIDE
{return HashStringList();};
397 NoActionItem(pkgAcquire
* const Owner
, IndexTarget
const &Target
) :
398 pkgAcquire::Item(Owner
), Target(Target
)
401 DestFile
= GetFinalFileNameFromURI(Target
.URI
);
406 // Acquire::Item::Item - Constructor /*{{{*/
407 APT_IGNORE_DEPRECATED_PUSH
408 pkgAcquire::Item::Item(pkgAcquire
* const owner
) :
409 FileSize(0), PartialSize(0), Mode(0), ID(0), Complete(false), Local(false),
410 QueueCounter(0), ExpectedAdditionalItems(0), Owner(owner
), d(NULL
)
415 APT_IGNORE_DEPRECATED_POP
417 // Acquire::Item::~Item - Destructor /*{{{*/
418 pkgAcquire::Item::~Item()
423 std::string
pkgAcquire::Item::Custom600Headers() const /*{{{*/
425 return std::string();
428 std::string
pkgAcquire::Item::ShortDesc() const /*{{{*/
433 APT_CONST
void pkgAcquire::Item::Finished() /*{{{*/
437 APT_PURE pkgAcquire
* pkgAcquire::Item::GetOwner() const /*{{{*/
442 APT_CONST
pkgAcquire::ItemDesc
&pkgAcquire::Item::GetItemDesc() /*{{{*/
447 APT_CONST
bool pkgAcquire::Item::IsTrusted() const /*{{{*/
452 // Acquire::Item::Failed - Item failed to download /*{{{*/
453 // ---------------------------------------------------------------------
454 /* We return to an idle state if there are still other queues that could
456 void pkgAcquire::Item::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)
458 if(ErrorText
.empty())
459 ErrorText
= LookupTag(Message
,"Message");
460 if (QueueCounter
<= 1)
462 /* This indicates that the file is not available right now but might
463 be sometime later. If we do a retry cycle then this should be
465 if (Cnf
!= NULL
&& Cnf
->LocalOnly
== true &&
466 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
482 case StatTransientNetworkError
:
489 string
const FailReason
= LookupTag(Message
, "FailReason");
490 if (FailReason
== "MaximumSizeExceeded")
491 RenameOnError(MaximumSizeExceeded
);
492 else if (Status
== StatAuthError
)
493 RenameOnError(HashSumMismatch
);
495 // report mirror failure back to LP if we actually use a mirror
496 if (FailReason
.empty() == false)
497 ReportMirrorFailure(FailReason
);
499 ReportMirrorFailure(ErrorText
);
501 if (QueueCounter
> 1)
505 // Acquire::Item::Start - Item has begun to download /*{{{*/
506 // ---------------------------------------------------------------------
507 /* Stash status and the file size. Note that setting Complete means
508 sub-phases of the acquire process such as decompresion are operating */
509 void pkgAcquire::Item::Start(string
const &/*Message*/, unsigned long long const Size
)
511 Status
= StatFetching
;
513 if (FileSize
== 0 && Complete
== false)
517 // Acquire::Item::VerifyDone - check if Item was downloaded OK /*{{{*/
518 /* Note that hash-verification is 'hardcoded' in acquire-worker and has
519 * already passed if this method is called. */
520 bool pkgAcquire::Item::VerifyDone(std::string
const &Message
,
521 pkgAcquire::MethodConfig
const * const /*Cnf*/)
523 std::string
const FileName
= LookupTag(Message
,"Filename");
524 if (FileName
.empty() == true)
527 ErrorText
= "Method gave a blank filename";
534 // Acquire::Item::Done - Item downloaded OK /*{{{*/
535 void pkgAcquire::Item::Done(string
const &/*Message*/, HashStringList
const &Hashes
,
536 pkgAcquire::MethodConfig
const * const /*Cnf*/)
538 // We just downloaded something..
541 unsigned long long const downloadedSize
= Hashes
.FileSize();
542 if (downloadedSize
!= 0)
544 FileSize
= downloadedSize
;
548 ErrorText
= string();
549 Owner
->Dequeue(this);
552 // Acquire::Item::Rename - Rename a file /*{{{*/
553 // ---------------------------------------------------------------------
554 /* This helper function is used by a lot of item methods as their final
556 bool pkgAcquire::Item::Rename(string
const &From
,string
const &To
)
558 if (From
== To
|| rename(From
.c_str(),To
.c_str()) == 0)
562 strprintf(S
, _("rename failed, %s (%s -> %s)."), strerror(errno
),
563 From
.c_str(),To
.c_str());
565 if (ErrorText
.empty())
568 ErrorText
= ErrorText
+ ": " + S
;
572 void pkgAcquire::Item::Dequeue() /*{{{*/
574 Owner
->Dequeue(this);
577 bool pkgAcquire::Item::RenameOnError(pkgAcquire::Item::RenameOnErrorState
const error
)/*{{{*/
579 if (RealFileExists(DestFile
))
580 Rename(DestFile
, DestFile
+ ".FAILED");
585 case HashSumMismatch
:
586 errtext
= _("Hash Sum mismatch");
587 Status
= StatAuthError
;
588 ReportMirrorFailure("HashChecksumFailure");
591 errtext
= _("Size mismatch");
592 Status
= StatAuthError
;
593 ReportMirrorFailure("SizeFailure");
596 errtext
= _("Invalid file format");
598 // do not report as usually its not the mirrors fault, but Portal/Proxy
601 errtext
= _("Signature error");
605 strprintf(errtext
, _("Clearsigned file isn't valid, got '%s' (does the network require authentication?)"), "NOSPLIT");
606 Status
= StatAuthError
;
608 case MaximumSizeExceeded
:
609 // the method is expected to report a good error for this
613 // no handling here, done by callers
616 if (ErrorText
.empty())
621 void pkgAcquire::Item::SetActiveSubprocess(const std::string
&subprocess
)/*{{{*/
623 ActiveSubprocess
= subprocess
;
624 APT_IGNORE_DEPRECATED(Mode
= ActiveSubprocess
.c_str();)
627 // Acquire::Item::ReportMirrorFailure /*{{{*/
628 void pkgAcquire::Item::ReportMirrorFailure(string
const &FailCode
)
630 // we only act if a mirror was used at all
631 if(UsedMirror
.empty())
634 std::cerr
<< "\nReportMirrorFailure: "
636 << " Uri: " << DescURI()
638 << FailCode
<< std::endl
;
640 string report
= _config
->Find("Methods::Mirror::ProblemReporting",
641 "/usr/lib/apt/apt-report-mirror-failure");
642 if(!FileExists(report
))
645 std::vector
<char const*> Args
;
646 Args
.push_back(report
.c_str());
647 Args
.push_back(UsedMirror
.c_str());
648 Args
.push_back(DescURI().c_str());
649 Args
.push_back(FailCode
.c_str());
650 Args
.push_back(NULL
);
652 pid_t pid
= ExecFork();
655 _error
->Error("ReportMirrorFailure Fork failed");
660 execvp(Args
[0], (char**)Args
.data());
661 std::cerr
<< "Could not exec " << Args
[0] << std::endl
;
664 if(!ExecWait(pid
, "report-mirror-failure"))
666 _error
->Warning("Couldn't report problem to '%s'",
667 _config
->Find("Methods::Mirror::ProblemReporting").c_str());
671 std::string
pkgAcquire::Item::HashSum() const /*{{{*/
673 HashStringList
const hashes
= GetExpectedHashes();
674 HashString
const * const hs
= hashes
.find(NULL
);
675 return hs
!= NULL
? hs
->toStr() : "";
679 pkgAcqTransactionItem::pkgAcqTransactionItem(pkgAcquire
* const Owner
, /*{{{*/
680 pkgAcqMetaClearSig
* const transactionManager
, IndexTarget
const &target
) :
681 pkgAcquire::Item(Owner
), d(NULL
), Target(target
), TransactionManager(transactionManager
)
683 if (TransactionManager
!= this)
684 TransactionManager
->Add(this);
687 pkgAcqTransactionItem::~pkgAcqTransactionItem() /*{{{*/
691 HashStringList
pkgAcqTransactionItem::GetExpectedHashesFor(std::string
const &MetaKey
) const /*{{{*/
693 return GetExpectedHashesFromFor(TransactionManager
->MetaIndexParser
, MetaKey
);
697 // AcqMetaBase - Constructor /*{{{*/
698 pkgAcqMetaBase::pkgAcqMetaBase(pkgAcquire
* const Owner
,
699 pkgAcqMetaClearSig
* const TransactionManager
,
700 std::vector
<IndexTarget
> const &IndexTargets
,
701 IndexTarget
const &DataTarget
)
702 : pkgAcqTransactionItem(Owner
, TransactionManager
, DataTarget
), d(NULL
),
703 IndexTargets(IndexTargets
),
704 AuthPass(false), IMSHit(false)
708 // AcqMetaBase::Add - Add a item to the current Transaction /*{{{*/
709 void pkgAcqMetaBase::Add(pkgAcqTransactionItem
* const I
)
711 Transaction
.push_back(I
);
714 // AcqMetaBase::AbortTransaction - Abort the current Transaction /*{{{*/
715 void pkgAcqMetaBase::AbortTransaction()
717 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
718 std::clog
<< "AbortTransaction: " << TransactionManager
<< std::endl
;
720 // ensure the toplevel is in error state too
721 for (std::vector
<pkgAcqTransactionItem
*>::iterator I
= Transaction
.begin();
722 I
!= Transaction
.end(); ++I
)
724 (*I
)->TransactionState(TransactionAbort
);
729 // AcqMetaBase::TransactionHasError - Check for errors in Transaction /*{{{*/
730 APT_PURE
bool pkgAcqMetaBase::TransactionHasError() const
732 for (std::vector
<pkgAcqTransactionItem
*>::const_iterator I
= Transaction
.begin();
733 I
!= Transaction
.end(); ++I
)
735 switch((*I
)->Status
) {
736 case StatDone
: break;
737 case StatIdle
: break;
738 case StatAuthError
: return true;
739 case StatError
: return true;
740 case StatTransientNetworkError
: return true;
741 case StatFetching
: break;
747 // AcqMetaBase::CommitTransaction - Commit a transaction /*{{{*/
748 void pkgAcqMetaBase::CommitTransaction()
750 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
751 std::clog
<< "CommitTransaction: " << this << std::endl
;
753 // move new files into place *and* remove files that are not
754 // part of the transaction but are still on disk
755 for (std::vector
<pkgAcqTransactionItem
*>::iterator I
= Transaction
.begin();
756 I
!= Transaction
.end(); ++I
)
758 (*I
)->TransactionState(TransactionCommit
);
763 // AcqMetaBase::TransactionStageCopy - Stage a file for copying /*{{{*/
764 void pkgAcqMetaBase::TransactionStageCopy(pkgAcqTransactionItem
* const I
,
765 const std::string
&From
,
766 const std::string
&To
)
768 I
->PartialFile
= From
;
772 // AcqMetaBase::TransactionStageRemoval - Stage a file for removal /*{{{*/
773 void pkgAcqMetaBase::TransactionStageRemoval(pkgAcqTransactionItem
* const I
,
774 const std::string
&FinalFile
)
777 I
->DestFile
= FinalFile
;
780 // AcqMetaBase::GenerateAuthWarning - Check gpg authentication error /*{{{*/
781 bool pkgAcqMetaBase::CheckStopAuthentication(pkgAcquire::Item
* const I
, const std::string
&Message
)
783 // FIXME: this entire function can do now that we disallow going to
784 // a unauthenticated state and can cleanly rollback
786 string
const Final
= I
->GetFinalFilename();
787 if(FileExists(Final
))
789 I
->Status
= StatTransientNetworkError
;
790 _error
->Warning(_("An error occurred during the signature "
791 "verification. The repository is not updated "
792 "and the previous index files will be used. "
793 "GPG error: %s: %s"),
794 Desc
.Description
.c_str(),
795 LookupTag(Message
,"Message").c_str());
796 RunScripts("APT::Update::Auth-Failure");
798 } else if (LookupTag(Message
,"Message").find("NODATA") != string::npos
) {
799 /* Invalid signature file, reject (LP: #346386) (Closes: #627642) */
800 _error
->Error(_("GPG error: %s: %s"),
801 Desc
.Description
.c_str(),
802 LookupTag(Message
,"Message").c_str());
803 I
->Status
= StatAuthError
;
806 _error
->Warning(_("GPG error: %s: %s"),
807 Desc
.Description
.c_str(),
808 LookupTag(Message
,"Message").c_str());
810 // gpgv method failed
811 ReportMirrorFailure("GPGFailure");
815 // AcqMetaBase::Custom600Headers - Get header for AcqMetaBase /*{{{*/
816 // ---------------------------------------------------------------------
817 string
pkgAcqMetaBase::Custom600Headers() const
819 std::string Header
= "\nIndex-File: true";
820 std::string MaximumSize
;
821 strprintf(MaximumSize
, "\nMaximum-Size: %i",
822 _config
->FindI("Acquire::MaxReleaseFileSize", 10*1000*1000));
823 Header
+= MaximumSize
;
825 string
const FinalFile
= GetFinalFilename();
827 if (stat(FinalFile
.c_str(),&Buf
) == 0)
828 Header
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
833 // AcqMetaBase::QueueForSignatureVerify /*{{{*/
834 void pkgAcqMetaBase::QueueForSignatureVerify(pkgAcqTransactionItem
* const I
, std::string
const &File
, std::string
const &Signature
)
837 I
->Desc
.URI
= "gpgv:" + Signature
;
840 I
->SetActiveSubprocess("gpgv");
843 // AcqMetaBase::CheckDownloadDone /*{{{*/
844 bool pkgAcqMetaBase::CheckDownloadDone(pkgAcqTransactionItem
* const I
, const std::string
&Message
, HashStringList
const &Hashes
) const
846 // We have just finished downloading a Release file (it is not
849 std::string
const FileName
= LookupTag(Message
,"Filename");
850 if (FileName
!= I
->DestFile
&& RealFileExists(I
->DestFile
) == false)
853 I
->Desc
.URI
= "copy:" + FileName
;
854 I
->QueueURI(I
->Desc
);
858 // make sure to verify against the right file on I-M-S hit
859 bool IMSHit
= StringToBool(LookupTag(Message
,"IMS-Hit"), false);
860 if (IMSHit
== false && Hashes
.usable())
862 // detect IMS-Hits servers haven't detected by Hash comparison
863 std::string
const FinalFile
= I
->GetFinalFilename();
864 if (RealFileExists(FinalFile
) && Hashes
.VerifyFile(FinalFile
) == true)
867 unlink(I
->DestFile
.c_str());
873 // for simplicity, the transaction manager is always InRelease
874 // even if it doesn't exist.
875 if (TransactionManager
!= NULL
)
876 TransactionManager
->IMSHit
= true;
877 I
->PartialFile
= I
->DestFile
= I
->GetFinalFilename();
880 // set Item to complete as the remaining work is all local (verify etc)
886 bool pkgAcqMetaBase::CheckAuthDone(string
const &Message
) /*{{{*/
888 // At this point, the gpgv method has succeeded, so there is a
889 // valid signature from a key in the trusted keyring. We
890 // perform additional verification of its contents, and use them
891 // to verify the indexes we are about to download
893 if (TransactionManager
->IMSHit
== false)
895 // open the last (In)Release if we have it
896 std::string
const FinalFile
= GetFinalFilename();
897 std::string FinalRelease
;
898 std::string FinalInRelease
;
899 if (APT::String::Endswith(FinalFile
, "InRelease"))
901 FinalInRelease
= FinalFile
;
902 FinalRelease
= FinalFile
.substr(0, FinalFile
.length() - strlen("InRelease")) + "Release";
906 FinalInRelease
= FinalFile
.substr(0, FinalFile
.length() - strlen("Release")) + "InRelease";
907 FinalRelease
= FinalFile
;
909 if (RealFileExists(FinalInRelease
) || RealFileExists(FinalRelease
))
911 TransactionManager
->LastMetaIndexParser
= TransactionManager
->MetaIndexParser
->UnloadedClone();
912 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
914 _error
->PushToStack();
915 if (RealFileExists(FinalInRelease
))
916 TransactionManager
->LastMetaIndexParser
->Load(FinalInRelease
, NULL
);
918 TransactionManager
->LastMetaIndexParser
->Load(FinalRelease
, NULL
);
919 // its unlikely to happen, but if what we have is bad ignore it
920 if (_error
->PendingError())
922 delete TransactionManager
->LastMetaIndexParser
;
923 TransactionManager
->LastMetaIndexParser
= NULL
;
925 _error
->RevertToStack();
930 if (TransactionManager
->MetaIndexParser
->Load(DestFile
, &ErrorText
) == false)
932 Status
= StatAuthError
;
936 if (!VerifyVendor(Message
))
938 Status
= StatAuthError
;
942 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
943 std::cerr
<< "Signature verification succeeded: "
944 << DestFile
<< std::endl
;
946 // Download further indexes with verification
952 void pkgAcqMetaBase::QueueIndexes(bool const verify
) /*{{{*/
954 // at this point the real Items are loaded in the fetcher
955 ExpectedAdditionalItems
= 0;
957 for (std::vector
<IndexTarget
>::const_iterator Target
= IndexTargets
.begin();
958 Target
!= IndexTargets
.end();
961 bool trypdiff
= _config
->FindB("Acquire::PDiffs", true);
964 if (TransactionManager
->MetaIndexParser
->Exists(Target
->MetaKey
) == false)
966 // optional targets that we do not have in the Release file are skipped
967 if (Target
->IsOptional
)
970 Status
= StatAuthError
;
971 strprintf(ErrorText
, _("Unable to find expected entry '%s' in Release file (Wrong sources.list entry or malformed file)"), Target
->MetaKey
.c_str());
975 if (RealFileExists(GetFinalFileNameFromURI(Target
->URI
)))
977 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
979 HashStringList
const newFile
= GetExpectedHashesFromFor(TransactionManager
->MetaIndexParser
, Target
->MetaKey
);
980 HashStringList
const oldFile
= GetExpectedHashesFromFor(TransactionManager
->LastMetaIndexParser
, Target
->MetaKey
);
981 if (newFile
== oldFile
)
983 // we have the file already, no point in trying to acquire it again
984 new NoActionItem(Owner
, *Target
);
988 else if (TransactionManager
->IMSHit
== true)
990 // we have the file already, no point in trying to acquire it again
991 new NoActionItem(Owner
, *Target
);
996 trypdiff
= false; // no file to patch
998 // check if we have patches available
999 trypdiff
&= TransactionManager
->MetaIndexParser
->Exists(Target
->MetaKey
+ ".diff/Index");
1001 // if we have no file to patch, no point in trying
1002 trypdiff
&= RealFileExists(GetFinalFileNameFromURI(Target
->URI
));
1004 // no point in patching from local sources
1007 std::string
const proto
= Target
->URI
.substr(0, strlen("file:/"));
1008 if (proto
== "file:/" || proto
== "copy:/" || proto
== "cdrom:")
1012 // Queue the Index file (Packages, Sources, Translation-$foo, …)
1014 new pkgAcqDiffIndex(Owner
, TransactionManager
, *Target
);
1016 new pkgAcqIndex(Owner
, TransactionManager
, *Target
);
1020 bool pkgAcqMetaBase::VerifyVendor(string
const &Message
) /*{{{*/
1022 string::size_type pos
;
1024 // check for missing sigs (that where not fatal because otherwise we had
1027 string msg
= _("There is no public key available for the "
1028 "following key IDs:\n");
1029 pos
= Message
.find("NO_PUBKEY ");
1030 if (pos
!= std::string::npos
)
1032 string::size_type start
= pos
+strlen("NO_PUBKEY ");
1033 string Fingerprint
= Message
.substr(start
, Message
.find("\n")-start
);
1034 missingkeys
+= (Fingerprint
);
1036 if(!missingkeys
.empty())
1037 _error
->Warning("%s", (msg
+ missingkeys
).c_str());
1039 string Transformed
= TransactionManager
->MetaIndexParser
->GetExpectedDist();
1041 if (Transformed
== "../project/experimental")
1043 Transformed
= "experimental";
1046 pos
= Transformed
.rfind('/');
1047 if (pos
!= string::npos
)
1049 Transformed
= Transformed
.substr(0, pos
);
1052 if (Transformed
== ".")
1057 if (TransactionManager
->MetaIndexParser
->GetValidUntil() > 0)
1059 time_t const invalid_since
= time(NULL
) - TransactionManager
->MetaIndexParser
->GetValidUntil();
1060 if (invalid_since
> 0)
1064 // TRANSLATOR: The first %s is the URL of the bad Release file, the second is
1065 // the time since then the file is invalid - formatted in the same way as in
1066 // the download progress display (e.g. 7d 3h 42min 1s)
1067 _("Release file for %s is expired (invalid since %s). "
1068 "Updates for this repository will not be applied."),
1069 Target
.URI
.c_str(), TimeToStr(invalid_since
).c_str());
1070 if (ErrorText
.empty())
1072 return _error
->Error("%s", errmsg
.c_str());
1076 /* Did we get a file older than what we have? This is a last minute IMS hit and doubles
1077 as a prevention of downgrading us to older (still valid) files */
1078 if (TransactionManager
->IMSHit
== false && TransactionManager
->LastMetaIndexParser
!= NULL
&&
1079 TransactionManager
->LastMetaIndexParser
->GetDate() > TransactionManager
->MetaIndexParser
->GetDate())
1081 TransactionManager
->IMSHit
= true;
1082 unlink(DestFile
.c_str());
1083 PartialFile
= DestFile
= GetFinalFilename();
1084 // load the 'old' file in the 'new' one instead of flipping pointers as
1085 // the new one isn't owned by us, while the old one is so cleanup would be confused.
1086 TransactionManager
->MetaIndexParser
->swapLoad(TransactionManager
->LastMetaIndexParser
);
1087 delete TransactionManager
->LastMetaIndexParser
;
1088 TransactionManager
->LastMetaIndexParser
= NULL
;
1091 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1093 std::cerr
<< "Got Codename: " << TransactionManager
->MetaIndexParser
->GetCodename() << std::endl
;
1094 std::cerr
<< "Expecting Dist: " << TransactionManager
->MetaIndexParser
->GetExpectedDist() << std::endl
;
1095 std::cerr
<< "Transformed Dist: " << Transformed
<< std::endl
;
1098 if (TransactionManager
->MetaIndexParser
->CheckDist(Transformed
) == false)
1100 // This might become fatal one day
1101 // Status = StatAuthError;
1102 // ErrorText = "Conflicting distribution; expected "
1103 // + MetaIndexParser->GetExpectedDist() + " but got "
1104 // + MetaIndexParser->GetCodename();
1106 if (!Transformed
.empty())
1108 _error
->Warning(_("Conflicting distribution: %s (expected %s but got %s)"),
1109 Desc
.Description
.c_str(),
1110 Transformed
.c_str(),
1111 TransactionManager
->MetaIndexParser
->GetCodename().c_str());
1118 pkgAcqMetaBase::~pkgAcqMetaBase()
1122 pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire
* const Owner
, /*{{{*/
1123 IndexTarget
const &ClearsignedTarget
,
1124 IndexTarget
const &DetachedDataTarget
, IndexTarget
const &DetachedSigTarget
,
1125 std::vector
<IndexTarget
> const &IndexTargets
,
1126 metaIndex
* const MetaIndexParser
) :
1127 pkgAcqMetaIndex(Owner
, this, ClearsignedTarget
, DetachedSigTarget
, IndexTargets
),
1128 d(NULL
), ClearsignedTarget(ClearsignedTarget
),
1129 DetachedDataTarget(DetachedDataTarget
),
1130 MetaIndexParser(MetaIndexParser
), LastMetaIndexParser(NULL
)
1132 // index targets + (worst case:) Release/Release.gpg
1133 ExpectedAdditionalItems
= IndexTargets
.size() + 2;
1134 TransactionManager
->Add(this);
1137 pkgAcqMetaClearSig::~pkgAcqMetaClearSig() /*{{{*/
1139 if (LastMetaIndexParser
!= NULL
)
1140 delete LastMetaIndexParser
;
1143 // pkgAcqMetaClearSig::Custom600Headers - Insert custom request headers /*{{{*/
1144 string
pkgAcqMetaClearSig::Custom600Headers() const
1146 string Header
= pkgAcqMetaBase::Custom600Headers();
1147 Header
+= "\nFail-Ignore: true";
1148 std::string
const key
= TransactionManager
->MetaIndexParser
->GetSignedBy();
1149 if (key
.empty() == false)
1150 Header
+= "\nSigned-By: " + key
;
1155 bool pkgAcqMetaClearSig::VerifyDone(std::string
const &Message
,
1156 pkgAcquire::MethodConfig
const * const Cnf
)
1158 Item::VerifyDone(Message
, Cnf
);
1160 if (FileExists(DestFile
) && !StartsWithGPGClearTextSignature(DestFile
))
1161 return RenameOnError(NotClearsigned
);
1165 // pkgAcqMetaClearSig::Done - We got a file /*{{{*/
1166 void pkgAcqMetaClearSig::Done(std::string
const &Message
,
1167 HashStringList
const &Hashes
,
1168 pkgAcquire::MethodConfig
const * const Cnf
)
1170 Item::Done(Message
, Hashes
, Cnf
);
1172 if(AuthPass
== false)
1174 if(CheckDownloadDone(this, Message
, Hashes
) == true)
1175 QueueForSignatureVerify(this, DestFile
, DestFile
);
1178 else if(CheckAuthDone(Message
) == true)
1180 if (TransactionManager
->IMSHit
== false)
1181 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
1182 else if (RealFileExists(GetFinalFilename()) == false)
1184 // We got an InRelease file IMSHit, but we haven't one, which means
1185 // we had a valid Release/Release.gpg combo stepping in, which we have
1186 // to 'acquire' now to ensure list cleanup isn't removing them
1187 new NoActionItem(Owner
, DetachedDataTarget
);
1188 new NoActionItem(Owner
, DetachedSigTarget
);
1193 void pkgAcqMetaClearSig::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
) /*{{{*/
1195 Item::Failed(Message
, Cnf
);
1197 // we failed, we will not get additional items from this method
1198 ExpectedAdditionalItems
= 0;
1200 if (AuthPass
== false)
1202 if (Status
== StatAuthError
)
1204 // if we expected a ClearTextSignature (InRelease) and got a file,
1205 // but it wasn't valid we end up here (see VerifyDone).
1206 // As these is usually called by web-portals we do not try Release/Release.gpg
1207 // as this is gonna fail anyway and instead abort our try (LP#346386)
1208 TransactionManager
->AbortTransaction();
1212 // Queue the 'old' InRelease file for removal if we try Release.gpg
1213 // as otherwise the file will stay around and gives a false-auth
1214 // impression (CVE-2012-0214)
1215 TransactionManager
->TransactionStageRemoval(this, GetFinalFilename());
1218 new pkgAcqMetaIndex(Owner
, TransactionManager
, DetachedDataTarget
, DetachedSigTarget
, IndexTargets
);
1222 if(CheckStopAuthentication(this, Message
))
1225 _error
->Warning(_("The data from '%s' is not signed. Packages "
1226 "from that repository can not be authenticated."),
1227 ClearsignedTarget
.Description
.c_str());
1229 // No Release file was present, or verification failed, so fall
1230 // back to queueing Packages files without verification
1231 // only allow going further if the users explicitely wants it
1232 if(AllowInsecureRepositories(TransactionManager
->MetaIndexParser
, TransactionManager
, this) == true)
1236 /* InRelease files become Release files, otherwise
1237 * they would be considered as trusted later on */
1238 string
const FinalRelease
= GetFinalFileNameFromURI(DetachedDataTarget
.URI
);
1239 string
const PartialRelease
= GetPartialFileNameFromURI(DetachedDataTarget
.URI
);
1240 string
const FinalReleasegpg
= GetFinalFileNameFromURI(DetachedSigTarget
.URI
);
1241 string
const FinalInRelease
= GetFinalFilename();
1242 Rename(DestFile
, PartialRelease
);
1243 TransactionManager
->TransactionStageCopy(this, PartialRelease
, FinalRelease
);
1245 if (RealFileExists(FinalReleasegpg
) || RealFileExists(FinalInRelease
))
1247 // open the last Release if we have it
1248 if (TransactionManager
->IMSHit
== false)
1250 TransactionManager
->LastMetaIndexParser
= TransactionManager
->MetaIndexParser
->UnloadedClone();
1251 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1253 _error
->PushToStack();
1254 if (RealFileExists(FinalInRelease
))
1255 TransactionManager
->LastMetaIndexParser
->Load(FinalInRelease
, NULL
);
1257 TransactionManager
->LastMetaIndexParser
->Load(FinalRelease
, NULL
);
1258 // its unlikely to happen, but if what we have is bad ignore it
1259 if (_error
->PendingError())
1261 delete TransactionManager
->LastMetaIndexParser
;
1262 TransactionManager
->LastMetaIndexParser
= NULL
;
1264 _error
->RevertToStack();
1269 // we parse the indexes here because at this point the user wanted
1270 // a repository that may potentially harm him
1271 if (TransactionManager
->MetaIndexParser
->Load(PartialRelease
, &ErrorText
) == false || VerifyVendor(Message
) == false)
1272 /* expired Release files are still a problem you need extra force for */;
1280 pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire
* const Owner
, /*{{{*/
1281 pkgAcqMetaClearSig
* const TransactionManager
,
1282 IndexTarget
const &DataTarget
,
1283 IndexTarget
const &DetachedSigTarget
,
1284 vector
<IndexTarget
> const &IndexTargets
) :
1285 pkgAcqMetaBase(Owner
, TransactionManager
, IndexTargets
, DataTarget
), d(NULL
),
1286 DetachedSigTarget(DetachedSigTarget
)
1288 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1289 std::clog
<< "New pkgAcqMetaIndex with TransactionManager "
1290 << this->TransactionManager
<< std::endl
;
1292 DestFile
= GetPartialFileNameFromURI(DataTarget
.URI
);
1295 Desc
.Description
= DataTarget
.Description
;
1297 Desc
.ShortDesc
= DataTarget
.ShortDesc
;
1298 Desc
.URI
= DataTarget
.URI
;
1300 // we expect more item
1301 ExpectedAdditionalItems
= IndexTargets
.size();
1305 void pkgAcqMetaIndex::Done(string
const &Message
, /*{{{*/
1306 HashStringList
const &Hashes
,
1307 pkgAcquire::MethodConfig
const * const Cfg
)
1309 Item::Done(Message
,Hashes
,Cfg
);
1311 if(CheckDownloadDone(this, Message
, Hashes
))
1313 // we have a Release file, now download the Signature, all further
1314 // verify/queue for additional downloads will be done in the
1315 // pkgAcqMetaSig::Done() code
1316 new pkgAcqMetaSig(Owner
, TransactionManager
, DetachedSigTarget
, this);
1320 // pkgAcqMetaIndex::Failed - no Release file present /*{{{*/
1321 void pkgAcqMetaIndex::Failed(string
const &Message
,
1322 pkgAcquire::MethodConfig
const * const Cnf
)
1324 pkgAcquire::Item::Failed(Message
, Cnf
);
1327 _error
->Warning(_("The repository '%s' does not have a Release file. "
1328 "This is deprecated, please contact the owner of the "
1329 "repository."), Target
.Description
.c_str());
1331 // No Release file was present so fall
1332 // back to queueing Packages files without verification
1333 // only allow going further if the users explicitely wants it
1334 if(AllowInsecureRepositories(TransactionManager
->MetaIndexParser
, TransactionManager
, this) == true)
1336 // ensure old Release files are removed
1337 TransactionManager
->TransactionStageRemoval(this, GetFinalFilename());
1339 // queue without any kind of hashsum support
1340 QueueIndexes(false);
1344 void pkgAcqMetaIndex::Finished() /*{{{*/
1346 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1347 std::clog
<< "Finished: " << DestFile
<<std::endl
;
1348 if(TransactionManager
!= NULL
&&
1349 TransactionManager
->TransactionHasError() == false)
1350 TransactionManager
->CommitTransaction();
1353 std::string
pkgAcqMetaIndex::DescURI() const /*{{{*/
1358 pkgAcqMetaIndex::~pkgAcqMetaIndex() {}
1360 // AcqMetaSig::AcqMetaSig - Constructor /*{{{*/
1361 pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire
* const Owner
,
1362 pkgAcqMetaClearSig
* const TransactionManager
,
1363 IndexTarget
const &Target
,
1364 pkgAcqMetaIndex
* const MetaIndex
) :
1365 pkgAcqTransactionItem(Owner
, TransactionManager
, Target
), d(NULL
), MetaIndex(MetaIndex
)
1367 DestFile
= GetPartialFileNameFromURI(Target
.URI
);
1369 // remove any partial downloaded sig-file in partial/.
1370 // it may confuse proxies and is too small to warrant a
1371 // partial download anyway
1372 unlink(DestFile
.c_str());
1374 // set the TransactionManager
1375 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1376 std::clog
<< "New pkgAcqMetaSig with TransactionManager "
1377 << TransactionManager
<< std::endl
;
1380 Desc
.Description
= Target
.Description
;
1382 Desc
.ShortDesc
= Target
.ShortDesc
;
1383 Desc
.URI
= Target
.URI
;
1385 // If we got a hit for Release, we will get one for Release.gpg too (or obscure errors),
1386 // so we skip the download step and go instantly to verification
1387 if (TransactionManager
->IMSHit
== true && RealFileExists(GetFinalFilename()))
1391 PartialFile
= DestFile
= GetFinalFilename();
1392 MetaIndexFileSignature
= DestFile
;
1393 MetaIndex
->QueueForSignatureVerify(this, MetaIndex
->DestFile
, DestFile
);
1399 pkgAcqMetaSig::~pkgAcqMetaSig() /*{{{*/
1403 // pkgAcqMetaSig::Custom600Headers - Insert custom request headers /*{{{*/
1404 std::string
pkgAcqMetaSig::Custom600Headers() const
1406 std::string Header
= pkgAcqTransactionItem::Custom600Headers();
1407 std::string
const key
= TransactionManager
->MetaIndexParser
->GetSignedBy();
1408 if (key
.empty() == false)
1409 Header
+= "\nSigned-By: " + key
;
1413 // AcqMetaSig::Done - The signature was downloaded/verified /*{{{*/
1414 void pkgAcqMetaSig::Done(string
const &Message
, HashStringList
const &Hashes
,
1415 pkgAcquire::MethodConfig
const * const Cfg
)
1417 if (MetaIndexFileSignature
.empty() == false)
1419 DestFile
= MetaIndexFileSignature
;
1420 MetaIndexFileSignature
.clear();
1422 Item::Done(Message
, Hashes
, Cfg
);
1424 if(MetaIndex
->AuthPass
== false)
1426 if(MetaIndex
->CheckDownloadDone(this, Message
, Hashes
) == true)
1428 // destfile will be modified to point to MetaIndexFile for the
1429 // gpgv method, so we need to save it here
1430 MetaIndexFileSignature
= DestFile
;
1431 MetaIndex
->QueueForSignatureVerify(this, MetaIndex
->DestFile
, DestFile
);
1435 else if(MetaIndex
->CheckAuthDone(Message
) == true)
1437 if (TransactionManager
->IMSHit
== false)
1439 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
1440 TransactionManager
->TransactionStageCopy(MetaIndex
, MetaIndex
->DestFile
, MetaIndex
->GetFinalFilename());
1445 void pkgAcqMetaSig::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
1447 Item::Failed(Message
,Cnf
);
1449 // check if we need to fail at this point
1450 if (MetaIndex
->AuthPass
== true && MetaIndex
->CheckStopAuthentication(this, Message
))
1453 string
const FinalRelease
= MetaIndex
->GetFinalFilename();
1454 string
const FinalReleasegpg
= GetFinalFilename();
1455 string
const FinalInRelease
= TransactionManager
->GetFinalFilename();
1457 if (RealFileExists(FinalReleasegpg
) || RealFileExists(FinalInRelease
))
1459 std::string downgrade_msg
;
1460 strprintf(downgrade_msg
, _("The repository '%s' is no longer signed."),
1461 MetaIndex
->Target
.Description
.c_str());
1462 if(_config
->FindB("Acquire::AllowDowngradeToInsecureRepositories"))
1464 // meh, the users wants to take risks (we still mark the packages
1465 // from this repository as unauthenticated)
1466 _error
->Warning("%s", downgrade_msg
.c_str());
1467 _error
->Warning(_("This is normally not allowed, but the option "
1468 "Acquire::AllowDowngradeToInsecureRepositories was "
1469 "given to override it."));
1472 _error
->Error("%s", downgrade_msg
.c_str());
1473 if (TransactionManager
->IMSHit
== false)
1474 Rename(MetaIndex
->DestFile
, MetaIndex
->DestFile
+ ".FAILED");
1475 Item::Failed("Message: " + downgrade_msg
, Cnf
);
1476 TransactionManager
->AbortTransaction();
1481 _error
->Warning(_("The data from '%s' is not signed. Packages "
1482 "from that repository can not be authenticated."),
1483 MetaIndex
->Target
.Description
.c_str());
1485 // ensures that a Release.gpg file in the lists/ is removed by the transaction
1486 TransactionManager
->TransactionStageRemoval(this, DestFile
);
1488 // only allow going further if the users explicitely wants it
1489 if(AllowInsecureRepositories(TransactionManager
->MetaIndexParser
, TransactionManager
, this) == true)
1491 if (RealFileExists(FinalReleasegpg
) || RealFileExists(FinalInRelease
))
1493 // open the last Release if we have it
1494 if (TransactionManager
->IMSHit
== false)
1496 TransactionManager
->LastMetaIndexParser
= TransactionManager
->MetaIndexParser
->UnloadedClone();
1497 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1499 _error
->PushToStack();
1500 if (RealFileExists(FinalInRelease
))
1501 TransactionManager
->LastMetaIndexParser
->Load(FinalInRelease
, NULL
);
1503 TransactionManager
->LastMetaIndexParser
->Load(FinalRelease
, NULL
);
1504 // its unlikely to happen, but if what we have is bad ignore it
1505 if (_error
->PendingError())
1507 delete TransactionManager
->LastMetaIndexParser
;
1508 TransactionManager
->LastMetaIndexParser
= NULL
;
1510 _error
->RevertToStack();
1515 // we parse the indexes here because at this point the user wanted
1516 // a repository that may potentially harm him
1517 if (TransactionManager
->MetaIndexParser
->Load(MetaIndex
->DestFile
, &ErrorText
) == false || MetaIndex
->VerifyVendor(Message
) == false)
1518 /* expired Release files are still a problem you need extra force for */;
1520 MetaIndex
->QueueIndexes(true);
1522 TransactionManager
->TransactionStageCopy(MetaIndex
, MetaIndex
->DestFile
, MetaIndex
->GetFinalFilename());
1525 // FIXME: this is used often (e.g. in pkgAcqIndexTrans) so refactor
1526 if (Cnf
->LocalOnly
== true ||
1527 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1536 // AcqBaseIndex - Constructor /*{{{*/
1537 pkgAcqBaseIndex::pkgAcqBaseIndex(pkgAcquire
* const Owner
,
1538 pkgAcqMetaClearSig
* const TransactionManager
,
1539 IndexTarget
const &Target
)
1540 : pkgAcqTransactionItem(Owner
, TransactionManager
, Target
), d(NULL
)
1544 pkgAcqBaseIndex::~pkgAcqBaseIndex() {}
1546 // AcqDiffIndex::AcqDiffIndex - Constructor /*{{{*/
1547 // ---------------------------------------------------------------------
1548 /* Get the DiffIndex file first and see if there are patches available
1549 * If so, create a pkgAcqIndexDiffs fetcher that will get and apply the
1550 * patches. If anything goes wrong in that process, it will fall back to
1551 * the original packages file
1553 pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire
* const Owner
,
1554 pkgAcqMetaClearSig
* const TransactionManager
,
1555 IndexTarget
const &Target
)
1556 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
), diffs(NULL
)
1558 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
1561 Desc
.Description
= Target
.Description
+ ".diff/Index";
1562 Desc
.ShortDesc
= Target
.ShortDesc
;
1563 Desc
.URI
= Target
.URI
+ ".diff/Index";
1565 DestFile
= GetPartialFileNameFromURI(Desc
.URI
);
1568 std::clog
<< "pkgAcqDiffIndex: " << Desc
.URI
<< std::endl
;
1573 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
1574 // ---------------------------------------------------------------------
1575 /* The only header we use is the last-modified header. */
1576 string
pkgAcqDiffIndex::Custom600Headers() const
1578 string
const Final
= GetFinalFilename();
1581 std::clog
<< "Custom600Header-IMS: " << Final
<< std::endl
;
1584 if (stat(Final
.c_str(),&Buf
) != 0)
1585 return "\nIndex-File: true";
1587 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1590 void pkgAcqDiffIndex::QueueOnIMSHit() const /*{{{*/
1592 // list cleanup needs to know that this file as well as the already
1593 // present index is ours, so we create an empty diff to save it for us
1594 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
);
1597 bool pkgAcqDiffIndex::ParseDiffIndex(string
const &IndexDiffFile
) /*{{{*/
1599 // failing here is fine: our caller will take care of trying to
1600 // get the complete file if patching fails
1602 std::clog
<< "pkgAcqDiffIndex::ParseIndexDiff() " << IndexDiffFile
1605 FileFd
Fd(IndexDiffFile
,FileFd::ReadOnly
);
1607 if (_error
->PendingError() == true)
1611 if(unlikely(TF
.Step(Tags
) == false))
1614 HashStringList ServerHashes
;
1615 unsigned long long ServerSize
= 0;
1617 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
1619 std::string tagname
= *type
;
1620 tagname
.append("-Current");
1621 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1622 if (tmp
.empty() == true)
1626 unsigned long long size
;
1627 std::stringstream
ss(tmp
);
1629 if (unlikely(hash
.empty() == true))
1631 if (unlikely(ServerSize
!= 0 && ServerSize
!= size
))
1633 ServerHashes
.push_back(HashString(*type
, hash
));
1637 if (ServerHashes
.usable() == false)
1640 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": Did not find a good hashsum in the index" << std::endl
;
1644 std::string
const CurrentPackagesFile
= GetFinalFileNameFromURI(Target
.URI
);
1645 HashStringList
const TargetFileHashes
= GetExpectedHashesFor(Target
.MetaKey
);
1646 if (TargetFileHashes
.usable() == false || ServerHashes
!= TargetFileHashes
)
1650 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": Index has different hashes than parser, probably older, so fail pdiffing" << std::endl
;
1651 printHashSumComparision(CurrentPackagesFile
, ServerHashes
, TargetFileHashes
);
1656 HashStringList LocalHashes
;
1657 // try avoiding calculating the hash here as this is costly
1658 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1659 LocalHashes
= GetExpectedHashesFromFor(TransactionManager
->LastMetaIndexParser
, Target
.MetaKey
);
1660 if (LocalHashes
.usable() == false)
1662 FileFd
fd(CurrentPackagesFile
, FileFd::ReadOnly
);
1663 Hashes
LocalHashesCalc(ServerHashes
);
1664 LocalHashesCalc
.AddFD(fd
);
1665 LocalHashes
= LocalHashesCalc
.GetHashStringList();
1668 if (ServerHashes
== LocalHashes
)
1670 // we have the same sha1 as the server so we are done here
1672 std::clog
<< "pkgAcqDiffIndex: Package file " << CurrentPackagesFile
<< " is up-to-date" << std::endl
;
1678 std::clog
<< "Server-Current: " << ServerHashes
.find(NULL
)->toStr() << " and we start at "
1679 << CurrentPackagesFile
<< " " << LocalHashes
.FileSize() << " " << LocalHashes
.find(NULL
)->toStr() << std::endl
;
1681 // parse all of (provided) history
1682 vector
<DiffInfo
> available_patches
;
1683 bool firstAcceptedHashes
= true;
1684 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
1686 if (LocalHashes
.find(*type
) == NULL
)
1689 std::string tagname
= *type
;
1690 tagname
.append("-History");
1691 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1692 if (tmp
.empty() == true)
1695 string hash
, filename
;
1696 unsigned long long size
;
1697 std::stringstream
ss(tmp
);
1699 while (ss
>> hash
>> size
>> filename
)
1701 if (unlikely(hash
.empty() == true || filename
.empty() == true))
1704 // see if we have a record for this file already
1705 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
1706 for (; cur
!= available_patches
.end(); ++cur
)
1708 if (cur
->file
!= filename
)
1710 cur
->result_hashes
.push_back(HashString(*type
, hash
));
1713 if (cur
!= available_patches
.end())
1715 if (firstAcceptedHashes
== true)
1718 next
.file
= filename
;
1719 next
.result_hashes
.push_back(HashString(*type
, hash
));
1720 next
.result_hashes
.FileSize(size
);
1721 available_patches
.push_back(next
);
1726 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
1727 << " wasn't in the list for the first parsed hash! (history)" << std::endl
;
1731 firstAcceptedHashes
= false;
1734 if (unlikely(available_patches
.empty() == true))
1737 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": "
1738 << "Couldn't find any patches for the patch series." << std::endl
;
1742 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
1744 if (LocalHashes
.find(*type
) == NULL
)
1747 std::string tagname
= *type
;
1748 tagname
.append("-Patches");
1749 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1750 if (tmp
.empty() == true)
1753 string hash
, filename
;
1754 unsigned long long size
;
1755 std::stringstream
ss(tmp
);
1757 while (ss
>> hash
>> size
>> filename
)
1759 if (unlikely(hash
.empty() == true || filename
.empty() == true))
1762 // see if we have a record for this file already
1763 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
1764 for (; cur
!= available_patches
.end(); ++cur
)
1766 if (cur
->file
!= filename
)
1768 if (cur
->patch_hashes
.empty())
1769 cur
->patch_hashes
.FileSize(size
);
1770 cur
->patch_hashes
.push_back(HashString(*type
, hash
));
1773 if (cur
!= available_patches
.end())
1776 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
1777 << " wasn't in the list for the first parsed hash! (patches)" << std::endl
;
1782 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
1784 std::string tagname
= *type
;
1785 tagname
.append("-Download");
1786 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1787 if (tmp
.empty() == true)
1790 string hash
, filename
;
1791 unsigned long long size
;
1792 std::stringstream
ss(tmp
);
1794 // FIXME: all of pdiff supports only .gz compressed patches
1795 while (ss
>> hash
>> size
>> filename
)
1797 if (unlikely(hash
.empty() == true || filename
.empty() == true))
1799 if (unlikely(APT::String::Endswith(filename
, ".gz") == false))
1801 filename
.erase(filename
.length() - 3);
1803 // see if we have a record for this file already
1804 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
1805 for (; cur
!= available_patches
.end(); ++cur
)
1807 if (cur
->file
!= filename
)
1809 if (cur
->download_hashes
.empty())
1810 cur
->download_hashes
.FileSize(size
);
1811 cur
->download_hashes
.push_back(HashString(*type
, hash
));
1814 if (cur
!= available_patches
.end())
1817 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
1818 << " wasn't in the list for the first parsed hash! (download)" << std::endl
;
1824 bool foundStart
= false;
1825 for (std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
1826 cur
!= available_patches
.end(); ++cur
)
1828 if (LocalHashes
!= cur
->result_hashes
)
1831 available_patches
.erase(available_patches
.begin(), cur
);
1836 if (foundStart
== false || unlikely(available_patches
.empty() == true))
1839 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": "
1840 << "Couldn't find the start of the patch series." << std::endl
;
1844 // patching with too many files is rather slow compared to a fast download
1845 unsigned long const fileLimit
= _config
->FindI("Acquire::PDiffs::FileLimit", 0);
1846 if (fileLimit
!= 0 && fileLimit
< available_patches
.size())
1849 std::clog
<< "Need " << available_patches
.size() << " diffs (Limit is " << fileLimit
1850 << ") so fallback to complete download" << std::endl
;
1854 // calculate the size of all patches we have to get
1855 // note that all sizes are uncompressed, while we download compressed files
1856 unsigned long long patchesSize
= 0;
1857 for (std::vector
<DiffInfo
>::const_iterator cur
= available_patches
.begin();
1858 cur
!= available_patches
.end(); ++cur
)
1859 patchesSize
+= cur
->patch_hashes
.FileSize();
1860 unsigned long long const sizeLimit
= ServerSize
* _config
->FindI("Acquire::PDiffs::SizeLimit", 100);
1861 if (sizeLimit
> 0 && (sizeLimit
/100) < patchesSize
)
1864 std::clog
<< "Need " << patchesSize
<< " bytes (Limit is " << sizeLimit
/100
1865 << ") so fallback to complete download" << std::endl
;
1869 // we have something, queue the diffs
1870 string::size_type
const last_space
= Description
.rfind(" ");
1871 if(last_space
!= string::npos
)
1872 Description
.erase(last_space
, Description
.size()-last_space
);
1874 /* decide if we should download patches one by one or in one go:
1875 The first is good if the server merges patches, but many don't so client
1876 based merging can be attempt in which case the second is better.
1877 "bad things" will happen if patches are merged on the server,
1878 but client side merging is attempt as well */
1879 bool pdiff_merge
= _config
->FindB("Acquire::PDiffs::Merge", true);
1880 if (pdiff_merge
== true)
1882 // reprepro adds this flag if it has merged patches on the server
1883 std::string
const precedence
= Tags
.FindS("X-Patch-Precedence");
1884 pdiff_merge
= (precedence
!= "merged");
1887 if (pdiff_merge
== false)
1888 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
, available_patches
);
1891 diffs
= new std::vector
<pkgAcqIndexMergeDiffs
*>(available_patches
.size());
1892 for(size_t i
= 0; i
< available_patches
.size(); ++i
)
1893 (*diffs
)[i
] = new pkgAcqIndexMergeDiffs(Owner
, TransactionManager
,
1895 available_patches
[i
],
1905 void pkgAcqDiffIndex::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
1907 Item::Failed(Message
,Cnf
);
1911 std::clog
<< "pkgAcqDiffIndex failed: " << Desc
.URI
<< " with " << Message
<< std::endl
1912 << "Falling back to normal index file acquire" << std::endl
;
1914 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
1917 void pkgAcqDiffIndex::Done(string
const &Message
,HashStringList
const &Hashes
, /*{{{*/
1918 pkgAcquire::MethodConfig
const * const Cnf
)
1921 std::clog
<< "pkgAcqDiffIndex::Done(): " << Desc
.URI
<< std::endl
;
1923 Item::Done(Message
, Hashes
, Cnf
);
1925 string
const FinalFile
= GetFinalFilename();
1926 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false))
1927 DestFile
= FinalFile
;
1929 if(ParseDiffIndex(DestFile
) == false)
1931 Failed("Message: Couldn't parse pdiff index", Cnf
);
1932 // queue for final move - this should happen even if we fail
1933 // while parsing (e.g. on sizelimit) and download the complete file.
1934 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
1938 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
1947 pkgAcqDiffIndex::~pkgAcqDiffIndex()
1953 // AcqIndexDiffs::AcqIndexDiffs - Constructor /*{{{*/
1954 // ---------------------------------------------------------------------
1955 /* The package diff is added to the queue. one object is constructed
1956 * for each diff and the index
1958 pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire
* const Owner
,
1959 pkgAcqMetaClearSig
* const TransactionManager
,
1960 IndexTarget
const &Target
,
1961 vector
<DiffInfo
> const &diffs
)
1962 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
),
1963 available_patches(diffs
)
1965 DestFile
= GetPartialFileNameFromURI(Target
.URI
);
1967 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
1970 Description
= Target
.Description
;
1971 Desc
.ShortDesc
= Target
.ShortDesc
;
1973 if(available_patches
.empty() == true)
1975 // we are done (yeah!), check hashes against the final file
1976 DestFile
= GetFinalFileNameFromURI(Target
.URI
);
1981 // patching needs to be bootstrapped with the 'old' version
1982 std::string
const PartialFile
= GetPartialFileNameFromURI(Target
.URI
);
1983 if (RealFileExists(PartialFile
) == false)
1985 if (symlink(GetFinalFilename().c_str(), PartialFile
.c_str()) != 0)
1987 Failed("Link creation of " + PartialFile
+ " to " + GetFinalFilename() + " failed", NULL
);
1992 // get the next diff
1993 State
= StateFetchDiff
;
1998 void pkgAcqIndexDiffs::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
2000 Item::Failed(Message
,Cnf
);
2004 std::clog
<< "pkgAcqIndexDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
2005 << "Falling back to normal index file acquire" << std::endl
;
2006 DestFile
= GetPartialFileNameFromURI(Target
.URI
);
2007 RenameOnError(PDiffError
);
2008 std::string
const patchname
= GetDiffsPatchFileName(DestFile
);
2009 if (RealFileExists(patchname
))
2010 rename(patchname
.c_str(), std::string(patchname
+ ".FAILED").c_str());
2011 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
2015 // Finish - helper that cleans the item out of the fetcher queue /*{{{*/
2016 void pkgAcqIndexDiffs::Finish(bool allDone
)
2019 std::clog
<< "pkgAcqIndexDiffs::Finish(): "
2021 << Desc
.URI
<< std::endl
;
2023 // we restore the original name, this is required, otherwise
2024 // the file will be cleaned
2027 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
2029 // this is for the "real" finish
2034 std::clog
<< "\n\nallDone: " << DestFile
<< "\n" << std::endl
;
2039 std::clog
<< "Finishing: " << Desc
.URI
<< std::endl
;
2046 bool pkgAcqIndexDiffs::QueueNextDiff() /*{{{*/
2048 // calc sha1 of the just patched file
2049 std::string
const FinalFile
= GetPartialFileNameFromURI(Target
.URI
);
2051 if(!FileExists(FinalFile
))
2053 Failed("Message: No FinalFile " + FinalFile
+ " available", NULL
);
2057 FileFd
fd(FinalFile
, FileFd::ReadOnly
);
2058 Hashes LocalHashesCalc
;
2059 LocalHashesCalc
.AddFD(fd
);
2060 HashStringList
const LocalHashes
= LocalHashesCalc
.GetHashStringList();
2063 std::clog
<< "QueueNextDiff: " << FinalFile
<< " (" << LocalHashes
.find(NULL
)->toStr() << ")" << std::endl
;
2065 HashStringList
const TargetFileHashes
= GetExpectedHashesFor(Target
.MetaKey
);
2066 if (unlikely(LocalHashes
.usable() == false || TargetFileHashes
.usable() == false))
2068 Failed("Local/Expected hashes are not usable", NULL
);
2073 // final file reached before all patches are applied
2074 if(LocalHashes
== TargetFileHashes
)
2080 // remove all patches until the next matching patch is found
2081 // this requires the Index file to be ordered
2082 for(vector
<DiffInfo
>::iterator I
= available_patches
.begin();
2083 available_patches
.empty() == false &&
2084 I
!= available_patches
.end() &&
2085 I
->result_hashes
!= LocalHashes
;
2088 available_patches
.erase(I
);
2091 // error checking and falling back if no patch was found
2092 if(available_patches
.empty() == true)
2094 Failed("No patches left to reach target", NULL
);
2098 // queue the right diff
2099 Desc
.URI
= Target
.URI
+ ".diff/" + available_patches
[0].file
+ ".gz";
2100 Desc
.Description
= Description
+ " " + available_patches
[0].file
+ string(".pdiff");
2101 DestFile
= GetPartialFileNameFromURI(Target
.URI
+ ".diff/" + available_patches
[0].file
);
2104 std::clog
<< "pkgAcqIndexDiffs::QueueNextDiff(): " << Desc
.URI
<< std::endl
;
2111 void pkgAcqIndexDiffs::Done(string
const &Message
, HashStringList
const &Hashes
, /*{{{*/
2112 pkgAcquire::MethodConfig
const * const Cnf
)
2115 std::clog
<< "pkgAcqIndexDiffs::Done(): " << Desc
.URI
<< std::endl
;
2117 Item::Done(Message
, Hashes
, Cnf
);
2119 std::string
const FinalFile
= GetPartialFileNameFromURI(Target
.URI
);
2120 std::string
const PatchFile
= GetDiffsPatchFileName(FinalFile
);
2122 // success in downloading a diff, enter ApplyDiff state
2123 if(State
== StateFetchDiff
)
2125 Rename(DestFile
, PatchFile
);
2128 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
2130 State
= StateApplyDiff
;
2132 Desc
.URI
= "rred:" + FinalFile
;
2134 SetActiveSubprocess("rred");
2138 // success in download/apply a diff, queue next (if needed)
2139 if(State
== StateApplyDiff
)
2141 // remove the just applied patch
2142 available_patches
.erase(available_patches
.begin());
2143 unlink(PatchFile
.c_str());
2148 std::clog
<< "Moving patched file in place: " << std::endl
2149 << DestFile
<< " -> " << FinalFile
<< std::endl
;
2151 Rename(DestFile
,FinalFile
);
2152 chmod(FinalFile
.c_str(),0644);
2154 // see if there is more to download
2155 if(available_patches
.empty() == false) {
2156 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
,
2161 DestFile
= FinalFile
;
2162 return Finish(true);
2166 std::string
pkgAcqIndexDiffs::Custom600Headers() const /*{{{*/
2168 if(State
!= StateApplyDiff
)
2169 return pkgAcqBaseIndex::Custom600Headers();
2170 std::ostringstream patchhashes
;
2171 HashStringList
const ExpectedHashes
= available_patches
[0].patch_hashes
;
2172 for (HashStringList::const_iterator hs
= ExpectedHashes
.begin(); hs
!= ExpectedHashes
.end(); ++hs
)
2173 patchhashes
<< "\nPatch-0-" << hs
->HashType() << "-Hash: " << hs
->HashValue();
2174 patchhashes
<< pkgAcqBaseIndex::Custom600Headers();
2175 return patchhashes
.str();
2178 pkgAcqIndexDiffs::~pkgAcqIndexDiffs() {}
2180 // AcqIndexMergeDiffs::AcqIndexMergeDiffs - Constructor /*{{{*/
2181 pkgAcqIndexMergeDiffs::pkgAcqIndexMergeDiffs(pkgAcquire
* const Owner
,
2182 pkgAcqMetaClearSig
* const TransactionManager
,
2183 IndexTarget
const &Target
,
2184 DiffInfo
const &patch
,
2185 std::vector
<pkgAcqIndexMergeDiffs
*> const * const allPatches
)
2186 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
),
2187 patch(patch
), allPatches(allPatches
), State(StateFetchDiff
)
2189 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
2192 Description
= Target
.Description
;
2193 Desc
.ShortDesc
= Target
.ShortDesc
;
2195 Desc
.URI
= Target
.URI
+ ".diff/" + patch
.file
+ ".gz";
2196 Desc
.Description
= Description
+ " " + patch
.file
+ string(".pdiff");
2198 DestFile
= GetPartialFileNameFromURI(Target
.URI
+ ".diff/" + patch
.file
);
2201 std::clog
<< "pkgAcqIndexMergeDiffs: " << Desc
.URI
<< std::endl
;
2206 void pkgAcqIndexMergeDiffs::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
2209 std::clog
<< "pkgAcqIndexMergeDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
;
2211 Item::Failed(Message
,Cnf
);
2214 // check if we are the first to fail, otherwise we are done here
2215 State
= StateDoneDiff
;
2216 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2217 I
!= allPatches
->end(); ++I
)
2218 if ((*I
)->State
== StateErrorDiff
)
2221 // first failure means we should fallback
2222 State
= StateErrorDiff
;
2224 std::clog
<< "Falling back to normal index file acquire" << std::endl
;
2225 DestFile
= GetPartialFileNameFromURI(Target
.URI
);
2226 RenameOnError(PDiffError
);
2227 std::string
const patchname
= GetMergeDiffsPatchFileName(DestFile
, patch
.file
);
2228 if (RealFileExists(patchname
))
2229 rename(patchname
.c_str(), std::string(patchname
+ ".FAILED").c_str());
2230 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
2233 void pkgAcqIndexMergeDiffs::Done(string
const &Message
, HashStringList
const &Hashes
, /*{{{*/
2234 pkgAcquire::MethodConfig
const * const Cnf
)
2237 std::clog
<< "pkgAcqIndexMergeDiffs::Done(): " << Desc
.URI
<< std::endl
;
2239 Item::Done(Message
, Hashes
, Cnf
);
2241 string
const FinalFile
= GetPartialFileNameFromURI(Target
.URI
);
2242 if (State
== StateFetchDiff
)
2244 Rename(DestFile
, GetMergeDiffsPatchFileName(FinalFile
, patch
.file
));
2246 // check if this is the last completed diff
2247 State
= StateDoneDiff
;
2248 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2249 I
!= allPatches
->end(); ++I
)
2250 if ((*I
)->State
!= StateDoneDiff
)
2253 std::clog
<< "Not the last done diff in the batch: " << Desc
.URI
<< std::endl
;
2257 // this is the last completed diff, so we are ready to apply now
2258 State
= StateApplyDiff
;
2260 // patching needs to be bootstrapped with the 'old' version
2261 if (symlink(GetFinalFilename().c_str(), FinalFile
.c_str()) != 0)
2263 Failed("Link creation of " + FinalFile
+ " to " + GetFinalFilename() + " failed", NULL
);
2268 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
2271 Desc
.URI
= "rred:" + FinalFile
;
2273 SetActiveSubprocess("rred");
2276 // success in download/apply all diffs, clean up
2277 else if (State
== StateApplyDiff
)
2279 // move the result into place
2280 std::string
const Final
= GetFinalFilename();
2282 std::clog
<< "Queue patched file in place: " << std::endl
2283 << DestFile
<< " -> " << Final
<< std::endl
;
2285 // queue for copy by the transaction manager
2286 TransactionManager
->TransactionStageCopy(this, DestFile
, Final
);
2288 // ensure the ed's are gone regardless of list-cleanup
2289 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2290 I
!= allPatches
->end(); ++I
)
2292 std::string
const PartialFile
= GetPartialFileNameFromURI(Target
.URI
);
2293 std::string
const patch
= GetMergeDiffsPatchFileName(PartialFile
, (*I
)->patch
.file
);
2294 unlink(patch
.c_str());
2296 unlink(FinalFile
.c_str());
2301 std::clog
<< "allDone: " << DestFile
<< "\n" << std::endl
;
2305 std::string
pkgAcqIndexMergeDiffs::Custom600Headers() const /*{{{*/
2307 if(State
!= StateApplyDiff
)
2308 return pkgAcqBaseIndex::Custom600Headers();
2309 std::ostringstream patchhashes
;
2310 unsigned int seen_patches
= 0;
2311 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2312 I
!= allPatches
->end(); ++I
)
2314 HashStringList
const ExpectedHashes
= (*I
)->patch
.patch_hashes
;
2315 for (HashStringList::const_iterator hs
= ExpectedHashes
.begin(); hs
!= ExpectedHashes
.end(); ++hs
)
2316 patchhashes
<< "\nPatch-" << seen_patches
<< "-" << hs
->HashType() << "-Hash: " << hs
->HashValue();
2319 patchhashes
<< pkgAcqBaseIndex::Custom600Headers();
2320 return patchhashes
.str();
2323 pkgAcqIndexMergeDiffs::~pkgAcqIndexMergeDiffs() {}
2325 // AcqIndex::AcqIndex - Constructor /*{{{*/
2326 pkgAcqIndex::pkgAcqIndex(pkgAcquire
* const Owner
,
2327 pkgAcqMetaClearSig
* const TransactionManager
,
2328 IndexTarget
const &Target
)
2329 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
), Stage(STAGE_DOWNLOAD
)
2331 // autoselect the compression method
2332 AutoSelectCompression();
2333 Init(Target
.URI
, Target
.Description
, Target
.ShortDesc
);
2335 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
2336 std::clog
<< "New pkgIndex with TransactionManager "
2337 << TransactionManager
<< std::endl
;
2340 // AcqIndex::AutoSelectCompression - Select compression /*{{{*/
2341 void pkgAcqIndex::AutoSelectCompression()
2343 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
2344 CompressionExtensions
= "";
2345 if (TransactionManager
->MetaIndexParser
!= NULL
&& TransactionManager
->MetaIndexParser
->Exists(Target
.MetaKey
))
2347 for (std::vector
<std::string
>::const_iterator t
= types
.begin();
2348 t
!= types
.end(); ++t
)
2350 std::string CompressedMetaKey
= string(Target
.MetaKey
).append(".").append(*t
);
2351 if (*t
== "uncompressed" ||
2352 TransactionManager
->MetaIndexParser
->Exists(CompressedMetaKey
) == true)
2353 CompressionExtensions
.append(*t
).append(" ");
2358 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
2359 CompressionExtensions
.append(*t
).append(" ");
2361 if (CompressionExtensions
.empty() == false)
2362 CompressionExtensions
.erase(CompressionExtensions
.end()-1);
2365 // AcqIndex::Init - defered Constructor /*{{{*/
2366 void pkgAcqIndex::Init(string
const &URI
, string
const &URIDesc
,
2367 string
const &ShortDesc
)
2369 Stage
= STAGE_DOWNLOAD
;
2371 DestFile
= GetPartialFileNameFromURI(URI
);
2373 size_t const nextExt
= CompressionExtensions
.find(' ');
2374 if (nextExt
== std::string::npos
)
2376 CurrentCompressionExtension
= CompressionExtensions
;
2377 CompressionExtensions
.clear();
2381 CurrentCompressionExtension
= CompressionExtensions
.substr(0, nextExt
);
2382 CompressionExtensions
= CompressionExtensions
.substr(nextExt
+1);
2385 if (CurrentCompressionExtension
== "uncompressed")
2389 else if (unlikely(CurrentCompressionExtension
.empty()))
2393 Desc
.URI
= URI
+ '.' + CurrentCompressionExtension
;
2394 DestFile
= DestFile
+ '.' + CurrentCompressionExtension
;
2397 if(TransactionManager
->MetaIndexParser
!= NULL
)
2398 InitByHashIfNeeded();
2400 Desc
.Description
= URIDesc
;
2402 Desc
.ShortDesc
= ShortDesc
;
2407 // AcqIndex::AdjustForByHash - modify URI for by-hash support /*{{{*/
2408 void pkgAcqIndex::InitByHashIfNeeded()
2411 // - (maybe?) add support for by-hash into the sources.list as flag
2412 // - make apt-ftparchive generate the hashes (and expire?)
2413 std::string HostKnob
= "APT::Acquire::" + ::URI(Desc
.URI
).Host
+ "::By-Hash";
2414 if(_config
->FindB("APT::Acquire::By-Hash", false) == true ||
2415 _config
->FindB(HostKnob
, false) == true ||
2416 TransactionManager
->MetaIndexParser
->GetSupportsAcquireByHash())
2418 HashStringList
const Hashes
= GetExpectedHashes();
2421 // FIXME: should we really use the best hash here? or a fixed one?
2422 HashString
const * const TargetHash
= Hashes
.find("");
2423 std::string
const ByHash
= "/by-hash/" + TargetHash
->HashType() + "/" + TargetHash
->HashValue();
2424 size_t const trailing_slash
= Desc
.URI
.find_last_of("/");
2425 Desc
.URI
= Desc
.URI
.replace(
2427 Desc
.URI
.substr(trailing_slash
+1).size()+1,
2431 "Fetching ByHash requested but can not find record for %s",
2432 GetMetaKey().c_str());
2437 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
2438 // ---------------------------------------------------------------------
2439 /* The only header we use is the last-modified header. */
2440 string
pkgAcqIndex::Custom600Headers() const
2442 string Final
= GetFinalFilename();
2444 string msg
= "\nIndex-File: true";
2446 if (stat(Final
.c_str(),&Buf
) == 0)
2447 msg
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
2449 if(Target
.IsOptional
)
2450 msg
+= "\nFail-Ignore: true";
2455 // AcqIndex::Failed - getting the indexfile failed /*{{{*/
2456 void pkgAcqIndex::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)
2458 Item::Failed(Message
,Cnf
);
2460 // authorisation matches will not be fixed by other compression types
2461 if (Status
!= StatAuthError
)
2463 if (CompressionExtensions
.empty() == false)
2465 Init(Target
.URI
, Desc
.Description
, Desc
.ShortDesc
);
2471 if(Target
.IsOptional
&& GetExpectedHashes().empty() && Stage
== STAGE_DOWNLOAD
)
2474 TransactionManager
->AbortTransaction();
2477 // AcqIndex::ReverifyAfterIMS - Reverify index after an ims-hit /*{{{*/
2478 void pkgAcqIndex::ReverifyAfterIMS()
2480 // update destfile to *not* include the compression extension when doing
2481 // a reverify (as its uncompressed on disk already)
2482 DestFile
= GetCompressedFileName(Target
, GetPartialFileNameFromURI(Target
.URI
), CurrentCompressionExtension
);
2484 // copy FinalFile into partial/ so that we check the hash again
2485 string FinalFile
= GetFinalFilename();
2486 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
2487 Desc
.URI
= "copy:" + FinalFile
;
2491 // AcqIndex::Done - Finished a fetch /*{{{*/
2492 // ---------------------------------------------------------------------
2493 /* This goes through a number of states.. On the initial fetch the
2494 method could possibly return an alternate filename which points
2495 to the uncompressed version of the file. If this is so the file
2496 is copied into the partial directory. In all other cases the file
2497 is decompressed with a compressed uri. */
2498 void pkgAcqIndex::Done(string
const &Message
,
2499 HashStringList
const &Hashes
,
2500 pkgAcquire::MethodConfig
const * const Cfg
)
2502 Item::Done(Message
,Hashes
,Cfg
);
2506 case STAGE_DOWNLOAD
:
2507 StageDownloadDone(Message
, Hashes
, Cfg
);
2509 case STAGE_DECOMPRESS_AND_VERIFY
:
2510 StageDecompressDone(Message
, Hashes
, Cfg
);
2515 // AcqIndex::StageDownloadDone - Queue for decompress and verify /*{{{*/
2516 void pkgAcqIndex::StageDownloadDone(string
const &Message
, HashStringList
const &,
2517 pkgAcquire::MethodConfig
const * const)
2521 // Handle the unzipd case
2522 std::string FileName
= LookupTag(Message
,"Alt-Filename");
2523 if (FileName
.empty() == false)
2525 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
2527 DestFile
+= ".decomp";
2528 Desc
.URI
= "copy:" + FileName
;
2530 SetActiveSubprocess("copy");
2533 FileName
= LookupTag(Message
,"Filename");
2535 // Methods like e.g. "file:" will give us a (compressed) FileName that is
2536 // not the "DestFile" we set, in this case we uncompress from the local file
2537 if (FileName
!= DestFile
&& RealFileExists(DestFile
) == false)
2540 EraseFileName
= FileName
;
2542 // we need to verify the file against the current Release file again
2543 // on if-modfied-since hit to avoid a stale attack against us
2544 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
2546 // The files timestamp matches, reverify by copy into partial/
2552 // If we want compressed indexes, just copy in place for hash verification
2553 if (Target
.KeepCompressed
== true)
2555 DestFile
= GetPartialFileNameFromURI(Target
.URI
+ '.' + CurrentCompressionExtension
);
2557 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
2558 Desc
.URI
= "copy:" + FileName
;
2560 SetActiveSubprocess("copy");
2564 // get the binary name for your used compression type
2566 if(CurrentCompressionExtension
== "uncompressed")
2567 decompProg
= "copy";
2569 decompProg
= _config
->Find(string("Acquire::CompressionTypes::").append(CurrentCompressionExtension
),"");
2570 if(decompProg
.empty() == true)
2572 _error
->Error("Unsupported extension: %s", CurrentCompressionExtension
.c_str());
2576 // queue uri for the next stage
2577 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
2578 DestFile
+= ".decomp";
2579 Desc
.URI
= decompProg
+ ":" + FileName
;
2581 SetActiveSubprocess(decompProg
);
2584 // AcqIndex::StageDecompressDone - Final verification /*{{{*/
2585 void pkgAcqIndex::StageDecompressDone(string
const &,
2586 HashStringList
const &,
2587 pkgAcquire::MethodConfig
const * const)
2589 // Done, queue for rename on transaction finished
2590 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
2594 pkgAcqIndex::~pkgAcqIndex() {}
2597 // AcqArchive::AcqArchive - Constructor /*{{{*/
2598 // ---------------------------------------------------------------------
2599 /* This just sets up the initial fetch environment and queues the first
2601 pkgAcqArchive::pkgAcqArchive(pkgAcquire
* const Owner
,pkgSourceList
* const Sources
,
2602 pkgRecords
* const Recs
,pkgCache::VerIterator
const &Version
,
2603 string
&StoreFilename
) :
2604 Item(Owner
), d(NULL
), LocalSource(false), Version(Version
), Sources(Sources
), Recs(Recs
),
2605 StoreFilename(StoreFilename
), Vf(Version
.FileList()),
2608 Retries
= _config
->FindI("Acquire::Retries",0);
2610 if (Version
.Arch() == 0)
2612 _error
->Error(_("I wasn't able to locate a file for the %s package. "
2613 "This might mean you need to manually fix this package. "
2614 "(due to missing arch)"),
2615 Version
.ParentPkg().FullName().c_str());
2619 /* We need to find a filename to determine the extension. We make the
2620 assumption here that all the available sources for this version share
2621 the same extension.. */
2622 // Skip not source sources, they do not have file fields.
2623 for (; Vf
.end() == false; ++Vf
)
2625 if (Vf
.File().Flagged(pkgCache::Flag::NotSource
))
2630 // Does not really matter here.. we are going to fail out below
2631 if (Vf
.end() != true)
2633 // If this fails to get a file name we will bomb out below.
2634 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2635 if (_error
->PendingError() == true)
2638 // Generate the final file name as: package_version_arch.foo
2639 StoreFilename
= QuoteString(Version
.ParentPkg().Name(),"_:") + '_' +
2640 QuoteString(Version
.VerStr(),"_:") + '_' +
2641 QuoteString(Version
.Arch(),"_:.") +
2642 "." + flExtension(Parse
.FileName());
2645 // check if we have one trusted source for the package. if so, switch
2646 // to "TrustedOnly" mode - but only if not in AllowUnauthenticated mode
2647 bool const allowUnauth
= _config
->FindB("APT::Get::AllowUnauthenticated", false);
2648 bool const debugAuth
= _config
->FindB("Debug::pkgAcquire::Auth", false);
2649 bool seenUntrusted
= false;
2650 for (pkgCache::VerFileIterator i
= Version
.FileList(); i
.end() == false; ++i
)
2652 pkgIndexFile
*Index
;
2653 if (Sources
->FindIndex(i
.File(),Index
) == false)
2656 if (debugAuth
== true)
2657 std::cerr
<< "Checking index: " << Index
->Describe()
2658 << "(Trusted=" << Index
->IsTrusted() << ")" << std::endl
;
2660 if (Index
->IsTrusted() == true)
2663 if (allowUnauth
== false)
2667 seenUntrusted
= true;
2670 // "allow-unauthenticated" restores apts old fetching behaviour
2671 // that means that e.g. unauthenticated file:// uris are higher
2672 // priority than authenticated http:// uris
2673 if (allowUnauth
== true && seenUntrusted
== true)
2677 if (QueueNext() == false && _error
->PendingError() == false)
2678 _error
->Error(_("Can't find a source to download version '%s' of '%s'"),
2679 Version
.VerStr(), Version
.ParentPkg().FullName(false).c_str());
2682 // AcqArchive::QueueNext - Queue the next file source /*{{{*/
2683 // ---------------------------------------------------------------------
2684 /* This queues the next available file version for download. It checks if
2685 the archive is already available in the cache and stashs the MD5 for
2687 bool pkgAcqArchive::QueueNext()
2689 for (; Vf
.end() == false; ++Vf
)
2691 pkgCache::PkgFileIterator
const PkgF
= Vf
.File();
2692 // Ignore not source sources
2693 if (PkgF
.Flagged(pkgCache::Flag::NotSource
))
2696 // Try to cross match against the source list
2697 pkgIndexFile
*Index
;
2698 if (Sources
->FindIndex(PkgF
, Index
) == false)
2700 LocalSource
= PkgF
.Flagged(pkgCache::Flag::LocalSource
);
2702 // only try to get a trusted package from another source if that source
2704 if(Trusted
&& !Index
->IsTrusted())
2707 // Grab the text package record
2708 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2709 if (_error
->PendingError() == true)
2712 string PkgFile
= Parse
.FileName();
2713 ExpectedHashes
= Parse
.Hashes();
2715 if (PkgFile
.empty() == true)
2716 return _error
->Error(_("The package index files are corrupted. No Filename: "
2717 "field for package %s."),
2718 Version
.ParentPkg().Name());
2720 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
2721 Desc
.Description
= Index
->ArchiveInfo(Version
);
2723 Desc
.ShortDesc
= Version
.ParentPkg().FullName(true);
2725 // See if we already have the file. (Legacy filenames)
2726 FileSize
= Version
->Size
;
2727 string FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile
);
2729 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2731 // Make sure the size matches
2732 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2737 StoreFilename
= DestFile
= FinalFile
;
2741 /* Hmm, we have a file and its size does not match, this means it is
2742 an old style mismatched arch */
2743 unlink(FinalFile
.c_str());
2746 // Check it again using the new style output filenames
2747 FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
2748 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2750 // Make sure the size matches
2751 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2756 StoreFilename
= DestFile
= FinalFile
;
2760 /* Hmm, we have a file and its size does not match, this shouldn't
2762 unlink(FinalFile
.c_str());
2765 DestFile
= _config
->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename
);
2767 // Check the destination file
2768 if (stat(DestFile
.c_str(),&Buf
) == 0)
2770 // Hmm, the partial file is too big, erase it
2771 if ((unsigned long long)Buf
.st_size
> Version
->Size
)
2772 unlink(DestFile
.c_str());
2774 PartialSize
= Buf
.st_size
;
2777 // Disables download of archives - useful if no real installation follows,
2778 // e.g. if we are just interested in proposed installation order
2779 if (_config
->FindB("Debug::pkgAcqArchive::NoQueue", false) == true)
2784 StoreFilename
= DestFile
= FinalFile
;
2798 // AcqArchive::Done - Finished fetching /*{{{*/
2799 // ---------------------------------------------------------------------
2801 void pkgAcqArchive::Done(string
const &Message
, HashStringList
const &Hashes
,
2802 pkgAcquire::MethodConfig
const * const Cfg
)
2804 Item::Done(Message
, Hashes
, Cfg
);
2806 // Grab the output filename
2807 std::string
const FileName
= LookupTag(Message
,"Filename");
2808 if (DestFile
!= FileName
&& RealFileExists(DestFile
) == false)
2810 StoreFilename
= DestFile
= FileName
;
2816 // Done, move it into position
2817 string
const FinalFile
= GetFinalFilename();
2818 Rename(DestFile
,FinalFile
);
2819 StoreFilename
= DestFile
= FinalFile
;
2823 // AcqArchive::Failed - Failure handler /*{{{*/
2824 // ---------------------------------------------------------------------
2825 /* Here we try other sources */
2826 void pkgAcqArchive::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)
2828 Item::Failed(Message
,Cnf
);
2830 /* We don't really want to retry on failed media swaps, this prevents
2831 that. An interesting observation is that permanent failures are not
2833 if (Cnf
->Removable
== true &&
2834 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2836 // Vf = Version.FileList();
2837 while (Vf
.end() == false) ++Vf
;
2838 StoreFilename
= string();
2843 if (QueueNext() == false)
2845 // This is the retry counter
2847 Cnf
->LocalOnly
== false &&
2848 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2851 Vf
= Version
.FileList();
2852 if (QueueNext() == true)
2856 StoreFilename
= string();
2861 APT_PURE
bool pkgAcqArchive::IsTrusted() const /*{{{*/
2866 void pkgAcqArchive::Finished() /*{{{*/
2868 if (Status
== pkgAcquire::Item::StatDone
&&
2871 StoreFilename
= string();
2874 std::string
pkgAcqArchive::DescURI() const /*{{{*/
2879 std::string
pkgAcqArchive::ShortDesc() const /*{{{*/
2881 return Desc
.ShortDesc
;
2884 pkgAcqArchive::~pkgAcqArchive() {}
2886 // AcqChangelog::pkgAcqChangelog - Constructors /*{{{*/
2887 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire
* const Owner
, pkgCache::VerIterator
const &Ver
,
2888 std::string
const &DestDir
, std::string
const &DestFilename
) :
2889 pkgAcquire::Item(Owner
), d(NULL
), SrcName(Ver
.SourcePkgName()), SrcVersion(Ver
.SourceVerStr())
2891 Desc
.URI
= URI(Ver
);
2892 Init(DestDir
, DestFilename
);
2894 // some parameters are char* here as they come likely from char* interfaces – which can also return NULL
2895 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire
* const Owner
, pkgCache::RlsFileIterator
const &RlsFile
,
2896 char const * const Component
, char const * const SrcName
, char const * const SrcVersion
,
2897 const string
&DestDir
, const string
&DestFilename
) :
2898 pkgAcquire::Item(Owner
), d(NULL
), SrcName(SrcName
), SrcVersion(SrcVersion
)
2900 Desc
.URI
= URI(RlsFile
, Component
, SrcName
, SrcVersion
);
2901 Init(DestDir
, DestFilename
);
2903 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire
* const Owner
,
2904 std::string
const &URI
, char const * const SrcName
, char const * const SrcVersion
,
2905 const string
&DestDir
, const string
&DestFilename
) :
2906 pkgAcquire::Item(Owner
), d(NULL
), SrcName(SrcName
), SrcVersion(SrcVersion
)
2909 Init(DestDir
, DestFilename
);
2911 void pkgAcqChangelog::Init(std::string
const &DestDir
, std::string
const &DestFilename
)
2913 if (Desc
.URI
.empty())
2916 // TRANSLATOR: %s=%s is sourcename=sourceversion, e.g. apt=1.1
2917 strprintf(ErrorText
, _("Changelog unavailable for %s=%s"), SrcName
.c_str(), SrcVersion
.c_str());
2918 // Let the error message print something sensible rather than "Failed to fetch /"
2919 if (DestFilename
.empty())
2920 DestFile
= SrcName
+ ".changelog";
2922 DestFile
= DestFilename
;
2923 Desc
.URI
= "changelog:/" + DestFile
;
2927 if (DestDir
.empty())
2929 std::string
const systemTemp
= GetTempDir();
2931 snprintf(tmpname
, sizeof(tmpname
), "%s/apt-changelog-XXXXXX", systemTemp
.c_str());
2932 if (NULL
== mkdtemp(tmpname
))
2934 _error
->Errno("mkdtemp", "mkdtemp failed in changelog acquire of %s %s", SrcName
.c_str(), SrcVersion
.c_str());
2938 DestFile
= TemporaryDirectory
= tmpname
;
2943 if (DestFilename
.empty())
2944 DestFile
= flCombine(DestFile
, SrcName
+ ".changelog");
2946 DestFile
= flCombine(DestFile
, DestFilename
);
2948 Desc
.ShortDesc
= "Changelog";
2949 strprintf(Desc
.Description
, "%s %s %s Changelog", URI::SiteOnly(Desc
.URI
).c_str(), SrcName
.c_str(), SrcVersion
.c_str());
2954 std::string
pkgAcqChangelog::URI(pkgCache::VerIterator
const &Ver
) /*{{{*/
2956 char const * const SrcName
= Ver
.SourcePkgName();
2957 char const * const SrcVersion
= Ver
.SourceVerStr();
2958 pkgCache::PkgFileIterator PkgFile
;
2959 // find the first source for this version which promises a changelog
2960 for (pkgCache::VerFileIterator VF
= Ver
.FileList(); VF
.end() == false; ++VF
)
2962 pkgCache::PkgFileIterator
const PF
= VF
.File();
2963 if (PF
.Flagged(pkgCache::Flag::NotSource
) || PF
->Release
== 0)
2966 pkgCache::RlsFileIterator
const RF
= PF
.ReleaseFile();
2967 std::string
const uri
= URI(RF
, PF
.Component(), SrcName
, SrcVersion
);
2974 std::string
pkgAcqChangelog::URITemplate(pkgCache::RlsFileIterator
const &Rls
)
2976 if (Rls
.end() == true || (Rls
->Label
== 0 && Rls
->Origin
== 0))
2978 std::string
const serverConfig
= "Acquire::Changelogs::URI";
2980 #define APT_EMPTY_SERVER \
2981 if (server.empty() == false) \
2983 if (server != "no") \
2987 #define APT_CHECK_SERVER(X, Y) \
2990 std::string const specialServerConfig = serverConfig + "::" + Y + #X + "::" + Rls.X(); \
2991 server = _config->Find(specialServerConfig); \
2994 // this way e.g. Debian-Security can fallback to Debian
2995 APT_CHECK_SERVER(Label
, "Override::")
2996 APT_CHECK_SERVER(Origin
, "Override::")
2998 if (RealFileExists(Rls
.FileName()))
3000 _error
->PushToStack();
3002 /* This can be costly. A caller wanting to get millions of URIs might
3003 want to do this on its own once and use Override settings.
3004 We don't do this here as Origin/Label are not as unique as they
3005 should be so this could produce request order-dependent anomalies */
3006 if (OpenMaybeClearSignedFile(Rls
.FileName(), rf
) == true)
3008 pkgTagFile
TagFile(&rf
, rf
.Size());
3009 pkgTagSection Section
;
3010 if (TagFile
.Step(Section
) == true)
3011 server
= Section
.FindS("Changelogs");
3013 _error
->RevertToStack();
3017 APT_CHECK_SERVER(Label
, "")
3018 APT_CHECK_SERVER(Origin
, "")
3019 #undef APT_CHECK_SERVER
3020 #undef APT_EMPTY_SERVER
3023 std::string
pkgAcqChangelog::URI(pkgCache::RlsFileIterator
const &Rls
,
3024 char const * const Component
, char const * const SrcName
,
3025 char const * const SrcVersion
)
3027 return URI(URITemplate(Rls
), Component
, SrcName
, SrcVersion
);
3029 std::string
pkgAcqChangelog::URI(std::string
const &Template
,
3030 char const * const Component
, char const * const SrcName
,
3031 char const * const SrcVersion
)
3033 if (Template
.find("CHANGEPATH") == std::string::npos
)
3036 // the path is: COMPONENT/SRC/SRCNAME/SRCNAME_SRCVER, e.g. main/a/apt/1.1 or contrib/liba/libapt/2.0
3037 std::string Src
= SrcName
;
3038 std::string path
= APT::String::Startswith(SrcName
, "lib") ? Src
.substr(0, 4) : Src
.substr(0,1);
3039 path
.append("/").append(Src
).append("/");
3040 path
.append(Src
).append("_").append(StripEpoch(SrcVersion
));
3041 // we omit component for releases without one (= flat-style repositories)
3042 if (Component
!= NULL
&& strlen(Component
) != 0)
3043 path
= std::string(Component
) + "/" + path
;
3045 return SubstVar(Template
, "CHANGEPATH", path
);
3048 // AcqChangelog::Failed - Failure handler /*{{{*/
3049 void pkgAcqChangelog::Failed(string
const &Message
, pkgAcquire::MethodConfig
const * const Cnf
)
3051 Item::Failed(Message
,Cnf
);
3053 std::string errText
;
3054 // TRANSLATOR: %s=%s is sourcename=sourceversion, e.g. apt=1.1
3055 strprintf(errText
, _("Changelog unavailable for %s=%s"), SrcName
.c_str(), SrcVersion
.c_str());
3057 // Error is probably something techy like 404 Not Found
3058 if (ErrorText
.empty())
3059 ErrorText
= errText
;
3061 ErrorText
= errText
+ " (" + ErrorText
+ ")";
3065 // AcqChangelog::Done - Item downloaded OK /*{{{*/
3066 void pkgAcqChangelog::Done(string
const &Message
,HashStringList
const &CalcHashes
,
3067 pkgAcquire::MethodConfig
const * const Cnf
)
3069 Item::Done(Message
,CalcHashes
,Cnf
);
3074 pkgAcqChangelog::~pkgAcqChangelog() /*{{{*/
3076 if (TemporaryDirectory
.empty() == false)
3078 unlink(DestFile
.c_str());
3079 rmdir(TemporaryDirectory
.c_str());
3084 // AcqFile::pkgAcqFile - Constructor /*{{{*/
3085 pkgAcqFile::pkgAcqFile(pkgAcquire
* const Owner
,string
const &URI
, HashStringList
const &Hashes
,
3086 unsigned long long const Size
,string
const &Dsc
,string
const &ShortDesc
,
3087 const string
&DestDir
, const string
&DestFilename
,
3088 bool const IsIndexFile
) :
3089 Item(Owner
), d(NULL
), IsIndexFile(IsIndexFile
), ExpectedHashes(Hashes
)
3091 Retries
= _config
->FindI("Acquire::Retries",0);
3093 if(!DestFilename
.empty())
3094 DestFile
= DestFilename
;
3095 else if(!DestDir
.empty())
3096 DestFile
= DestDir
+ "/" + flNotDir(URI
);
3098 DestFile
= flNotDir(URI
);
3102 Desc
.Description
= Dsc
;
3105 // Set the short description to the archive component
3106 Desc
.ShortDesc
= ShortDesc
;
3108 // Get the transfer sizes
3111 if (stat(DestFile
.c_str(),&Buf
) == 0)
3113 // Hmm, the partial file is too big, erase it
3114 if ((Size
> 0) && (unsigned long long)Buf
.st_size
> Size
)
3115 unlink(DestFile
.c_str());
3117 PartialSize
= Buf
.st_size
;
3123 // AcqFile::Done - Item downloaded OK /*{{{*/
3124 void pkgAcqFile::Done(string
const &Message
,HashStringList
const &CalcHashes
,
3125 pkgAcquire::MethodConfig
const * const Cnf
)
3127 Item::Done(Message
,CalcHashes
,Cnf
);
3129 std::string
const FileName
= LookupTag(Message
,"Filename");
3132 // The files timestamp matches
3133 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
3136 // We have to copy it into place
3137 if (RealFileExists(DestFile
.c_str()) == false)
3140 if (_config
->FindB("Acquire::Source-Symlinks",true) == false ||
3141 Cnf
->Removable
== true)
3143 Desc
.URI
= "copy:" + FileName
;
3148 // Erase the file if it is a symlink so we can overwrite it
3150 if (lstat(DestFile
.c_str(),&St
) == 0)
3152 if (S_ISLNK(St
.st_mode
) != 0)
3153 unlink(DestFile
.c_str());
3157 if (symlink(FileName
.c_str(),DestFile
.c_str()) != 0)
3159 _error
->PushToStack();
3160 _error
->Errno("pkgAcqFile::Done", "Symlinking file %s failed", DestFile
.c_str());
3161 std::stringstream msg
;
3162 _error
->DumpErrors(msg
);
3163 _error
->RevertToStack();
3164 ErrorText
= msg
.str();
3171 // AcqFile::Failed - Failure handler /*{{{*/
3172 // ---------------------------------------------------------------------
3173 /* Here we try other sources */
3174 void pkgAcqFile::Failed(string
const &Message
, pkgAcquire::MethodConfig
const * const Cnf
)
3176 Item::Failed(Message
,Cnf
);
3178 // This is the retry counter
3180 Cnf
->LocalOnly
== false &&
3181 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
3191 string
pkgAcqFile::Custom600Headers() const /*{{{*/
3194 return "\nIndex-File: true";
3198 pkgAcqFile::~pkgAcqFile() {}