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(std::string
const &URI
, 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 (URI
.substr(0,6) == "cdrom:")
93 // adjust DestFile if its compressed on disk
94 if (_config
->FindB("Acquire::GzipIndexes",false) == 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
.URI
, 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 {return Target
.URI
;};
395 virtual HashStringList
GetExpectedHashes() const {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 UsedMirror
= LookupTag(Message
,"UsedMirror");
461 if (QueueCounter
<= 1)
463 /* This indicates that the file is not available right now but might
464 be sometime later. If we do a retry cycle then this should be
466 if (Cnf
!= NULL
&& Cnf
->LocalOnly
== true &&
467 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
483 case StatTransientNetworkError
:
490 string
const FailReason
= LookupTag(Message
, "FailReason");
491 if (FailReason
== "MaximumSizeExceeded")
492 RenameOnError(MaximumSizeExceeded
);
493 else if (Status
== StatAuthError
)
494 RenameOnError(HashSumMismatch
);
496 // report mirror failure back to LP if we actually use a mirror
497 if (FailReason
.empty() == false)
498 ReportMirrorFailure(FailReason
);
500 ReportMirrorFailure(ErrorText
);
502 if (QueueCounter
> 1)
506 // Acquire::Item::Start - Item has begun to download /*{{{*/
507 // ---------------------------------------------------------------------
508 /* Stash status and the file size. Note that setting Complete means
509 sub-phases of the acquire process such as decompresion are operating */
510 void pkgAcquire::Item::Start(string
const &/*Message*/, unsigned long long const Size
)
512 Status
= StatFetching
;
514 if (FileSize
== 0 && Complete
== false)
518 // Acquire::Item::Done - Item downloaded OK /*{{{*/
519 void pkgAcquire::Item::Done(string
const &Message
, HashStringList
const &Hashes
,
520 pkgAcquire::MethodConfig
const * const /*Cnf*/)
522 // We just downloaded something..
523 UsedMirror
= LookupTag(Message
,"UsedMirror");
526 unsigned long long const downloadedSize
= Hashes
.FileSize();
527 if (downloadedSize
!= 0)
529 FileSize
= downloadedSize
;
533 ErrorText
= string();
534 Owner
->Dequeue(this);
537 // Acquire::Item::Rename - Rename a file /*{{{*/
538 // ---------------------------------------------------------------------
539 /* This helper function is used by a lot of item methods as their final
541 bool pkgAcquire::Item::Rename(string
const &From
,string
const &To
)
543 if (From
== To
|| rename(From
.c_str(),To
.c_str()) == 0)
547 strprintf(S
, _("rename failed, %s (%s -> %s)."), strerror(errno
),
548 From
.c_str(),To
.c_str());
550 if (ErrorText
.empty())
553 ErrorText
= ErrorText
+ ": " + S
;
557 void pkgAcquire::Item::Dequeue() /*{{{*/
559 Owner
->Dequeue(this);
562 bool pkgAcquire::Item::RenameOnError(pkgAcquire::Item::RenameOnErrorState
const error
)/*{{{*/
564 if (RealFileExists(DestFile
))
565 Rename(DestFile
, DestFile
+ ".FAILED");
570 case HashSumMismatch
:
571 errtext
= _("Hash Sum mismatch");
572 Status
= StatAuthError
;
573 ReportMirrorFailure("HashChecksumFailure");
576 errtext
= _("Size mismatch");
577 Status
= StatAuthError
;
578 ReportMirrorFailure("SizeFailure");
581 errtext
= _("Invalid file format");
583 // do not report as usually its not the mirrors fault, but Portal/Proxy
586 errtext
= _("Signature error");
590 errtext
= _("Does not start with a cleartext signature");
593 case MaximumSizeExceeded
:
594 // the method is expected to report a good error for this
598 // no handling here, done by callers
601 if (ErrorText
.empty())
606 void pkgAcquire::Item::SetActiveSubprocess(const std::string
&subprocess
)/*{{{*/
608 ActiveSubprocess
= subprocess
;
609 APT_IGNORE_DEPRECATED(Mode
= ActiveSubprocess
.c_str();)
612 // Acquire::Item::ReportMirrorFailure /*{{{*/
613 void pkgAcquire::Item::ReportMirrorFailure(string
const &FailCode
)
615 // we only act if a mirror was used at all
616 if(UsedMirror
.empty())
619 std::cerr
<< "\nReportMirrorFailure: "
621 << " Uri: " << DescURI()
623 << FailCode
<< std::endl
;
625 string report
= _config
->Find("Methods::Mirror::ProblemReporting",
626 "/usr/lib/apt/apt-report-mirror-failure");
627 if(!FileExists(report
))
630 std::vector
<char const*> Args
;
631 Args
.push_back(report
.c_str());
632 Args
.push_back(UsedMirror
.c_str());
633 Args
.push_back(DescURI().c_str());
634 Args
.push_back(FailCode
.c_str());
635 Args
.push_back(NULL
);
637 pid_t pid
= ExecFork();
640 _error
->Error("ReportMirrorFailure Fork failed");
645 execvp(Args
[0], (char**)Args
.data());
646 std::cerr
<< "Could not exec " << Args
[0] << std::endl
;
649 if(!ExecWait(pid
, "report-mirror-failure"))
651 _error
->Warning("Couldn't report problem to '%s'",
652 _config
->Find("Methods::Mirror::ProblemReporting").c_str());
656 std::string
pkgAcquire::Item::HashSum() const /*{{{*/
658 HashStringList
const hashes
= GetExpectedHashes();
659 HashString
const * const hs
= hashes
.find(NULL
);
660 return hs
!= NULL
? hs
->toStr() : "";
664 pkgAcqTransactionItem::pkgAcqTransactionItem(pkgAcquire
* const Owner
, /*{{{*/
665 pkgAcqMetaClearSig
* const transactionManager
, IndexTarget
const &target
) :
666 pkgAcquire::Item(Owner
), d(NULL
), Target(target
), TransactionManager(transactionManager
)
668 if (TransactionManager
!= this)
669 TransactionManager
->Add(this);
672 pkgAcqTransactionItem::~pkgAcqTransactionItem() /*{{{*/
676 HashStringList
pkgAcqTransactionItem::GetExpectedHashesFor(std::string
const &MetaKey
) const /*{{{*/
678 return GetExpectedHashesFromFor(TransactionManager
->MetaIndexParser
, MetaKey
);
682 // AcqMetaBase - Constructor /*{{{*/
683 pkgAcqMetaBase::pkgAcqMetaBase(pkgAcquire
* const Owner
,
684 pkgAcqMetaClearSig
* const TransactionManager
,
685 std::vector
<IndexTarget
> const &IndexTargets
,
686 IndexTarget
const &DataTarget
)
687 : pkgAcqTransactionItem(Owner
, TransactionManager
, DataTarget
), d(NULL
),
688 IndexTargets(IndexTargets
),
689 AuthPass(false), IMSHit(false)
693 // AcqMetaBase::Add - Add a item to the current Transaction /*{{{*/
694 void pkgAcqMetaBase::Add(pkgAcqTransactionItem
* const I
)
696 Transaction
.push_back(I
);
699 // AcqMetaBase::AbortTransaction - Abort the current Transaction /*{{{*/
700 void pkgAcqMetaBase::AbortTransaction()
702 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
703 std::clog
<< "AbortTransaction: " << TransactionManager
<< std::endl
;
705 // ensure the toplevel is in error state too
706 for (std::vector
<pkgAcqTransactionItem
*>::iterator I
= Transaction
.begin();
707 I
!= Transaction
.end(); ++I
)
709 (*I
)->TransactionState(TransactionAbort
);
714 // AcqMetaBase::TransactionHasError - Check for errors in Transaction /*{{{*/
715 APT_PURE
bool pkgAcqMetaBase::TransactionHasError() const
717 for (std::vector
<pkgAcqTransactionItem
*>::const_iterator I
= Transaction
.begin();
718 I
!= Transaction
.end(); ++I
)
720 switch((*I
)->Status
) {
721 case StatDone
: break;
722 case StatIdle
: break;
723 case StatAuthError
: return true;
724 case StatError
: return true;
725 case StatTransientNetworkError
: return true;
726 case StatFetching
: break;
732 // AcqMetaBase::CommitTransaction - Commit a transaction /*{{{*/
733 void pkgAcqMetaBase::CommitTransaction()
735 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
736 std::clog
<< "CommitTransaction: " << this << std::endl
;
738 // move new files into place *and* remove files that are not
739 // part of the transaction but are still on disk
740 for (std::vector
<pkgAcqTransactionItem
*>::iterator I
= Transaction
.begin();
741 I
!= Transaction
.end(); ++I
)
743 (*I
)->TransactionState(TransactionCommit
);
748 // AcqMetaBase::TransactionStageCopy - Stage a file for copying /*{{{*/
749 void pkgAcqMetaBase::TransactionStageCopy(pkgAcqTransactionItem
* const I
,
750 const std::string
&From
,
751 const std::string
&To
)
753 I
->PartialFile
= From
;
757 // AcqMetaBase::TransactionStageRemoval - Stage a file for removal /*{{{*/
758 void pkgAcqMetaBase::TransactionStageRemoval(pkgAcqTransactionItem
* const I
,
759 const std::string
&FinalFile
)
762 I
->DestFile
= FinalFile
;
765 // AcqMetaBase::GenerateAuthWarning - Check gpg authentication error /*{{{*/
766 bool pkgAcqMetaBase::CheckStopAuthentication(pkgAcquire::Item
* const I
, const std::string
&Message
)
768 // FIXME: this entire function can do now that we disallow going to
769 // a unauthenticated state and can cleanly rollback
771 string
const Final
= I
->GetFinalFilename();
772 if(FileExists(Final
))
774 I
->Status
= StatTransientNetworkError
;
775 _error
->Warning(_("An error occurred during the signature "
776 "verification. The repository is not updated "
777 "and the previous index files will be used. "
778 "GPG error: %s: %s\n"),
779 Desc
.Description
.c_str(),
780 LookupTag(Message
,"Message").c_str());
781 RunScripts("APT::Update::Auth-Failure");
783 } else if (LookupTag(Message
,"Message").find("NODATA") != string::npos
) {
784 /* Invalid signature file, reject (LP: #346386) (Closes: #627642) */
785 _error
->Error(_("GPG error: %s: %s"),
786 Desc
.Description
.c_str(),
787 LookupTag(Message
,"Message").c_str());
788 I
->Status
= StatError
;
791 _error
->Warning(_("GPG error: %s: %s"),
792 Desc
.Description
.c_str(),
793 LookupTag(Message
,"Message").c_str());
795 // gpgv method failed
796 ReportMirrorFailure("GPGFailure");
800 // AcqMetaBase::Custom600Headers - Get header for AcqMetaBase /*{{{*/
801 // ---------------------------------------------------------------------
802 string
pkgAcqMetaBase::Custom600Headers() const
804 std::string Header
= "\nIndex-File: true";
805 std::string MaximumSize
;
806 strprintf(MaximumSize
, "\nMaximum-Size: %i",
807 _config
->FindI("Acquire::MaxReleaseFileSize", 10*1000*1000));
808 Header
+= MaximumSize
;
810 string
const FinalFile
= GetFinalFilename();
812 if (stat(FinalFile
.c_str(),&Buf
) == 0)
813 Header
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
818 // AcqMetaBase::QueueForSignatureVerify /*{{{*/
819 void pkgAcqMetaBase::QueueForSignatureVerify(pkgAcqTransactionItem
* const I
, std::string
const &File
, std::string
const &Signature
)
822 I
->Desc
.URI
= "gpgv:" + Signature
;
825 I
->SetActiveSubprocess("gpgv");
828 // AcqMetaBase::CheckDownloadDone /*{{{*/
829 bool pkgAcqMetaBase::CheckDownloadDone(pkgAcqTransactionItem
* const I
, const std::string
&Message
, HashStringList
const &Hashes
) const
831 // We have just finished downloading a Release file (it is not
834 string
const FileName
= LookupTag(Message
,"Filename");
835 if (FileName
.empty() == true)
837 I
->Status
= StatError
;
838 I
->ErrorText
= "Method gave a blank filename";
842 if (FileName
!= I
->DestFile
&& RealFileExists(I
->DestFile
) == false)
845 I
->Desc
.URI
= "copy:" + FileName
;
846 I
->QueueURI(I
->Desc
);
850 // make sure to verify against the right file on I-M-S hit
851 bool IMSHit
= StringToBool(LookupTag(Message
,"IMS-Hit"), false);
852 if (IMSHit
== false && Hashes
.usable())
854 // detect IMS-Hits servers haven't detected by Hash comparison
855 std::string
const FinalFile
= I
->GetFinalFilename();
856 if (RealFileExists(FinalFile
) && Hashes
.VerifyFile(FinalFile
) == true)
859 unlink(I
->DestFile
.c_str());
865 // for simplicity, the transaction manager is always InRelease
866 // even if it doesn't exist.
867 if (TransactionManager
!= NULL
)
868 TransactionManager
->IMSHit
= true;
869 I
->PartialFile
= I
->DestFile
= I
->GetFinalFilename();
872 // set Item to complete as the remaining work is all local (verify etc)
878 bool pkgAcqMetaBase::CheckAuthDone(string
const &Message
) /*{{{*/
880 // At this point, the gpgv method has succeeded, so there is a
881 // valid signature from a key in the trusted keyring. We
882 // perform additional verification of its contents, and use them
883 // to verify the indexes we are about to download
885 if (TransactionManager
->IMSHit
== false)
887 // open the last (In)Release if we have it
888 std::string
const FinalFile
= GetFinalFilename();
889 std::string FinalRelease
;
890 std::string FinalInRelease
;
891 if (APT::String::Endswith(FinalFile
, "InRelease"))
893 FinalInRelease
= FinalFile
;
894 FinalRelease
= FinalFile
.substr(0, FinalFile
.length() - strlen("InRelease")) + "Release";
898 FinalInRelease
= FinalFile
.substr(0, FinalFile
.length() - strlen("Release")) + "InRelease";
899 FinalRelease
= FinalFile
;
901 if (RealFileExists(FinalInRelease
) || RealFileExists(FinalRelease
))
903 TransactionManager
->LastMetaIndexParser
= TransactionManager
->MetaIndexParser
->UnloadedClone();
904 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
906 _error
->PushToStack();
907 if (RealFileExists(FinalInRelease
))
908 TransactionManager
->LastMetaIndexParser
->Load(FinalInRelease
, NULL
);
910 TransactionManager
->LastMetaIndexParser
->Load(FinalRelease
, NULL
);
911 // its unlikely to happen, but if what we have is bad ignore it
912 if (_error
->PendingError())
914 delete TransactionManager
->LastMetaIndexParser
;
915 TransactionManager
->LastMetaIndexParser
= NULL
;
917 _error
->RevertToStack();
922 if (TransactionManager
->MetaIndexParser
->Load(DestFile
, &ErrorText
) == false)
924 Status
= StatAuthError
;
928 if (!VerifyVendor(Message
))
930 Status
= StatAuthError
;
934 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
935 std::cerr
<< "Signature verification succeeded: "
936 << DestFile
<< std::endl
;
938 // Download further indexes with verification
944 void pkgAcqMetaBase::QueueIndexes(bool const verify
) /*{{{*/
946 // at this point the real Items are loaded in the fetcher
947 ExpectedAdditionalItems
= 0;
949 for (std::vector
<IndexTarget
>::const_iterator Target
= IndexTargets
.begin();
950 Target
!= IndexTargets
.end();
953 bool trypdiff
= _config
->FindB("Acquire::PDiffs", true);
956 if (TransactionManager
->MetaIndexParser
->Exists(Target
->MetaKey
) == false)
958 // optional targets that we do not have in the Release file are skipped
959 if (Target
->IsOptional
)
962 Status
= StatAuthError
;
963 strprintf(ErrorText
, _("Unable to find expected entry '%s' in Release file (Wrong sources.list entry or malformed file)"), Target
->MetaKey
.c_str());
967 if (RealFileExists(GetFinalFileNameFromURI(Target
->URI
)))
969 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
971 HashStringList
const newFile
= GetExpectedHashesFromFor(TransactionManager
->MetaIndexParser
, Target
->MetaKey
);
972 HashStringList
const oldFile
= GetExpectedHashesFromFor(TransactionManager
->LastMetaIndexParser
, Target
->MetaKey
);
973 if (newFile
== oldFile
)
975 // we have the file already, no point in trying to acquire it again
976 new NoActionItem(Owner
, *Target
);
982 trypdiff
= false; // no file to patch
984 // check if we have patches available
985 trypdiff
&= TransactionManager
->MetaIndexParser
->Exists(Target
->MetaKey
+ ".diff/Index");
987 // if we have no file to patch, no point in trying
988 trypdiff
&= RealFileExists(GetFinalFileNameFromURI(Target
->URI
));
990 // no point in patching from local sources
993 std::string
const proto
= Target
->URI
.substr(0, strlen("file:/"));
994 if (proto
== "file:/" || proto
== "copy:/" || proto
== "cdrom:")
998 // Queue the Index file (Packages, Sources, Translation-$foo, …)
1000 new pkgAcqDiffIndex(Owner
, TransactionManager
, *Target
);
1002 new pkgAcqIndex(Owner
, TransactionManager
, *Target
);
1006 bool pkgAcqMetaBase::VerifyVendor(string
const &Message
) /*{{{*/
1008 string::size_type pos
;
1010 // check for missing sigs (that where not fatal because otherwise we had
1013 string msg
= _("There is no public key available for the "
1014 "following key IDs:\n");
1015 pos
= Message
.find("NO_PUBKEY ");
1016 if (pos
!= std::string::npos
)
1018 string::size_type start
= pos
+strlen("NO_PUBKEY ");
1019 string Fingerprint
= Message
.substr(start
, Message
.find("\n")-start
);
1020 missingkeys
+= (Fingerprint
);
1022 if(!missingkeys
.empty())
1023 _error
->Warning("%s", (msg
+ missingkeys
).c_str());
1025 string Transformed
= TransactionManager
->MetaIndexParser
->GetExpectedDist();
1027 if (Transformed
== "../project/experimental")
1029 Transformed
= "experimental";
1032 pos
= Transformed
.rfind('/');
1033 if (pos
!= string::npos
)
1035 Transformed
= Transformed
.substr(0, pos
);
1038 if (Transformed
== ".")
1043 if (TransactionManager
->MetaIndexParser
->GetValidUntil() > 0)
1045 time_t const invalid_since
= time(NULL
) - TransactionManager
->MetaIndexParser
->GetValidUntil();
1046 if (invalid_since
> 0)
1050 // TRANSLATOR: The first %s is the URL of the bad Release file, the second is
1051 // the time since then the file is invalid - formatted in the same way as in
1052 // the download progress display (e.g. 7d 3h 42min 1s)
1053 _("Release file for %s is expired (invalid since %s). "
1054 "Updates for this repository will not be applied."),
1055 Target
.URI
.c_str(), TimeToStr(invalid_since
).c_str());
1056 if (ErrorText
.empty())
1058 return _error
->Error("%s", errmsg
.c_str());
1062 /* Did we get a file older than what we have? This is a last minute IMS hit and doubles
1063 as a prevention of downgrading us to older (still valid) files */
1064 if (TransactionManager
->IMSHit
== false && TransactionManager
->LastMetaIndexParser
!= NULL
&&
1065 TransactionManager
->LastMetaIndexParser
->GetDate() > TransactionManager
->MetaIndexParser
->GetDate())
1067 TransactionManager
->IMSHit
= true;
1068 unlink(DestFile
.c_str());
1069 PartialFile
= DestFile
= GetFinalFilename();
1070 // load the 'old' file in the 'new' one instead of flipping pointers as
1071 // the new one isn't owned by us, while the old one is so cleanup would be confused.
1072 TransactionManager
->MetaIndexParser
->swapLoad(TransactionManager
->LastMetaIndexParser
);
1073 delete TransactionManager
->LastMetaIndexParser
;
1074 TransactionManager
->LastMetaIndexParser
= NULL
;
1077 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1079 std::cerr
<< "Got Codename: " << TransactionManager
->MetaIndexParser
->GetCodename() << std::endl
;
1080 std::cerr
<< "Expecting Dist: " << TransactionManager
->MetaIndexParser
->GetExpectedDist() << std::endl
;
1081 std::cerr
<< "Transformed Dist: " << Transformed
<< std::endl
;
1084 if (TransactionManager
->MetaIndexParser
->CheckDist(Transformed
) == false)
1086 // This might become fatal one day
1087 // Status = StatAuthError;
1088 // ErrorText = "Conflicting distribution; expected "
1089 // + MetaIndexParser->GetExpectedDist() + " but got "
1090 // + MetaIndexParser->GetCodename();
1092 if (!Transformed
.empty())
1094 _error
->Warning(_("Conflicting distribution: %s (expected %s but got %s)"),
1095 Desc
.Description
.c_str(),
1096 Transformed
.c_str(),
1097 TransactionManager
->MetaIndexParser
->GetCodename().c_str());
1104 pkgAcqMetaBase::~pkgAcqMetaBase()
1108 pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire
* const Owner
, /*{{{*/
1109 IndexTarget
const &ClearsignedTarget
,
1110 IndexTarget
const &DetachedDataTarget
, IndexTarget
const &DetachedSigTarget
,
1111 std::vector
<IndexTarget
> const &IndexTargets
,
1112 metaIndex
* const MetaIndexParser
) :
1113 pkgAcqMetaIndex(Owner
, this, ClearsignedTarget
, DetachedSigTarget
, IndexTargets
),
1114 d(NULL
), ClearsignedTarget(ClearsignedTarget
),
1115 DetachedDataTarget(DetachedDataTarget
),
1116 MetaIndexParser(MetaIndexParser
), LastMetaIndexParser(NULL
)
1118 // index targets + (worst case:) Release/Release.gpg
1119 ExpectedAdditionalItems
= IndexTargets
.size() + 2;
1120 TransactionManager
->Add(this);
1123 pkgAcqMetaClearSig::~pkgAcqMetaClearSig() /*{{{*/
1125 if (LastMetaIndexParser
!= NULL
)
1126 delete LastMetaIndexParser
;
1129 // pkgAcqMetaClearSig::Custom600Headers - Insert custom request headers /*{{{*/
1130 string
pkgAcqMetaClearSig::Custom600Headers() const
1132 string Header
= pkgAcqMetaBase::Custom600Headers();
1133 Header
+= "\nFail-Ignore: true";
1134 std::string
const key
= TransactionManager
->MetaIndexParser
->GetSignedBy();
1135 if (key
.empty() == false)
1136 Header
+= "\nSigned-By: " + key
;
1141 // pkgAcqMetaClearSig::Done - We got a file /*{{{*/
1142 void pkgAcqMetaClearSig::Done(std::string
const &Message
,
1143 HashStringList
const &Hashes
,
1144 pkgAcquire::MethodConfig
const * const Cnf
)
1146 Item::Done(Message
, Hashes
, Cnf
);
1148 // if we expect a ClearTextSignature (InRelease), ensure that
1149 // this is what we get and if not fail to queue a
1150 // Release/Release.gpg, see #346386
1151 if (FileExists(DestFile
) && !StartsWithGPGClearTextSignature(DestFile
))
1153 pkgAcquire::Item::Failed(Message
, Cnf
);
1154 RenameOnError(NotClearsigned
);
1155 TransactionManager
->AbortTransaction();
1159 if(AuthPass
== false)
1161 if(CheckDownloadDone(this, Message
, Hashes
) == true)
1162 QueueForSignatureVerify(this, DestFile
, DestFile
);
1165 else if(CheckAuthDone(Message
) == true)
1167 if (TransactionManager
->IMSHit
== false)
1168 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
1169 else if (RealFileExists(GetFinalFilename()) == false)
1171 // We got an InRelease file IMSHit, but we haven't one, which means
1172 // we had a valid Release/Release.gpg combo stepping in, which we have
1173 // to 'acquire' now to ensure list cleanup isn't removing them
1174 new NoActionItem(Owner
, DetachedDataTarget
);
1175 new NoActionItem(Owner
, DetachedSigTarget
);
1180 void pkgAcqMetaClearSig::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
) /*{{{*/
1182 Item::Failed(Message
, Cnf
);
1184 // we failed, we will not get additional items from this method
1185 ExpectedAdditionalItems
= 0;
1187 if (AuthPass
== false)
1189 // Queue the 'old' InRelease file for removal if we try Release.gpg
1190 // as otherwise the file will stay around and gives a false-auth
1191 // impression (CVE-2012-0214)
1192 TransactionManager
->TransactionStageRemoval(this, GetFinalFilename());
1195 new pkgAcqMetaIndex(Owner
, TransactionManager
, DetachedDataTarget
, DetachedSigTarget
, IndexTargets
);
1199 if(CheckStopAuthentication(this, Message
))
1202 _error
->Warning(_("The data from '%s' is not signed. Packages "
1203 "from that repository can not be authenticated."),
1204 ClearsignedTarget
.Description
.c_str());
1206 // No Release file was present, or verification failed, so fall
1207 // back to queueing Packages files without verification
1208 // only allow going further if the users explicitely wants it
1209 if(AllowInsecureRepositories(TransactionManager
->MetaIndexParser
, TransactionManager
, this) == true)
1213 /* InRelease files become Release files, otherwise
1214 * they would be considered as trusted later on */
1215 string
const FinalRelease
= GetFinalFileNameFromURI(DetachedDataTarget
.URI
);
1216 string
const PartialRelease
= GetPartialFileNameFromURI(DetachedDataTarget
.URI
);
1217 string
const FinalReleasegpg
= GetFinalFileNameFromURI(DetachedSigTarget
.URI
);
1218 string
const FinalInRelease
= GetFinalFilename();
1219 Rename(DestFile
, PartialRelease
);
1220 TransactionManager
->TransactionStageCopy(this, PartialRelease
, FinalRelease
);
1222 if (RealFileExists(FinalReleasegpg
) || RealFileExists(FinalInRelease
))
1224 // open the last Release if we have it
1225 if (TransactionManager
->IMSHit
== false)
1227 TransactionManager
->LastMetaIndexParser
= TransactionManager
->MetaIndexParser
->UnloadedClone();
1228 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1230 _error
->PushToStack();
1231 if (RealFileExists(FinalInRelease
))
1232 TransactionManager
->LastMetaIndexParser
->Load(FinalInRelease
, NULL
);
1234 TransactionManager
->LastMetaIndexParser
->Load(FinalRelease
, NULL
);
1235 // its unlikely to happen, but if what we have is bad ignore it
1236 if (_error
->PendingError())
1238 delete TransactionManager
->LastMetaIndexParser
;
1239 TransactionManager
->LastMetaIndexParser
= NULL
;
1241 _error
->RevertToStack();
1246 // we parse the indexes here because at this point the user wanted
1247 // a repository that may potentially harm him
1248 if (TransactionManager
->MetaIndexParser
->Load(PartialRelease
, &ErrorText
) == false || VerifyVendor(Message
) == false)
1249 /* expired Release files are still a problem you need extra force for */;
1257 pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire
* const Owner
, /*{{{*/
1258 pkgAcqMetaClearSig
* const TransactionManager
,
1259 IndexTarget
const &DataTarget
,
1260 IndexTarget
const &DetachedSigTarget
,
1261 vector
<IndexTarget
> const &IndexTargets
) :
1262 pkgAcqMetaBase(Owner
, TransactionManager
, IndexTargets
, DataTarget
), d(NULL
),
1263 DetachedSigTarget(DetachedSigTarget
)
1265 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1266 std::clog
<< "New pkgAcqMetaIndex with TransactionManager "
1267 << this->TransactionManager
<< std::endl
;
1269 DestFile
= GetPartialFileNameFromURI(DataTarget
.URI
);
1272 Desc
.Description
= DataTarget
.Description
;
1274 Desc
.ShortDesc
= DataTarget
.ShortDesc
;
1275 Desc
.URI
= DataTarget
.URI
;
1277 // we expect more item
1278 ExpectedAdditionalItems
= IndexTargets
.size();
1282 void pkgAcqMetaIndex::Done(string
const &Message
, /*{{{*/
1283 HashStringList
const &Hashes
,
1284 pkgAcquire::MethodConfig
const * const Cfg
)
1286 Item::Done(Message
,Hashes
,Cfg
);
1288 if(CheckDownloadDone(this, Message
, Hashes
))
1290 // we have a Release file, now download the Signature, all further
1291 // verify/queue for additional downloads will be done in the
1292 // pkgAcqMetaSig::Done() code
1293 new pkgAcqMetaSig(Owner
, TransactionManager
, DetachedSigTarget
, this);
1297 // pkgAcqMetaIndex::Failed - no Release file present /*{{{*/
1298 void pkgAcqMetaIndex::Failed(string
const &Message
,
1299 pkgAcquire::MethodConfig
const * const Cnf
)
1301 pkgAcquire::Item::Failed(Message
, Cnf
);
1304 _error
->Warning(_("The repository '%s' does not have a Release file. "
1305 "This is deprecated, please contact the owner of the "
1306 "repository."), Target
.Description
.c_str());
1308 // No Release file was present so fall
1309 // back to queueing Packages files without verification
1310 // only allow going further if the users explicitely wants it
1311 if(AllowInsecureRepositories(TransactionManager
->MetaIndexParser
, TransactionManager
, this) == true)
1313 // ensure old Release files are removed
1314 TransactionManager
->TransactionStageRemoval(this, GetFinalFilename());
1316 // queue without any kind of hashsum support
1317 QueueIndexes(false);
1321 void pkgAcqMetaIndex::Finished() /*{{{*/
1323 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1324 std::clog
<< "Finished: " << DestFile
<<std::endl
;
1325 if(TransactionManager
!= NULL
&&
1326 TransactionManager
->TransactionHasError() == false)
1327 TransactionManager
->CommitTransaction();
1330 std::string
pkgAcqMetaIndex::DescURI() const /*{{{*/
1335 pkgAcqMetaIndex::~pkgAcqMetaIndex() {}
1337 // AcqMetaSig::AcqMetaSig - Constructor /*{{{*/
1338 pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire
* const Owner
,
1339 pkgAcqMetaClearSig
* const TransactionManager
,
1340 IndexTarget
const &Target
,
1341 pkgAcqMetaIndex
* const MetaIndex
) :
1342 pkgAcqTransactionItem(Owner
, TransactionManager
, Target
), d(NULL
), MetaIndex(MetaIndex
)
1344 DestFile
= GetPartialFileNameFromURI(Target
.URI
);
1346 // remove any partial downloaded sig-file in partial/.
1347 // it may confuse proxies and is too small to warrant a
1348 // partial download anyway
1349 unlink(DestFile
.c_str());
1351 // set the TransactionManager
1352 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1353 std::clog
<< "New pkgAcqMetaSig with TransactionManager "
1354 << TransactionManager
<< std::endl
;
1357 Desc
.Description
= Target
.Description
;
1359 Desc
.ShortDesc
= Target
.ShortDesc
;
1360 Desc
.URI
= Target
.URI
;
1362 // If we got a hit for Release, we will get one for Release.gpg too (or obscure errors),
1363 // so we skip the download step and go instantly to verification
1364 if (TransactionManager
->IMSHit
== true && RealFileExists(GetFinalFilename()))
1368 PartialFile
= DestFile
= GetFinalFilename();
1369 MetaIndexFileSignature
= DestFile
;
1370 MetaIndex
->QueueForSignatureVerify(this, MetaIndex
->DestFile
, DestFile
);
1376 pkgAcqMetaSig::~pkgAcqMetaSig() /*{{{*/
1380 // pkgAcqMetaSig::Custom600Headers - Insert custom request headers /*{{{*/
1381 std::string
pkgAcqMetaSig::Custom600Headers() const
1383 std::string Header
= pkgAcqTransactionItem::Custom600Headers();
1384 std::string
const key
= TransactionManager
->MetaIndexParser
->GetSignedBy();
1385 if (key
.empty() == false)
1386 Header
+= "\nSigned-By: " + key
;
1390 // AcqMetaSig::Done - The signature was downloaded/verified /*{{{*/
1391 void pkgAcqMetaSig::Done(string
const &Message
, HashStringList
const &Hashes
,
1392 pkgAcquire::MethodConfig
const * const Cfg
)
1394 if (MetaIndexFileSignature
.empty() == false)
1396 DestFile
= MetaIndexFileSignature
;
1397 MetaIndexFileSignature
.clear();
1399 Item::Done(Message
, Hashes
, Cfg
);
1401 if(MetaIndex
->AuthPass
== false)
1403 if(MetaIndex
->CheckDownloadDone(this, Message
, Hashes
) == true)
1405 // destfile will be modified to point to MetaIndexFile for the
1406 // gpgv method, so we need to save it here
1407 MetaIndexFileSignature
= DestFile
;
1408 MetaIndex
->QueueForSignatureVerify(this, MetaIndex
->DestFile
, DestFile
);
1412 else if(MetaIndex
->CheckAuthDone(Message
) == true)
1414 if (TransactionManager
->IMSHit
== false)
1416 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
1417 TransactionManager
->TransactionStageCopy(MetaIndex
, MetaIndex
->DestFile
, MetaIndex
->GetFinalFilename());
1422 void pkgAcqMetaSig::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
1424 Item::Failed(Message
,Cnf
);
1426 // check if we need to fail at this point
1427 if (MetaIndex
->AuthPass
== true && MetaIndex
->CheckStopAuthentication(this, Message
))
1430 string
const FinalRelease
= MetaIndex
->GetFinalFilename();
1431 string
const FinalReleasegpg
= GetFinalFilename();
1432 string
const FinalInRelease
= TransactionManager
->GetFinalFilename();
1434 if (RealFileExists(FinalReleasegpg
) || RealFileExists(FinalInRelease
))
1436 std::string downgrade_msg
;
1437 strprintf(downgrade_msg
, _("The repository '%s' is no longer signed."),
1438 MetaIndex
->Target
.Description
.c_str());
1439 if(_config
->FindB("Acquire::AllowDowngradeToInsecureRepositories"))
1441 // meh, the users wants to take risks (we still mark the packages
1442 // from this repository as unauthenticated)
1443 _error
->Warning("%s", downgrade_msg
.c_str());
1444 _error
->Warning(_("This is normally not allowed, but the option "
1445 "Acquire::AllowDowngradeToInsecureRepositories was "
1446 "given to override it."));
1449 _error
->Error("%s", downgrade_msg
.c_str());
1450 if (TransactionManager
->IMSHit
== false)
1451 Rename(MetaIndex
->DestFile
, MetaIndex
->DestFile
+ ".FAILED");
1452 Item::Failed("Message: " + downgrade_msg
, Cnf
);
1453 TransactionManager
->AbortTransaction();
1458 _error
->Warning(_("The data from '%s' is not signed. Packages "
1459 "from that repository can not be authenticated."),
1460 MetaIndex
->Target
.Description
.c_str());
1462 // ensures that a Release.gpg file in the lists/ is removed by the transaction
1463 TransactionManager
->TransactionStageRemoval(this, DestFile
);
1465 // only allow going further if the users explicitely wants it
1466 if(AllowInsecureRepositories(TransactionManager
->MetaIndexParser
, TransactionManager
, this) == true)
1468 if (RealFileExists(FinalReleasegpg
) || RealFileExists(FinalInRelease
))
1470 // open the last Release if we have it
1471 if (TransactionManager
->IMSHit
== false)
1473 TransactionManager
->LastMetaIndexParser
= TransactionManager
->MetaIndexParser
->UnloadedClone();
1474 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1476 _error
->PushToStack();
1477 if (RealFileExists(FinalInRelease
))
1478 TransactionManager
->LastMetaIndexParser
->Load(FinalInRelease
, NULL
);
1480 TransactionManager
->LastMetaIndexParser
->Load(FinalRelease
, NULL
);
1481 // its unlikely to happen, but if what we have is bad ignore it
1482 if (_error
->PendingError())
1484 delete TransactionManager
->LastMetaIndexParser
;
1485 TransactionManager
->LastMetaIndexParser
= NULL
;
1487 _error
->RevertToStack();
1492 // we parse the indexes here because at this point the user wanted
1493 // a repository that may potentially harm him
1494 if (TransactionManager
->MetaIndexParser
->Load(MetaIndex
->DestFile
, &ErrorText
) == false || MetaIndex
->VerifyVendor(Message
) == false)
1495 /* expired Release files are still a problem you need extra force for */;
1497 MetaIndex
->QueueIndexes(true);
1499 TransactionManager
->TransactionStageCopy(MetaIndex
, MetaIndex
->DestFile
, MetaIndex
->GetFinalFilename());
1502 // FIXME: this is used often (e.g. in pkgAcqIndexTrans) so refactor
1503 if (Cnf
->LocalOnly
== true ||
1504 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1513 // AcqBaseIndex - Constructor /*{{{*/
1514 pkgAcqBaseIndex::pkgAcqBaseIndex(pkgAcquire
* const Owner
,
1515 pkgAcqMetaClearSig
* const TransactionManager
,
1516 IndexTarget
const &Target
)
1517 : pkgAcqTransactionItem(Owner
, TransactionManager
, Target
), d(NULL
)
1521 pkgAcqBaseIndex::~pkgAcqBaseIndex() {}
1523 // AcqDiffIndex::AcqDiffIndex - Constructor /*{{{*/
1524 // ---------------------------------------------------------------------
1525 /* Get the DiffIndex file first and see if there are patches available
1526 * If so, create a pkgAcqIndexDiffs fetcher that will get and apply the
1527 * patches. If anything goes wrong in that process, it will fall back to
1528 * the original packages file
1530 pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire
* const Owner
,
1531 pkgAcqMetaClearSig
* const TransactionManager
,
1532 IndexTarget
const &Target
)
1533 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
), diffs(NULL
)
1535 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
1538 Desc
.Description
= Target
.Description
+ ".diff/Index";
1539 Desc
.ShortDesc
= Target
.ShortDesc
;
1540 Desc
.URI
= Target
.URI
+ ".diff/Index";
1542 DestFile
= GetPartialFileNameFromURI(Desc
.URI
);
1545 std::clog
<< "pkgAcqDiffIndex: " << Desc
.URI
<< std::endl
;
1550 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
1551 // ---------------------------------------------------------------------
1552 /* The only header we use is the last-modified header. */
1553 string
pkgAcqDiffIndex::Custom600Headers() const
1555 string
const Final
= GetFinalFilename();
1558 std::clog
<< "Custom600Header-IMS: " << Final
<< std::endl
;
1561 if (stat(Final
.c_str(),&Buf
) != 0)
1562 return "\nIndex-File: true";
1564 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1567 void pkgAcqDiffIndex::QueueOnIMSHit() const /*{{{*/
1569 // list cleanup needs to know that this file as well as the already
1570 // present index is ours, so we create an empty diff to save it for us
1571 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
);
1574 bool pkgAcqDiffIndex::ParseDiffIndex(string
const &IndexDiffFile
) /*{{{*/
1576 // failing here is fine: our caller will take care of trying to
1577 // get the complete file if patching fails
1579 std::clog
<< "pkgAcqDiffIndex::ParseIndexDiff() " << IndexDiffFile
1582 FileFd
Fd(IndexDiffFile
,FileFd::ReadOnly
);
1584 if (_error
->PendingError() == true)
1588 if(unlikely(TF
.Step(Tags
) == false))
1591 HashStringList ServerHashes
;
1592 unsigned long long ServerSize
= 0;
1594 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
1596 std::string tagname
= *type
;
1597 tagname
.append("-Current");
1598 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1599 if (tmp
.empty() == true)
1603 unsigned long long size
;
1604 std::stringstream
ss(tmp
);
1606 if (unlikely(hash
.empty() == true))
1608 if (unlikely(ServerSize
!= 0 && ServerSize
!= size
))
1610 ServerHashes
.push_back(HashString(*type
, hash
));
1614 if (ServerHashes
.usable() == false)
1617 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": Did not find a good hashsum in the index" << std::endl
;
1621 std::string
const CurrentPackagesFile
= GetFinalFileNameFromURI(Target
.URI
);
1622 HashStringList
const TargetFileHashes
= GetExpectedHashesFor(Target
.MetaKey
);
1623 if (TargetFileHashes
.usable() == false || ServerHashes
!= TargetFileHashes
)
1627 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": Index has different hashes than parser, probably older, so fail pdiffing" << std::endl
;
1628 printHashSumComparision(CurrentPackagesFile
, ServerHashes
, TargetFileHashes
);
1633 HashStringList LocalHashes
;
1634 // try avoiding calculating the hash here as this is costly
1635 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1636 LocalHashes
= GetExpectedHashesFromFor(TransactionManager
->LastMetaIndexParser
, Target
.MetaKey
);
1637 if (LocalHashes
.usable() == false)
1639 FileFd
fd(CurrentPackagesFile
, FileFd::ReadOnly
);
1640 Hashes
LocalHashesCalc(ServerHashes
);
1641 LocalHashesCalc
.AddFD(fd
);
1642 LocalHashes
= LocalHashesCalc
.GetHashStringList();
1645 if (ServerHashes
== LocalHashes
)
1647 // we have the same sha1 as the server so we are done here
1649 std::clog
<< "pkgAcqDiffIndex: Package file " << CurrentPackagesFile
<< " is up-to-date" << std::endl
;
1655 std::clog
<< "Server-Current: " << ServerHashes
.find(NULL
)->toStr() << " and we start at "
1656 << CurrentPackagesFile
<< " " << LocalHashes
.FileSize() << " " << LocalHashes
.find(NULL
)->toStr() << std::endl
;
1658 // parse all of (provided) history
1659 vector
<DiffInfo
> available_patches
;
1660 bool firstAcceptedHashes
= true;
1661 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
1663 if (LocalHashes
.find(*type
) == NULL
)
1666 std::string tagname
= *type
;
1667 tagname
.append("-History");
1668 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1669 if (tmp
.empty() == true)
1672 string hash
, filename
;
1673 unsigned long long size
;
1674 std::stringstream
ss(tmp
);
1676 while (ss
>> hash
>> size
>> filename
)
1678 if (unlikely(hash
.empty() == true || filename
.empty() == true))
1681 // see if we have a record for this file already
1682 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
1683 for (; cur
!= available_patches
.end(); ++cur
)
1685 if (cur
->file
!= filename
)
1687 cur
->result_hashes
.push_back(HashString(*type
, hash
));
1690 if (cur
!= available_patches
.end())
1692 if (firstAcceptedHashes
== true)
1695 next
.file
= filename
;
1696 next
.result_hashes
.push_back(HashString(*type
, hash
));
1697 next
.result_hashes
.FileSize(size
);
1698 available_patches
.push_back(next
);
1703 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
1704 << " wasn't in the list for the first parsed hash! (history)" << std::endl
;
1708 firstAcceptedHashes
= false;
1711 if (unlikely(available_patches
.empty() == true))
1714 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": "
1715 << "Couldn't find any patches for the patch series." << std::endl
;
1719 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
1721 if (LocalHashes
.find(*type
) == NULL
)
1724 std::string tagname
= *type
;
1725 tagname
.append("-Patches");
1726 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1727 if (tmp
.empty() == true)
1730 string hash
, filename
;
1731 unsigned long long size
;
1732 std::stringstream
ss(tmp
);
1734 while (ss
>> hash
>> size
>> filename
)
1736 if (unlikely(hash
.empty() == true || filename
.empty() == true))
1739 // see if we have a record for this file already
1740 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
1741 for (; cur
!= available_patches
.end(); ++cur
)
1743 if (cur
->file
!= filename
)
1745 if (cur
->patch_hashes
.empty())
1746 cur
->patch_hashes
.FileSize(size
);
1747 cur
->patch_hashes
.push_back(HashString(*type
, hash
));
1750 if (cur
!= available_patches
.end())
1753 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
1754 << " wasn't in the list for the first parsed hash! (patches)" << std::endl
;
1759 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
1761 std::string tagname
= *type
;
1762 tagname
.append("-Download");
1763 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1764 if (tmp
.empty() == true)
1767 string hash
, filename
;
1768 unsigned long long size
;
1769 std::stringstream
ss(tmp
);
1771 // FIXME: all of pdiff supports only .gz compressed patches
1772 while (ss
>> hash
>> size
>> filename
)
1774 if (unlikely(hash
.empty() == true || filename
.empty() == true))
1776 if (unlikely(APT::String::Endswith(filename
, ".gz") == false))
1778 filename
.erase(filename
.length() - 3);
1780 // see if we have a record for this file already
1781 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
1782 for (; cur
!= available_patches
.end(); ++cur
)
1784 if (cur
->file
!= filename
)
1786 if (cur
->download_hashes
.empty())
1787 cur
->download_hashes
.FileSize(size
);
1788 cur
->download_hashes
.push_back(HashString(*type
, hash
));
1791 if (cur
!= available_patches
.end())
1794 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
1795 << " wasn't in the list for the first parsed hash! (download)" << std::endl
;
1801 bool foundStart
= false;
1802 for (std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
1803 cur
!= available_patches
.end(); ++cur
)
1805 if (LocalHashes
!= cur
->result_hashes
)
1808 available_patches
.erase(available_patches
.begin(), cur
);
1813 if (foundStart
== false || unlikely(available_patches
.empty() == true))
1816 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": "
1817 << "Couldn't find the start of the patch series." << std::endl
;
1821 // patching with too many files is rather slow compared to a fast download
1822 unsigned long const fileLimit
= _config
->FindI("Acquire::PDiffs::FileLimit", 0);
1823 if (fileLimit
!= 0 && fileLimit
< available_patches
.size())
1826 std::clog
<< "Need " << available_patches
.size() << " diffs (Limit is " << fileLimit
1827 << ") so fallback to complete download" << std::endl
;
1831 // calculate the size of all patches we have to get
1832 // note that all sizes are uncompressed, while we download compressed files
1833 unsigned long long patchesSize
= 0;
1834 for (std::vector
<DiffInfo
>::const_iterator cur
= available_patches
.begin();
1835 cur
!= available_patches
.end(); ++cur
)
1836 patchesSize
+= cur
->patch_hashes
.FileSize();
1837 unsigned long long const sizeLimit
= ServerSize
* _config
->FindI("Acquire::PDiffs::SizeLimit", 100);
1838 if (sizeLimit
> 0 && (sizeLimit
/100) < patchesSize
)
1841 std::clog
<< "Need " << patchesSize
<< " bytes (Limit is " << sizeLimit
/100
1842 << ") so fallback to complete download" << std::endl
;
1846 // we have something, queue the diffs
1847 string::size_type
const last_space
= Description
.rfind(" ");
1848 if(last_space
!= string::npos
)
1849 Description
.erase(last_space
, Description
.size()-last_space
);
1851 /* decide if we should download patches one by one or in one go:
1852 The first is good if the server merges patches, but many don't so client
1853 based merging can be attempt in which case the second is better.
1854 "bad things" will happen if patches are merged on the server,
1855 but client side merging is attempt as well */
1856 bool pdiff_merge
= _config
->FindB("Acquire::PDiffs::Merge", true);
1857 if (pdiff_merge
== true)
1859 // reprepro adds this flag if it has merged patches on the server
1860 std::string
const precedence
= Tags
.FindS("X-Patch-Precedence");
1861 pdiff_merge
= (precedence
!= "merged");
1864 if (pdiff_merge
== false)
1865 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
, available_patches
);
1868 diffs
= new std::vector
<pkgAcqIndexMergeDiffs
*>(available_patches
.size());
1869 for(size_t i
= 0; i
< available_patches
.size(); ++i
)
1870 (*diffs
)[i
] = new pkgAcqIndexMergeDiffs(Owner
, TransactionManager
,
1872 available_patches
[i
],
1882 void pkgAcqDiffIndex::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
1884 Item::Failed(Message
,Cnf
);
1888 std::clog
<< "pkgAcqDiffIndex failed: " << Desc
.URI
<< " with " << Message
<< std::endl
1889 << "Falling back to normal index file acquire" << std::endl
;
1891 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
1894 void pkgAcqDiffIndex::Done(string
const &Message
,HashStringList
const &Hashes
, /*{{{*/
1895 pkgAcquire::MethodConfig
const * const Cnf
)
1898 std::clog
<< "pkgAcqDiffIndex::Done(): " << Desc
.URI
<< std::endl
;
1900 Item::Done(Message
, Hashes
, Cnf
);
1902 string
const FinalFile
= GetFinalFilename();
1903 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false))
1904 DestFile
= FinalFile
;
1906 if(ParseDiffIndex(DestFile
) == false)
1908 Failed("Message: Couldn't parse pdiff index", Cnf
);
1909 // queue for final move - this should happen even if we fail
1910 // while parsing (e.g. on sizelimit) and download the complete file.
1911 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
1915 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
1924 pkgAcqDiffIndex::~pkgAcqDiffIndex()
1930 // AcqIndexDiffs::AcqIndexDiffs - Constructor /*{{{*/
1931 // ---------------------------------------------------------------------
1932 /* The package diff is added to the queue. one object is constructed
1933 * for each diff and the index
1935 pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire
* const Owner
,
1936 pkgAcqMetaClearSig
* const TransactionManager
,
1937 IndexTarget
const &Target
,
1938 vector
<DiffInfo
> const &diffs
)
1939 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
),
1940 available_patches(diffs
)
1942 DestFile
= GetPartialFileNameFromURI(Target
.URI
);
1944 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
1947 Description
= Target
.Description
;
1948 Desc
.ShortDesc
= Target
.ShortDesc
;
1950 if(available_patches
.empty() == true)
1952 // we are done (yeah!), check hashes against the final file
1953 DestFile
= GetFinalFileNameFromURI(Target
.URI
);
1958 // patching needs to be bootstrapped with the 'old' version
1959 std::string
const PartialFile
= GetPartialFileNameFromURI(Target
.URI
);
1960 if (RealFileExists(PartialFile
) == false)
1962 if (symlink(GetFinalFilename().c_str(), PartialFile
.c_str()) != 0)
1964 Failed("Link creation of " + PartialFile
+ " to " + GetFinalFilename() + " failed", NULL
);
1969 // get the next diff
1970 State
= StateFetchDiff
;
1975 void pkgAcqIndexDiffs::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
1977 Item::Failed(Message
,Cnf
);
1981 std::clog
<< "pkgAcqIndexDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
1982 << "Falling back to normal index file acquire" << std::endl
;
1983 DestFile
= GetPartialFileNameFromURI(Target
.URI
);
1984 RenameOnError(PDiffError
);
1985 std::string
const patchname
= GetDiffsPatchFileName(DestFile
);
1986 if (RealFileExists(patchname
))
1987 rename(patchname
.c_str(), std::string(patchname
+ ".FAILED").c_str());
1988 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
1992 // Finish - helper that cleans the item out of the fetcher queue /*{{{*/
1993 void pkgAcqIndexDiffs::Finish(bool allDone
)
1996 std::clog
<< "pkgAcqIndexDiffs::Finish(): "
1998 << Desc
.URI
<< std::endl
;
2000 // we restore the original name, this is required, otherwise
2001 // the file will be cleaned
2004 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
2006 // this is for the "real" finish
2011 std::clog
<< "\n\nallDone: " << DestFile
<< "\n" << std::endl
;
2016 std::clog
<< "Finishing: " << Desc
.URI
<< std::endl
;
2023 bool pkgAcqIndexDiffs::QueueNextDiff() /*{{{*/
2025 // calc sha1 of the just patched file
2026 std::string
const FinalFile
= GetPartialFileNameFromURI(Target
.URI
);
2028 if(!FileExists(FinalFile
))
2030 Failed("Message: No FinalFile " + FinalFile
+ " available", NULL
);
2034 FileFd
fd(FinalFile
, FileFd::ReadOnly
);
2035 Hashes LocalHashesCalc
;
2036 LocalHashesCalc
.AddFD(fd
);
2037 HashStringList
const LocalHashes
= LocalHashesCalc
.GetHashStringList();
2040 std::clog
<< "QueueNextDiff: " << FinalFile
<< " (" << LocalHashes
.find(NULL
)->toStr() << ")" << std::endl
;
2042 HashStringList
const TargetFileHashes
= GetExpectedHashesFor(Target
.MetaKey
);
2043 if (unlikely(LocalHashes
.usable() == false || TargetFileHashes
.usable() == false))
2045 Failed("Local/Expected hashes are not usable", NULL
);
2050 // final file reached before all patches are applied
2051 if(LocalHashes
== TargetFileHashes
)
2057 // remove all patches until the next matching patch is found
2058 // this requires the Index file to be ordered
2059 for(vector
<DiffInfo
>::iterator I
= available_patches
.begin();
2060 available_patches
.empty() == false &&
2061 I
!= available_patches
.end() &&
2062 I
->result_hashes
!= LocalHashes
;
2065 available_patches
.erase(I
);
2068 // error checking and falling back if no patch was found
2069 if(available_patches
.empty() == true)
2071 Failed("No patches left to reach target", NULL
);
2075 // queue the right diff
2076 Desc
.URI
= Target
.URI
+ ".diff/" + available_patches
[0].file
+ ".gz";
2077 Desc
.Description
= Description
+ " " + available_patches
[0].file
+ string(".pdiff");
2078 DestFile
= GetPartialFileNameFromURI(Target
.URI
+ ".diff/" + available_patches
[0].file
);
2081 std::clog
<< "pkgAcqIndexDiffs::QueueNextDiff(): " << Desc
.URI
<< std::endl
;
2088 void pkgAcqIndexDiffs::Done(string
const &Message
, HashStringList
const &Hashes
, /*{{{*/
2089 pkgAcquire::MethodConfig
const * const Cnf
)
2092 std::clog
<< "pkgAcqIndexDiffs::Done(): " << Desc
.URI
<< std::endl
;
2094 Item::Done(Message
, Hashes
, Cnf
);
2096 std::string
const FinalFile
= GetPartialFileNameFromURI(Target
.URI
);
2097 std::string
const PatchFile
= GetDiffsPatchFileName(FinalFile
);
2099 // success in downloading a diff, enter ApplyDiff state
2100 if(State
== StateFetchDiff
)
2102 Rename(DestFile
, PatchFile
);
2105 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
2107 State
= StateApplyDiff
;
2109 Desc
.URI
= "rred:" + FinalFile
;
2111 SetActiveSubprocess("rred");
2115 // success in download/apply a diff, queue next (if needed)
2116 if(State
== StateApplyDiff
)
2118 // remove the just applied patch
2119 available_patches
.erase(available_patches
.begin());
2120 unlink(PatchFile
.c_str());
2125 std::clog
<< "Moving patched file in place: " << std::endl
2126 << DestFile
<< " -> " << FinalFile
<< std::endl
;
2128 Rename(DestFile
,FinalFile
);
2129 chmod(FinalFile
.c_str(),0644);
2131 // see if there is more to download
2132 if(available_patches
.empty() == false) {
2133 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
,
2138 DestFile
= FinalFile
;
2139 return Finish(true);
2143 std::string
pkgAcqIndexDiffs::Custom600Headers() const /*{{{*/
2145 if(State
!= StateApplyDiff
)
2146 return pkgAcqBaseIndex::Custom600Headers();
2147 std::ostringstream patchhashes
;
2148 HashStringList
const ExpectedHashes
= available_patches
[0].patch_hashes
;
2149 for (HashStringList::const_iterator hs
= ExpectedHashes
.begin(); hs
!= ExpectedHashes
.end(); ++hs
)
2150 patchhashes
<< "\nPatch-0-" << hs
->HashType() << "-Hash: " << hs
->HashValue();
2151 patchhashes
<< pkgAcqBaseIndex::Custom600Headers();
2152 return patchhashes
.str();
2155 pkgAcqIndexDiffs::~pkgAcqIndexDiffs() {}
2157 // AcqIndexMergeDiffs::AcqIndexMergeDiffs - Constructor /*{{{*/
2158 pkgAcqIndexMergeDiffs::pkgAcqIndexMergeDiffs(pkgAcquire
* const Owner
,
2159 pkgAcqMetaClearSig
* const TransactionManager
,
2160 IndexTarget
const &Target
,
2161 DiffInfo
const &patch
,
2162 std::vector
<pkgAcqIndexMergeDiffs
*> const * const allPatches
)
2163 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
),
2164 patch(patch
), allPatches(allPatches
), State(StateFetchDiff
)
2166 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
2169 Description
= Target
.Description
;
2170 Desc
.ShortDesc
= Target
.ShortDesc
;
2172 Desc
.URI
= Target
.URI
+ ".diff/" + patch
.file
+ ".gz";
2173 Desc
.Description
= Description
+ " " + patch
.file
+ string(".pdiff");
2175 DestFile
= GetPartialFileNameFromURI(Target
.URI
+ ".diff/" + patch
.file
);
2178 std::clog
<< "pkgAcqIndexMergeDiffs: " << Desc
.URI
<< std::endl
;
2183 void pkgAcqIndexMergeDiffs::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
2186 std::clog
<< "pkgAcqIndexMergeDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
;
2188 Item::Failed(Message
,Cnf
);
2191 // check if we are the first to fail, otherwise we are done here
2192 State
= StateDoneDiff
;
2193 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2194 I
!= allPatches
->end(); ++I
)
2195 if ((*I
)->State
== StateErrorDiff
)
2198 // first failure means we should fallback
2199 State
= StateErrorDiff
;
2201 std::clog
<< "Falling back to normal index file acquire" << std::endl
;
2202 DestFile
= GetPartialFileNameFromURI(Target
.URI
);
2203 RenameOnError(PDiffError
);
2204 std::string
const patchname
= GetMergeDiffsPatchFileName(DestFile
, patch
.file
);
2205 if (RealFileExists(patchname
))
2206 rename(patchname
.c_str(), std::string(patchname
+ ".FAILED").c_str());
2207 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
2210 void pkgAcqIndexMergeDiffs::Done(string
const &Message
, HashStringList
const &Hashes
, /*{{{*/
2211 pkgAcquire::MethodConfig
const * const Cnf
)
2214 std::clog
<< "pkgAcqIndexMergeDiffs::Done(): " << Desc
.URI
<< std::endl
;
2216 Item::Done(Message
, Hashes
, Cnf
);
2218 string
const FinalFile
= GetPartialFileNameFromURI(Target
.URI
);
2219 if (State
== StateFetchDiff
)
2221 Rename(DestFile
, GetMergeDiffsPatchFileName(FinalFile
, patch
.file
));
2223 // check if this is the last completed diff
2224 State
= StateDoneDiff
;
2225 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2226 I
!= allPatches
->end(); ++I
)
2227 if ((*I
)->State
!= StateDoneDiff
)
2230 std::clog
<< "Not the last done diff in the batch: " << Desc
.URI
<< std::endl
;
2234 // this is the last completed diff, so we are ready to apply now
2235 State
= StateApplyDiff
;
2237 // patching needs to be bootstrapped with the 'old' version
2238 if (symlink(GetFinalFilename().c_str(), FinalFile
.c_str()) != 0)
2240 Failed("Link creation of " + FinalFile
+ " to " + GetFinalFilename() + " failed", NULL
);
2245 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
2248 Desc
.URI
= "rred:" + FinalFile
;
2250 SetActiveSubprocess("rred");
2253 // success in download/apply all diffs, clean up
2254 else if (State
== StateApplyDiff
)
2256 // move the result into place
2257 std::string
const Final
= GetFinalFilename();
2259 std::clog
<< "Queue patched file in place: " << std::endl
2260 << DestFile
<< " -> " << Final
<< std::endl
;
2262 // queue for copy by the transaction manager
2263 TransactionManager
->TransactionStageCopy(this, DestFile
, Final
);
2265 // ensure the ed's are gone regardless of list-cleanup
2266 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2267 I
!= allPatches
->end(); ++I
)
2269 std::string
const PartialFile
= GetPartialFileNameFromURI(Target
.URI
);
2270 std::string
const patch
= GetMergeDiffsPatchFileName(PartialFile
, (*I
)->patch
.file
);
2271 unlink(patch
.c_str());
2273 unlink(FinalFile
.c_str());
2278 std::clog
<< "allDone: " << DestFile
<< "\n" << std::endl
;
2282 std::string
pkgAcqIndexMergeDiffs::Custom600Headers() const /*{{{*/
2284 if(State
!= StateApplyDiff
)
2285 return pkgAcqBaseIndex::Custom600Headers();
2286 std::ostringstream patchhashes
;
2287 unsigned int seen_patches
= 0;
2288 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2289 I
!= allPatches
->end(); ++I
)
2291 HashStringList
const ExpectedHashes
= (*I
)->patch
.patch_hashes
;
2292 for (HashStringList::const_iterator hs
= ExpectedHashes
.begin(); hs
!= ExpectedHashes
.end(); ++hs
)
2293 patchhashes
<< "\nPatch-" << seen_patches
<< "-" << hs
->HashType() << "-Hash: " << hs
->HashValue();
2296 patchhashes
<< pkgAcqBaseIndex::Custom600Headers();
2297 return patchhashes
.str();
2300 pkgAcqIndexMergeDiffs::~pkgAcqIndexMergeDiffs() {}
2302 // AcqIndex::AcqIndex - Constructor /*{{{*/
2303 pkgAcqIndex::pkgAcqIndex(pkgAcquire
* const Owner
,
2304 pkgAcqMetaClearSig
* const TransactionManager
,
2305 IndexTarget
const &Target
)
2306 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
), Stage(STAGE_DOWNLOAD
)
2308 // autoselect the compression method
2309 AutoSelectCompression();
2310 Init(Target
.URI
, Target
.Description
, Target
.ShortDesc
);
2312 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
2313 std::clog
<< "New pkgIndex with TransactionManager "
2314 << TransactionManager
<< std::endl
;
2317 // AcqIndex::AutoSelectCompression - Select compression /*{{{*/
2318 void pkgAcqIndex::AutoSelectCompression()
2320 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
2321 CompressionExtensions
= "";
2322 if (TransactionManager
->MetaIndexParser
!= NULL
&& TransactionManager
->MetaIndexParser
->Exists(Target
.MetaKey
))
2324 for (std::vector
<std::string
>::const_iterator t
= types
.begin();
2325 t
!= types
.end(); ++t
)
2327 std::string CompressedMetaKey
= string(Target
.MetaKey
).append(".").append(*t
);
2328 if (*t
== "uncompressed" ||
2329 TransactionManager
->MetaIndexParser
->Exists(CompressedMetaKey
) == true)
2330 CompressionExtensions
.append(*t
).append(" ");
2335 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
2336 CompressionExtensions
.append(*t
).append(" ");
2338 if (CompressionExtensions
.empty() == false)
2339 CompressionExtensions
.erase(CompressionExtensions
.end()-1);
2342 // AcqIndex::Init - defered Constructor /*{{{*/
2343 void pkgAcqIndex::Init(string
const &URI
, string
const &URIDesc
,
2344 string
const &ShortDesc
)
2346 Stage
= STAGE_DOWNLOAD
;
2348 DestFile
= GetPartialFileNameFromURI(URI
);
2350 size_t const nextExt
= CompressionExtensions
.find(' ');
2351 if (nextExt
== std::string::npos
)
2353 CurrentCompressionExtension
= CompressionExtensions
;
2354 CompressionExtensions
.clear();
2358 CurrentCompressionExtension
= CompressionExtensions
.substr(0, nextExt
);
2359 CompressionExtensions
= CompressionExtensions
.substr(nextExt
+1);
2362 if (CurrentCompressionExtension
== "uncompressed")
2366 else if (unlikely(CurrentCompressionExtension
.empty()))
2370 Desc
.URI
= URI
+ '.' + CurrentCompressionExtension
;
2371 DestFile
= DestFile
+ '.' + CurrentCompressionExtension
;
2374 if(TransactionManager
->MetaIndexParser
!= NULL
)
2375 InitByHashIfNeeded();
2377 Desc
.Description
= URIDesc
;
2379 Desc
.ShortDesc
= ShortDesc
;
2384 // AcqIndex::AdjustForByHash - modify URI for by-hash support /*{{{*/
2385 void pkgAcqIndex::InitByHashIfNeeded()
2388 // - (maybe?) add support for by-hash into the sources.list as flag
2389 // - make apt-ftparchive generate the hashes (and expire?)
2390 std::string HostKnob
= "APT::Acquire::" + ::URI(Desc
.URI
).Host
+ "::By-Hash";
2391 if(_config
->FindB("APT::Acquire::By-Hash", false) == true ||
2392 _config
->FindB(HostKnob
, false) == true ||
2393 TransactionManager
->MetaIndexParser
->GetSupportsAcquireByHash())
2395 HashStringList
const Hashes
= GetExpectedHashes();
2398 // FIXME: should we really use the best hash here? or a fixed one?
2399 HashString
const * const TargetHash
= Hashes
.find("");
2400 std::string
const ByHash
= "/by-hash/" + TargetHash
->HashType() + "/" + TargetHash
->HashValue();
2401 size_t const trailing_slash
= Desc
.URI
.find_last_of("/");
2402 Desc
.URI
= Desc
.URI
.replace(
2404 Desc
.URI
.substr(trailing_slash
+1).size()+1,
2408 "Fetching ByHash requested but can not find record for %s",
2409 GetMetaKey().c_str());
2414 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
2415 // ---------------------------------------------------------------------
2416 /* The only header we use is the last-modified header. */
2417 string
pkgAcqIndex::Custom600Headers() const
2419 string Final
= GetFinalFilename();
2421 string msg
= "\nIndex-File: true";
2423 if (stat(Final
.c_str(),&Buf
) == 0)
2424 msg
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
2426 if(Target
.IsOptional
)
2427 msg
+= "\nFail-Ignore: true";
2432 // AcqIndex::Failed - getting the indexfile failed /*{{{*/
2433 void pkgAcqIndex::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)
2435 Item::Failed(Message
,Cnf
);
2437 // authorisation matches will not be fixed by other compression types
2438 if (Status
!= StatAuthError
)
2440 if (CompressionExtensions
.empty() == false)
2442 Init(Target
.URI
, Desc
.Description
, Desc
.ShortDesc
);
2448 if(Target
.IsOptional
&& GetExpectedHashes().empty() && Stage
== STAGE_DOWNLOAD
)
2451 TransactionManager
->AbortTransaction();
2454 // AcqIndex::ReverifyAfterIMS - Reverify index after an ims-hit /*{{{*/
2455 void pkgAcqIndex::ReverifyAfterIMS()
2457 // update destfile to *not* include the compression extension when doing
2458 // a reverify (as its uncompressed on disk already)
2459 DestFile
= GetCompressedFileName(Target
.URI
, GetPartialFileNameFromURI(Target
.URI
), CurrentCompressionExtension
);
2461 // copy FinalFile into partial/ so that we check the hash again
2462 string FinalFile
= GetFinalFilename();
2463 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
2464 Desc
.URI
= "copy:" + FinalFile
;
2468 // AcqIndex::Done - Finished a fetch /*{{{*/
2469 // ---------------------------------------------------------------------
2470 /* This goes through a number of states.. On the initial fetch the
2471 method could possibly return an alternate filename which points
2472 to the uncompressed version of the file. If this is so the file
2473 is copied into the partial directory. In all other cases the file
2474 is decompressed with a compressed uri. */
2475 void pkgAcqIndex::Done(string
const &Message
,
2476 HashStringList
const &Hashes
,
2477 pkgAcquire::MethodConfig
const * const Cfg
)
2479 Item::Done(Message
,Hashes
,Cfg
);
2483 case STAGE_DOWNLOAD
:
2484 StageDownloadDone(Message
, Hashes
, Cfg
);
2486 case STAGE_DECOMPRESS_AND_VERIFY
:
2487 StageDecompressDone(Message
, Hashes
, Cfg
);
2492 // AcqIndex::StageDownloadDone - Queue for decompress and verify /*{{{*/
2493 void pkgAcqIndex::StageDownloadDone(string
const &Message
, HashStringList
const &,
2494 pkgAcquire::MethodConfig
const * const)
2498 // Handle the unzipd case
2499 string FileName
= LookupTag(Message
,"Alt-Filename");
2500 if (FileName
.empty() == false)
2502 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
2504 DestFile
+= ".decomp";
2505 Desc
.URI
= "copy:" + FileName
;
2507 SetActiveSubprocess("copy");
2511 FileName
= LookupTag(Message
,"Filename");
2512 if (FileName
.empty() == true)
2515 ErrorText
= "Method gave a blank filename";
2518 // Methods like e.g. "file:" will give us a (compressed) FileName that is
2519 // not the "DestFile" we set, in this case we uncompress from the local file
2520 if (FileName
!= DestFile
&& RealFileExists(DestFile
) == false)
2523 EraseFileName
= FileName
;
2525 // we need to verify the file against the current Release file again
2526 // on if-modfied-since hit to avoid a stale attack against us
2527 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
2529 // The files timestamp matches, reverify by copy into partial/
2535 // If we have compressed indexes enabled, queue for hash verification
2536 if (_config
->FindB("Acquire::GzipIndexes",false))
2538 DestFile
= GetPartialFileNameFromURI(Target
.URI
+ '.' + CurrentCompressionExtension
);
2540 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
2541 Desc
.URI
= "copy:" + FileName
;
2543 SetActiveSubprocess("copy");
2547 // get the binary name for your used compression type
2549 if(CurrentCompressionExtension
== "uncompressed")
2550 decompProg
= "copy";
2552 decompProg
= _config
->Find(string("Acquire::CompressionTypes::").append(CurrentCompressionExtension
),"");
2553 if(decompProg
.empty() == true)
2555 _error
->Error("Unsupported extension: %s", CurrentCompressionExtension
.c_str());
2559 // queue uri for the next stage
2560 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
2561 DestFile
+= ".decomp";
2562 Desc
.URI
= decompProg
+ ":" + FileName
;
2564 SetActiveSubprocess(decompProg
);
2567 // AcqIndex::StageDecompressDone - Final verification /*{{{*/
2568 void pkgAcqIndex::StageDecompressDone(string
const &,
2569 HashStringList
const &,
2570 pkgAcquire::MethodConfig
const * const)
2572 // Done, queue for rename on transaction finished
2573 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
2577 pkgAcqIndex::~pkgAcqIndex() {}
2580 // AcqArchive::AcqArchive - Constructor /*{{{*/
2581 // ---------------------------------------------------------------------
2582 /* This just sets up the initial fetch environment and queues the first
2584 pkgAcqArchive::pkgAcqArchive(pkgAcquire
* const Owner
,pkgSourceList
* const Sources
,
2585 pkgRecords
* const Recs
,pkgCache::VerIterator
const &Version
,
2586 string
&StoreFilename
) :
2587 Item(Owner
), d(NULL
), LocalSource(false), Version(Version
), Sources(Sources
), Recs(Recs
),
2588 StoreFilename(StoreFilename
), Vf(Version
.FileList()),
2591 Retries
= _config
->FindI("Acquire::Retries",0);
2593 if (Version
.Arch() == 0)
2595 _error
->Error(_("I wasn't able to locate a file for the %s package. "
2596 "This might mean you need to manually fix this package. "
2597 "(due to missing arch)"),
2598 Version
.ParentPkg().FullName().c_str());
2602 /* We need to find a filename to determine the extension. We make the
2603 assumption here that all the available sources for this version share
2604 the same extension.. */
2605 // Skip not source sources, they do not have file fields.
2606 for (; Vf
.end() == false; ++Vf
)
2608 if (Vf
.File().Flagged(pkgCache::Flag::NotSource
))
2613 // Does not really matter here.. we are going to fail out below
2614 if (Vf
.end() != true)
2616 // If this fails to get a file name we will bomb out below.
2617 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2618 if (_error
->PendingError() == true)
2621 // Generate the final file name as: package_version_arch.foo
2622 StoreFilename
= QuoteString(Version
.ParentPkg().Name(),"_:") + '_' +
2623 QuoteString(Version
.VerStr(),"_:") + '_' +
2624 QuoteString(Version
.Arch(),"_:.") +
2625 "." + flExtension(Parse
.FileName());
2628 // check if we have one trusted source for the package. if so, switch
2629 // to "TrustedOnly" mode - but only if not in AllowUnauthenticated mode
2630 bool const allowUnauth
= _config
->FindB("APT::Get::AllowUnauthenticated", false);
2631 bool const debugAuth
= _config
->FindB("Debug::pkgAcquire::Auth", false);
2632 bool seenUntrusted
= false;
2633 for (pkgCache::VerFileIterator i
= Version
.FileList(); i
.end() == false; ++i
)
2635 pkgIndexFile
*Index
;
2636 if (Sources
->FindIndex(i
.File(),Index
) == false)
2639 if (debugAuth
== true)
2640 std::cerr
<< "Checking index: " << Index
->Describe()
2641 << "(Trusted=" << Index
->IsTrusted() << ")" << std::endl
;
2643 if (Index
->IsTrusted() == true)
2646 if (allowUnauth
== false)
2650 seenUntrusted
= true;
2653 // "allow-unauthenticated" restores apts old fetching behaviour
2654 // that means that e.g. unauthenticated file:// uris are higher
2655 // priority than authenticated http:// uris
2656 if (allowUnauth
== true && seenUntrusted
== true)
2660 if (QueueNext() == false && _error
->PendingError() == false)
2661 _error
->Error(_("Can't find a source to download version '%s' of '%s'"),
2662 Version
.VerStr(), Version
.ParentPkg().FullName(false).c_str());
2665 // AcqArchive::QueueNext - Queue the next file source /*{{{*/
2666 // ---------------------------------------------------------------------
2667 /* This queues the next available file version for download. It checks if
2668 the archive is already available in the cache and stashs the MD5 for
2670 bool pkgAcqArchive::QueueNext()
2672 for (; Vf
.end() == false; ++Vf
)
2674 pkgCache::PkgFileIterator
const PkgF
= Vf
.File();
2675 // Ignore not source sources
2676 if (PkgF
.Flagged(pkgCache::Flag::NotSource
))
2679 // Try to cross match against the source list
2680 pkgIndexFile
*Index
;
2681 if (Sources
->FindIndex(PkgF
, Index
) == false)
2683 LocalSource
= PkgF
.Flagged(pkgCache::Flag::LocalSource
);
2685 // only try to get a trusted package from another source if that source
2687 if(Trusted
&& !Index
->IsTrusted())
2690 // Grab the text package record
2691 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2692 if (_error
->PendingError() == true)
2695 string PkgFile
= Parse
.FileName();
2696 ExpectedHashes
= Parse
.Hashes();
2698 if (PkgFile
.empty() == true)
2699 return _error
->Error(_("The package index files are corrupted. No Filename: "
2700 "field for package %s."),
2701 Version
.ParentPkg().Name());
2703 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
2704 Desc
.Description
= Index
->ArchiveInfo(Version
);
2706 Desc
.ShortDesc
= Version
.ParentPkg().FullName(true);
2708 // See if we already have the file. (Legacy filenames)
2709 FileSize
= Version
->Size
;
2710 string FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile
);
2712 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2714 // Make sure the size matches
2715 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2720 StoreFilename
= DestFile
= FinalFile
;
2724 /* Hmm, we have a file and its size does not match, this means it is
2725 an old style mismatched arch */
2726 unlink(FinalFile
.c_str());
2729 // Check it again using the new style output filenames
2730 FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
2731 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2733 // Make sure the size matches
2734 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2739 StoreFilename
= DestFile
= FinalFile
;
2743 /* Hmm, we have a file and its size does not match, this shouldn't
2745 unlink(FinalFile
.c_str());
2748 DestFile
= _config
->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename
);
2750 // Check the destination file
2751 if (stat(DestFile
.c_str(),&Buf
) == 0)
2753 // Hmm, the partial file is too big, erase it
2754 if ((unsigned long long)Buf
.st_size
> Version
->Size
)
2755 unlink(DestFile
.c_str());
2757 PartialSize
= Buf
.st_size
;
2760 // Disables download of archives - useful if no real installation follows,
2761 // e.g. if we are just interested in proposed installation order
2762 if (_config
->FindB("Debug::pkgAcqArchive::NoQueue", false) == true)
2767 StoreFilename
= DestFile
= FinalFile
;
2781 // AcqArchive::Done - Finished fetching /*{{{*/
2782 // ---------------------------------------------------------------------
2784 void pkgAcqArchive::Done(string
const &Message
, HashStringList
const &Hashes
,
2785 pkgAcquire::MethodConfig
const * const Cfg
)
2787 Item::Done(Message
, Hashes
, Cfg
);
2789 // Grab the output filename
2790 string FileName
= LookupTag(Message
,"Filename");
2791 if (FileName
.empty() == true)
2794 ErrorText
= "Method gave a blank filename";
2798 // Reference filename
2799 if (DestFile
!= FileName
&& RealFileExists(DestFile
) == false)
2801 StoreFilename
= DestFile
= FileName
;
2807 // Done, move it into position
2808 string
const FinalFile
= GetFinalFilename();
2809 Rename(DestFile
,FinalFile
);
2810 StoreFilename
= DestFile
= FinalFile
;
2814 // AcqArchive::Failed - Failure handler /*{{{*/
2815 // ---------------------------------------------------------------------
2816 /* Here we try other sources */
2817 void pkgAcqArchive::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)
2819 Item::Failed(Message
,Cnf
);
2821 /* We don't really want to retry on failed media swaps, this prevents
2822 that. An interesting observation is that permanent failures are not
2824 if (Cnf
->Removable
== true &&
2825 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2827 // Vf = Version.FileList();
2828 while (Vf
.end() == false) ++Vf
;
2829 StoreFilename
= string();
2834 if (QueueNext() == false)
2836 // This is the retry counter
2838 Cnf
->LocalOnly
== false &&
2839 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2842 Vf
= Version
.FileList();
2843 if (QueueNext() == true)
2847 StoreFilename
= string();
2852 APT_PURE
bool pkgAcqArchive::IsTrusted() const /*{{{*/
2857 void pkgAcqArchive::Finished() /*{{{*/
2859 if (Status
== pkgAcquire::Item::StatDone
&&
2862 StoreFilename
= string();
2865 std::string
pkgAcqArchive::DescURI() const /*{{{*/
2870 std::string
pkgAcqArchive::ShortDesc() const /*{{{*/
2872 return Desc
.ShortDesc
;
2875 pkgAcqArchive::~pkgAcqArchive() {}
2877 // AcqChangelog::pkgAcqChangelog - Constructors /*{{{*/
2878 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire
* const Owner
, pkgCache::VerIterator
const &Ver
,
2879 std::string
const &DestDir
, std::string
const &DestFilename
) :
2880 pkgAcquire::Item(Owner
), d(NULL
), SrcName(Ver
.SourcePkgName()), SrcVersion(Ver
.SourceVerStr())
2882 Desc
.URI
= URI(Ver
);
2883 Init(DestDir
, DestFilename
);
2885 // some parameters are char* here as they come likely from char* interfaces – which can also return NULL
2886 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire
* const Owner
, pkgCache::RlsFileIterator
const &RlsFile
,
2887 char const * const Component
, char const * const SrcName
, char const * const SrcVersion
,
2888 const string
&DestDir
, const string
&DestFilename
) :
2889 pkgAcquire::Item(Owner
), d(NULL
), SrcName(SrcName
), SrcVersion(SrcVersion
)
2891 Desc
.URI
= URI(RlsFile
, Component
, SrcName
, SrcVersion
);
2892 Init(DestDir
, DestFilename
);
2894 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire
* const Owner
,
2895 std::string
const &URI
, char const * const SrcName
, char const * const SrcVersion
,
2896 const string
&DestDir
, const string
&DestFilename
) :
2897 pkgAcquire::Item(Owner
), d(NULL
), SrcName(SrcName
), SrcVersion(SrcVersion
)
2900 Init(DestDir
, DestFilename
);
2902 void pkgAcqChangelog::Init(std::string
const &DestDir
, std::string
const &DestFilename
)
2904 if (Desc
.URI
.empty())
2907 // TRANSLATOR: %s=%s is sourcename=sourceversion, e.g. apt=1.1
2908 strprintf(ErrorText
, _("Changelog unavailable for %s=%s"), SrcName
.c_str(), SrcVersion
.c_str());
2909 // Let the error message print something sensible rather than "Failed to fetch /"
2910 if (DestFilename
.empty())
2911 DestFile
= SrcName
+ ".changelog";
2913 DestFile
= DestFilename
;
2914 Desc
.URI
= "changelog:/" + DestFile
;
2918 if (DestDir
.empty())
2920 std::string
const systemTemp
= GetTempDir();
2922 snprintf(tmpname
, sizeof(tmpname
), "%s/apt-changelog-XXXXXX", systemTemp
.c_str());
2923 if (NULL
== mkdtemp(tmpname
))
2925 _error
->Errno("mkdtemp", "mkdtemp failed in changelog acquire of %s %s", SrcName
.c_str(), SrcVersion
.c_str());
2929 DestFile
= TemporaryDirectory
= tmpname
;
2934 if (DestFilename
.empty())
2935 DestFile
= flCombine(DestFile
, SrcName
+ ".changelog");
2937 DestFile
= flCombine(DestFile
, DestFilename
);
2939 Desc
.ShortDesc
= "Changelog";
2940 strprintf(Desc
.Description
, "%s %s %s Changelog", URI::SiteOnly(Desc
.URI
).c_str(), SrcName
.c_str(), SrcVersion
.c_str());
2945 std::string
pkgAcqChangelog::URI(pkgCache::VerIterator
const &Ver
) /*{{{*/
2947 char const * const SrcName
= Ver
.SourcePkgName();
2948 char const * const SrcVersion
= Ver
.SourceVerStr();
2949 pkgCache::PkgFileIterator PkgFile
;
2950 // find the first source for this version which promises a changelog
2951 for (pkgCache::VerFileIterator VF
= Ver
.FileList(); VF
.end() == false; ++VF
)
2953 pkgCache::PkgFileIterator
const PF
= VF
.File();
2954 if (PF
.Flagged(pkgCache::Flag::NotSource
) || PF
->Release
== 0)
2957 pkgCache::RlsFileIterator
const RF
= PF
.ReleaseFile();
2958 std::string
const uri
= URI(RF
, PF
.Component(), SrcName
, SrcVersion
);
2965 std::string
pkgAcqChangelog::URITemplate(pkgCache::RlsFileIterator
const &Rls
)
2967 if (Rls
.end() == true || (Rls
->Label
== 0 && Rls
->Origin
== 0))
2969 std::string
const serverConfig
= "Acquire::Changelogs::URI";
2971 #define APT_EMPTY_SERVER \
2972 if (server.empty() == false) \
2974 if (server != "no") \
2978 #define APT_CHECK_SERVER(X, Y) \
2981 std::string const specialServerConfig = serverConfig + "::" + Y + #X + "::" + Rls.X(); \
2982 server = _config->Find(specialServerConfig); \
2985 // this way e.g. Debian-Security can fallback to Debian
2986 APT_CHECK_SERVER(Label
, "Override::")
2987 APT_CHECK_SERVER(Origin
, "Override::")
2989 if (RealFileExists(Rls
.FileName()))
2991 _error
->PushToStack();
2993 /* This can be costly. A caller wanting to get millions of URIs might
2994 want to do this on its own once and use Override settings.
2995 We don't do this here as Origin/Label are not as unique as they
2996 should be so this could produce request order-dependent anomalies */
2997 if (OpenMaybeClearSignedFile(Rls
.FileName(), rf
) == true)
2999 pkgTagFile
TagFile(&rf
, rf
.Size());
3000 pkgTagSection Section
;
3001 if (TagFile
.Step(Section
) == true)
3002 server
= Section
.FindS("Changelogs");
3004 _error
->RevertToStack();
3008 APT_CHECK_SERVER(Label
, "")
3009 APT_CHECK_SERVER(Origin
, "")
3010 #undef APT_CHECK_SERVER
3011 #undef APT_EMPTY_SERVER
3014 std::string
pkgAcqChangelog::URI(pkgCache::RlsFileIterator
const &Rls
,
3015 char const * const Component
, char const * const SrcName
,
3016 char const * const SrcVersion
)
3018 return URI(URITemplate(Rls
), Component
, SrcName
, SrcVersion
);
3020 std::string
pkgAcqChangelog::URI(std::string
const &Template
,
3021 char const * const Component
, char const * const SrcName
,
3022 char const * const SrcVersion
)
3024 if (Template
.find("CHANGEPATH") == std::string::npos
)
3027 // the path is: COMPONENT/SRC/SRCNAME/SRCNAME_SRCVER, e.g. main/a/apt/1.1 or contrib/liba/libapt/2.0
3028 std::string Src
= SrcName
;
3029 std::string path
= APT::String::Startswith(SrcName
, "lib") ? Src
.substr(0, 4) : Src
.substr(0,1);
3030 path
.append("/").append(Src
).append("/");
3031 path
.append(Src
).append("_").append(StripEpoch(SrcVersion
));
3032 // we omit component for releases without one (= flat-style repositories)
3033 if (Component
!= NULL
&& strlen(Component
) != 0)
3034 path
= std::string(Component
) + "/" + path
;
3036 return SubstVar(Template
, "CHANGEPATH", path
);
3039 // AcqChangelog::Failed - Failure handler /*{{{*/
3040 void pkgAcqChangelog::Failed(string
const &Message
, pkgAcquire::MethodConfig
const * const Cnf
)
3042 Item::Failed(Message
,Cnf
);
3044 std::string errText
;
3045 // TRANSLATOR: %s=%s is sourcename=sourceversion, e.g. apt=1.1
3046 strprintf(errText
, _("Changelog unavailable for %s=%s"), SrcName
.c_str(), SrcVersion
.c_str());
3048 // Error is probably something techy like 404 Not Found
3049 if (ErrorText
.empty())
3050 ErrorText
= errText
;
3052 ErrorText
= errText
+ " (" + ErrorText
+ ")";
3056 // AcqChangelog::Done - Item downloaded OK /*{{{*/
3057 void pkgAcqChangelog::Done(string
const &Message
,HashStringList
const &CalcHashes
,
3058 pkgAcquire::MethodConfig
const * const Cnf
)
3060 Item::Done(Message
,CalcHashes
,Cnf
);
3065 pkgAcqChangelog::~pkgAcqChangelog() /*{{{*/
3067 if (TemporaryDirectory
.empty() == false)
3069 unlink(DestFile
.c_str());
3070 rmdir(TemporaryDirectory
.c_str());
3075 // AcqFile::pkgAcqFile - Constructor /*{{{*/
3076 pkgAcqFile::pkgAcqFile(pkgAcquire
* const Owner
,string
const &URI
, HashStringList
const &Hashes
,
3077 unsigned long long const Size
,string
const &Dsc
,string
const &ShortDesc
,
3078 const string
&DestDir
, const string
&DestFilename
,
3079 bool const IsIndexFile
) :
3080 Item(Owner
), d(NULL
), IsIndexFile(IsIndexFile
), ExpectedHashes(Hashes
)
3082 Retries
= _config
->FindI("Acquire::Retries",0);
3084 if(!DestFilename
.empty())
3085 DestFile
= DestFilename
;
3086 else if(!DestDir
.empty())
3087 DestFile
= DestDir
+ "/" + flNotDir(URI
);
3089 DestFile
= flNotDir(URI
);
3093 Desc
.Description
= Dsc
;
3096 // Set the short description to the archive component
3097 Desc
.ShortDesc
= ShortDesc
;
3099 // Get the transfer sizes
3102 if (stat(DestFile
.c_str(),&Buf
) == 0)
3104 // Hmm, the partial file is too big, erase it
3105 if ((Size
> 0) && (unsigned long long)Buf
.st_size
> Size
)
3106 unlink(DestFile
.c_str());
3108 PartialSize
= Buf
.st_size
;
3114 // AcqFile::Done - Item downloaded OK /*{{{*/
3115 void pkgAcqFile::Done(string
const &Message
,HashStringList
const &CalcHashes
,
3116 pkgAcquire::MethodConfig
const * const Cnf
)
3118 Item::Done(Message
,CalcHashes
,Cnf
);
3120 string FileName
= LookupTag(Message
,"Filename");
3121 if (FileName
.empty() == true)
3124 ErrorText
= "Method gave a blank filename";
3130 // The files timestamp matches
3131 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
3134 // We have to copy it into place
3135 if (RealFileExists(DestFile
.c_str()) == false)
3138 if (_config
->FindB("Acquire::Source-Symlinks",true) == false ||
3139 Cnf
->Removable
== true)
3141 Desc
.URI
= "copy:" + FileName
;
3146 // Erase the file if it is a symlink so we can overwrite it
3148 if (lstat(DestFile
.c_str(),&St
) == 0)
3150 if (S_ISLNK(St
.st_mode
) != 0)
3151 unlink(DestFile
.c_str());
3155 if (symlink(FileName
.c_str(),DestFile
.c_str()) != 0)
3157 _error
->PushToStack();
3158 _error
->Errno("pkgAcqFile::Done", "Symlinking file %s failed", DestFile
.c_str());
3159 std::stringstream msg
;
3160 _error
->DumpErrors(msg
);
3161 _error
->RevertToStack();
3162 ErrorText
= msg
.str();
3169 // AcqFile::Failed - Failure handler /*{{{*/
3170 // ---------------------------------------------------------------------
3171 /* Here we try other sources */
3172 void pkgAcqFile::Failed(string
const &Message
, pkgAcquire::MethodConfig
const * const Cnf
)
3174 Item::Failed(Message
,Cnf
);
3176 // This is the retry counter
3178 Cnf
->LocalOnly
== false &&
3179 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
3189 string
pkgAcqFile::Custom600Headers() const /*{{{*/
3192 return "\nIndex-File: true";
3196 pkgAcqFile::~pkgAcqFile() {}