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::Done - Item downloaded OK /*{{{*/
518 void pkgAcquire::Item::Done(string
const &/*Message*/, HashStringList
const &Hashes
,
519 pkgAcquire::MethodConfig
const * const /*Cnf*/)
521 // We just downloaded something..
524 unsigned long long const downloadedSize
= Hashes
.FileSize();
525 if (downloadedSize
!= 0)
527 FileSize
= downloadedSize
;
531 ErrorText
= string();
532 Owner
->Dequeue(this);
535 // Acquire::Item::Rename - Rename a file /*{{{*/
536 // ---------------------------------------------------------------------
537 /* This helper function is used by a lot of item methods as their final
539 bool pkgAcquire::Item::Rename(string
const &From
,string
const &To
)
541 if (From
== To
|| rename(From
.c_str(),To
.c_str()) == 0)
545 strprintf(S
, _("rename failed, %s (%s -> %s)."), strerror(errno
),
546 From
.c_str(),To
.c_str());
548 if (ErrorText
.empty())
551 ErrorText
= ErrorText
+ ": " + S
;
555 void pkgAcquire::Item::Dequeue() /*{{{*/
557 Owner
->Dequeue(this);
560 bool pkgAcquire::Item::RenameOnError(pkgAcquire::Item::RenameOnErrorState
const error
)/*{{{*/
562 if (RealFileExists(DestFile
))
563 Rename(DestFile
, DestFile
+ ".FAILED");
568 case HashSumMismatch
:
569 errtext
= _("Hash Sum mismatch");
570 Status
= StatAuthError
;
571 ReportMirrorFailure("HashChecksumFailure");
574 errtext
= _("Size mismatch");
575 Status
= StatAuthError
;
576 ReportMirrorFailure("SizeFailure");
579 errtext
= _("Invalid file format");
581 // do not report as usually its not the mirrors fault, but Portal/Proxy
584 errtext
= _("Signature error");
588 errtext
= _("Does not start with a cleartext signature");
591 case MaximumSizeExceeded
:
592 // the method is expected to report a good error for this
596 // no handling here, done by callers
599 if (ErrorText
.empty())
604 void pkgAcquire::Item::SetActiveSubprocess(const std::string
&subprocess
)/*{{{*/
606 ActiveSubprocess
= subprocess
;
607 APT_IGNORE_DEPRECATED(Mode
= ActiveSubprocess
.c_str();)
610 // Acquire::Item::ReportMirrorFailure /*{{{*/
611 void pkgAcquire::Item::ReportMirrorFailure(string
const &FailCode
)
613 // we only act if a mirror was used at all
614 if(UsedMirror
.empty())
617 std::cerr
<< "\nReportMirrorFailure: "
619 << " Uri: " << DescURI()
621 << FailCode
<< std::endl
;
623 string report
= _config
->Find("Methods::Mirror::ProblemReporting",
624 "/usr/lib/apt/apt-report-mirror-failure");
625 if(!FileExists(report
))
628 std::vector
<char const*> Args
;
629 Args
.push_back(report
.c_str());
630 Args
.push_back(UsedMirror
.c_str());
631 Args
.push_back(DescURI().c_str());
632 Args
.push_back(FailCode
.c_str());
633 Args
.push_back(NULL
);
635 pid_t pid
= ExecFork();
638 _error
->Error("ReportMirrorFailure Fork failed");
643 execvp(Args
[0], (char**)Args
.data());
644 std::cerr
<< "Could not exec " << Args
[0] << std::endl
;
647 if(!ExecWait(pid
, "report-mirror-failure"))
649 _error
->Warning("Couldn't report problem to '%s'",
650 _config
->Find("Methods::Mirror::ProblemReporting").c_str());
654 std::string
pkgAcquire::Item::HashSum() const /*{{{*/
656 HashStringList
const hashes
= GetExpectedHashes();
657 HashString
const * const hs
= hashes
.find(NULL
);
658 return hs
!= NULL
? hs
->toStr() : "";
662 pkgAcqTransactionItem::pkgAcqTransactionItem(pkgAcquire
* const Owner
, /*{{{*/
663 pkgAcqMetaClearSig
* const transactionManager
, IndexTarget
const &target
) :
664 pkgAcquire::Item(Owner
), d(NULL
), Target(target
), TransactionManager(transactionManager
)
666 if (TransactionManager
!= this)
667 TransactionManager
->Add(this);
670 pkgAcqTransactionItem::~pkgAcqTransactionItem() /*{{{*/
674 HashStringList
pkgAcqTransactionItem::GetExpectedHashesFor(std::string
const &MetaKey
) const /*{{{*/
676 return GetExpectedHashesFromFor(TransactionManager
->MetaIndexParser
, MetaKey
);
680 // AcqMetaBase - Constructor /*{{{*/
681 pkgAcqMetaBase::pkgAcqMetaBase(pkgAcquire
* const Owner
,
682 pkgAcqMetaClearSig
* const TransactionManager
,
683 std::vector
<IndexTarget
> const &IndexTargets
,
684 IndexTarget
const &DataTarget
)
685 : pkgAcqTransactionItem(Owner
, TransactionManager
, DataTarget
), d(NULL
),
686 IndexTargets(IndexTargets
),
687 AuthPass(false), IMSHit(false)
691 // AcqMetaBase::Add - Add a item to the current Transaction /*{{{*/
692 void pkgAcqMetaBase::Add(pkgAcqTransactionItem
* const I
)
694 Transaction
.push_back(I
);
697 // AcqMetaBase::AbortTransaction - Abort the current Transaction /*{{{*/
698 void pkgAcqMetaBase::AbortTransaction()
700 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
701 std::clog
<< "AbortTransaction: " << TransactionManager
<< std::endl
;
703 // ensure the toplevel is in error state too
704 for (std::vector
<pkgAcqTransactionItem
*>::iterator I
= Transaction
.begin();
705 I
!= Transaction
.end(); ++I
)
707 (*I
)->TransactionState(TransactionAbort
);
712 // AcqMetaBase::TransactionHasError - Check for errors in Transaction /*{{{*/
713 APT_PURE
bool pkgAcqMetaBase::TransactionHasError() const
715 for (std::vector
<pkgAcqTransactionItem
*>::const_iterator I
= Transaction
.begin();
716 I
!= Transaction
.end(); ++I
)
718 switch((*I
)->Status
) {
719 case StatDone
: break;
720 case StatIdle
: break;
721 case StatAuthError
: return true;
722 case StatError
: return true;
723 case StatTransientNetworkError
: return true;
724 case StatFetching
: break;
730 // AcqMetaBase::CommitTransaction - Commit a transaction /*{{{*/
731 void pkgAcqMetaBase::CommitTransaction()
733 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
734 std::clog
<< "CommitTransaction: " << this << std::endl
;
736 // move new files into place *and* remove files that are not
737 // part of the transaction but are still on disk
738 for (std::vector
<pkgAcqTransactionItem
*>::iterator I
= Transaction
.begin();
739 I
!= Transaction
.end(); ++I
)
741 (*I
)->TransactionState(TransactionCommit
);
746 // AcqMetaBase::TransactionStageCopy - Stage a file for copying /*{{{*/
747 void pkgAcqMetaBase::TransactionStageCopy(pkgAcqTransactionItem
* const I
,
748 const std::string
&From
,
749 const std::string
&To
)
751 I
->PartialFile
= From
;
755 // AcqMetaBase::TransactionStageRemoval - Stage a file for removal /*{{{*/
756 void pkgAcqMetaBase::TransactionStageRemoval(pkgAcqTransactionItem
* const I
,
757 const std::string
&FinalFile
)
760 I
->DestFile
= FinalFile
;
763 // AcqMetaBase::GenerateAuthWarning - Check gpg authentication error /*{{{*/
764 bool pkgAcqMetaBase::CheckStopAuthentication(pkgAcquire::Item
* const I
, const std::string
&Message
)
766 // FIXME: this entire function can do now that we disallow going to
767 // a unauthenticated state and can cleanly rollback
769 string
const Final
= I
->GetFinalFilename();
770 if(FileExists(Final
))
772 I
->Status
= StatTransientNetworkError
;
773 _error
->Warning(_("An error occurred during the signature "
774 "verification. The repository is not updated "
775 "and the previous index files will be used. "
776 "GPG error: %s: %s\n"),
777 Desc
.Description
.c_str(),
778 LookupTag(Message
,"Message").c_str());
779 RunScripts("APT::Update::Auth-Failure");
781 } else if (LookupTag(Message
,"Message").find("NODATA") != string::npos
) {
782 /* Invalid signature file, reject (LP: #346386) (Closes: #627642) */
783 _error
->Error(_("GPG error: %s: %s"),
784 Desc
.Description
.c_str(),
785 LookupTag(Message
,"Message").c_str());
786 I
->Status
= StatError
;
789 _error
->Warning(_("GPG error: %s: %s"),
790 Desc
.Description
.c_str(),
791 LookupTag(Message
,"Message").c_str());
793 // gpgv method failed
794 ReportMirrorFailure("GPGFailure");
798 // AcqMetaBase::Custom600Headers - Get header for AcqMetaBase /*{{{*/
799 // ---------------------------------------------------------------------
800 string
pkgAcqMetaBase::Custom600Headers() const
802 std::string Header
= "\nIndex-File: true";
803 std::string MaximumSize
;
804 strprintf(MaximumSize
, "\nMaximum-Size: %i",
805 _config
->FindI("Acquire::MaxReleaseFileSize", 10*1000*1000));
806 Header
+= MaximumSize
;
808 string
const FinalFile
= GetFinalFilename();
810 if (stat(FinalFile
.c_str(),&Buf
) == 0)
811 Header
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
816 // AcqMetaBase::QueueForSignatureVerify /*{{{*/
817 void pkgAcqMetaBase::QueueForSignatureVerify(pkgAcqTransactionItem
* const I
, std::string
const &File
, std::string
const &Signature
)
820 I
->Desc
.URI
= "gpgv:" + Signature
;
823 I
->SetActiveSubprocess("gpgv");
826 // AcqMetaBase::CheckDownloadDone /*{{{*/
827 bool pkgAcqMetaBase::CheckDownloadDone(pkgAcqTransactionItem
* const I
, const std::string
&Message
, HashStringList
const &Hashes
) const
829 // We have just finished downloading a Release file (it is not
832 string
const FileName
= LookupTag(Message
,"Filename");
833 if (FileName
.empty() == true)
835 I
->Status
= StatError
;
836 I
->ErrorText
= "Method gave a blank filename";
840 if (FileName
!= I
->DestFile
&& RealFileExists(I
->DestFile
) == false)
843 I
->Desc
.URI
= "copy:" + FileName
;
844 I
->QueueURI(I
->Desc
);
848 // make sure to verify against the right file on I-M-S hit
849 bool IMSHit
= StringToBool(LookupTag(Message
,"IMS-Hit"), false);
850 if (IMSHit
== false && Hashes
.usable())
852 // detect IMS-Hits servers haven't detected by Hash comparison
853 std::string
const FinalFile
= I
->GetFinalFilename();
854 if (RealFileExists(FinalFile
) && Hashes
.VerifyFile(FinalFile
) == true)
857 unlink(I
->DestFile
.c_str());
863 // for simplicity, the transaction manager is always InRelease
864 // even if it doesn't exist.
865 if (TransactionManager
!= NULL
)
866 TransactionManager
->IMSHit
= true;
867 I
->PartialFile
= I
->DestFile
= I
->GetFinalFilename();
870 // set Item to complete as the remaining work is all local (verify etc)
876 bool pkgAcqMetaBase::CheckAuthDone(string
const &Message
) /*{{{*/
878 // At this point, the gpgv method has succeeded, so there is a
879 // valid signature from a key in the trusted keyring. We
880 // perform additional verification of its contents, and use them
881 // to verify the indexes we are about to download
883 if (TransactionManager
->IMSHit
== false)
885 // open the last (In)Release if we have it
886 std::string
const FinalFile
= GetFinalFilename();
887 std::string FinalRelease
;
888 std::string FinalInRelease
;
889 if (APT::String::Endswith(FinalFile
, "InRelease"))
891 FinalInRelease
= FinalFile
;
892 FinalRelease
= FinalFile
.substr(0, FinalFile
.length() - strlen("InRelease")) + "Release";
896 FinalInRelease
= FinalFile
.substr(0, FinalFile
.length() - strlen("Release")) + "InRelease";
897 FinalRelease
= FinalFile
;
899 if (RealFileExists(FinalInRelease
) || RealFileExists(FinalRelease
))
901 TransactionManager
->LastMetaIndexParser
= TransactionManager
->MetaIndexParser
->UnloadedClone();
902 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
904 _error
->PushToStack();
905 if (RealFileExists(FinalInRelease
))
906 TransactionManager
->LastMetaIndexParser
->Load(FinalInRelease
, NULL
);
908 TransactionManager
->LastMetaIndexParser
->Load(FinalRelease
, NULL
);
909 // its unlikely to happen, but if what we have is bad ignore it
910 if (_error
->PendingError())
912 delete TransactionManager
->LastMetaIndexParser
;
913 TransactionManager
->LastMetaIndexParser
= NULL
;
915 _error
->RevertToStack();
920 if (TransactionManager
->MetaIndexParser
->Load(DestFile
, &ErrorText
) == false)
922 Status
= StatAuthError
;
926 if (!VerifyVendor(Message
))
928 Status
= StatAuthError
;
932 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
933 std::cerr
<< "Signature verification succeeded: "
934 << DestFile
<< std::endl
;
936 // Download further indexes with verification
942 void pkgAcqMetaBase::QueueIndexes(bool const verify
) /*{{{*/
944 // at this point the real Items are loaded in the fetcher
945 ExpectedAdditionalItems
= 0;
947 for (std::vector
<IndexTarget
>::const_iterator Target
= IndexTargets
.begin();
948 Target
!= IndexTargets
.end();
951 bool trypdiff
= _config
->FindB("Acquire::PDiffs", true);
954 if (TransactionManager
->MetaIndexParser
->Exists(Target
->MetaKey
) == false)
956 // optional targets that we do not have in the Release file are skipped
957 if (Target
->IsOptional
)
960 Status
= StatAuthError
;
961 strprintf(ErrorText
, _("Unable to find expected entry '%s' in Release file (Wrong sources.list entry or malformed file)"), Target
->MetaKey
.c_str());
965 if (RealFileExists(GetFinalFileNameFromURI(Target
->URI
)))
967 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
969 HashStringList
const newFile
= GetExpectedHashesFromFor(TransactionManager
->MetaIndexParser
, Target
->MetaKey
);
970 HashStringList
const oldFile
= GetExpectedHashesFromFor(TransactionManager
->LastMetaIndexParser
, Target
->MetaKey
);
971 if (newFile
== oldFile
)
973 // we have the file already, no point in trying to acquire it again
974 new NoActionItem(Owner
, *Target
);
978 else if (TransactionManager
->IMSHit
== true)
980 // we have the file already, no point in trying to acquire it again
981 new NoActionItem(Owner
, *Target
);
986 trypdiff
= false; // no file to patch
988 // check if we have patches available
989 trypdiff
&= TransactionManager
->MetaIndexParser
->Exists(Target
->MetaKey
+ ".diff/Index");
991 // if we have no file to patch, no point in trying
992 trypdiff
&= RealFileExists(GetFinalFileNameFromURI(Target
->URI
));
994 // no point in patching from local sources
997 std::string
const proto
= Target
->URI
.substr(0, strlen("file:/"));
998 if (proto
== "file:/" || proto
== "copy:/" || proto
== "cdrom:")
1002 // Queue the Index file (Packages, Sources, Translation-$foo, …)
1004 new pkgAcqDiffIndex(Owner
, TransactionManager
, *Target
);
1006 new pkgAcqIndex(Owner
, TransactionManager
, *Target
);
1010 bool pkgAcqMetaBase::VerifyVendor(string
const &Message
) /*{{{*/
1012 string::size_type pos
;
1014 // check for missing sigs (that where not fatal because otherwise we had
1017 string msg
= _("There is no public key available for the "
1018 "following key IDs:\n");
1019 pos
= Message
.find("NO_PUBKEY ");
1020 if (pos
!= std::string::npos
)
1022 string::size_type start
= pos
+strlen("NO_PUBKEY ");
1023 string Fingerprint
= Message
.substr(start
, Message
.find("\n")-start
);
1024 missingkeys
+= (Fingerprint
);
1026 if(!missingkeys
.empty())
1027 _error
->Warning("%s", (msg
+ missingkeys
).c_str());
1029 string Transformed
= TransactionManager
->MetaIndexParser
->GetExpectedDist();
1031 if (Transformed
== "../project/experimental")
1033 Transformed
= "experimental";
1036 pos
= Transformed
.rfind('/');
1037 if (pos
!= string::npos
)
1039 Transformed
= Transformed
.substr(0, pos
);
1042 if (Transformed
== ".")
1047 if (TransactionManager
->MetaIndexParser
->GetValidUntil() > 0)
1049 time_t const invalid_since
= time(NULL
) - TransactionManager
->MetaIndexParser
->GetValidUntil();
1050 if (invalid_since
> 0)
1054 // TRANSLATOR: The first %s is the URL of the bad Release file, the second is
1055 // the time since then the file is invalid - formatted in the same way as in
1056 // the download progress display (e.g. 7d 3h 42min 1s)
1057 _("Release file for %s is expired (invalid since %s). "
1058 "Updates for this repository will not be applied."),
1059 Target
.URI
.c_str(), TimeToStr(invalid_since
).c_str());
1060 if (ErrorText
.empty())
1062 return _error
->Error("%s", errmsg
.c_str());
1066 /* Did we get a file older than what we have? This is a last minute IMS hit and doubles
1067 as a prevention of downgrading us to older (still valid) files */
1068 if (TransactionManager
->IMSHit
== false && TransactionManager
->LastMetaIndexParser
!= NULL
&&
1069 TransactionManager
->LastMetaIndexParser
->GetDate() > TransactionManager
->MetaIndexParser
->GetDate())
1071 TransactionManager
->IMSHit
= true;
1072 unlink(DestFile
.c_str());
1073 PartialFile
= DestFile
= GetFinalFilename();
1074 // load the 'old' file in the 'new' one instead of flipping pointers as
1075 // the new one isn't owned by us, while the old one is so cleanup would be confused.
1076 TransactionManager
->MetaIndexParser
->swapLoad(TransactionManager
->LastMetaIndexParser
);
1077 delete TransactionManager
->LastMetaIndexParser
;
1078 TransactionManager
->LastMetaIndexParser
= NULL
;
1081 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1083 std::cerr
<< "Got Codename: " << TransactionManager
->MetaIndexParser
->GetCodename() << std::endl
;
1084 std::cerr
<< "Expecting Dist: " << TransactionManager
->MetaIndexParser
->GetExpectedDist() << std::endl
;
1085 std::cerr
<< "Transformed Dist: " << Transformed
<< std::endl
;
1088 if (TransactionManager
->MetaIndexParser
->CheckDist(Transformed
) == false)
1090 // This might become fatal one day
1091 // Status = StatAuthError;
1092 // ErrorText = "Conflicting distribution; expected "
1093 // + MetaIndexParser->GetExpectedDist() + " but got "
1094 // + MetaIndexParser->GetCodename();
1096 if (!Transformed
.empty())
1098 _error
->Warning(_("Conflicting distribution: %s (expected %s but got %s)"),
1099 Desc
.Description
.c_str(),
1100 Transformed
.c_str(),
1101 TransactionManager
->MetaIndexParser
->GetCodename().c_str());
1108 pkgAcqMetaBase::~pkgAcqMetaBase()
1112 pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire
* const Owner
, /*{{{*/
1113 IndexTarget
const &ClearsignedTarget
,
1114 IndexTarget
const &DetachedDataTarget
, IndexTarget
const &DetachedSigTarget
,
1115 std::vector
<IndexTarget
> const &IndexTargets
,
1116 metaIndex
* const MetaIndexParser
) :
1117 pkgAcqMetaIndex(Owner
, this, ClearsignedTarget
, DetachedSigTarget
, IndexTargets
),
1118 d(NULL
), ClearsignedTarget(ClearsignedTarget
),
1119 DetachedDataTarget(DetachedDataTarget
),
1120 MetaIndexParser(MetaIndexParser
), LastMetaIndexParser(NULL
)
1122 // index targets + (worst case:) Release/Release.gpg
1123 ExpectedAdditionalItems
= IndexTargets
.size() + 2;
1124 TransactionManager
->Add(this);
1127 pkgAcqMetaClearSig::~pkgAcqMetaClearSig() /*{{{*/
1129 if (LastMetaIndexParser
!= NULL
)
1130 delete LastMetaIndexParser
;
1133 // pkgAcqMetaClearSig::Custom600Headers - Insert custom request headers /*{{{*/
1134 string
pkgAcqMetaClearSig::Custom600Headers() const
1136 string Header
= pkgAcqMetaBase::Custom600Headers();
1137 Header
+= "\nFail-Ignore: true";
1138 std::string
const key
= TransactionManager
->MetaIndexParser
->GetSignedBy();
1139 if (key
.empty() == false)
1140 Header
+= "\nSigned-By: " + key
;
1145 // pkgAcqMetaClearSig::Done - We got a file /*{{{*/
1146 void pkgAcqMetaClearSig::Done(std::string
const &Message
,
1147 HashStringList
const &Hashes
,
1148 pkgAcquire::MethodConfig
const * const Cnf
)
1150 Item::Done(Message
, Hashes
, Cnf
);
1152 // if we expect a ClearTextSignature (InRelease), ensure that
1153 // this is what we get and if not fail to queue a
1154 // Release/Release.gpg, see #346386
1155 if (FileExists(DestFile
) && !StartsWithGPGClearTextSignature(DestFile
))
1157 pkgAcquire::Item::Failed(Message
, Cnf
);
1158 RenameOnError(NotClearsigned
);
1159 TransactionManager
->AbortTransaction();
1163 if(AuthPass
== false)
1165 if(CheckDownloadDone(this, Message
, Hashes
) == true)
1166 QueueForSignatureVerify(this, DestFile
, DestFile
);
1169 else if(CheckAuthDone(Message
) == true)
1171 if (TransactionManager
->IMSHit
== false)
1172 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
1173 else if (RealFileExists(GetFinalFilename()) == false)
1175 // We got an InRelease file IMSHit, but we haven't one, which means
1176 // we had a valid Release/Release.gpg combo stepping in, which we have
1177 // to 'acquire' now to ensure list cleanup isn't removing them
1178 new NoActionItem(Owner
, DetachedDataTarget
);
1179 new NoActionItem(Owner
, DetachedSigTarget
);
1184 void pkgAcqMetaClearSig::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
) /*{{{*/
1186 Item::Failed(Message
, Cnf
);
1188 // we failed, we will not get additional items from this method
1189 ExpectedAdditionalItems
= 0;
1191 if (AuthPass
== false)
1193 // Queue the 'old' InRelease file for removal if we try Release.gpg
1194 // as otherwise the file will stay around and gives a false-auth
1195 // impression (CVE-2012-0214)
1196 TransactionManager
->TransactionStageRemoval(this, GetFinalFilename());
1199 new pkgAcqMetaIndex(Owner
, TransactionManager
, DetachedDataTarget
, DetachedSigTarget
, IndexTargets
);
1203 if(CheckStopAuthentication(this, Message
))
1206 _error
->Warning(_("The data from '%s' is not signed. Packages "
1207 "from that repository can not be authenticated."),
1208 ClearsignedTarget
.Description
.c_str());
1210 // No Release file was present, or verification failed, so fall
1211 // back to queueing Packages files without verification
1212 // only allow going further if the users explicitely wants it
1213 if(AllowInsecureRepositories(TransactionManager
->MetaIndexParser
, TransactionManager
, this) == true)
1217 /* InRelease files become Release files, otherwise
1218 * they would be considered as trusted later on */
1219 string
const FinalRelease
= GetFinalFileNameFromURI(DetachedDataTarget
.URI
);
1220 string
const PartialRelease
= GetPartialFileNameFromURI(DetachedDataTarget
.URI
);
1221 string
const FinalReleasegpg
= GetFinalFileNameFromURI(DetachedSigTarget
.URI
);
1222 string
const FinalInRelease
= GetFinalFilename();
1223 Rename(DestFile
, PartialRelease
);
1224 TransactionManager
->TransactionStageCopy(this, PartialRelease
, FinalRelease
);
1226 if (RealFileExists(FinalReleasegpg
) || RealFileExists(FinalInRelease
))
1228 // open the last Release if we have it
1229 if (TransactionManager
->IMSHit
== false)
1231 TransactionManager
->LastMetaIndexParser
= TransactionManager
->MetaIndexParser
->UnloadedClone();
1232 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1234 _error
->PushToStack();
1235 if (RealFileExists(FinalInRelease
))
1236 TransactionManager
->LastMetaIndexParser
->Load(FinalInRelease
, NULL
);
1238 TransactionManager
->LastMetaIndexParser
->Load(FinalRelease
, NULL
);
1239 // its unlikely to happen, but if what we have is bad ignore it
1240 if (_error
->PendingError())
1242 delete TransactionManager
->LastMetaIndexParser
;
1243 TransactionManager
->LastMetaIndexParser
= NULL
;
1245 _error
->RevertToStack();
1250 // we parse the indexes here because at this point the user wanted
1251 // a repository that may potentially harm him
1252 if (TransactionManager
->MetaIndexParser
->Load(PartialRelease
, &ErrorText
) == false || VerifyVendor(Message
) == false)
1253 /* expired Release files are still a problem you need extra force for */;
1261 pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire
* const Owner
, /*{{{*/
1262 pkgAcqMetaClearSig
* const TransactionManager
,
1263 IndexTarget
const &DataTarget
,
1264 IndexTarget
const &DetachedSigTarget
,
1265 vector
<IndexTarget
> const &IndexTargets
) :
1266 pkgAcqMetaBase(Owner
, TransactionManager
, IndexTargets
, DataTarget
), d(NULL
),
1267 DetachedSigTarget(DetachedSigTarget
)
1269 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1270 std::clog
<< "New pkgAcqMetaIndex with TransactionManager "
1271 << this->TransactionManager
<< std::endl
;
1273 DestFile
= GetPartialFileNameFromURI(DataTarget
.URI
);
1276 Desc
.Description
= DataTarget
.Description
;
1278 Desc
.ShortDesc
= DataTarget
.ShortDesc
;
1279 Desc
.URI
= DataTarget
.URI
;
1281 // we expect more item
1282 ExpectedAdditionalItems
= IndexTargets
.size();
1286 void pkgAcqMetaIndex::Done(string
const &Message
, /*{{{*/
1287 HashStringList
const &Hashes
,
1288 pkgAcquire::MethodConfig
const * const Cfg
)
1290 Item::Done(Message
,Hashes
,Cfg
);
1292 if(CheckDownloadDone(this, Message
, Hashes
))
1294 // we have a Release file, now download the Signature, all further
1295 // verify/queue for additional downloads will be done in the
1296 // pkgAcqMetaSig::Done() code
1297 new pkgAcqMetaSig(Owner
, TransactionManager
, DetachedSigTarget
, this);
1301 // pkgAcqMetaIndex::Failed - no Release file present /*{{{*/
1302 void pkgAcqMetaIndex::Failed(string
const &Message
,
1303 pkgAcquire::MethodConfig
const * const Cnf
)
1305 pkgAcquire::Item::Failed(Message
, Cnf
);
1308 _error
->Warning(_("The repository '%s' does not have a Release file. "
1309 "This is deprecated, please contact the owner of the "
1310 "repository."), Target
.Description
.c_str());
1312 // No Release file was present so fall
1313 // back to queueing Packages files without verification
1314 // only allow going further if the users explicitely wants it
1315 if(AllowInsecureRepositories(TransactionManager
->MetaIndexParser
, TransactionManager
, this) == true)
1317 // ensure old Release files are removed
1318 TransactionManager
->TransactionStageRemoval(this, GetFinalFilename());
1320 // queue without any kind of hashsum support
1321 QueueIndexes(false);
1325 void pkgAcqMetaIndex::Finished() /*{{{*/
1327 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1328 std::clog
<< "Finished: " << DestFile
<<std::endl
;
1329 if(TransactionManager
!= NULL
&&
1330 TransactionManager
->TransactionHasError() == false)
1331 TransactionManager
->CommitTransaction();
1334 std::string
pkgAcqMetaIndex::DescURI() const /*{{{*/
1339 pkgAcqMetaIndex::~pkgAcqMetaIndex() {}
1341 // AcqMetaSig::AcqMetaSig - Constructor /*{{{*/
1342 pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire
* const Owner
,
1343 pkgAcqMetaClearSig
* const TransactionManager
,
1344 IndexTarget
const &Target
,
1345 pkgAcqMetaIndex
* const MetaIndex
) :
1346 pkgAcqTransactionItem(Owner
, TransactionManager
, Target
), d(NULL
), MetaIndex(MetaIndex
)
1348 DestFile
= GetPartialFileNameFromURI(Target
.URI
);
1350 // remove any partial downloaded sig-file in partial/.
1351 // it may confuse proxies and is too small to warrant a
1352 // partial download anyway
1353 unlink(DestFile
.c_str());
1355 // set the TransactionManager
1356 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1357 std::clog
<< "New pkgAcqMetaSig with TransactionManager "
1358 << TransactionManager
<< std::endl
;
1361 Desc
.Description
= Target
.Description
;
1363 Desc
.ShortDesc
= Target
.ShortDesc
;
1364 Desc
.URI
= Target
.URI
;
1366 // If we got a hit for Release, we will get one for Release.gpg too (or obscure errors),
1367 // so we skip the download step and go instantly to verification
1368 if (TransactionManager
->IMSHit
== true && RealFileExists(GetFinalFilename()))
1372 PartialFile
= DestFile
= GetFinalFilename();
1373 MetaIndexFileSignature
= DestFile
;
1374 MetaIndex
->QueueForSignatureVerify(this, MetaIndex
->DestFile
, DestFile
);
1380 pkgAcqMetaSig::~pkgAcqMetaSig() /*{{{*/
1384 // pkgAcqMetaSig::Custom600Headers - Insert custom request headers /*{{{*/
1385 std::string
pkgAcqMetaSig::Custom600Headers() const
1387 std::string Header
= pkgAcqTransactionItem::Custom600Headers();
1388 std::string
const key
= TransactionManager
->MetaIndexParser
->GetSignedBy();
1389 if (key
.empty() == false)
1390 Header
+= "\nSigned-By: " + key
;
1394 // AcqMetaSig::Done - The signature was downloaded/verified /*{{{*/
1395 void pkgAcqMetaSig::Done(string
const &Message
, HashStringList
const &Hashes
,
1396 pkgAcquire::MethodConfig
const * const Cfg
)
1398 if (MetaIndexFileSignature
.empty() == false)
1400 DestFile
= MetaIndexFileSignature
;
1401 MetaIndexFileSignature
.clear();
1403 Item::Done(Message
, Hashes
, Cfg
);
1405 if(MetaIndex
->AuthPass
== false)
1407 if(MetaIndex
->CheckDownloadDone(this, Message
, Hashes
) == true)
1409 // destfile will be modified to point to MetaIndexFile for the
1410 // gpgv method, so we need to save it here
1411 MetaIndexFileSignature
= DestFile
;
1412 MetaIndex
->QueueForSignatureVerify(this, MetaIndex
->DestFile
, DestFile
);
1416 else if(MetaIndex
->CheckAuthDone(Message
) == true)
1418 if (TransactionManager
->IMSHit
== false)
1420 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
1421 TransactionManager
->TransactionStageCopy(MetaIndex
, MetaIndex
->DestFile
, MetaIndex
->GetFinalFilename());
1426 void pkgAcqMetaSig::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
1428 Item::Failed(Message
,Cnf
);
1430 // check if we need to fail at this point
1431 if (MetaIndex
->AuthPass
== true && MetaIndex
->CheckStopAuthentication(this, Message
))
1434 string
const FinalRelease
= MetaIndex
->GetFinalFilename();
1435 string
const FinalReleasegpg
= GetFinalFilename();
1436 string
const FinalInRelease
= TransactionManager
->GetFinalFilename();
1438 if (RealFileExists(FinalReleasegpg
) || RealFileExists(FinalInRelease
))
1440 std::string downgrade_msg
;
1441 strprintf(downgrade_msg
, _("The repository '%s' is no longer signed."),
1442 MetaIndex
->Target
.Description
.c_str());
1443 if(_config
->FindB("Acquire::AllowDowngradeToInsecureRepositories"))
1445 // meh, the users wants to take risks (we still mark the packages
1446 // from this repository as unauthenticated)
1447 _error
->Warning("%s", downgrade_msg
.c_str());
1448 _error
->Warning(_("This is normally not allowed, but the option "
1449 "Acquire::AllowDowngradeToInsecureRepositories was "
1450 "given to override it."));
1453 _error
->Error("%s", downgrade_msg
.c_str());
1454 if (TransactionManager
->IMSHit
== false)
1455 Rename(MetaIndex
->DestFile
, MetaIndex
->DestFile
+ ".FAILED");
1456 Item::Failed("Message: " + downgrade_msg
, Cnf
);
1457 TransactionManager
->AbortTransaction();
1462 _error
->Warning(_("The data from '%s' is not signed. Packages "
1463 "from that repository can not be authenticated."),
1464 MetaIndex
->Target
.Description
.c_str());
1466 // ensures that a Release.gpg file in the lists/ is removed by the transaction
1467 TransactionManager
->TransactionStageRemoval(this, DestFile
);
1469 // only allow going further if the users explicitely wants it
1470 if(AllowInsecureRepositories(TransactionManager
->MetaIndexParser
, TransactionManager
, this) == true)
1472 if (RealFileExists(FinalReleasegpg
) || RealFileExists(FinalInRelease
))
1474 // open the last Release if we have it
1475 if (TransactionManager
->IMSHit
== false)
1477 TransactionManager
->LastMetaIndexParser
= TransactionManager
->MetaIndexParser
->UnloadedClone();
1478 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1480 _error
->PushToStack();
1481 if (RealFileExists(FinalInRelease
))
1482 TransactionManager
->LastMetaIndexParser
->Load(FinalInRelease
, NULL
);
1484 TransactionManager
->LastMetaIndexParser
->Load(FinalRelease
, NULL
);
1485 // its unlikely to happen, but if what we have is bad ignore it
1486 if (_error
->PendingError())
1488 delete TransactionManager
->LastMetaIndexParser
;
1489 TransactionManager
->LastMetaIndexParser
= NULL
;
1491 _error
->RevertToStack();
1496 // we parse the indexes here because at this point the user wanted
1497 // a repository that may potentially harm him
1498 if (TransactionManager
->MetaIndexParser
->Load(MetaIndex
->DestFile
, &ErrorText
) == false || MetaIndex
->VerifyVendor(Message
) == false)
1499 /* expired Release files are still a problem you need extra force for */;
1501 MetaIndex
->QueueIndexes(true);
1503 TransactionManager
->TransactionStageCopy(MetaIndex
, MetaIndex
->DestFile
, MetaIndex
->GetFinalFilename());
1506 // FIXME: this is used often (e.g. in pkgAcqIndexTrans) so refactor
1507 if (Cnf
->LocalOnly
== true ||
1508 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1517 // AcqBaseIndex - Constructor /*{{{*/
1518 pkgAcqBaseIndex::pkgAcqBaseIndex(pkgAcquire
* const Owner
,
1519 pkgAcqMetaClearSig
* const TransactionManager
,
1520 IndexTarget
const &Target
)
1521 : pkgAcqTransactionItem(Owner
, TransactionManager
, Target
), d(NULL
)
1525 pkgAcqBaseIndex::~pkgAcqBaseIndex() {}
1527 // AcqDiffIndex::AcqDiffIndex - Constructor /*{{{*/
1528 // ---------------------------------------------------------------------
1529 /* Get the DiffIndex file first and see if there are patches available
1530 * If so, create a pkgAcqIndexDiffs fetcher that will get and apply the
1531 * patches. If anything goes wrong in that process, it will fall back to
1532 * the original packages file
1534 pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire
* const Owner
,
1535 pkgAcqMetaClearSig
* const TransactionManager
,
1536 IndexTarget
const &Target
)
1537 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
), diffs(NULL
)
1539 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
1542 Desc
.Description
= Target
.Description
+ ".diff/Index";
1543 Desc
.ShortDesc
= Target
.ShortDesc
;
1544 Desc
.URI
= Target
.URI
+ ".diff/Index";
1546 DestFile
= GetPartialFileNameFromURI(Desc
.URI
);
1549 std::clog
<< "pkgAcqDiffIndex: " << Desc
.URI
<< std::endl
;
1554 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
1555 // ---------------------------------------------------------------------
1556 /* The only header we use is the last-modified header. */
1557 string
pkgAcqDiffIndex::Custom600Headers() const
1559 string
const Final
= GetFinalFilename();
1562 std::clog
<< "Custom600Header-IMS: " << Final
<< std::endl
;
1565 if (stat(Final
.c_str(),&Buf
) != 0)
1566 return "\nIndex-File: true";
1568 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1571 void pkgAcqDiffIndex::QueueOnIMSHit() const /*{{{*/
1573 // list cleanup needs to know that this file as well as the already
1574 // present index is ours, so we create an empty diff to save it for us
1575 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
);
1578 bool pkgAcqDiffIndex::ParseDiffIndex(string
const &IndexDiffFile
) /*{{{*/
1580 // failing here is fine: our caller will take care of trying to
1581 // get the complete file if patching fails
1583 std::clog
<< "pkgAcqDiffIndex::ParseIndexDiff() " << IndexDiffFile
1586 FileFd
Fd(IndexDiffFile
,FileFd::ReadOnly
);
1588 if (_error
->PendingError() == true)
1592 if(unlikely(TF
.Step(Tags
) == false))
1595 HashStringList ServerHashes
;
1596 unsigned long long ServerSize
= 0;
1598 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
1600 std::string tagname
= *type
;
1601 tagname
.append("-Current");
1602 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1603 if (tmp
.empty() == true)
1607 unsigned long long size
;
1608 std::stringstream
ss(tmp
);
1610 if (unlikely(hash
.empty() == true))
1612 if (unlikely(ServerSize
!= 0 && ServerSize
!= size
))
1614 ServerHashes
.push_back(HashString(*type
, hash
));
1618 if (ServerHashes
.usable() == false)
1621 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": Did not find a good hashsum in the index" << std::endl
;
1625 std::string
const CurrentPackagesFile
= GetFinalFileNameFromURI(Target
.URI
);
1626 HashStringList
const TargetFileHashes
= GetExpectedHashesFor(Target
.MetaKey
);
1627 if (TargetFileHashes
.usable() == false || ServerHashes
!= TargetFileHashes
)
1631 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": Index has different hashes than parser, probably older, so fail pdiffing" << std::endl
;
1632 printHashSumComparision(CurrentPackagesFile
, ServerHashes
, TargetFileHashes
);
1637 HashStringList LocalHashes
;
1638 // try avoiding calculating the hash here as this is costly
1639 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1640 LocalHashes
= GetExpectedHashesFromFor(TransactionManager
->LastMetaIndexParser
, Target
.MetaKey
);
1641 if (LocalHashes
.usable() == false)
1643 FileFd
fd(CurrentPackagesFile
, FileFd::ReadOnly
);
1644 Hashes
LocalHashesCalc(ServerHashes
);
1645 LocalHashesCalc
.AddFD(fd
);
1646 LocalHashes
= LocalHashesCalc
.GetHashStringList();
1649 if (ServerHashes
== LocalHashes
)
1651 // we have the same sha1 as the server so we are done here
1653 std::clog
<< "pkgAcqDiffIndex: Package file " << CurrentPackagesFile
<< " is up-to-date" << std::endl
;
1659 std::clog
<< "Server-Current: " << ServerHashes
.find(NULL
)->toStr() << " and we start at "
1660 << CurrentPackagesFile
<< " " << LocalHashes
.FileSize() << " " << LocalHashes
.find(NULL
)->toStr() << std::endl
;
1662 // parse all of (provided) history
1663 vector
<DiffInfo
> available_patches
;
1664 bool firstAcceptedHashes
= true;
1665 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
1667 if (LocalHashes
.find(*type
) == NULL
)
1670 std::string tagname
= *type
;
1671 tagname
.append("-History");
1672 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1673 if (tmp
.empty() == true)
1676 string hash
, filename
;
1677 unsigned long long size
;
1678 std::stringstream
ss(tmp
);
1680 while (ss
>> hash
>> size
>> filename
)
1682 if (unlikely(hash
.empty() == true || filename
.empty() == true))
1685 // see if we have a record for this file already
1686 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
1687 for (; cur
!= available_patches
.end(); ++cur
)
1689 if (cur
->file
!= filename
)
1691 cur
->result_hashes
.push_back(HashString(*type
, hash
));
1694 if (cur
!= available_patches
.end())
1696 if (firstAcceptedHashes
== true)
1699 next
.file
= filename
;
1700 next
.result_hashes
.push_back(HashString(*type
, hash
));
1701 next
.result_hashes
.FileSize(size
);
1702 available_patches
.push_back(next
);
1707 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
1708 << " wasn't in the list for the first parsed hash! (history)" << std::endl
;
1712 firstAcceptedHashes
= false;
1715 if (unlikely(available_patches
.empty() == true))
1718 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": "
1719 << "Couldn't find any patches for the patch series." << std::endl
;
1723 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
1725 if (LocalHashes
.find(*type
) == NULL
)
1728 std::string tagname
= *type
;
1729 tagname
.append("-Patches");
1730 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1731 if (tmp
.empty() == true)
1734 string hash
, filename
;
1735 unsigned long long size
;
1736 std::stringstream
ss(tmp
);
1738 while (ss
>> hash
>> size
>> filename
)
1740 if (unlikely(hash
.empty() == true || filename
.empty() == true))
1743 // see if we have a record for this file already
1744 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
1745 for (; cur
!= available_patches
.end(); ++cur
)
1747 if (cur
->file
!= filename
)
1749 if (cur
->patch_hashes
.empty())
1750 cur
->patch_hashes
.FileSize(size
);
1751 cur
->patch_hashes
.push_back(HashString(*type
, hash
));
1754 if (cur
!= available_patches
.end())
1757 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
1758 << " wasn't in the list for the first parsed hash! (patches)" << std::endl
;
1763 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
1765 std::string tagname
= *type
;
1766 tagname
.append("-Download");
1767 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1768 if (tmp
.empty() == true)
1771 string hash
, filename
;
1772 unsigned long long size
;
1773 std::stringstream
ss(tmp
);
1775 // FIXME: all of pdiff supports only .gz compressed patches
1776 while (ss
>> hash
>> size
>> filename
)
1778 if (unlikely(hash
.empty() == true || filename
.empty() == true))
1780 if (unlikely(APT::String::Endswith(filename
, ".gz") == false))
1782 filename
.erase(filename
.length() - 3);
1784 // see if we have a record for this file already
1785 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
1786 for (; cur
!= available_patches
.end(); ++cur
)
1788 if (cur
->file
!= filename
)
1790 if (cur
->download_hashes
.empty())
1791 cur
->download_hashes
.FileSize(size
);
1792 cur
->download_hashes
.push_back(HashString(*type
, hash
));
1795 if (cur
!= available_patches
.end())
1798 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
1799 << " wasn't in the list for the first parsed hash! (download)" << std::endl
;
1805 bool foundStart
= false;
1806 for (std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
1807 cur
!= available_patches
.end(); ++cur
)
1809 if (LocalHashes
!= cur
->result_hashes
)
1812 available_patches
.erase(available_patches
.begin(), cur
);
1817 if (foundStart
== false || unlikely(available_patches
.empty() == true))
1820 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": "
1821 << "Couldn't find the start of the patch series." << std::endl
;
1825 // patching with too many files is rather slow compared to a fast download
1826 unsigned long const fileLimit
= _config
->FindI("Acquire::PDiffs::FileLimit", 0);
1827 if (fileLimit
!= 0 && fileLimit
< available_patches
.size())
1830 std::clog
<< "Need " << available_patches
.size() << " diffs (Limit is " << fileLimit
1831 << ") so fallback to complete download" << std::endl
;
1835 // calculate the size of all patches we have to get
1836 // note that all sizes are uncompressed, while we download compressed files
1837 unsigned long long patchesSize
= 0;
1838 for (std::vector
<DiffInfo
>::const_iterator cur
= available_patches
.begin();
1839 cur
!= available_patches
.end(); ++cur
)
1840 patchesSize
+= cur
->patch_hashes
.FileSize();
1841 unsigned long long const sizeLimit
= ServerSize
* _config
->FindI("Acquire::PDiffs::SizeLimit", 100);
1842 if (sizeLimit
> 0 && (sizeLimit
/100) < patchesSize
)
1845 std::clog
<< "Need " << patchesSize
<< " bytes (Limit is " << sizeLimit
/100
1846 << ") so fallback to complete download" << std::endl
;
1850 // we have something, queue the diffs
1851 string::size_type
const last_space
= Description
.rfind(" ");
1852 if(last_space
!= string::npos
)
1853 Description
.erase(last_space
, Description
.size()-last_space
);
1855 /* decide if we should download patches one by one or in one go:
1856 The first is good if the server merges patches, but many don't so client
1857 based merging can be attempt in which case the second is better.
1858 "bad things" will happen if patches are merged on the server,
1859 but client side merging is attempt as well */
1860 bool pdiff_merge
= _config
->FindB("Acquire::PDiffs::Merge", true);
1861 if (pdiff_merge
== true)
1863 // reprepro adds this flag if it has merged patches on the server
1864 std::string
const precedence
= Tags
.FindS("X-Patch-Precedence");
1865 pdiff_merge
= (precedence
!= "merged");
1868 if (pdiff_merge
== false)
1869 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
, available_patches
);
1872 diffs
= new std::vector
<pkgAcqIndexMergeDiffs
*>(available_patches
.size());
1873 for(size_t i
= 0; i
< available_patches
.size(); ++i
)
1874 (*diffs
)[i
] = new pkgAcqIndexMergeDiffs(Owner
, TransactionManager
,
1876 available_patches
[i
],
1886 void pkgAcqDiffIndex::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
1888 Item::Failed(Message
,Cnf
);
1892 std::clog
<< "pkgAcqDiffIndex failed: " << Desc
.URI
<< " with " << Message
<< std::endl
1893 << "Falling back to normal index file acquire" << std::endl
;
1895 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
1898 void pkgAcqDiffIndex::Done(string
const &Message
,HashStringList
const &Hashes
, /*{{{*/
1899 pkgAcquire::MethodConfig
const * const Cnf
)
1902 std::clog
<< "pkgAcqDiffIndex::Done(): " << Desc
.URI
<< std::endl
;
1904 Item::Done(Message
, Hashes
, Cnf
);
1906 string
const FinalFile
= GetFinalFilename();
1907 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false))
1908 DestFile
= FinalFile
;
1910 if(ParseDiffIndex(DestFile
) == false)
1912 Failed("Message: Couldn't parse pdiff index", Cnf
);
1913 // queue for final move - this should happen even if we fail
1914 // while parsing (e.g. on sizelimit) and download the complete file.
1915 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
1919 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
1928 pkgAcqDiffIndex::~pkgAcqDiffIndex()
1934 // AcqIndexDiffs::AcqIndexDiffs - Constructor /*{{{*/
1935 // ---------------------------------------------------------------------
1936 /* The package diff is added to the queue. one object is constructed
1937 * for each diff and the index
1939 pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire
* const Owner
,
1940 pkgAcqMetaClearSig
* const TransactionManager
,
1941 IndexTarget
const &Target
,
1942 vector
<DiffInfo
> const &diffs
)
1943 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
),
1944 available_patches(diffs
)
1946 DestFile
= GetPartialFileNameFromURI(Target
.URI
);
1948 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
1951 Description
= Target
.Description
;
1952 Desc
.ShortDesc
= Target
.ShortDesc
;
1954 if(available_patches
.empty() == true)
1956 // we are done (yeah!), check hashes against the final file
1957 DestFile
= GetFinalFileNameFromURI(Target
.URI
);
1962 // patching needs to be bootstrapped with the 'old' version
1963 std::string
const PartialFile
= GetPartialFileNameFromURI(Target
.URI
);
1964 if (RealFileExists(PartialFile
) == false)
1966 if (symlink(GetFinalFilename().c_str(), PartialFile
.c_str()) != 0)
1968 Failed("Link creation of " + PartialFile
+ " to " + GetFinalFilename() + " failed", NULL
);
1973 // get the next diff
1974 State
= StateFetchDiff
;
1979 void pkgAcqIndexDiffs::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
1981 Item::Failed(Message
,Cnf
);
1985 std::clog
<< "pkgAcqIndexDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
1986 << "Falling back to normal index file acquire" << std::endl
;
1987 DestFile
= GetPartialFileNameFromURI(Target
.URI
);
1988 RenameOnError(PDiffError
);
1989 std::string
const patchname
= GetDiffsPatchFileName(DestFile
);
1990 if (RealFileExists(patchname
))
1991 rename(patchname
.c_str(), std::string(patchname
+ ".FAILED").c_str());
1992 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
1996 // Finish - helper that cleans the item out of the fetcher queue /*{{{*/
1997 void pkgAcqIndexDiffs::Finish(bool allDone
)
2000 std::clog
<< "pkgAcqIndexDiffs::Finish(): "
2002 << Desc
.URI
<< std::endl
;
2004 // we restore the original name, this is required, otherwise
2005 // the file will be cleaned
2008 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
2010 // this is for the "real" finish
2015 std::clog
<< "\n\nallDone: " << DestFile
<< "\n" << std::endl
;
2020 std::clog
<< "Finishing: " << Desc
.URI
<< std::endl
;
2027 bool pkgAcqIndexDiffs::QueueNextDiff() /*{{{*/
2029 // calc sha1 of the just patched file
2030 std::string
const FinalFile
= GetPartialFileNameFromURI(Target
.URI
);
2032 if(!FileExists(FinalFile
))
2034 Failed("Message: No FinalFile " + FinalFile
+ " available", NULL
);
2038 FileFd
fd(FinalFile
, FileFd::ReadOnly
);
2039 Hashes LocalHashesCalc
;
2040 LocalHashesCalc
.AddFD(fd
);
2041 HashStringList
const LocalHashes
= LocalHashesCalc
.GetHashStringList();
2044 std::clog
<< "QueueNextDiff: " << FinalFile
<< " (" << LocalHashes
.find(NULL
)->toStr() << ")" << std::endl
;
2046 HashStringList
const TargetFileHashes
= GetExpectedHashesFor(Target
.MetaKey
);
2047 if (unlikely(LocalHashes
.usable() == false || TargetFileHashes
.usable() == false))
2049 Failed("Local/Expected hashes are not usable", NULL
);
2054 // final file reached before all patches are applied
2055 if(LocalHashes
== TargetFileHashes
)
2061 // remove all patches until the next matching patch is found
2062 // this requires the Index file to be ordered
2063 for(vector
<DiffInfo
>::iterator I
= available_patches
.begin();
2064 available_patches
.empty() == false &&
2065 I
!= available_patches
.end() &&
2066 I
->result_hashes
!= LocalHashes
;
2069 available_patches
.erase(I
);
2072 // error checking and falling back if no patch was found
2073 if(available_patches
.empty() == true)
2075 Failed("No patches left to reach target", NULL
);
2079 // queue the right diff
2080 Desc
.URI
= Target
.URI
+ ".diff/" + available_patches
[0].file
+ ".gz";
2081 Desc
.Description
= Description
+ " " + available_patches
[0].file
+ string(".pdiff");
2082 DestFile
= GetPartialFileNameFromURI(Target
.URI
+ ".diff/" + available_patches
[0].file
);
2085 std::clog
<< "pkgAcqIndexDiffs::QueueNextDiff(): " << Desc
.URI
<< std::endl
;
2092 void pkgAcqIndexDiffs::Done(string
const &Message
, HashStringList
const &Hashes
, /*{{{*/
2093 pkgAcquire::MethodConfig
const * const Cnf
)
2096 std::clog
<< "pkgAcqIndexDiffs::Done(): " << Desc
.URI
<< std::endl
;
2098 Item::Done(Message
, Hashes
, Cnf
);
2100 std::string
const FinalFile
= GetPartialFileNameFromURI(Target
.URI
);
2101 std::string
const PatchFile
= GetDiffsPatchFileName(FinalFile
);
2103 // success in downloading a diff, enter ApplyDiff state
2104 if(State
== StateFetchDiff
)
2106 Rename(DestFile
, PatchFile
);
2109 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
2111 State
= StateApplyDiff
;
2113 Desc
.URI
= "rred:" + FinalFile
;
2115 SetActiveSubprocess("rred");
2119 // success in download/apply a diff, queue next (if needed)
2120 if(State
== StateApplyDiff
)
2122 // remove the just applied patch
2123 available_patches
.erase(available_patches
.begin());
2124 unlink(PatchFile
.c_str());
2129 std::clog
<< "Moving patched file in place: " << std::endl
2130 << DestFile
<< " -> " << FinalFile
<< std::endl
;
2132 Rename(DestFile
,FinalFile
);
2133 chmod(FinalFile
.c_str(),0644);
2135 // see if there is more to download
2136 if(available_patches
.empty() == false) {
2137 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
,
2142 DestFile
= FinalFile
;
2143 return Finish(true);
2147 std::string
pkgAcqIndexDiffs::Custom600Headers() const /*{{{*/
2149 if(State
!= StateApplyDiff
)
2150 return pkgAcqBaseIndex::Custom600Headers();
2151 std::ostringstream patchhashes
;
2152 HashStringList
const ExpectedHashes
= available_patches
[0].patch_hashes
;
2153 for (HashStringList::const_iterator hs
= ExpectedHashes
.begin(); hs
!= ExpectedHashes
.end(); ++hs
)
2154 patchhashes
<< "\nPatch-0-" << hs
->HashType() << "-Hash: " << hs
->HashValue();
2155 patchhashes
<< pkgAcqBaseIndex::Custom600Headers();
2156 return patchhashes
.str();
2159 pkgAcqIndexDiffs::~pkgAcqIndexDiffs() {}
2161 // AcqIndexMergeDiffs::AcqIndexMergeDiffs - Constructor /*{{{*/
2162 pkgAcqIndexMergeDiffs::pkgAcqIndexMergeDiffs(pkgAcquire
* const Owner
,
2163 pkgAcqMetaClearSig
* const TransactionManager
,
2164 IndexTarget
const &Target
,
2165 DiffInfo
const &patch
,
2166 std::vector
<pkgAcqIndexMergeDiffs
*> const * const allPatches
)
2167 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
),
2168 patch(patch
), allPatches(allPatches
), State(StateFetchDiff
)
2170 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
2173 Description
= Target
.Description
;
2174 Desc
.ShortDesc
= Target
.ShortDesc
;
2176 Desc
.URI
= Target
.URI
+ ".diff/" + patch
.file
+ ".gz";
2177 Desc
.Description
= Description
+ " " + patch
.file
+ string(".pdiff");
2179 DestFile
= GetPartialFileNameFromURI(Target
.URI
+ ".diff/" + patch
.file
);
2182 std::clog
<< "pkgAcqIndexMergeDiffs: " << Desc
.URI
<< std::endl
;
2187 void pkgAcqIndexMergeDiffs::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
2190 std::clog
<< "pkgAcqIndexMergeDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
;
2192 Item::Failed(Message
,Cnf
);
2195 // check if we are the first to fail, otherwise we are done here
2196 State
= StateDoneDiff
;
2197 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2198 I
!= allPatches
->end(); ++I
)
2199 if ((*I
)->State
== StateErrorDiff
)
2202 // first failure means we should fallback
2203 State
= StateErrorDiff
;
2205 std::clog
<< "Falling back to normal index file acquire" << std::endl
;
2206 DestFile
= GetPartialFileNameFromURI(Target
.URI
);
2207 RenameOnError(PDiffError
);
2208 std::string
const patchname
= GetMergeDiffsPatchFileName(DestFile
, patch
.file
);
2209 if (RealFileExists(patchname
))
2210 rename(patchname
.c_str(), std::string(patchname
+ ".FAILED").c_str());
2211 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
2214 void pkgAcqIndexMergeDiffs::Done(string
const &Message
, HashStringList
const &Hashes
, /*{{{*/
2215 pkgAcquire::MethodConfig
const * const Cnf
)
2218 std::clog
<< "pkgAcqIndexMergeDiffs::Done(): " << Desc
.URI
<< std::endl
;
2220 Item::Done(Message
, Hashes
, Cnf
);
2222 string
const FinalFile
= GetPartialFileNameFromURI(Target
.URI
);
2223 if (State
== StateFetchDiff
)
2225 Rename(DestFile
, GetMergeDiffsPatchFileName(FinalFile
, patch
.file
));
2227 // check if this is the last completed diff
2228 State
= StateDoneDiff
;
2229 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2230 I
!= allPatches
->end(); ++I
)
2231 if ((*I
)->State
!= StateDoneDiff
)
2234 std::clog
<< "Not the last done diff in the batch: " << Desc
.URI
<< std::endl
;
2238 // this is the last completed diff, so we are ready to apply now
2239 State
= StateApplyDiff
;
2241 // patching needs to be bootstrapped with the 'old' version
2242 if (symlink(GetFinalFilename().c_str(), FinalFile
.c_str()) != 0)
2244 Failed("Link creation of " + FinalFile
+ " to " + GetFinalFilename() + " failed", NULL
);
2249 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
2252 Desc
.URI
= "rred:" + FinalFile
;
2254 SetActiveSubprocess("rred");
2257 // success in download/apply all diffs, clean up
2258 else if (State
== StateApplyDiff
)
2260 // move the result into place
2261 std::string
const Final
= GetFinalFilename();
2263 std::clog
<< "Queue patched file in place: " << std::endl
2264 << DestFile
<< " -> " << Final
<< std::endl
;
2266 // queue for copy by the transaction manager
2267 TransactionManager
->TransactionStageCopy(this, DestFile
, Final
);
2269 // ensure the ed's are gone regardless of list-cleanup
2270 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2271 I
!= allPatches
->end(); ++I
)
2273 std::string
const PartialFile
= GetPartialFileNameFromURI(Target
.URI
);
2274 std::string
const patch
= GetMergeDiffsPatchFileName(PartialFile
, (*I
)->patch
.file
);
2275 unlink(patch
.c_str());
2277 unlink(FinalFile
.c_str());
2282 std::clog
<< "allDone: " << DestFile
<< "\n" << std::endl
;
2286 std::string
pkgAcqIndexMergeDiffs::Custom600Headers() const /*{{{*/
2288 if(State
!= StateApplyDiff
)
2289 return pkgAcqBaseIndex::Custom600Headers();
2290 std::ostringstream patchhashes
;
2291 unsigned int seen_patches
= 0;
2292 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2293 I
!= allPatches
->end(); ++I
)
2295 HashStringList
const ExpectedHashes
= (*I
)->patch
.patch_hashes
;
2296 for (HashStringList::const_iterator hs
= ExpectedHashes
.begin(); hs
!= ExpectedHashes
.end(); ++hs
)
2297 patchhashes
<< "\nPatch-" << seen_patches
<< "-" << hs
->HashType() << "-Hash: " << hs
->HashValue();
2300 patchhashes
<< pkgAcqBaseIndex::Custom600Headers();
2301 return patchhashes
.str();
2304 pkgAcqIndexMergeDiffs::~pkgAcqIndexMergeDiffs() {}
2306 // AcqIndex::AcqIndex - Constructor /*{{{*/
2307 pkgAcqIndex::pkgAcqIndex(pkgAcquire
* const Owner
,
2308 pkgAcqMetaClearSig
* const TransactionManager
,
2309 IndexTarget
const &Target
)
2310 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
), Stage(STAGE_DOWNLOAD
)
2312 // autoselect the compression method
2313 AutoSelectCompression();
2314 Init(Target
.URI
, Target
.Description
, Target
.ShortDesc
);
2316 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
2317 std::clog
<< "New pkgIndex with TransactionManager "
2318 << TransactionManager
<< std::endl
;
2321 // AcqIndex::AutoSelectCompression - Select compression /*{{{*/
2322 void pkgAcqIndex::AutoSelectCompression()
2324 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
2325 CompressionExtensions
= "";
2326 if (TransactionManager
->MetaIndexParser
!= NULL
&& TransactionManager
->MetaIndexParser
->Exists(Target
.MetaKey
))
2328 for (std::vector
<std::string
>::const_iterator t
= types
.begin();
2329 t
!= types
.end(); ++t
)
2331 std::string CompressedMetaKey
= string(Target
.MetaKey
).append(".").append(*t
);
2332 if (*t
== "uncompressed" ||
2333 TransactionManager
->MetaIndexParser
->Exists(CompressedMetaKey
) == true)
2334 CompressionExtensions
.append(*t
).append(" ");
2339 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
2340 CompressionExtensions
.append(*t
).append(" ");
2342 if (CompressionExtensions
.empty() == false)
2343 CompressionExtensions
.erase(CompressionExtensions
.end()-1);
2346 // AcqIndex::Init - defered Constructor /*{{{*/
2347 void pkgAcqIndex::Init(string
const &URI
, string
const &URIDesc
,
2348 string
const &ShortDesc
)
2350 Stage
= STAGE_DOWNLOAD
;
2352 DestFile
= GetPartialFileNameFromURI(URI
);
2354 size_t const nextExt
= CompressionExtensions
.find(' ');
2355 if (nextExt
== std::string::npos
)
2357 CurrentCompressionExtension
= CompressionExtensions
;
2358 CompressionExtensions
.clear();
2362 CurrentCompressionExtension
= CompressionExtensions
.substr(0, nextExt
);
2363 CompressionExtensions
= CompressionExtensions
.substr(nextExt
+1);
2366 if (CurrentCompressionExtension
== "uncompressed")
2370 else if (unlikely(CurrentCompressionExtension
.empty()))
2374 Desc
.URI
= URI
+ '.' + CurrentCompressionExtension
;
2375 DestFile
= DestFile
+ '.' + CurrentCompressionExtension
;
2378 if(TransactionManager
->MetaIndexParser
!= NULL
)
2379 InitByHashIfNeeded();
2381 Desc
.Description
= URIDesc
;
2383 Desc
.ShortDesc
= ShortDesc
;
2388 // AcqIndex::AdjustForByHash - modify URI for by-hash support /*{{{*/
2389 void pkgAcqIndex::InitByHashIfNeeded()
2392 // - (maybe?) add support for by-hash into the sources.list as flag
2393 // - make apt-ftparchive generate the hashes (and expire?)
2394 std::string HostKnob
= "APT::Acquire::" + ::URI(Desc
.URI
).Host
+ "::By-Hash";
2395 if(_config
->FindB("APT::Acquire::By-Hash", false) == true ||
2396 _config
->FindB(HostKnob
, false) == true ||
2397 TransactionManager
->MetaIndexParser
->GetSupportsAcquireByHash())
2399 HashStringList
const Hashes
= GetExpectedHashes();
2402 // FIXME: should we really use the best hash here? or a fixed one?
2403 HashString
const * const TargetHash
= Hashes
.find("");
2404 std::string
const ByHash
= "/by-hash/" + TargetHash
->HashType() + "/" + TargetHash
->HashValue();
2405 size_t const trailing_slash
= Desc
.URI
.find_last_of("/");
2406 Desc
.URI
= Desc
.URI
.replace(
2408 Desc
.URI
.substr(trailing_slash
+1).size()+1,
2412 "Fetching ByHash requested but can not find record for %s",
2413 GetMetaKey().c_str());
2418 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
2419 // ---------------------------------------------------------------------
2420 /* The only header we use is the last-modified header. */
2421 string
pkgAcqIndex::Custom600Headers() const
2423 string Final
= GetFinalFilename();
2425 string msg
= "\nIndex-File: true";
2427 if (stat(Final
.c_str(),&Buf
) == 0)
2428 msg
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
2430 if(Target
.IsOptional
)
2431 msg
+= "\nFail-Ignore: true";
2436 // AcqIndex::Failed - getting the indexfile failed /*{{{*/
2437 void pkgAcqIndex::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)
2439 Item::Failed(Message
,Cnf
);
2441 // authorisation matches will not be fixed by other compression types
2442 if (Status
!= StatAuthError
)
2444 if (CompressionExtensions
.empty() == false)
2446 Init(Target
.URI
, Desc
.Description
, Desc
.ShortDesc
);
2452 if(Target
.IsOptional
&& GetExpectedHashes().empty() && Stage
== STAGE_DOWNLOAD
)
2455 TransactionManager
->AbortTransaction();
2458 // AcqIndex::ReverifyAfterIMS - Reverify index after an ims-hit /*{{{*/
2459 void pkgAcqIndex::ReverifyAfterIMS()
2461 // update destfile to *not* include the compression extension when doing
2462 // a reverify (as its uncompressed on disk already)
2463 DestFile
= GetCompressedFileName(Target
, GetPartialFileNameFromURI(Target
.URI
), CurrentCompressionExtension
);
2465 // copy FinalFile into partial/ so that we check the hash again
2466 string FinalFile
= GetFinalFilename();
2467 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
2468 Desc
.URI
= "copy:" + FinalFile
;
2472 // AcqIndex::Done - Finished a fetch /*{{{*/
2473 // ---------------------------------------------------------------------
2474 /* This goes through a number of states.. On the initial fetch the
2475 method could possibly return an alternate filename which points
2476 to the uncompressed version of the file. If this is so the file
2477 is copied into the partial directory. In all other cases the file
2478 is decompressed with a compressed uri. */
2479 void pkgAcqIndex::Done(string
const &Message
,
2480 HashStringList
const &Hashes
,
2481 pkgAcquire::MethodConfig
const * const Cfg
)
2483 Item::Done(Message
,Hashes
,Cfg
);
2487 case STAGE_DOWNLOAD
:
2488 StageDownloadDone(Message
, Hashes
, Cfg
);
2490 case STAGE_DECOMPRESS_AND_VERIFY
:
2491 StageDecompressDone(Message
, Hashes
, Cfg
);
2496 // AcqIndex::StageDownloadDone - Queue for decompress and verify /*{{{*/
2497 void pkgAcqIndex::StageDownloadDone(string
const &Message
, HashStringList
const &,
2498 pkgAcquire::MethodConfig
const * const)
2502 // Handle the unzipd case
2503 string FileName
= LookupTag(Message
,"Alt-Filename");
2504 if (FileName
.empty() == false)
2506 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
2508 DestFile
+= ".decomp";
2509 Desc
.URI
= "copy:" + FileName
;
2511 SetActiveSubprocess("copy");
2515 FileName
= LookupTag(Message
,"Filename");
2516 if (FileName
.empty() == true)
2519 ErrorText
= "Method gave a blank filename";
2522 // Methods like e.g. "file:" will give us a (compressed) FileName that is
2523 // not the "DestFile" we set, in this case we uncompress from the local file
2524 if (FileName
!= DestFile
&& RealFileExists(DestFile
) == false)
2527 EraseFileName
= FileName
;
2529 // we need to verify the file against the current Release file again
2530 // on if-modfied-since hit to avoid a stale attack against us
2531 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
2533 // The files timestamp matches, reverify by copy into partial/
2539 // If we want compressed indexes, just copy in place for hash verification
2540 if (Target
.KeepCompressed
== true)
2542 DestFile
= GetPartialFileNameFromURI(Target
.URI
+ '.' + CurrentCompressionExtension
);
2544 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
2545 Desc
.URI
= "copy:" + FileName
;
2547 SetActiveSubprocess("copy");
2551 // get the binary name for your used compression type
2553 if(CurrentCompressionExtension
== "uncompressed")
2554 decompProg
= "copy";
2556 decompProg
= _config
->Find(string("Acquire::CompressionTypes::").append(CurrentCompressionExtension
),"");
2557 if(decompProg
.empty() == true)
2559 _error
->Error("Unsupported extension: %s", CurrentCompressionExtension
.c_str());
2563 // queue uri for the next stage
2564 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
2565 DestFile
+= ".decomp";
2566 Desc
.URI
= decompProg
+ ":" + FileName
;
2568 SetActiveSubprocess(decompProg
);
2571 // AcqIndex::StageDecompressDone - Final verification /*{{{*/
2572 void pkgAcqIndex::StageDecompressDone(string
const &,
2573 HashStringList
const &,
2574 pkgAcquire::MethodConfig
const * const)
2576 // Done, queue for rename on transaction finished
2577 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
2581 pkgAcqIndex::~pkgAcqIndex() {}
2584 // AcqArchive::AcqArchive - Constructor /*{{{*/
2585 // ---------------------------------------------------------------------
2586 /* This just sets up the initial fetch environment and queues the first
2588 pkgAcqArchive::pkgAcqArchive(pkgAcquire
* const Owner
,pkgSourceList
* const Sources
,
2589 pkgRecords
* const Recs
,pkgCache::VerIterator
const &Version
,
2590 string
&StoreFilename
) :
2591 Item(Owner
), d(NULL
), LocalSource(false), Version(Version
), Sources(Sources
), Recs(Recs
),
2592 StoreFilename(StoreFilename
), Vf(Version
.FileList()),
2595 Retries
= _config
->FindI("Acquire::Retries",0);
2597 if (Version
.Arch() == 0)
2599 _error
->Error(_("I wasn't able to locate a file for the %s package. "
2600 "This might mean you need to manually fix this package. "
2601 "(due to missing arch)"),
2602 Version
.ParentPkg().FullName().c_str());
2606 /* We need to find a filename to determine the extension. We make the
2607 assumption here that all the available sources for this version share
2608 the same extension.. */
2609 // Skip not source sources, they do not have file fields.
2610 for (; Vf
.end() == false; ++Vf
)
2612 if (Vf
.File().Flagged(pkgCache::Flag::NotSource
))
2617 // Does not really matter here.. we are going to fail out below
2618 if (Vf
.end() != true)
2620 // If this fails to get a file name we will bomb out below.
2621 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2622 if (_error
->PendingError() == true)
2625 // Generate the final file name as: package_version_arch.foo
2626 StoreFilename
= QuoteString(Version
.ParentPkg().Name(),"_:") + '_' +
2627 QuoteString(Version
.VerStr(),"_:") + '_' +
2628 QuoteString(Version
.Arch(),"_:.") +
2629 "." + flExtension(Parse
.FileName());
2632 // check if we have one trusted source for the package. if so, switch
2633 // to "TrustedOnly" mode - but only if not in AllowUnauthenticated mode
2634 bool const allowUnauth
= _config
->FindB("APT::Get::AllowUnauthenticated", false);
2635 bool const debugAuth
= _config
->FindB("Debug::pkgAcquire::Auth", false);
2636 bool seenUntrusted
= false;
2637 for (pkgCache::VerFileIterator i
= Version
.FileList(); i
.end() == false; ++i
)
2639 pkgIndexFile
*Index
;
2640 if (Sources
->FindIndex(i
.File(),Index
) == false)
2643 if (debugAuth
== true)
2644 std::cerr
<< "Checking index: " << Index
->Describe()
2645 << "(Trusted=" << Index
->IsTrusted() << ")" << std::endl
;
2647 if (Index
->IsTrusted() == true)
2650 if (allowUnauth
== false)
2654 seenUntrusted
= true;
2657 // "allow-unauthenticated" restores apts old fetching behaviour
2658 // that means that e.g. unauthenticated file:// uris are higher
2659 // priority than authenticated http:// uris
2660 if (allowUnauth
== true && seenUntrusted
== true)
2664 if (QueueNext() == false && _error
->PendingError() == false)
2665 _error
->Error(_("Can't find a source to download version '%s' of '%s'"),
2666 Version
.VerStr(), Version
.ParentPkg().FullName(false).c_str());
2669 // AcqArchive::QueueNext - Queue the next file source /*{{{*/
2670 // ---------------------------------------------------------------------
2671 /* This queues the next available file version for download. It checks if
2672 the archive is already available in the cache and stashs the MD5 for
2674 bool pkgAcqArchive::QueueNext()
2676 for (; Vf
.end() == false; ++Vf
)
2678 pkgCache::PkgFileIterator
const PkgF
= Vf
.File();
2679 // Ignore not source sources
2680 if (PkgF
.Flagged(pkgCache::Flag::NotSource
))
2683 // Try to cross match against the source list
2684 pkgIndexFile
*Index
;
2685 if (Sources
->FindIndex(PkgF
, Index
) == false)
2687 LocalSource
= PkgF
.Flagged(pkgCache::Flag::LocalSource
);
2689 // only try to get a trusted package from another source if that source
2691 if(Trusted
&& !Index
->IsTrusted())
2694 // Grab the text package record
2695 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2696 if (_error
->PendingError() == true)
2699 string PkgFile
= Parse
.FileName();
2700 ExpectedHashes
= Parse
.Hashes();
2702 if (PkgFile
.empty() == true)
2703 return _error
->Error(_("The package index files are corrupted. No Filename: "
2704 "field for package %s."),
2705 Version
.ParentPkg().Name());
2707 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
2708 Desc
.Description
= Index
->ArchiveInfo(Version
);
2710 Desc
.ShortDesc
= Version
.ParentPkg().FullName(true);
2712 // See if we already have the file. (Legacy filenames)
2713 FileSize
= Version
->Size
;
2714 string FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile
);
2716 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2718 // Make sure the size matches
2719 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2724 StoreFilename
= DestFile
= FinalFile
;
2728 /* Hmm, we have a file and its size does not match, this means it is
2729 an old style mismatched arch */
2730 unlink(FinalFile
.c_str());
2733 // Check it again using the new style output filenames
2734 FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
2735 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2737 // Make sure the size matches
2738 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2743 StoreFilename
= DestFile
= FinalFile
;
2747 /* Hmm, we have a file and its size does not match, this shouldn't
2749 unlink(FinalFile
.c_str());
2752 DestFile
= _config
->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename
);
2754 // Check the destination file
2755 if (stat(DestFile
.c_str(),&Buf
) == 0)
2757 // Hmm, the partial file is too big, erase it
2758 if ((unsigned long long)Buf
.st_size
> Version
->Size
)
2759 unlink(DestFile
.c_str());
2761 PartialSize
= Buf
.st_size
;
2764 // Disables download of archives - useful if no real installation follows,
2765 // e.g. if we are just interested in proposed installation order
2766 if (_config
->FindB("Debug::pkgAcqArchive::NoQueue", false) == true)
2771 StoreFilename
= DestFile
= FinalFile
;
2785 // AcqArchive::Done - Finished fetching /*{{{*/
2786 // ---------------------------------------------------------------------
2788 void pkgAcqArchive::Done(string
const &Message
, HashStringList
const &Hashes
,
2789 pkgAcquire::MethodConfig
const * const Cfg
)
2791 Item::Done(Message
, Hashes
, Cfg
);
2793 // Grab the output filename
2794 string FileName
= LookupTag(Message
,"Filename");
2795 if (FileName
.empty() == true)
2798 ErrorText
= "Method gave a blank filename";
2802 // Reference filename
2803 if (DestFile
!= FileName
&& RealFileExists(DestFile
) == false)
2805 StoreFilename
= DestFile
= FileName
;
2811 // Done, move it into position
2812 string
const FinalFile
= GetFinalFilename();
2813 Rename(DestFile
,FinalFile
);
2814 StoreFilename
= DestFile
= FinalFile
;
2818 // AcqArchive::Failed - Failure handler /*{{{*/
2819 // ---------------------------------------------------------------------
2820 /* Here we try other sources */
2821 void pkgAcqArchive::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)
2823 Item::Failed(Message
,Cnf
);
2825 /* We don't really want to retry on failed media swaps, this prevents
2826 that. An interesting observation is that permanent failures are not
2828 if (Cnf
->Removable
== true &&
2829 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2831 // Vf = Version.FileList();
2832 while (Vf
.end() == false) ++Vf
;
2833 StoreFilename
= string();
2838 if (QueueNext() == false)
2840 // This is the retry counter
2842 Cnf
->LocalOnly
== false &&
2843 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2846 Vf
= Version
.FileList();
2847 if (QueueNext() == true)
2851 StoreFilename
= string();
2856 APT_PURE
bool pkgAcqArchive::IsTrusted() const /*{{{*/
2861 void pkgAcqArchive::Finished() /*{{{*/
2863 if (Status
== pkgAcquire::Item::StatDone
&&
2866 StoreFilename
= string();
2869 std::string
pkgAcqArchive::DescURI() const /*{{{*/
2874 std::string
pkgAcqArchive::ShortDesc() const /*{{{*/
2876 return Desc
.ShortDesc
;
2879 pkgAcqArchive::~pkgAcqArchive() {}
2881 // AcqChangelog::pkgAcqChangelog - Constructors /*{{{*/
2882 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire
* const Owner
, pkgCache::VerIterator
const &Ver
,
2883 std::string
const &DestDir
, std::string
const &DestFilename
) :
2884 pkgAcquire::Item(Owner
), d(NULL
), SrcName(Ver
.SourcePkgName()), SrcVersion(Ver
.SourceVerStr())
2886 Desc
.URI
= URI(Ver
);
2887 Init(DestDir
, DestFilename
);
2889 // some parameters are char* here as they come likely from char* interfaces – which can also return NULL
2890 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire
* const Owner
, pkgCache::RlsFileIterator
const &RlsFile
,
2891 char const * const Component
, char const * const SrcName
, char const * const SrcVersion
,
2892 const string
&DestDir
, const string
&DestFilename
) :
2893 pkgAcquire::Item(Owner
), d(NULL
), SrcName(SrcName
), SrcVersion(SrcVersion
)
2895 Desc
.URI
= URI(RlsFile
, Component
, SrcName
, SrcVersion
);
2896 Init(DestDir
, DestFilename
);
2898 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire
* const Owner
,
2899 std::string
const &URI
, char const * const SrcName
, char const * const SrcVersion
,
2900 const string
&DestDir
, const string
&DestFilename
) :
2901 pkgAcquire::Item(Owner
), d(NULL
), SrcName(SrcName
), SrcVersion(SrcVersion
)
2904 Init(DestDir
, DestFilename
);
2906 void pkgAcqChangelog::Init(std::string
const &DestDir
, std::string
const &DestFilename
)
2908 if (Desc
.URI
.empty())
2911 // TRANSLATOR: %s=%s is sourcename=sourceversion, e.g. apt=1.1
2912 strprintf(ErrorText
, _("Changelog unavailable for %s=%s"), SrcName
.c_str(), SrcVersion
.c_str());
2913 // Let the error message print something sensible rather than "Failed to fetch /"
2914 if (DestFilename
.empty())
2915 DestFile
= SrcName
+ ".changelog";
2917 DestFile
= DestFilename
;
2918 Desc
.URI
= "changelog:/" + DestFile
;
2922 if (DestDir
.empty())
2924 std::string
const systemTemp
= GetTempDir();
2926 snprintf(tmpname
, sizeof(tmpname
), "%s/apt-changelog-XXXXXX", systemTemp
.c_str());
2927 if (NULL
== mkdtemp(tmpname
))
2929 _error
->Errno("mkdtemp", "mkdtemp failed in changelog acquire of %s %s", SrcName
.c_str(), SrcVersion
.c_str());
2933 DestFile
= TemporaryDirectory
= tmpname
;
2938 if (DestFilename
.empty())
2939 DestFile
= flCombine(DestFile
, SrcName
+ ".changelog");
2941 DestFile
= flCombine(DestFile
, DestFilename
);
2943 Desc
.ShortDesc
= "Changelog";
2944 strprintf(Desc
.Description
, "%s %s %s Changelog", URI::SiteOnly(Desc
.URI
).c_str(), SrcName
.c_str(), SrcVersion
.c_str());
2949 std::string
pkgAcqChangelog::URI(pkgCache::VerIterator
const &Ver
) /*{{{*/
2951 char const * const SrcName
= Ver
.SourcePkgName();
2952 char const * const SrcVersion
= Ver
.SourceVerStr();
2953 pkgCache::PkgFileIterator PkgFile
;
2954 // find the first source for this version which promises a changelog
2955 for (pkgCache::VerFileIterator VF
= Ver
.FileList(); VF
.end() == false; ++VF
)
2957 pkgCache::PkgFileIterator
const PF
= VF
.File();
2958 if (PF
.Flagged(pkgCache::Flag::NotSource
) || PF
->Release
== 0)
2961 pkgCache::RlsFileIterator
const RF
= PF
.ReleaseFile();
2962 std::string
const uri
= URI(RF
, PF
.Component(), SrcName
, SrcVersion
);
2969 std::string
pkgAcqChangelog::URITemplate(pkgCache::RlsFileIterator
const &Rls
)
2971 if (Rls
.end() == true || (Rls
->Label
== 0 && Rls
->Origin
== 0))
2973 std::string
const serverConfig
= "Acquire::Changelogs::URI";
2975 #define APT_EMPTY_SERVER \
2976 if (server.empty() == false) \
2978 if (server != "no") \
2982 #define APT_CHECK_SERVER(X, Y) \
2985 std::string const specialServerConfig = serverConfig + "::" + Y + #X + "::" + Rls.X(); \
2986 server = _config->Find(specialServerConfig); \
2989 // this way e.g. Debian-Security can fallback to Debian
2990 APT_CHECK_SERVER(Label
, "Override::")
2991 APT_CHECK_SERVER(Origin
, "Override::")
2993 if (RealFileExists(Rls
.FileName()))
2995 _error
->PushToStack();
2997 /* This can be costly. A caller wanting to get millions of URIs might
2998 want to do this on its own once and use Override settings.
2999 We don't do this here as Origin/Label are not as unique as they
3000 should be so this could produce request order-dependent anomalies */
3001 if (OpenMaybeClearSignedFile(Rls
.FileName(), rf
) == true)
3003 pkgTagFile
TagFile(&rf
, rf
.Size());
3004 pkgTagSection Section
;
3005 if (TagFile
.Step(Section
) == true)
3006 server
= Section
.FindS("Changelogs");
3008 _error
->RevertToStack();
3012 APT_CHECK_SERVER(Label
, "")
3013 APT_CHECK_SERVER(Origin
, "")
3014 #undef APT_CHECK_SERVER
3015 #undef APT_EMPTY_SERVER
3018 std::string
pkgAcqChangelog::URI(pkgCache::RlsFileIterator
const &Rls
,
3019 char const * const Component
, char const * const SrcName
,
3020 char const * const SrcVersion
)
3022 return URI(URITemplate(Rls
), Component
, SrcName
, SrcVersion
);
3024 std::string
pkgAcqChangelog::URI(std::string
const &Template
,
3025 char const * const Component
, char const * const SrcName
,
3026 char const * const SrcVersion
)
3028 if (Template
.find("CHANGEPATH") == std::string::npos
)
3031 // the path is: COMPONENT/SRC/SRCNAME/SRCNAME_SRCVER, e.g. main/a/apt/1.1 or contrib/liba/libapt/2.0
3032 std::string Src
= SrcName
;
3033 std::string path
= APT::String::Startswith(SrcName
, "lib") ? Src
.substr(0, 4) : Src
.substr(0,1);
3034 path
.append("/").append(Src
).append("/");
3035 path
.append(Src
).append("_").append(StripEpoch(SrcVersion
));
3036 // we omit component for releases without one (= flat-style repositories)
3037 if (Component
!= NULL
&& strlen(Component
) != 0)
3038 path
= std::string(Component
) + "/" + path
;
3040 return SubstVar(Template
, "CHANGEPATH", path
);
3043 // AcqChangelog::Failed - Failure handler /*{{{*/
3044 void pkgAcqChangelog::Failed(string
const &Message
, pkgAcquire::MethodConfig
const * const Cnf
)
3046 Item::Failed(Message
,Cnf
);
3048 std::string errText
;
3049 // TRANSLATOR: %s=%s is sourcename=sourceversion, e.g. apt=1.1
3050 strprintf(errText
, _("Changelog unavailable for %s=%s"), SrcName
.c_str(), SrcVersion
.c_str());
3052 // Error is probably something techy like 404 Not Found
3053 if (ErrorText
.empty())
3054 ErrorText
= errText
;
3056 ErrorText
= errText
+ " (" + ErrorText
+ ")";
3060 // AcqChangelog::Done - Item downloaded OK /*{{{*/
3061 void pkgAcqChangelog::Done(string
const &Message
,HashStringList
const &CalcHashes
,
3062 pkgAcquire::MethodConfig
const * const Cnf
)
3064 Item::Done(Message
,CalcHashes
,Cnf
);
3069 pkgAcqChangelog::~pkgAcqChangelog() /*{{{*/
3071 if (TemporaryDirectory
.empty() == false)
3073 unlink(DestFile
.c_str());
3074 rmdir(TemporaryDirectory
.c_str());
3079 // AcqFile::pkgAcqFile - Constructor /*{{{*/
3080 pkgAcqFile::pkgAcqFile(pkgAcquire
* const Owner
,string
const &URI
, HashStringList
const &Hashes
,
3081 unsigned long long const Size
,string
const &Dsc
,string
const &ShortDesc
,
3082 const string
&DestDir
, const string
&DestFilename
,
3083 bool const IsIndexFile
) :
3084 Item(Owner
), d(NULL
), IsIndexFile(IsIndexFile
), ExpectedHashes(Hashes
)
3086 Retries
= _config
->FindI("Acquire::Retries",0);
3088 if(!DestFilename
.empty())
3089 DestFile
= DestFilename
;
3090 else if(!DestDir
.empty())
3091 DestFile
= DestDir
+ "/" + flNotDir(URI
);
3093 DestFile
= flNotDir(URI
);
3097 Desc
.Description
= Dsc
;
3100 // Set the short description to the archive component
3101 Desc
.ShortDesc
= ShortDesc
;
3103 // Get the transfer sizes
3106 if (stat(DestFile
.c_str(),&Buf
) == 0)
3108 // Hmm, the partial file is too big, erase it
3109 if ((Size
> 0) && (unsigned long long)Buf
.st_size
> Size
)
3110 unlink(DestFile
.c_str());
3112 PartialSize
= Buf
.st_size
;
3118 // AcqFile::Done - Item downloaded OK /*{{{*/
3119 void pkgAcqFile::Done(string
const &Message
,HashStringList
const &CalcHashes
,
3120 pkgAcquire::MethodConfig
const * const Cnf
)
3122 Item::Done(Message
,CalcHashes
,Cnf
);
3124 string FileName
= LookupTag(Message
,"Filename");
3125 if (FileName
.empty() == true)
3128 ErrorText
= "Method gave a blank filename";
3134 // The files timestamp matches
3135 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
3138 // We have to copy it into place
3139 if (RealFileExists(DestFile
.c_str()) == false)
3142 if (_config
->FindB("Acquire::Source-Symlinks",true) == false ||
3143 Cnf
->Removable
== true)
3145 Desc
.URI
= "copy:" + FileName
;
3150 // Erase the file if it is a symlink so we can overwrite it
3152 if (lstat(DestFile
.c_str(),&St
) == 0)
3154 if (S_ISLNK(St
.st_mode
) != 0)
3155 unlink(DestFile
.c_str());
3159 if (symlink(FileName
.c_str(),DestFile
.c_str()) != 0)
3161 _error
->PushToStack();
3162 _error
->Errno("pkgAcqFile::Done", "Symlinking file %s failed", DestFile
.c_str());
3163 std::stringstream msg
;
3164 _error
->DumpErrors(msg
);
3165 _error
->RevertToStack();
3166 ErrorText
= msg
.str();
3173 // AcqFile::Failed - Failure handler /*{{{*/
3174 // ---------------------------------------------------------------------
3175 /* Here we try other sources */
3176 void pkgAcqFile::Failed(string
const &Message
, pkgAcquire::MethodConfig
const * const Cnf
)
3178 Item::Failed(Message
,Cnf
);
3180 // This is the retry counter
3182 Cnf
->LocalOnly
== false &&
3183 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
3193 string
pkgAcqFile::Custom600Headers() const /*{{{*/
3196 return "\nIndex-File: true";
3200 pkgAcqFile::~pkgAcqFile() {}