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/indexrecords.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(indexRecords
const * const MetaIndexParser
, pkgAcqMetaBase
* const TransactionManager
, pkgAcquire::Item
* const I
) /*{{{*/
114 if(MetaIndexParser
->IsAlwaysTrusted() || _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(indexRecords
* const Parser
, std::string
const &MetaKey
)/*{{{*/
126 return HashStringList();
127 indexRecords::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
;
149 HashStringList
pkgAcqTransactionItem::GetExpectedHashes() const
151 return GetExpectedHashesFor(GetMetaKey());
154 APT_CONST
bool pkgAcqMetaBase::HashesRequired() const
156 // Release and co have no hashes 'by design'.
159 HashStringList
pkgAcqMetaBase::GetExpectedHashes() const
161 return HashStringList();
164 APT_CONST
bool pkgAcqIndexDiffs::HashesRequired() const
166 /* We don't always have the diff of the downloaded pdiff file.
167 What we have for sure is hashes for the uncompressed file,
168 but rred uncompresses them on the fly while parsing, so not handled here.
169 Hashes are (also) checked while searching for (next) patch to apply. */
170 if (State
== StateFetchDiff
)
171 return available_patches
[0].download_hashes
.empty() == false;
174 HashStringList
pkgAcqIndexDiffs::GetExpectedHashes() const
176 if (State
== StateFetchDiff
)
177 return available_patches
[0].download_hashes
;
178 return HashStringList();
181 APT_CONST
bool pkgAcqIndexMergeDiffs::HashesRequired() const
183 /* @see #pkgAcqIndexDiffs::HashesRequired, with the difference that
184 we can check the rred result after all patches are applied as
185 we know the expected result rather than potentially apply more patches */
186 if (State
== StateFetchDiff
)
187 return patch
.download_hashes
.empty() == false;
188 return State
== StateApplyDiff
;
190 HashStringList
pkgAcqIndexMergeDiffs::GetExpectedHashes() const
192 if (State
== StateFetchDiff
)
193 return patch
.download_hashes
;
194 else if (State
== StateApplyDiff
)
195 return GetExpectedHashesFor(Target
.MetaKey
);
196 return HashStringList();
199 APT_CONST
bool pkgAcqArchive::HashesRequired() const
201 return LocalSource
== false;
203 HashStringList
pkgAcqArchive::GetExpectedHashes() const
205 // figured out while parsing the records
206 return ExpectedHashes
;
209 APT_CONST
bool pkgAcqFile::HashesRequired() const
211 // supplied as parameter at creation time, so the caller decides
212 return ExpectedHashes
.usable();
214 HashStringList
pkgAcqFile::GetExpectedHashes() const
216 return ExpectedHashes
;
219 // Acquire::Item::QueueURI and specialisations from child classes /*{{{*/
220 bool pkgAcquire::Item::QueueURI(pkgAcquire::ItemDesc
&Item
)
222 Owner
->Enqueue(Item
);
225 /* The idea here is that an item isn't queued if it exists on disk and the
226 transition manager was a hit as this means that the files it contains
227 the checksums for can't be updated either (or they are and we are asking
228 for a hashsum mismatch to happen which helps nobody) */
229 bool pkgAcqTransactionItem::QueueURI(pkgAcquire::ItemDesc
&Item
)
231 std::string
const FinalFile
= GetFinalFilename();
232 if (TransactionManager
!= NULL
&& TransactionManager
->IMSHit
== true &&
233 FileExists(FinalFile
) == true)
235 PartialFile
= DestFile
= FinalFile
;
239 return pkgAcquire::Item::QueueURI(Item
);
241 /* The transition manager InRelease itself (or its older sisters-in-law
242 Release & Release.gpg) is always queued as this allows us to rerun gpgv
243 on it to verify that we aren't stalled with old files */
244 bool pkgAcqMetaBase::QueueURI(pkgAcquire::ItemDesc
&Item
)
246 return pkgAcquire::Item::QueueURI(Item
);
248 /* the Diff/Index needs to queue also the up-to-date complete index file
249 to ensure that the list cleaner isn't eating it */
250 bool pkgAcqDiffIndex::QueueURI(pkgAcquire::ItemDesc
&Item
)
252 if (pkgAcqTransactionItem::QueueURI(Item
) == true)
258 // Acquire::Item::GetFinalFilename and specialisations for child classes /*{{{*/
259 std::string
pkgAcquire::Item::GetFinalFilename() const
261 return GetFinalFileNameFromURI(Desc
.URI
);
263 std::string
pkgAcqDiffIndex::GetFinalFilename() const
265 // the logic we inherent from pkgAcqBaseIndex isn't what we need here
266 return pkgAcquire::Item::GetFinalFilename();
268 std::string
pkgAcqIndex::GetFinalFilename() const
270 std::string
const FinalFile
= GetFinalFileNameFromURI(Target
.URI
);
271 return GetCompressedFileName(Target
.URI
, FinalFile
, CurrentCompressionExtension
);
273 std::string
pkgAcqMetaSig::GetFinalFilename() const
275 return GetFinalFileNameFromURI(Target
.URI
);
277 std::string
pkgAcqBaseIndex::GetFinalFilename() const
279 return GetFinalFileNameFromURI(Target
.URI
);
281 std::string
pkgAcqMetaBase::GetFinalFilename() const
283 return GetFinalFileNameFromURI(Target
.URI
);
285 std::string
pkgAcqArchive::GetFinalFilename() const
287 return _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
290 // pkgAcqTransactionItem::GetMetaKey and specialisations for child classes /*{{{*/
291 std::string
pkgAcqTransactionItem::GetMetaKey() const
293 return Target
.MetaKey
;
295 std::string
pkgAcqIndex::GetMetaKey() const
297 if (Stage
== STAGE_DECOMPRESS_AND_VERIFY
|| CurrentCompressionExtension
== "uncompressed")
298 return Target
.MetaKey
;
299 return Target
.MetaKey
+ "." + CurrentCompressionExtension
;
301 std::string
pkgAcqDiffIndex::GetMetaKey() const
303 return Target
.MetaKey
+ ".diff/Index";
306 //pkgAcqTransactionItem::TransactionState and specialisations for child classes /*{{{*/
307 bool pkgAcqTransactionItem::TransactionState(TransactionStates
const state
)
309 bool const Debug
= _config
->FindB("Debug::Acquire::Transaction", false);
312 case TransactionAbort
:
314 std::clog
<< " Cancel: " << DestFile
<< std::endl
;
315 if (Status
== pkgAcquire::Item::StatIdle
)
317 Status
= pkgAcquire::Item::StatDone
;
321 case TransactionCommit
:
322 if(PartialFile
!= "")
325 std::clog
<< "mv " << PartialFile
<< " -> "<< DestFile
<< " # " << DescURI() << std::endl
;
327 Rename(PartialFile
, DestFile
);
330 std::clog
<< "rm " << DestFile
<< " # " << DescURI() << std::endl
;
331 unlink(DestFile
.c_str());
337 bool pkgAcqMetaBase::TransactionState(TransactionStates
const state
)
339 // Do not remove InRelease on IMSHit of Release.gpg [yes, this is very edgecasey]
340 if (TransactionManager
->IMSHit
== false)
341 return pkgAcqTransactionItem::TransactionState(state
);
344 bool pkgAcqIndex::TransactionState(TransactionStates
const state
)
346 if (pkgAcqTransactionItem::TransactionState(state
) == false)
351 case TransactionAbort
:
352 if (Stage
== STAGE_DECOMPRESS_AND_VERIFY
)
354 // keep the compressed file, but drop the decompressed
355 EraseFileName
.clear();
356 if (PartialFile
.empty() == false && flExtension(PartialFile
) == "decomp")
357 unlink(PartialFile
.c_str());
360 case TransactionCommit
:
361 if (EraseFileName
.empty() == false)
362 unlink(EraseFileName
.c_str());
367 bool pkgAcqDiffIndex::TransactionState(TransactionStates
const state
)
369 if (pkgAcqTransactionItem::TransactionState(state
) == false)
374 case TransactionCommit
:
376 case TransactionAbort
:
377 std::string
const Partial
= GetPartialFileNameFromURI(Target
.URI
);
378 unlink(Partial
.c_str());
386 class APT_HIDDEN NoActionItem
: public pkgAcquire::Item
/*{{{*/
387 /* The sole purpose of this class is having an item which does nothing to
388 reach its done state to prevent cleanup deleting the mentioned file.
389 Handy in cases in which we know we have the file already, like IMS-Hits. */
391 IndexTarget
const Target
;
393 virtual std::string
DescURI() const {return Target
.URI
;};
394 virtual HashStringList
GetExpectedHashes() const {return HashStringList();};
396 NoActionItem(pkgAcquire
* const Owner
, IndexTarget
const &Target
) :
397 pkgAcquire::Item(Owner
), Target(Target
)
400 DestFile
= GetFinalFileNameFromURI(Target
.URI
);
405 // Acquire::Item::Item - Constructor /*{{{*/
406 APT_IGNORE_DEPRECATED_PUSH
407 pkgAcquire::Item::Item(pkgAcquire
* const owner
) :
408 FileSize(0), PartialSize(0), Mode(0), ID(0), Complete(false), Local(false),
409 QueueCounter(0), ExpectedAdditionalItems(0), Owner(owner
), d(NULL
)
414 APT_IGNORE_DEPRECATED_POP
416 // Acquire::Item::~Item - Destructor /*{{{*/
417 pkgAcquire::Item::~Item()
422 std::string
pkgAcquire::Item::Custom600Headers() const /*{{{*/
424 return std::string();
427 std::string
pkgAcquire::Item::ShortDesc() const /*{{{*/
432 APT_CONST
void pkgAcquire::Item::Finished() /*{{{*/
436 APT_PURE pkgAcquire
* pkgAcquire::Item::GetOwner() const /*{{{*/
441 APT_CONST
pkgAcquire::ItemDesc
&pkgAcquire::Item::GetItemDesc() /*{{{*/
446 APT_CONST
bool pkgAcquire::Item::IsTrusted() const /*{{{*/
451 // Acquire::Item::Failed - Item failed to download /*{{{*/
452 // ---------------------------------------------------------------------
453 /* We return to an idle state if there are still other queues that could
455 void pkgAcquire::Item::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)
457 if(ErrorText
.empty())
458 ErrorText
= LookupTag(Message
,"Message");
459 UsedMirror
= LookupTag(Message
,"UsedMirror");
460 if (QueueCounter
<= 1)
462 /* This indicates that the file is not available right now but might
463 be sometime later. If we do a retry cycle then this should be
465 if (Cnf
!= NULL
&& Cnf
->LocalOnly
== true &&
466 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
482 case StatTransientNetworkError
:
489 string
const FailReason
= LookupTag(Message
, "FailReason");
490 if (FailReason
== "MaximumSizeExceeded")
491 RenameOnError(MaximumSizeExceeded
);
492 else if (Status
== StatAuthError
)
493 RenameOnError(HashSumMismatch
);
495 // report mirror failure back to LP if we actually use a mirror
496 if (FailReason
.empty() == false)
497 ReportMirrorFailure(FailReason
);
499 ReportMirrorFailure(ErrorText
);
501 if (QueueCounter
> 1)
505 // Acquire::Item::Start - Item has begun to download /*{{{*/
506 // ---------------------------------------------------------------------
507 /* Stash status and the file size. Note that setting Complete means
508 sub-phases of the acquire process such as decompresion are operating */
509 void pkgAcquire::Item::Start(string
const &/*Message*/, unsigned long long const Size
)
511 Status
= StatFetching
;
513 if (FileSize
== 0 && Complete
== false)
517 // Acquire::Item::Done - Item downloaded OK /*{{{*/
518 void pkgAcquire::Item::Done(string
const &Message
, HashStringList
const &Hashes
,
519 pkgAcquire::MethodConfig
const * const /*Cnf*/)
521 // We just downloaded something..
522 UsedMirror
= LookupTag(Message
,"UsedMirror");
525 unsigned long long const downloadedSize
= Hashes
.FileSize();
526 if (downloadedSize
!= 0)
528 FileSize
= downloadedSize
;
532 ErrorText
= string();
533 Owner
->Dequeue(this);
536 // Acquire::Item::Rename - Rename a file /*{{{*/
537 // ---------------------------------------------------------------------
538 /* This helper function is used by a lot of item methods as their final
540 bool pkgAcquire::Item::Rename(string
const &From
,string
const &To
)
542 if (From
== To
|| rename(From
.c_str(),To
.c_str()) == 0)
546 strprintf(S
, _("rename failed, %s (%s -> %s)."), strerror(errno
),
547 From
.c_str(),To
.c_str());
549 if (ErrorText
.empty())
552 ErrorText
= ErrorText
+ ": " + S
;
556 void pkgAcquire::Item::Dequeue() /*{{{*/
558 Owner
->Dequeue(this);
561 bool pkgAcquire::Item::RenameOnError(pkgAcquire::Item::RenameOnErrorState
const error
)/*{{{*/
563 if (RealFileExists(DestFile
))
564 Rename(DestFile
, DestFile
+ ".FAILED");
569 case HashSumMismatch
:
570 errtext
= _("Hash Sum mismatch");
571 Status
= StatAuthError
;
572 ReportMirrorFailure("HashChecksumFailure");
575 errtext
= _("Size mismatch");
576 Status
= StatAuthError
;
577 ReportMirrorFailure("SizeFailure");
580 errtext
= _("Invalid file format");
582 // do not report as usually its not the mirrors fault, but Portal/Proxy
585 errtext
= _("Signature error");
589 errtext
= _("Does not start with a cleartext signature");
592 case MaximumSizeExceeded
:
593 // the method is expected to report a good error for this
597 // no handling here, done by callers
600 if (ErrorText
.empty())
605 void pkgAcquire::Item::SetActiveSubprocess(const std::string
&subprocess
)/*{{{*/
607 ActiveSubprocess
= subprocess
;
608 APT_IGNORE_DEPRECATED(Mode
= ActiveSubprocess
.c_str();)
611 // Acquire::Item::ReportMirrorFailure /*{{{*/
612 void pkgAcquire::Item::ReportMirrorFailure(string
const &FailCode
)
614 // we only act if a mirror was used at all
615 if(UsedMirror
.empty())
618 std::cerr
<< "\nReportMirrorFailure: "
620 << " Uri: " << DescURI()
622 << FailCode
<< std::endl
;
624 string report
= _config
->Find("Methods::Mirror::ProblemReporting",
625 "/usr/lib/apt/apt-report-mirror-failure");
626 if(!FileExists(report
))
629 std::vector
<char const*> Args
;
630 Args
.push_back(report
.c_str());
631 Args
.push_back(UsedMirror
.c_str());
632 Args
.push_back(DescURI().c_str());
633 Args
.push_back(FailCode
.c_str());
634 Args
.push_back(NULL
);
636 pid_t pid
= ExecFork();
639 _error
->Error("ReportMirrorFailure Fork failed");
644 execvp(Args
[0], (char**)Args
.data());
645 std::cerr
<< "Could not exec " << Args
[0] << std::endl
;
648 if(!ExecWait(pid
, "report-mirror-failure"))
650 _error
->Warning("Couldn't report problem to '%s'",
651 _config
->Find("Methods::Mirror::ProblemReporting").c_str());
655 std::string
pkgAcquire::Item::HashSum() const /*{{{*/
657 HashStringList
const hashes
= GetExpectedHashes();
658 HashString
const * const hs
= hashes
.find(NULL
);
659 return hs
!= NULL
? hs
->toStr() : "";
663 pkgAcqTransactionItem::pkgAcqTransactionItem(pkgAcquire
* const Owner
, /*{{{*/
664 pkgAcqMetaBase
* const transactionManager
, IndexTarget
const &target
) :
665 pkgAcquire::Item(Owner
), d(NULL
), Target(target
), TransactionManager(transactionManager
)
667 if (TransactionManager
!= this)
668 TransactionManager
->Add(this);
671 pkgAcqTransactionItem::~pkgAcqTransactionItem() /*{{{*/
675 HashStringList
pkgAcqTransactionItem::GetExpectedHashesFor(std::string
const &MetaKey
) const /*{{{*/
677 return GetExpectedHashesFromFor(TransactionManager
->MetaIndexParser
, MetaKey
);
681 // AcqMetaBase - Constructor /*{{{*/
682 pkgAcqMetaBase::pkgAcqMetaBase(pkgAcquire
* const Owner
,
683 pkgAcqMetaBase
* const TransactionManager
,
684 std::vector
<IndexTarget
> const &IndexTargets
,
685 IndexTarget
const &DataTarget
,
686 indexRecords
* const MetaIndexParser
)
687 : pkgAcqTransactionItem(Owner
, TransactionManager
, DataTarget
), d(NULL
),
688 MetaIndexParser(MetaIndexParser
), LastMetaIndexParser(NULL
), 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();
813 if (stat(FinalFile
.c_str(),&Buf
) == 0)
814 Header
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
819 // AcqMetaBase::QueueForSignatureVerify /*{{{*/
820 void pkgAcqMetaBase::QueueForSignatureVerify(pkgAcqTransactionItem
* const I
, std::string
const &File
, std::string
const &Signature
)
823 I
->Desc
.URI
= "gpgv:" + Signature
;
826 I
->SetActiveSubprocess("gpgv");
829 // AcqMetaBase::CheckDownloadDone /*{{{*/
830 bool pkgAcqMetaBase::CheckDownloadDone(pkgAcqTransactionItem
* const I
, const std::string
&Message
, HashStringList
const &Hashes
) const
832 // We have just finished downloading a Release file (it is not
835 string
const FileName
= LookupTag(Message
,"Filename");
836 if (FileName
.empty() == true)
838 I
->Status
= StatError
;
839 I
->ErrorText
= "Method gave a blank filename";
843 if (FileName
!= I
->DestFile
&& RealFileExists(I
->DestFile
) == false)
846 I
->Desc
.URI
= "copy:" + FileName
;
847 I
->QueueURI(I
->Desc
);
851 // make sure to verify against the right file on I-M-S hit
852 bool IMSHit
= StringToBool(LookupTag(Message
,"IMS-Hit"), false);
853 if (IMSHit
== false && Hashes
.usable())
855 // detect IMS-Hits servers haven't detected by Hash comparison
856 std::string
const FinalFile
= I
->GetFinalFilename();
857 if (RealFileExists(FinalFile
) && Hashes
.VerifyFile(FinalFile
) == true)
860 unlink(I
->DestFile
.c_str());
866 // for simplicity, the transaction manager is always InRelease
867 // even if it doesn't exist.
868 if (TransactionManager
!= NULL
)
869 TransactionManager
->IMSHit
= true;
870 I
->PartialFile
= I
->DestFile
= I
->GetFinalFilename();
873 // set Item to complete as the remaining work is all local (verify etc)
879 bool pkgAcqMetaBase::CheckAuthDone(string
const &Message
) /*{{{*/
881 // At this point, the gpgv method has succeeded, so there is a
882 // valid signature from a key in the trusted keyring. We
883 // perform additional verification of its contents, and use them
884 // to verify the indexes we are about to download
886 if (TransactionManager
->IMSHit
== false)
888 // open the last (In)Release if we have it
889 std::string
const FinalFile
= GetFinalFilename();
890 std::string FinalRelease
;
891 std::string FinalInRelease
;
892 if (APT::String::Endswith(FinalFile
, "InRelease"))
894 FinalInRelease
= FinalFile
;
895 FinalRelease
= FinalFile
.substr(0, FinalFile
.length() - strlen("InRelease")) + "Release";
899 FinalInRelease
= FinalFile
.substr(0, FinalFile
.length() - strlen("Release")) + "InRelease";
900 FinalRelease
= FinalFile
;
902 if (RealFileExists(FinalInRelease
) || RealFileExists(FinalRelease
))
904 TransactionManager
->LastMetaIndexParser
= new indexRecords
;
905 _error
->PushToStack();
906 if (RealFileExists(FinalInRelease
))
907 TransactionManager
->LastMetaIndexParser
->Load(FinalInRelease
);
909 TransactionManager
->LastMetaIndexParser
->Load(FinalRelease
);
910 // its unlikely to happen, but if what we have is bad ignore it
911 if (_error
->PendingError())
913 delete TransactionManager
->LastMetaIndexParser
;
914 TransactionManager
->LastMetaIndexParser
= NULL
;
916 _error
->RevertToStack();
920 if (TransactionManager
->MetaIndexParser
->Load(DestFile
) == false)
922 Status
= StatAuthError
;
923 ErrorText
= TransactionManager
->MetaIndexParser
->ErrorText
;
927 if (!VerifyVendor(Message
))
929 Status
= StatAuthError
;
933 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
934 std::cerr
<< "Signature verification succeeded: "
935 << DestFile
<< std::endl
;
937 // Download further indexes with verification
943 void pkgAcqMetaBase::QueueIndexes(bool const verify
) /*{{{*/
945 // at this point the real Items are loaded in the fetcher
946 ExpectedAdditionalItems
= 0;
948 for (std::vector
<IndexTarget
>::const_iterator Target
= IndexTargets
.begin();
949 Target
!= IndexTargets
.end();
952 bool trypdiff
= _config
->FindB("Acquire::PDiffs", true);
955 if (TransactionManager
->MetaIndexParser
->Exists(Target
->MetaKey
) == false)
957 // optional targets that we do not have in the Release file are skipped
958 if (Target
->IsOptional
)
961 Status
= StatAuthError
;
962 strprintf(ErrorText
, _("Unable to find expected entry '%s' in Release file (Wrong sources.list entry or malformed file)"), Target
->MetaKey
.c_str());
966 if (RealFileExists(GetFinalFileNameFromURI(Target
->URI
)))
968 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
970 HashStringList
const newFile
= GetExpectedHashesFromFor(TransactionManager
->MetaIndexParser
, Target
->MetaKey
);
971 HashStringList
const oldFile
= GetExpectedHashesFromFor(TransactionManager
->LastMetaIndexParser
, Target
->MetaKey
);
972 if (newFile
== oldFile
)
974 // we have the file already, no point in trying to acquire it again
975 new NoActionItem(Owner
, *Target
);
981 trypdiff
= false; // no file to patch
983 // check if we have patches available
984 trypdiff
&= TransactionManager
->MetaIndexParser
->Exists(Target
->MetaKey
+ ".diff/Index");
986 // if we have no file to patch, no point in trying
987 trypdiff
&= RealFileExists(GetFinalFileNameFromURI(Target
->URI
));
989 // no point in patching from local sources
992 std::string
const proto
= Target
->URI
.substr(0, strlen("file:/"));
993 if (proto
== "file:/" || proto
== "copy:/" || proto
== "cdrom:")
997 // Queue the Index file (Packages, Sources, Translation-$foo, …)
999 new pkgAcqDiffIndex(Owner
, TransactionManager
, *Target
);
1001 new pkgAcqIndex(Owner
, TransactionManager
, *Target
);
1005 bool pkgAcqMetaBase::VerifyVendor(string
const &Message
) /*{{{*/
1007 string::size_type pos
;
1009 // check for missing sigs (that where not fatal because otherwise we had
1012 string msg
= _("There is no public key available for the "
1013 "following key IDs:\n");
1014 pos
= Message
.find("NO_PUBKEY ");
1015 if (pos
!= std::string::npos
)
1017 string::size_type start
= pos
+strlen("NO_PUBKEY ");
1018 string Fingerprint
= Message
.substr(start
, Message
.find("\n")-start
);
1019 missingkeys
+= (Fingerprint
);
1021 if(!missingkeys
.empty())
1022 _error
->Warning("%s", (msg
+ missingkeys
).c_str());
1024 string Transformed
= TransactionManager
->MetaIndexParser
->GetExpectedDist();
1026 if (Transformed
== "../project/experimental")
1028 Transformed
= "experimental";
1031 pos
= Transformed
.rfind('/');
1032 if (pos
!= string::npos
)
1034 Transformed
= Transformed
.substr(0, pos
);
1037 if (Transformed
== ".")
1042 if (_config
->FindB("Acquire::Check-Valid-Until", true) == true &&
1043 TransactionManager
->MetaIndexParser
->GetValidUntil() > 0) {
1044 time_t const invalid_since
= time(NULL
) - TransactionManager
->MetaIndexParser
->GetValidUntil();
1045 if (invalid_since
> 0)
1049 // TRANSLATOR: The first %s is the URL of the bad Release file, the second is
1050 // the time since then the file is invalid - formated in the same way as in
1051 // the download progress display (e.g. 7d 3h 42min 1s)
1052 _("Release file for %s is expired (invalid since %s). "
1053 "Updates for this repository will not be applied."),
1054 Target
.URI
.c_str(), TimeToStr(invalid_since
).c_str());
1055 if (ErrorText
.empty())
1057 return _error
->Error("%s", errmsg
.c_str());
1061 /* Did we get a file older than what we have? This is a last minute IMS hit and doubles
1062 as a prevention of downgrading us to older (still valid) files */
1063 if (TransactionManager
->IMSHit
== false && TransactionManager
->LastMetaIndexParser
!= NULL
&&
1064 TransactionManager
->LastMetaIndexParser
->GetDate() > TransactionManager
->MetaIndexParser
->GetDate())
1066 TransactionManager
->IMSHit
= true;
1067 unlink(DestFile
.c_str());
1068 PartialFile
= DestFile
= GetFinalFilename();
1069 delete TransactionManager
->MetaIndexParser
;
1070 TransactionManager
->MetaIndexParser
= TransactionManager
->LastMetaIndexParser
;
1071 TransactionManager
->LastMetaIndexParser
= NULL
;
1074 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1076 std::cerr
<< "Got Codename: " << TransactionManager
->MetaIndexParser
->GetDist() << std::endl
;
1077 std::cerr
<< "Expecting Dist: " << TransactionManager
->MetaIndexParser
->GetExpectedDist() << std::endl
;
1078 std::cerr
<< "Transformed Dist: " << Transformed
<< std::endl
;
1081 if (TransactionManager
->MetaIndexParser
->CheckDist(Transformed
) == false)
1083 // This might become fatal one day
1084 // Status = StatAuthError;
1085 // ErrorText = "Conflicting distribution; expected "
1086 // + MetaIndexParser->GetExpectedDist() + " but got "
1087 // + MetaIndexParser->GetDist();
1089 if (!Transformed
.empty())
1091 _error
->Warning(_("Conflicting distribution: %s (expected %s but got %s)"),
1092 Desc
.Description
.c_str(),
1093 Transformed
.c_str(),
1094 TransactionManager
->MetaIndexParser
->GetDist().c_str());
1101 pkgAcqMetaBase::~pkgAcqMetaBase() {}
1103 pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire
* const Owner
, /*{{{*/
1104 IndexTarget
const &ClearsignedTarget
,
1105 IndexTarget
const &DetachedDataTarget
, IndexTarget
const &DetachedSigTarget
,
1106 std::vector
<IndexTarget
> const &IndexTargets
,
1107 indexRecords
* const MetaIndexParser
) :
1108 pkgAcqMetaIndex(Owner
, this, ClearsignedTarget
, DetachedSigTarget
, IndexTargets
, MetaIndexParser
),
1109 d(NULL
), ClearsignedTarget(ClearsignedTarget
),
1110 DetachedDataTarget(DetachedDataTarget
)
1112 // index targets + (worst case:) Release/Release.gpg
1113 ExpectedAdditionalItems
= IndexTargets
.size() + 2;
1114 TransactionManager
->Add(this);
1117 pkgAcqMetaClearSig::~pkgAcqMetaClearSig() /*{{{*/
1121 // pkgAcqMetaClearSig::Custom600Headers - Insert custom request headers /*{{{*/
1122 string
pkgAcqMetaClearSig::Custom600Headers() const
1124 string Header
= pkgAcqMetaBase::Custom600Headers();
1125 Header
+= "\nFail-Ignore: true";
1129 // pkgAcqMetaClearSig::Done - We got a file /*{{{*/
1130 void pkgAcqMetaClearSig::Done(std::string
const &Message
,
1131 HashStringList
const &Hashes
,
1132 pkgAcquire::MethodConfig
const * const Cnf
)
1134 Item::Done(Message
, Hashes
, Cnf
);
1136 // if we expect a ClearTextSignature (InRelease), ensure that
1137 // this is what we get and if not fail to queue a
1138 // Release/Release.gpg, see #346386
1139 if (FileExists(DestFile
) && !StartsWithGPGClearTextSignature(DestFile
))
1141 pkgAcquire::Item::Failed(Message
, Cnf
);
1142 RenameOnError(NotClearsigned
);
1143 TransactionManager
->AbortTransaction();
1147 if(AuthPass
== false)
1149 if(CheckDownloadDone(this, Message
, Hashes
) == true)
1150 QueueForSignatureVerify(this, DestFile
, DestFile
);
1153 else if(CheckAuthDone(Message
) == true)
1155 if (TransactionManager
->IMSHit
== false)
1156 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
1157 else if (RealFileExists(GetFinalFilename()) == false)
1159 // We got an InRelease file IMSHit, but we haven't one, which means
1160 // we had a valid Release/Release.gpg combo stepping in, which we have
1161 // to 'acquire' now to ensure list cleanup isn't removing them
1162 new NoActionItem(Owner
, DetachedDataTarget
);
1163 new NoActionItem(Owner
, DetachedSigTarget
);
1168 void pkgAcqMetaClearSig::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
) /*{{{*/
1170 Item::Failed(Message
, Cnf
);
1172 // we failed, we will not get additional items from this method
1173 ExpectedAdditionalItems
= 0;
1175 if (AuthPass
== false)
1177 // Queue the 'old' InRelease file for removal if we try Release.gpg
1178 // as otherwise the file will stay around and gives a false-auth
1179 // impression (CVE-2012-0214)
1180 TransactionManager
->TransactionStageRemoval(this, GetFinalFilename());
1183 new pkgAcqMetaIndex(Owner
, TransactionManager
, DetachedDataTarget
, DetachedSigTarget
, IndexTargets
, TransactionManager
->MetaIndexParser
);
1187 if(CheckStopAuthentication(this, Message
))
1190 _error
->Warning(_("The data from '%s' is not signed. Packages "
1191 "from that repository can not be authenticated."),
1192 ClearsignedTarget
.Description
.c_str());
1194 // No Release file was present, or verification failed, so fall
1195 // back to queueing Packages files without verification
1196 // only allow going further if the users explicitely wants it
1197 if(AllowInsecureRepositories(TransactionManager
->MetaIndexParser
, TransactionManager
, this) == true)
1201 /* InRelease files become Release files, otherwise
1202 * they would be considered as trusted later on */
1203 string
const FinalRelease
= GetFinalFileNameFromURI(DetachedDataTarget
.URI
);
1204 string
const PartialRelease
= GetPartialFileNameFromURI(DetachedDataTarget
.URI
);
1205 string
const FinalReleasegpg
= GetFinalFileNameFromURI(DetachedSigTarget
.URI
);
1206 string
const FinalInRelease
= GetFinalFilename();
1207 Rename(DestFile
, PartialRelease
);
1208 TransactionManager
->TransactionStageCopy(this, PartialRelease
, FinalRelease
);
1210 if (RealFileExists(FinalReleasegpg
) || RealFileExists(FinalInRelease
))
1212 // open the last Release if we have it
1213 if (TransactionManager
->IMSHit
== false)
1215 TransactionManager
->LastMetaIndexParser
= new indexRecords
;
1216 _error
->PushToStack();
1217 if (RealFileExists(FinalInRelease
))
1218 TransactionManager
->LastMetaIndexParser
->Load(FinalInRelease
);
1220 TransactionManager
->LastMetaIndexParser
->Load(FinalRelease
);
1221 // its unlikely to happen, but if what we have is bad ignore it
1222 if (_error
->PendingError())
1224 delete TransactionManager
->LastMetaIndexParser
;
1225 TransactionManager
->LastMetaIndexParser
= NULL
;
1227 _error
->RevertToStack();
1231 // we parse the indexes here because at this point the user wanted
1232 // a repository that may potentially harm him
1233 if (TransactionManager
->MetaIndexParser
->Load(PartialRelease
) == false || VerifyVendor(Message
) == false)
1234 /* expired Release files are still a problem you need extra force for */;
1242 pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire
* const Owner
, /*{{{*/
1243 pkgAcqMetaBase
* const TransactionManager
,
1244 IndexTarget
const &DataTarget
,
1245 IndexTarget
const &DetachedSigTarget
,
1246 vector
<IndexTarget
> const &IndexTargets
,
1247 indexRecords
* const MetaIndexParser
) :
1248 pkgAcqMetaBase(Owner
, TransactionManager
, IndexTargets
, DataTarget
, MetaIndexParser
), d(NULL
),
1249 DetachedSigTarget(DetachedSigTarget
)
1251 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1252 std::clog
<< "New pkgAcqMetaIndex with TransactionManager "
1253 << this->TransactionManager
<< std::endl
;
1255 DestFile
= GetPartialFileNameFromURI(DataTarget
.URI
);
1258 Desc
.Description
= DataTarget
.Description
;
1260 Desc
.ShortDesc
= DataTarget
.ShortDesc
;
1261 Desc
.URI
= DataTarget
.URI
;
1263 // we expect more item
1264 ExpectedAdditionalItems
= IndexTargets
.size();
1268 void pkgAcqMetaIndex::Done(string
const &Message
, /*{{{*/
1269 HashStringList
const &Hashes
,
1270 pkgAcquire::MethodConfig
const * const Cfg
)
1272 Item::Done(Message
,Hashes
,Cfg
);
1274 if(CheckDownloadDone(this, Message
, Hashes
))
1276 // we have a Release file, now download the Signature, all further
1277 // verify/queue for additional downloads will be done in the
1278 // pkgAcqMetaSig::Done() code
1279 new pkgAcqMetaSig(Owner
, TransactionManager
, DetachedSigTarget
, this);
1283 // pkgAcqMetaIndex::Failed - no Release file present /*{{{*/
1284 void pkgAcqMetaIndex::Failed(string
const &Message
,
1285 pkgAcquire::MethodConfig
const * const Cnf
)
1287 pkgAcquire::Item::Failed(Message
, Cnf
);
1290 _error
->Warning(_("The repository '%s' does not have a Release file. "
1291 "This is deprecated, please contact the owner of the "
1292 "repository."), Target
.Description
.c_str());
1294 // No Release file was present so fall
1295 // back to queueing Packages files without verification
1296 // only allow going further if the users explicitely wants it
1297 if(AllowInsecureRepositories(TransactionManager
->MetaIndexParser
, TransactionManager
, this) == true)
1299 // ensure old Release files are removed
1300 TransactionManager
->TransactionStageRemoval(this, GetFinalFilename());
1301 delete TransactionManager
->MetaIndexParser
;
1302 TransactionManager
->MetaIndexParser
= NULL
;
1304 // queue without any kind of hashsum support
1305 QueueIndexes(false);
1309 void pkgAcqMetaIndex::Finished() /*{{{*/
1311 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1312 std::clog
<< "Finished: " << DestFile
<<std::endl
;
1313 if(TransactionManager
!= NULL
&&
1314 TransactionManager
->TransactionHasError() == false)
1315 TransactionManager
->CommitTransaction();
1318 std::string
pkgAcqMetaIndex::DescURI() const /*{{{*/
1323 pkgAcqMetaIndex::~pkgAcqMetaIndex() {}
1325 // AcqMetaSig::AcqMetaSig - Constructor /*{{{*/
1326 pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire
* const Owner
,
1327 pkgAcqMetaBase
* const TransactionManager
,
1328 IndexTarget
const &Target
,
1329 pkgAcqMetaIndex
* const MetaIndex
) :
1330 pkgAcqTransactionItem(Owner
, TransactionManager
, Target
), d(NULL
), MetaIndex(MetaIndex
)
1332 DestFile
= GetPartialFileNameFromURI(Target
.URI
);
1334 // remove any partial downloaded sig-file in partial/.
1335 // it may confuse proxies and is too small to warrant a
1336 // partial download anyway
1337 unlink(DestFile
.c_str());
1339 // set the TransactionManager
1340 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1341 std::clog
<< "New pkgAcqMetaSig with TransactionManager "
1342 << TransactionManager
<< std::endl
;
1345 Desc
.Description
= Target
.Description
;
1347 Desc
.ShortDesc
= Target
.ShortDesc
;
1348 Desc
.URI
= Target
.URI
;
1350 // If we got a hit for Release, we will get one for Release.gpg too (or obscure errors),
1351 // so we skip the download step and go instantly to verification
1352 if (TransactionManager
->IMSHit
== true && RealFileExists(GetFinalFilename()))
1356 PartialFile
= DestFile
= GetFinalFilename();
1357 MetaIndexFileSignature
= DestFile
;
1358 MetaIndex
->QueueForSignatureVerify(this, MetaIndex
->DestFile
, DestFile
);
1364 pkgAcqMetaSig::~pkgAcqMetaSig() /*{{{*/
1368 // AcqMetaSig::Done - The signature was downloaded/verified /*{{{*/
1369 void pkgAcqMetaSig::Done(string
const &Message
, HashStringList
const &Hashes
,
1370 pkgAcquire::MethodConfig
const * const Cfg
)
1372 if (MetaIndexFileSignature
.empty() == false)
1374 DestFile
= MetaIndexFileSignature
;
1375 MetaIndexFileSignature
.clear();
1377 Item::Done(Message
, Hashes
, Cfg
);
1379 if(MetaIndex
->AuthPass
== false)
1381 if(MetaIndex
->CheckDownloadDone(this, Message
, Hashes
) == true)
1383 // destfile will be modified to point to MetaIndexFile for the
1384 // gpgv method, so we need to save it here
1385 MetaIndexFileSignature
= DestFile
;
1386 MetaIndex
->QueueForSignatureVerify(this, MetaIndex
->DestFile
, DestFile
);
1390 else if(MetaIndex
->CheckAuthDone(Message
) == true)
1392 if (TransactionManager
->IMSHit
== false)
1394 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
1395 TransactionManager
->TransactionStageCopy(MetaIndex
, MetaIndex
->DestFile
, MetaIndex
->GetFinalFilename());
1400 void pkgAcqMetaSig::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
1402 Item::Failed(Message
,Cnf
);
1404 // check if we need to fail at this point
1405 if (MetaIndex
->AuthPass
== true && MetaIndex
->CheckStopAuthentication(this, Message
))
1408 string
const FinalRelease
= MetaIndex
->GetFinalFilename();
1409 string
const FinalReleasegpg
= GetFinalFilename();
1410 string
const FinalInRelease
= TransactionManager
->GetFinalFilename();
1412 if (RealFileExists(FinalReleasegpg
) || RealFileExists(FinalInRelease
))
1414 std::string downgrade_msg
;
1415 strprintf(downgrade_msg
, _("The repository '%s' is no longer signed."),
1416 MetaIndex
->Target
.Description
.c_str());
1417 if(_config
->FindB("Acquire::AllowDowngradeToInsecureRepositories"))
1419 // meh, the users wants to take risks (we still mark the packages
1420 // from this repository as unauthenticated)
1421 _error
->Warning("%s", downgrade_msg
.c_str());
1422 _error
->Warning(_("This is normally not allowed, but the option "
1423 "Acquire::AllowDowngradeToInsecureRepositories was "
1424 "given to override it."));
1427 _error
->Error("%s", downgrade_msg
.c_str());
1428 if (TransactionManager
->IMSHit
== false)
1429 Rename(MetaIndex
->DestFile
, MetaIndex
->DestFile
+ ".FAILED");
1430 Item::Failed("Message: " + downgrade_msg
, Cnf
);
1431 TransactionManager
->AbortTransaction();
1436 _error
->Warning(_("The data from '%s' is not signed. Packages "
1437 "from that repository can not be authenticated."),
1438 MetaIndex
->Target
.Description
.c_str());
1440 // ensures that a Release.gpg file in the lists/ is removed by the transaction
1441 TransactionManager
->TransactionStageRemoval(this, DestFile
);
1443 // only allow going further if the users explicitely wants it
1444 if(AllowInsecureRepositories(TransactionManager
->MetaIndexParser
, TransactionManager
, this) == true)
1446 if (RealFileExists(FinalReleasegpg
) || RealFileExists(FinalInRelease
))
1448 // open the last Release if we have it
1449 if (TransactionManager
->IMSHit
== false)
1451 TransactionManager
->LastMetaIndexParser
= new indexRecords
;
1452 _error
->PushToStack();
1453 if (RealFileExists(FinalInRelease
))
1454 TransactionManager
->LastMetaIndexParser
->Load(FinalInRelease
);
1456 TransactionManager
->LastMetaIndexParser
->Load(FinalRelease
);
1457 // its unlikely to happen, but if what we have is bad ignore it
1458 if (_error
->PendingError())
1460 delete TransactionManager
->LastMetaIndexParser
;
1461 TransactionManager
->LastMetaIndexParser
= NULL
;
1463 _error
->RevertToStack();
1467 // we parse the indexes here because at this point the user wanted
1468 // a repository that may potentially harm him
1469 if (TransactionManager
->MetaIndexParser
->Load(MetaIndex
->DestFile
) == false || MetaIndex
->VerifyVendor(Message
) == false)
1470 /* expired Release files are still a problem you need extra force for */;
1472 MetaIndex
->QueueIndexes(true);
1474 TransactionManager
->TransactionStageCopy(MetaIndex
, MetaIndex
->DestFile
, MetaIndex
->GetFinalFilename());
1477 // FIXME: this is used often (e.g. in pkgAcqIndexTrans) so refactor
1478 if (Cnf
->LocalOnly
== true ||
1479 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1488 // AcqBaseIndex - Constructor /*{{{*/
1489 pkgAcqBaseIndex::pkgAcqBaseIndex(pkgAcquire
* const Owner
,
1490 pkgAcqMetaBase
* const TransactionManager
,
1491 IndexTarget
const &Target
)
1492 : pkgAcqTransactionItem(Owner
, TransactionManager
, Target
), d(NULL
)
1496 pkgAcqBaseIndex::~pkgAcqBaseIndex() {}
1498 // AcqDiffIndex::AcqDiffIndex - Constructor /*{{{*/
1499 // ---------------------------------------------------------------------
1500 /* Get the DiffIndex file first and see if there are patches available
1501 * If so, create a pkgAcqIndexDiffs fetcher that will get and apply the
1502 * patches. If anything goes wrong in that process, it will fall back to
1503 * the original packages file
1505 pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire
* const Owner
,
1506 pkgAcqMetaBase
* const TransactionManager
,
1507 IndexTarget
const &Target
)
1508 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
)
1510 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
1513 Desc
.Description
= Target
.Description
+ ".diff/Index";
1514 Desc
.ShortDesc
= Target
.ShortDesc
;
1515 Desc
.URI
= Target
.URI
+ ".diff/Index";
1517 DestFile
= GetPartialFileNameFromURI(Desc
.URI
);
1520 std::clog
<< "pkgAcqDiffIndex: " << Desc
.URI
<< std::endl
;
1525 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
1526 // ---------------------------------------------------------------------
1527 /* The only header we use is the last-modified header. */
1528 string
pkgAcqDiffIndex::Custom600Headers() const
1530 string
const Final
= GetFinalFilename();
1533 std::clog
<< "Custom600Header-IMS: " << Final
<< std::endl
;
1536 if (stat(Final
.c_str(),&Buf
) != 0)
1537 return "\nIndex-File: true";
1539 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1542 void pkgAcqDiffIndex::QueueOnIMSHit() const /*{{{*/
1544 // list cleanup needs to know that this file as well as the already
1545 // present index is ours, so we create an empty diff to save it for us
1546 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
);
1549 bool pkgAcqDiffIndex::ParseDiffIndex(string
const &IndexDiffFile
) /*{{{*/
1551 // failing here is fine: our caller will take care of trying to
1552 // get the complete file if patching fails
1554 std::clog
<< "pkgAcqDiffIndex::ParseIndexDiff() " << IndexDiffFile
1557 FileFd
Fd(IndexDiffFile
,FileFd::ReadOnly
);
1559 if (_error
->PendingError() == true)
1563 if(unlikely(TF
.Step(Tags
) == false))
1566 HashStringList ServerHashes
;
1567 unsigned long long ServerSize
= 0;
1569 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
1571 std::string tagname
= *type
;
1572 tagname
.append("-Current");
1573 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1574 if (tmp
.empty() == true)
1578 unsigned long long size
;
1579 std::stringstream
ss(tmp
);
1581 if (unlikely(hash
.empty() == true))
1583 if (unlikely(ServerSize
!= 0 && ServerSize
!= size
))
1585 ServerHashes
.push_back(HashString(*type
, hash
));
1589 if (ServerHashes
.usable() == false)
1592 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": Did not find a good hashsum in the index" << std::endl
;
1596 std::string
const CurrentPackagesFile
= GetFinalFileNameFromURI(Target
.URI
);
1597 HashStringList
const TargetFileHashes
= GetExpectedHashesFor(Target
.MetaKey
);
1598 if (TargetFileHashes
.usable() == false || ServerHashes
!= TargetFileHashes
)
1602 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": Index has different hashes than parser, probably older, so fail pdiffing" << std::endl
;
1603 printHashSumComparision(CurrentPackagesFile
, ServerHashes
, TargetFileHashes
);
1608 HashStringList LocalHashes
;
1609 // try avoiding calculating the hash here as this is costly
1610 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1611 LocalHashes
= GetExpectedHashesFromFor(TransactionManager
->LastMetaIndexParser
, Target
.MetaKey
);
1612 if (LocalHashes
.usable() == false)
1614 FileFd
fd(CurrentPackagesFile
, FileFd::ReadOnly
);
1615 Hashes
LocalHashesCalc(ServerHashes
);
1616 LocalHashesCalc
.AddFD(fd
);
1617 LocalHashes
= LocalHashesCalc
.GetHashStringList();
1620 if (ServerHashes
== LocalHashes
)
1622 // we have the same sha1 as the server so we are done here
1624 std::clog
<< "pkgAcqDiffIndex: Package file " << CurrentPackagesFile
<< " is up-to-date" << std::endl
;
1630 std::clog
<< "Server-Current: " << ServerHashes
.find(NULL
)->toStr() << " and we start at "
1631 << CurrentPackagesFile
<< " " << LocalHashes
.FileSize() << " " << LocalHashes
.find(NULL
)->toStr() << std::endl
;
1633 // parse all of (provided) history
1634 vector
<DiffInfo
> available_patches
;
1635 bool firstAcceptedHashes
= true;
1636 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
1638 if (LocalHashes
.find(*type
) == NULL
)
1641 std::string tagname
= *type
;
1642 tagname
.append("-History");
1643 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1644 if (tmp
.empty() == true)
1647 string hash
, filename
;
1648 unsigned long long size
;
1649 std::stringstream
ss(tmp
);
1651 while (ss
>> hash
>> size
>> filename
)
1653 if (unlikely(hash
.empty() == true || filename
.empty() == true))
1656 // see if we have a record for this file already
1657 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
1658 for (; cur
!= available_patches
.end(); ++cur
)
1660 if (cur
->file
!= filename
)
1662 cur
->result_hashes
.push_back(HashString(*type
, hash
));
1665 if (cur
!= available_patches
.end())
1667 if (firstAcceptedHashes
== true)
1670 next
.file
= filename
;
1671 next
.result_hashes
.push_back(HashString(*type
, hash
));
1672 next
.result_hashes
.FileSize(size
);
1673 available_patches
.push_back(next
);
1678 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
1679 << " wasn't in the list for the first parsed hash! (history)" << std::endl
;
1683 firstAcceptedHashes
= false;
1686 if (unlikely(available_patches
.empty() == true))
1689 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": "
1690 << "Couldn't find any patches for the patch series." << std::endl
;
1694 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
1696 if (LocalHashes
.find(*type
) == NULL
)
1699 std::string tagname
= *type
;
1700 tagname
.append("-Patches");
1701 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1702 if (tmp
.empty() == true)
1705 string hash
, filename
;
1706 unsigned long long size
;
1707 std::stringstream
ss(tmp
);
1709 while (ss
>> hash
>> size
>> filename
)
1711 if (unlikely(hash
.empty() == true || filename
.empty() == true))
1714 // see if we have a record for this file already
1715 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
1716 for (; cur
!= available_patches
.end(); ++cur
)
1718 if (cur
->file
!= filename
)
1720 if (cur
->patch_hashes
.empty())
1721 cur
->patch_hashes
.FileSize(size
);
1722 cur
->patch_hashes
.push_back(HashString(*type
, hash
));
1725 if (cur
!= available_patches
.end())
1728 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
1729 << " wasn't in the list for the first parsed hash! (patches)" << std::endl
;
1734 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
1736 std::string tagname
= *type
;
1737 tagname
.append("-Download");
1738 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1739 if (tmp
.empty() == true)
1742 string hash
, filename
;
1743 unsigned long long size
;
1744 std::stringstream
ss(tmp
);
1746 // FIXME: all of pdiff supports only .gz compressed patches
1747 while (ss
>> hash
>> size
>> filename
)
1749 if (unlikely(hash
.empty() == true || filename
.empty() == true))
1751 if (unlikely(APT::String::Endswith(filename
, ".gz") == false))
1753 filename
.erase(filename
.length() - 3);
1755 // see if we have a record for this file already
1756 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
1757 for (; cur
!= available_patches
.end(); ++cur
)
1759 if (cur
->file
!= filename
)
1761 if (cur
->download_hashes
.empty())
1762 cur
->download_hashes
.FileSize(size
);
1763 cur
->download_hashes
.push_back(HashString(*type
, hash
));
1766 if (cur
!= available_patches
.end())
1769 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
1770 << " wasn't in the list for the first parsed hash! (download)" << std::endl
;
1776 bool foundStart
= false;
1777 for (std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
1778 cur
!= available_patches
.end(); ++cur
)
1780 if (LocalHashes
!= cur
->result_hashes
)
1783 available_patches
.erase(available_patches
.begin(), cur
);
1788 if (foundStart
== false || unlikely(available_patches
.empty() == true))
1791 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": "
1792 << "Couldn't find the start of the patch series." << std::endl
;
1796 // patching with too many files is rather slow compared to a fast download
1797 unsigned long const fileLimit
= _config
->FindI("Acquire::PDiffs::FileLimit", 0);
1798 if (fileLimit
!= 0 && fileLimit
< available_patches
.size())
1801 std::clog
<< "Need " << available_patches
.size() << " diffs (Limit is " << fileLimit
1802 << ") so fallback to complete download" << std::endl
;
1806 // calculate the size of all patches we have to get
1807 // note that all sizes are uncompressed, while we download compressed files
1808 unsigned long long patchesSize
= 0;
1809 for (std::vector
<DiffInfo
>::const_iterator cur
= available_patches
.begin();
1810 cur
!= available_patches
.end(); ++cur
)
1811 patchesSize
+= cur
->patch_hashes
.FileSize();
1812 unsigned long long const sizeLimit
= ServerSize
* _config
->FindI("Acquire::PDiffs::SizeLimit", 100);
1813 if (sizeLimit
> 0 && (sizeLimit
/100) < patchesSize
)
1816 std::clog
<< "Need " << patchesSize
<< " bytes (Limit is " << sizeLimit
/100
1817 << ") so fallback to complete download" << std::endl
;
1821 // we have something, queue the diffs
1822 string::size_type
const last_space
= Description
.rfind(" ");
1823 if(last_space
!= string::npos
)
1824 Description
.erase(last_space
, Description
.size()-last_space
);
1826 /* decide if we should download patches one by one or in one go:
1827 The first is good if the server merges patches, but many don't so client
1828 based merging can be attempt in which case the second is better.
1829 "bad things" will happen if patches are merged on the server,
1830 but client side merging is attempt as well */
1831 bool pdiff_merge
= _config
->FindB("Acquire::PDiffs::Merge", true);
1832 if (pdiff_merge
== true)
1834 // reprepro adds this flag if it has merged patches on the server
1835 std::string
const precedence
= Tags
.FindS("X-Patch-Precedence");
1836 pdiff_merge
= (precedence
!= "merged");
1839 if (pdiff_merge
== false)
1840 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
, available_patches
);
1843 std::vector
<pkgAcqIndexMergeDiffs
*> *diffs
= new std::vector
<pkgAcqIndexMergeDiffs
*>(available_patches
.size());
1844 for(size_t i
= 0; i
< available_patches
.size(); ++i
)
1845 (*diffs
)[i
] = new pkgAcqIndexMergeDiffs(Owner
, TransactionManager
,
1847 available_patches
[i
],
1857 void pkgAcqDiffIndex::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
1859 Item::Failed(Message
,Cnf
);
1863 std::clog
<< "pkgAcqDiffIndex failed: " << Desc
.URI
<< " with " << Message
<< std::endl
1864 << "Falling back to normal index file acquire" << std::endl
;
1866 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
1869 void pkgAcqDiffIndex::Done(string
const &Message
,HashStringList
const &Hashes
, /*{{{*/
1870 pkgAcquire::MethodConfig
const * const Cnf
)
1873 std::clog
<< "pkgAcqDiffIndex::Done(): " << Desc
.URI
<< std::endl
;
1875 Item::Done(Message
, Hashes
, Cnf
);
1877 string
const FinalFile
= GetFinalFilename();
1878 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false))
1879 DestFile
= FinalFile
;
1881 if(ParseDiffIndex(DestFile
) == false)
1883 Failed("Message: Couldn't parse pdiff index", Cnf
);
1884 // queue for final move - this should happen even if we fail
1885 // while parsing (e.g. on sizelimit) and download the complete file.
1886 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
1890 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
1899 pkgAcqDiffIndex::~pkgAcqDiffIndex() {}
1901 // AcqIndexDiffs::AcqIndexDiffs - Constructor /*{{{*/
1902 // ---------------------------------------------------------------------
1903 /* The package diff is added to the queue. one object is constructed
1904 * for each diff and the index
1906 pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire
* const Owner
,
1907 pkgAcqMetaBase
* const TransactionManager
,
1908 IndexTarget
const &Target
,
1909 vector
<DiffInfo
> const &diffs
)
1910 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
),
1911 available_patches(diffs
)
1913 DestFile
= GetPartialFileNameFromURI(Target
.URI
);
1915 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
1918 Description
= Target
.Description
;
1919 Desc
.ShortDesc
= Target
.ShortDesc
;
1921 if(available_patches
.empty() == true)
1923 // we are done (yeah!), check hashes against the final file
1924 DestFile
= GetFinalFileNameFromURI(Target
.URI
);
1929 // patching needs to be bootstrapped with the 'old' version
1930 std::string
const PartialFile
= GetPartialFileNameFromURI(Target
.URI
);
1931 if (RealFileExists(PartialFile
) == false)
1933 if (symlink(GetFinalFilename().c_str(), PartialFile
.c_str()) != 0)
1935 Failed("Link creation of " + PartialFile
+ " to " + GetFinalFilename() + " failed", NULL
);
1940 // get the next diff
1941 State
= StateFetchDiff
;
1946 void pkgAcqIndexDiffs::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
1948 Item::Failed(Message
,Cnf
);
1952 std::clog
<< "pkgAcqIndexDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
1953 << "Falling back to normal index file acquire" << std::endl
;
1954 DestFile
= GetPartialFileNameFromURI(Target
.URI
);
1955 RenameOnError(PDiffError
);
1956 std::string
const patchname
= GetDiffsPatchFileName(DestFile
);
1957 if (RealFileExists(patchname
))
1958 rename(patchname
.c_str(), std::string(patchname
+ ".FAILED").c_str());
1959 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
1963 // Finish - helper that cleans the item out of the fetcher queue /*{{{*/
1964 void pkgAcqIndexDiffs::Finish(bool allDone
)
1967 std::clog
<< "pkgAcqIndexDiffs::Finish(): "
1969 << Desc
.URI
<< std::endl
;
1971 // we restore the original name, this is required, otherwise
1972 // the file will be cleaned
1975 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
1977 // this is for the "real" finish
1982 std::clog
<< "\n\nallDone: " << DestFile
<< "\n" << std::endl
;
1987 std::clog
<< "Finishing: " << Desc
.URI
<< std::endl
;
1994 bool pkgAcqIndexDiffs::QueueNextDiff() /*{{{*/
1996 // calc sha1 of the just patched file
1997 std::string
const FinalFile
= GetPartialFileNameFromURI(Target
.URI
);
1999 if(!FileExists(FinalFile
))
2001 Failed("Message: No FinalFile " + FinalFile
+ " available", NULL
);
2005 FileFd
fd(FinalFile
, FileFd::ReadOnly
);
2006 Hashes LocalHashesCalc
;
2007 LocalHashesCalc
.AddFD(fd
);
2008 HashStringList
const LocalHashes
= LocalHashesCalc
.GetHashStringList();
2011 std::clog
<< "QueueNextDiff: " << FinalFile
<< " (" << LocalHashes
.find(NULL
)->toStr() << ")" << std::endl
;
2013 HashStringList
const TargetFileHashes
= GetExpectedHashesFor(Target
.MetaKey
);
2014 if (unlikely(LocalHashes
.usable() == false || TargetFileHashes
.usable() == false))
2016 Failed("Local/Expected hashes are not usable", NULL
);
2021 // final file reached before all patches are applied
2022 if(LocalHashes
== TargetFileHashes
)
2028 // remove all patches until the next matching patch is found
2029 // this requires the Index file to be ordered
2030 for(vector
<DiffInfo
>::iterator I
= available_patches
.begin();
2031 available_patches
.empty() == false &&
2032 I
!= available_patches
.end() &&
2033 I
->result_hashes
!= LocalHashes
;
2036 available_patches
.erase(I
);
2039 // error checking and falling back if no patch was found
2040 if(available_patches
.empty() == true)
2042 Failed("No patches left to reach target", NULL
);
2046 // queue the right diff
2047 Desc
.URI
= Target
.URI
+ ".diff/" + available_patches
[0].file
+ ".gz";
2048 Desc
.Description
= Description
+ " " + available_patches
[0].file
+ string(".pdiff");
2049 DestFile
= GetPartialFileNameFromURI(Target
.URI
+ ".diff/" + available_patches
[0].file
);
2052 std::clog
<< "pkgAcqIndexDiffs::QueueNextDiff(): " << Desc
.URI
<< std::endl
;
2059 void pkgAcqIndexDiffs::Done(string
const &Message
, HashStringList
const &Hashes
, /*{{{*/
2060 pkgAcquire::MethodConfig
const * const Cnf
)
2063 std::clog
<< "pkgAcqIndexDiffs::Done(): " << Desc
.URI
<< std::endl
;
2065 Item::Done(Message
, Hashes
, Cnf
);
2067 std::string
const FinalFile
= GetPartialFileNameFromURI(Target
.URI
);
2068 std::string
const PatchFile
= GetDiffsPatchFileName(FinalFile
);
2070 // success in downloading a diff, enter ApplyDiff state
2071 if(State
== StateFetchDiff
)
2073 Rename(DestFile
, PatchFile
);
2076 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
2078 State
= StateApplyDiff
;
2080 Desc
.URI
= "rred:" + FinalFile
;
2082 SetActiveSubprocess("rred");
2086 // success in download/apply a diff, queue next (if needed)
2087 if(State
== StateApplyDiff
)
2089 // remove the just applied patch
2090 available_patches
.erase(available_patches
.begin());
2091 unlink(PatchFile
.c_str());
2096 std::clog
<< "Moving patched file in place: " << std::endl
2097 << DestFile
<< " -> " << FinalFile
<< std::endl
;
2099 Rename(DestFile
,FinalFile
);
2100 chmod(FinalFile
.c_str(),0644);
2102 // see if there is more to download
2103 if(available_patches
.empty() == false) {
2104 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
,
2109 DestFile
= FinalFile
;
2110 return Finish(true);
2114 std::string
pkgAcqIndexDiffs::Custom600Headers() const /*{{{*/
2116 if(State
!= StateApplyDiff
)
2117 return pkgAcqBaseIndex::Custom600Headers();
2118 std::ostringstream patchhashes
;
2119 HashStringList
const ExpectedHashes
= available_patches
[0].patch_hashes
;
2120 for (HashStringList::const_iterator hs
= ExpectedHashes
.begin(); hs
!= ExpectedHashes
.end(); ++hs
)
2121 patchhashes
<< "\nPatch-0-" << hs
->HashType() << "-Hash: " << hs
->HashValue();
2122 patchhashes
<< pkgAcqBaseIndex::Custom600Headers();
2123 return patchhashes
.str();
2126 pkgAcqIndexDiffs::~pkgAcqIndexDiffs() {}
2128 // AcqIndexMergeDiffs::AcqIndexMergeDiffs - Constructor /*{{{*/
2129 pkgAcqIndexMergeDiffs::pkgAcqIndexMergeDiffs(pkgAcquire
* const Owner
,
2130 pkgAcqMetaBase
* const TransactionManager
,
2131 IndexTarget
const &Target
,
2132 DiffInfo
const &patch
,
2133 std::vector
<pkgAcqIndexMergeDiffs
*> const * const allPatches
)
2134 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
),
2135 patch(patch
), allPatches(allPatches
), State(StateFetchDiff
)
2137 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
2140 Description
= Target
.Description
;
2141 Desc
.ShortDesc
= Target
.ShortDesc
;
2143 Desc
.URI
= Target
.URI
+ ".diff/" + patch
.file
+ ".gz";
2144 Desc
.Description
= Description
+ " " + patch
.file
+ string(".pdiff");
2146 DestFile
= GetPartialFileNameFromURI(Target
.URI
+ ".diff/" + patch
.file
);
2149 std::clog
<< "pkgAcqIndexMergeDiffs: " << Desc
.URI
<< std::endl
;
2154 void pkgAcqIndexMergeDiffs::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
2157 std::clog
<< "pkgAcqIndexMergeDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
;
2159 Item::Failed(Message
,Cnf
);
2162 // check if we are the first to fail, otherwise we are done here
2163 State
= StateDoneDiff
;
2164 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2165 I
!= allPatches
->end(); ++I
)
2166 if ((*I
)->State
== StateErrorDiff
)
2169 // first failure means we should fallback
2170 State
= StateErrorDiff
;
2172 std::clog
<< "Falling back to normal index file acquire" << std::endl
;
2173 DestFile
= GetPartialFileNameFromURI(Target
.URI
);
2174 RenameOnError(PDiffError
);
2175 std::string
const patchname
= GetMergeDiffsPatchFileName(DestFile
, patch
.file
);
2176 if (RealFileExists(patchname
))
2177 rename(patchname
.c_str(), std::string(patchname
+ ".FAILED").c_str());
2178 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
2181 void pkgAcqIndexMergeDiffs::Done(string
const &Message
, HashStringList
const &Hashes
, /*{{{*/
2182 pkgAcquire::MethodConfig
const * const Cnf
)
2185 std::clog
<< "pkgAcqIndexMergeDiffs::Done(): " << Desc
.URI
<< std::endl
;
2187 Item::Done(Message
, Hashes
, Cnf
);
2189 string
const FinalFile
= GetPartialFileNameFromURI(Target
.URI
);
2190 if (State
== StateFetchDiff
)
2192 Rename(DestFile
, GetMergeDiffsPatchFileName(FinalFile
, patch
.file
));
2194 // check if this is the last completed diff
2195 State
= StateDoneDiff
;
2196 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2197 I
!= allPatches
->end(); ++I
)
2198 if ((*I
)->State
!= StateDoneDiff
)
2201 std::clog
<< "Not the last done diff in the batch: " << Desc
.URI
<< std::endl
;
2205 // this is the last completed diff, so we are ready to apply now
2206 State
= StateApplyDiff
;
2208 // patching needs to be bootstrapped with the 'old' version
2209 if (symlink(GetFinalFilename().c_str(), FinalFile
.c_str()) != 0)
2211 Failed("Link creation of " + FinalFile
+ " to " + GetFinalFilename() + " failed", NULL
);
2216 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
2219 Desc
.URI
= "rred:" + FinalFile
;
2221 SetActiveSubprocess("rred");
2224 // success in download/apply all diffs, clean up
2225 else if (State
== StateApplyDiff
)
2227 // move the result into place
2228 std::string
const Final
= GetFinalFilename();
2230 std::clog
<< "Queue patched file in place: " << std::endl
2231 << DestFile
<< " -> " << Final
<< std::endl
;
2233 // queue for copy by the transaction manager
2234 TransactionManager
->TransactionStageCopy(this, DestFile
, Final
);
2236 // ensure the ed's are gone regardless of list-cleanup
2237 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2238 I
!= allPatches
->end(); ++I
)
2240 std::string
const PartialFile
= GetPartialFileNameFromURI(Target
.URI
);
2241 std::string
const patch
= GetMergeDiffsPatchFileName(PartialFile
, (*I
)->patch
.file
);
2242 unlink(patch
.c_str());
2244 unlink(FinalFile
.c_str());
2249 std::clog
<< "allDone: " << DestFile
<< "\n" << std::endl
;
2253 std::string
pkgAcqIndexMergeDiffs::Custom600Headers() const /*{{{*/
2255 if(State
!= StateApplyDiff
)
2256 return pkgAcqBaseIndex::Custom600Headers();
2257 std::ostringstream patchhashes
;
2258 unsigned int seen_patches
= 0;
2259 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2260 I
!= allPatches
->end(); ++I
)
2262 HashStringList
const ExpectedHashes
= (*I
)->patch
.patch_hashes
;
2263 for (HashStringList::const_iterator hs
= ExpectedHashes
.begin(); hs
!= ExpectedHashes
.end(); ++hs
)
2264 patchhashes
<< "\nPatch-" << seen_patches
<< "-" << hs
->HashType() << "-Hash: " << hs
->HashValue();
2267 patchhashes
<< pkgAcqBaseIndex::Custom600Headers();
2268 return patchhashes
.str();
2271 pkgAcqIndexMergeDiffs::~pkgAcqIndexMergeDiffs() {}
2273 // AcqIndex::AcqIndex - Constructor /*{{{*/
2274 pkgAcqIndex::pkgAcqIndex(pkgAcquire
* const Owner
,
2275 pkgAcqMetaBase
* const TransactionManager
,
2276 IndexTarget
const &Target
)
2277 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
), Stage(STAGE_DOWNLOAD
)
2279 // autoselect the compression method
2280 AutoSelectCompression();
2281 Init(Target
.URI
, Target
.Description
, Target
.ShortDesc
);
2283 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
2284 std::clog
<< "New pkgIndex with TransactionManager "
2285 << TransactionManager
<< std::endl
;
2288 // AcqIndex::AutoSelectCompression - Select compression /*{{{*/
2289 void pkgAcqIndex::AutoSelectCompression()
2291 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
2292 CompressionExtensions
= "";
2293 if (TransactionManager
->MetaIndexParser
!= NULL
&& TransactionManager
->MetaIndexParser
->Exists(Target
.MetaKey
))
2295 for (std::vector
<std::string
>::const_iterator t
= types
.begin();
2296 t
!= types
.end(); ++t
)
2298 std::string CompressedMetaKey
= string(Target
.MetaKey
).append(".").append(*t
);
2299 if (*t
== "uncompressed" ||
2300 TransactionManager
->MetaIndexParser
->Exists(CompressedMetaKey
) == true)
2301 CompressionExtensions
.append(*t
).append(" ");
2306 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
2307 CompressionExtensions
.append(*t
).append(" ");
2309 if (CompressionExtensions
.empty() == false)
2310 CompressionExtensions
.erase(CompressionExtensions
.end()-1);
2313 // AcqIndex::Init - defered Constructor /*{{{*/
2314 void pkgAcqIndex::Init(string
const &URI
, string
const &URIDesc
,
2315 string
const &ShortDesc
)
2317 Stage
= STAGE_DOWNLOAD
;
2319 DestFile
= GetPartialFileNameFromURI(URI
);
2321 size_t const nextExt
= CompressionExtensions
.find(' ');
2322 if (nextExt
== std::string::npos
)
2324 CurrentCompressionExtension
= CompressionExtensions
;
2325 CompressionExtensions
.clear();
2329 CurrentCompressionExtension
= CompressionExtensions
.substr(0, nextExt
);
2330 CompressionExtensions
= CompressionExtensions
.substr(nextExt
+1);
2333 if (CurrentCompressionExtension
== "uncompressed")
2337 else if (unlikely(CurrentCompressionExtension
.empty()))
2341 Desc
.URI
= URI
+ '.' + CurrentCompressionExtension
;
2342 DestFile
= DestFile
+ '.' + CurrentCompressionExtension
;
2345 if(TransactionManager
->MetaIndexParser
!= NULL
)
2346 InitByHashIfNeeded();
2348 Desc
.Description
= URIDesc
;
2350 Desc
.ShortDesc
= ShortDesc
;
2355 // AcqIndex::AdjustForByHash - modify URI for by-hash support /*{{{*/
2356 void pkgAcqIndex::InitByHashIfNeeded()
2359 // - (maybe?) add support for by-hash into the sources.list as flag
2360 // - make apt-ftparchive generate the hashes (and expire?)
2361 std::string HostKnob
= "APT::Acquire::" + ::URI(Desc
.URI
).Host
+ "::By-Hash";
2362 if(_config
->FindB("APT::Acquire::By-Hash", false) == true ||
2363 _config
->FindB(HostKnob
, false) == true ||
2364 TransactionManager
->MetaIndexParser
->GetSupportsAcquireByHash())
2366 HashStringList
const Hashes
= GetExpectedHashes();
2369 // FIXME: should we really use the best hash here? or a fixed one?
2370 HashString
const * const TargetHash
= Hashes
.find("");
2371 std::string
const ByHash
= "/by-hash/" + TargetHash
->HashType() + "/" + TargetHash
->HashValue();
2372 size_t const trailing_slash
= Desc
.URI
.find_last_of("/");
2373 Desc
.URI
= Desc
.URI
.replace(
2375 Desc
.URI
.substr(trailing_slash
+1).size()+1,
2379 "Fetching ByHash requested but can not find record for %s",
2380 GetMetaKey().c_str());
2385 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
2386 // ---------------------------------------------------------------------
2387 /* The only header we use is the last-modified header. */
2388 string
pkgAcqIndex::Custom600Headers() const
2390 string Final
= GetFinalFilename();
2392 string msg
= "\nIndex-File: true";
2394 if (stat(Final
.c_str(),&Buf
) == 0)
2395 msg
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
2397 if(Target
.IsOptional
)
2398 msg
+= "\nFail-Ignore: true";
2403 // AcqIndex::Failed - getting the indexfile failed /*{{{*/
2404 void pkgAcqIndex::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)
2406 Item::Failed(Message
,Cnf
);
2408 // authorisation matches will not be fixed by other compression types
2409 if (Status
!= StatAuthError
)
2411 if (CompressionExtensions
.empty() == false)
2413 Init(Target
.URI
, Desc
.Description
, Desc
.ShortDesc
);
2419 if(Target
.IsOptional
&& GetExpectedHashes().empty() && Stage
== STAGE_DOWNLOAD
)
2422 TransactionManager
->AbortTransaction();
2425 // AcqIndex::ReverifyAfterIMS - Reverify index after an ims-hit /*{{{*/
2426 void pkgAcqIndex::ReverifyAfterIMS()
2428 // update destfile to *not* include the compression extension when doing
2429 // a reverify (as its uncompressed on disk already)
2430 DestFile
= GetCompressedFileName(Target
.URI
, GetPartialFileNameFromURI(Target
.URI
), CurrentCompressionExtension
);
2432 // copy FinalFile into partial/ so that we check the hash again
2433 string FinalFile
= GetFinalFilename();
2434 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
2435 Desc
.URI
= "copy:" + FinalFile
;
2439 // AcqIndex::Done - Finished a fetch /*{{{*/
2440 // ---------------------------------------------------------------------
2441 /* This goes through a number of states.. On the initial fetch the
2442 method could possibly return an alternate filename which points
2443 to the uncompressed version of the file. If this is so the file
2444 is copied into the partial directory. In all other cases the file
2445 is decompressed with a compressed uri. */
2446 void pkgAcqIndex::Done(string
const &Message
,
2447 HashStringList
const &Hashes
,
2448 pkgAcquire::MethodConfig
const * const Cfg
)
2450 Item::Done(Message
,Hashes
,Cfg
);
2454 case STAGE_DOWNLOAD
:
2455 StageDownloadDone(Message
, Hashes
, Cfg
);
2457 case STAGE_DECOMPRESS_AND_VERIFY
:
2458 StageDecompressDone(Message
, Hashes
, Cfg
);
2463 // AcqIndex::StageDownloadDone - Queue for decompress and verify /*{{{*/
2464 void pkgAcqIndex::StageDownloadDone(string
const &Message
, HashStringList
const &,
2465 pkgAcquire::MethodConfig
const * const)
2469 // Handle the unzipd case
2470 string FileName
= LookupTag(Message
,"Alt-Filename");
2471 if (FileName
.empty() == false)
2473 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
2475 DestFile
+= ".decomp";
2476 Desc
.URI
= "copy:" + FileName
;
2478 SetActiveSubprocess("copy");
2482 FileName
= LookupTag(Message
,"Filename");
2483 if (FileName
.empty() == true)
2486 ErrorText
= "Method gave a blank filename";
2489 // Methods like e.g. "file:" will give us a (compressed) FileName that is
2490 // not the "DestFile" we set, in this case we uncompress from the local file
2491 if (FileName
!= DestFile
&& RealFileExists(DestFile
) == false)
2494 EraseFileName
= FileName
;
2496 // we need to verify the file against the current Release file again
2497 // on if-modfied-since hit to avoid a stale attack against us
2498 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
2500 // The files timestamp matches, reverify by copy into partial/
2506 // If we have compressed indexes enabled, queue for hash verification
2507 if (_config
->FindB("Acquire::GzipIndexes",false))
2509 DestFile
= GetPartialFileNameFromURI(Target
.URI
+ '.' + CurrentCompressionExtension
);
2511 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
2512 Desc
.URI
= "copy:" + FileName
;
2514 SetActiveSubprocess("copy");
2518 // get the binary name for your used compression type
2520 if(CurrentCompressionExtension
== "uncompressed")
2521 decompProg
= "copy";
2523 decompProg
= _config
->Find(string("Acquire::CompressionTypes::").append(CurrentCompressionExtension
),"");
2524 if(decompProg
.empty() == true)
2526 _error
->Error("Unsupported extension: %s", CurrentCompressionExtension
.c_str());
2530 // queue uri for the next stage
2531 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
2532 DestFile
+= ".decomp";
2533 Desc
.URI
= decompProg
+ ":" + FileName
;
2535 SetActiveSubprocess(decompProg
);
2538 // AcqIndex::StageDecompressDone - Final verification /*{{{*/
2539 void pkgAcqIndex::StageDecompressDone(string
const &,
2540 HashStringList
const &,
2541 pkgAcquire::MethodConfig
const * const)
2543 // Done, queue for rename on transaction finished
2544 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
2548 pkgAcqIndex::~pkgAcqIndex() {}
2551 // AcqArchive::AcqArchive - Constructor /*{{{*/
2552 // ---------------------------------------------------------------------
2553 /* This just sets up the initial fetch environment and queues the first
2555 pkgAcqArchive::pkgAcqArchive(pkgAcquire
* const Owner
,pkgSourceList
* const Sources
,
2556 pkgRecords
* const Recs
,pkgCache::VerIterator
const &Version
,
2557 string
&StoreFilename
) :
2558 Item(Owner
), d(NULL
), LocalSource(false), Version(Version
), Sources(Sources
), Recs(Recs
),
2559 StoreFilename(StoreFilename
), Vf(Version
.FileList()),
2562 Retries
= _config
->FindI("Acquire::Retries",0);
2564 if (Version
.Arch() == 0)
2566 _error
->Error(_("I wasn't able to locate a file for the %s package. "
2567 "This might mean you need to manually fix this package. "
2568 "(due to missing arch)"),
2569 Version
.ParentPkg().FullName().c_str());
2573 /* We need to find a filename to determine the extension. We make the
2574 assumption here that all the available sources for this version share
2575 the same extension.. */
2576 // Skip not source sources, they do not have file fields.
2577 for (; Vf
.end() == false; ++Vf
)
2579 if (Vf
.File().Flagged(pkgCache::Flag::NotSource
))
2584 // Does not really matter here.. we are going to fail out below
2585 if (Vf
.end() != true)
2587 // If this fails to get a file name we will bomb out below.
2588 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2589 if (_error
->PendingError() == true)
2592 // Generate the final file name as: package_version_arch.foo
2593 StoreFilename
= QuoteString(Version
.ParentPkg().Name(),"_:") + '_' +
2594 QuoteString(Version
.VerStr(),"_:") + '_' +
2595 QuoteString(Version
.Arch(),"_:.") +
2596 "." + flExtension(Parse
.FileName());
2599 // check if we have one trusted source for the package. if so, switch
2600 // to "TrustedOnly" mode - but only if not in AllowUnauthenticated mode
2601 bool const allowUnauth
= _config
->FindB("APT::Get::AllowUnauthenticated", false);
2602 bool const debugAuth
= _config
->FindB("Debug::pkgAcquire::Auth", false);
2603 bool seenUntrusted
= false;
2604 for (pkgCache::VerFileIterator i
= Version
.FileList(); i
.end() == false; ++i
)
2606 pkgIndexFile
*Index
;
2607 if (Sources
->FindIndex(i
.File(),Index
) == false)
2610 if (debugAuth
== true)
2611 std::cerr
<< "Checking index: " << Index
->Describe()
2612 << "(Trusted=" << Index
->IsTrusted() << ")" << std::endl
;
2614 if (Index
->IsTrusted() == true)
2617 if (allowUnauth
== false)
2621 seenUntrusted
= true;
2624 // "allow-unauthenticated" restores apts old fetching behaviour
2625 // that means that e.g. unauthenticated file:// uris are higher
2626 // priority than authenticated http:// uris
2627 if (allowUnauth
== true && seenUntrusted
== true)
2631 if (QueueNext() == false && _error
->PendingError() == false)
2632 _error
->Error(_("Can't find a source to download version '%s' of '%s'"),
2633 Version
.VerStr(), Version
.ParentPkg().FullName(false).c_str());
2636 // AcqArchive::QueueNext - Queue the next file source /*{{{*/
2637 // ---------------------------------------------------------------------
2638 /* This queues the next available file version for download. It checks if
2639 the archive is already available in the cache and stashs the MD5 for
2641 bool pkgAcqArchive::QueueNext()
2643 for (; Vf
.end() == false; ++Vf
)
2645 pkgCache::PkgFileIterator
const PkgF
= Vf
.File();
2646 // Ignore not source sources
2647 if (PkgF
.Flagged(pkgCache::Flag::NotSource
))
2650 // Try to cross match against the source list
2651 pkgIndexFile
*Index
;
2652 if (Sources
->FindIndex(PkgF
, Index
) == false)
2654 LocalSource
= PkgF
.Flagged(pkgCache::Flag::LocalSource
);
2656 // only try to get a trusted package from another source if that source
2658 if(Trusted
&& !Index
->IsTrusted())
2661 // Grab the text package record
2662 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2663 if (_error
->PendingError() == true)
2666 string PkgFile
= Parse
.FileName();
2667 ExpectedHashes
= Parse
.Hashes();
2669 if (PkgFile
.empty() == true)
2670 return _error
->Error(_("The package index files are corrupted. No Filename: "
2671 "field for package %s."),
2672 Version
.ParentPkg().Name());
2674 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
2675 Desc
.Description
= Index
->ArchiveInfo(Version
);
2677 Desc
.ShortDesc
= Version
.ParentPkg().FullName(true);
2679 // See if we already have the file. (Legacy filenames)
2680 FileSize
= Version
->Size
;
2681 string FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile
);
2683 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2685 // Make sure the size matches
2686 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2691 StoreFilename
= DestFile
= FinalFile
;
2695 /* Hmm, we have a file and its size does not match, this means it is
2696 an old style mismatched arch */
2697 unlink(FinalFile
.c_str());
2700 // Check it again using the new style output filenames
2701 FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
2702 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2704 // Make sure the size matches
2705 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2710 StoreFilename
= DestFile
= FinalFile
;
2714 /* Hmm, we have a file and its size does not match, this shouldn't
2716 unlink(FinalFile
.c_str());
2719 DestFile
= _config
->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename
);
2721 // Check the destination file
2722 if (stat(DestFile
.c_str(),&Buf
) == 0)
2724 // Hmm, the partial file is too big, erase it
2725 if ((unsigned long long)Buf
.st_size
> Version
->Size
)
2726 unlink(DestFile
.c_str());
2728 PartialSize
= Buf
.st_size
;
2731 // Disables download of archives - useful if no real installation follows,
2732 // e.g. if we are just interested in proposed installation order
2733 if (_config
->FindB("Debug::pkgAcqArchive::NoQueue", false) == true)
2738 StoreFilename
= DestFile
= FinalFile
;
2752 // AcqArchive::Done - Finished fetching /*{{{*/
2753 // ---------------------------------------------------------------------
2755 void pkgAcqArchive::Done(string
const &Message
, HashStringList
const &Hashes
,
2756 pkgAcquire::MethodConfig
const * const Cfg
)
2758 Item::Done(Message
, Hashes
, Cfg
);
2760 // Grab the output filename
2761 string FileName
= LookupTag(Message
,"Filename");
2762 if (FileName
.empty() == true)
2765 ErrorText
= "Method gave a blank filename";
2769 // Reference filename
2770 if (DestFile
!= FileName
&& RealFileExists(DestFile
) == false)
2772 StoreFilename
= DestFile
= FileName
;
2778 // Done, move it into position
2779 string
const FinalFile
= GetFinalFilename();
2780 Rename(DestFile
,FinalFile
);
2781 StoreFilename
= DestFile
= FinalFile
;
2785 // AcqArchive::Failed - Failure handler /*{{{*/
2786 // ---------------------------------------------------------------------
2787 /* Here we try other sources */
2788 void pkgAcqArchive::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)
2790 Item::Failed(Message
,Cnf
);
2792 /* We don't really want to retry on failed media swaps, this prevents
2793 that. An interesting observation is that permanent failures are not
2795 if (Cnf
->Removable
== true &&
2796 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2798 // Vf = Version.FileList();
2799 while (Vf
.end() == false) ++Vf
;
2800 StoreFilename
= string();
2805 if (QueueNext() == false)
2807 // This is the retry counter
2809 Cnf
->LocalOnly
== false &&
2810 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2813 Vf
= Version
.FileList();
2814 if (QueueNext() == true)
2818 StoreFilename
= string();
2823 APT_PURE
bool pkgAcqArchive::IsTrusted() const /*{{{*/
2828 void pkgAcqArchive::Finished() /*{{{*/
2830 if (Status
== pkgAcquire::Item::StatDone
&&
2833 StoreFilename
= string();
2836 std::string
pkgAcqArchive::DescURI() const /*{{{*/
2841 std::string
pkgAcqArchive::ShortDesc() const /*{{{*/
2843 return Desc
.ShortDesc
;
2846 pkgAcqArchive::~pkgAcqArchive() {}
2848 // AcqChangelog::pkgAcqChangelog - Constructors /*{{{*/
2849 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire
* const Owner
, pkgCache::VerIterator
const &Ver
,
2850 std::string
const &DestDir
, std::string
const &DestFilename
) :
2851 pkgAcquire::Item(Owner
), d(NULL
), SrcName(Ver
.SourcePkgName()), SrcVersion(Ver
.SourceVerStr())
2853 Desc
.URI
= URI(Ver
);
2854 Init(DestDir
, DestFilename
);
2856 // some parameters are char* here as they come likely from char* interfaces – which can also return NULL
2857 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire
* const Owner
, pkgCache::RlsFileIterator
const &RlsFile
,
2858 char const * const Component
, char const * const SrcName
, char const * const SrcVersion
,
2859 const string
&DestDir
, const string
&DestFilename
) :
2860 pkgAcquire::Item(Owner
), d(NULL
), SrcName(SrcName
), SrcVersion(SrcVersion
)
2862 Desc
.URI
= URI(RlsFile
, Component
, SrcName
, SrcVersion
);
2863 Init(DestDir
, DestFilename
);
2865 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire
* const Owner
,
2866 std::string
const &URI
, char const * const SrcName
, char const * const SrcVersion
,
2867 const string
&DestDir
, const string
&DestFilename
) :
2868 pkgAcquire::Item(Owner
), d(NULL
), SrcName(SrcName
), SrcVersion(SrcVersion
)
2871 Init(DestDir
, DestFilename
);
2873 void pkgAcqChangelog::Init(std::string
const &DestDir
, std::string
const &DestFilename
)
2875 if (Desc
.URI
.empty())
2878 // TRANSLATOR: %s=%s is sourcename=sourceversion, e.g. apt=1.1
2879 strprintf(ErrorText
, _("Changelog unavailable for %s=%s"), SrcName
.c_str(), SrcVersion
.c_str());
2880 // Let the error message print something sensible rather than "Failed to fetch /"
2881 if (DestFilename
.empty())
2882 DestFile
= SrcName
+ ".changelog";
2884 DestFile
= DestFilename
;
2885 Desc
.URI
= "changelog:/" + DestFile
;
2889 if (DestDir
.empty())
2891 std::string
const systemTemp
= GetTempDir();
2893 snprintf(tmpname
, sizeof(tmpname
), "%s/apt-changelog-XXXXXX", systemTemp
.c_str());
2894 if (NULL
== mkdtemp(tmpname
))
2896 _error
->Errno("mkdtemp", "mkdtemp failed in changelog acquire of %s %s", SrcName
.c_str(), SrcVersion
.c_str());
2900 DestFile
= TemporaryDirectory
= tmpname
;
2905 if (DestFilename
.empty())
2906 DestFile
= flCombine(DestFile
, SrcName
+ ".changelog");
2908 DestFile
= flCombine(DestFile
, DestFilename
);
2910 Desc
.ShortDesc
= "Changelog";
2911 strprintf(Desc
.Description
, "%s %s %s Changelog", URI::SiteOnly(Desc
.URI
).c_str(), SrcName
.c_str(), SrcVersion
.c_str());
2916 std::string
pkgAcqChangelog::URI(pkgCache::VerIterator
const &Ver
) /*{{{*/
2918 char const * const SrcName
= Ver
.SourcePkgName();
2919 char const * const SrcVersion
= Ver
.SourceVerStr();
2920 pkgCache::PkgFileIterator PkgFile
;
2921 // find the first source for this version which promises a changelog
2922 for (pkgCache::VerFileIterator VF
= Ver
.FileList(); VF
.end() == false; ++VF
)
2924 pkgCache::PkgFileIterator
const PF
= VF
.File();
2925 if (PF
.Flagged(pkgCache::Flag::NotSource
) || PF
->Release
== 0)
2928 pkgCache::RlsFileIterator
const RF
= PF
.ReleaseFile();
2929 std::string
const uri
= URI(RF
, PF
.Component(), SrcName
, SrcVersion
);
2936 std::string
pkgAcqChangelog::URITemplate(pkgCache::RlsFileIterator
const &Rls
)
2938 if (Rls
.end() == true || (Rls
->Label
== 0 && Rls
->Origin
== 0))
2940 std::string
const serverConfig
= "Acquire::Changelogs::URI";
2942 #define APT_EMPTY_SERVER \
2943 if (server.empty() == false) \
2945 if (server != "no") \
2949 #define APT_CHECK_SERVER(X, Y) \
2952 std::string const specialServerConfig = serverConfig + "::" + Y + #X + "::" + Rls.X(); \
2953 server = _config->Find(specialServerConfig); \
2956 // this way e.g. Debian-Security can fallback to Debian
2957 APT_CHECK_SERVER(Label
, "Override::")
2958 APT_CHECK_SERVER(Origin
, "Override::")
2960 if (RealFileExists(Rls
.FileName()))
2962 _error
->PushToStack();
2964 /* This can be costly. A caller wanting to get millions of URIs might
2965 want to do this on its own once and use Override settings.
2966 We don't do this here as Origin/Label are not as unique as they
2967 should be so this could produce request order-dependent anomalies */
2968 if (OpenMaybeClearSignedFile(Rls
.FileName(), rf
) == true)
2970 pkgTagFile
TagFile(&rf
, rf
.Size());
2971 pkgTagSection Section
;
2972 if (TagFile
.Step(Section
) == true)
2973 server
= Section
.FindS("Changelogs");
2975 _error
->RevertToStack();
2979 APT_CHECK_SERVER(Label
, "")
2980 APT_CHECK_SERVER(Origin
, "")
2981 #undef APT_CHECK_SERVER
2982 #undef APT_EMPTY_SERVER
2985 std::string
pkgAcqChangelog::URI(pkgCache::RlsFileIterator
const &Rls
,
2986 char const * const Component
, char const * const SrcName
,
2987 char const * const SrcVersion
)
2989 return URI(URITemplate(Rls
), Component
, SrcName
, SrcVersion
);
2991 std::string
pkgAcqChangelog::URI(std::string
const &Template
,
2992 char const * const Component
, char const * const SrcName
,
2993 char const * const SrcVersion
)
2995 if (Template
.find("CHANGEPATH") == std::string::npos
)
2998 // the path is: COMPONENT/SRC/SRCNAME/SRCNAME_SRCVER, e.g. main/a/apt/1.1 or contrib/liba/libapt/2.0
2999 std::string Src
= SrcName
;
3000 std::string path
= APT::String::Startswith(SrcName
, "lib") ? Src
.substr(0, 4) : Src
.substr(0,1);
3001 path
.append("/").append(Src
).append("/");
3002 path
.append(Src
).append("_").append(StripEpoch(SrcVersion
));
3003 // we omit component for releases without one (= flat-style repositories)
3004 if (Component
!= NULL
&& strlen(Component
) != 0)
3005 path
= std::string(Component
) + "/" + path
;
3007 return SubstVar(Template
, "CHANGEPATH", path
);
3010 // AcqChangelog::Failed - Failure handler /*{{{*/
3011 void pkgAcqChangelog::Failed(string
const &Message
, pkgAcquire::MethodConfig
const * const Cnf
)
3013 Item::Failed(Message
,Cnf
);
3015 std::string errText
;
3016 // TRANSLATOR: %s=%s is sourcename=sourceversion, e.g. apt=1.1
3017 strprintf(errText
, _("Changelog unavailable for %s=%s"), SrcName
.c_str(), SrcVersion
.c_str());
3019 // Error is probably something techy like 404 Not Found
3020 if (ErrorText
.empty())
3021 ErrorText
= errText
;
3023 ErrorText
= errText
+ " (" + ErrorText
+ ")";
3027 // AcqChangelog::Done - Item downloaded OK /*{{{*/
3028 void pkgAcqChangelog::Done(string
const &Message
,HashStringList
const &CalcHashes
,
3029 pkgAcquire::MethodConfig
const * const Cnf
)
3031 Item::Done(Message
,CalcHashes
,Cnf
);
3036 pkgAcqChangelog::~pkgAcqChangelog() /*{{{*/
3038 if (TemporaryDirectory
.empty() == false)
3040 unlink(DestFile
.c_str());
3041 rmdir(TemporaryDirectory
.c_str());
3046 // AcqFile::pkgAcqFile - Constructor /*{{{*/
3047 pkgAcqFile::pkgAcqFile(pkgAcquire
* const Owner
,string
const &URI
, HashStringList
const &Hashes
,
3048 unsigned long long const Size
,string
const &Dsc
,string
const &ShortDesc
,
3049 const string
&DestDir
, const string
&DestFilename
,
3050 bool const IsIndexFile
) :
3051 Item(Owner
), d(NULL
), IsIndexFile(IsIndexFile
), ExpectedHashes(Hashes
)
3053 Retries
= _config
->FindI("Acquire::Retries",0);
3055 if(!DestFilename
.empty())
3056 DestFile
= DestFilename
;
3057 else if(!DestDir
.empty())
3058 DestFile
= DestDir
+ "/" + flNotDir(URI
);
3060 DestFile
= flNotDir(URI
);
3064 Desc
.Description
= Dsc
;
3067 // Set the short description to the archive component
3068 Desc
.ShortDesc
= ShortDesc
;
3070 // Get the transfer sizes
3073 if (stat(DestFile
.c_str(),&Buf
) == 0)
3075 // Hmm, the partial file is too big, erase it
3076 if ((Size
> 0) && (unsigned long long)Buf
.st_size
> Size
)
3077 unlink(DestFile
.c_str());
3079 PartialSize
= Buf
.st_size
;
3085 // AcqFile::Done - Item downloaded OK /*{{{*/
3086 void pkgAcqFile::Done(string
const &Message
,HashStringList
const &CalcHashes
,
3087 pkgAcquire::MethodConfig
const * const Cnf
)
3089 Item::Done(Message
,CalcHashes
,Cnf
);
3091 string FileName
= LookupTag(Message
,"Filename");
3092 if (FileName
.empty() == true)
3095 ErrorText
= "Method gave a blank filename";
3101 // The files timestamp matches
3102 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
3105 // We have to copy it into place
3106 if (RealFileExists(DestFile
.c_str()) == false)
3109 if (_config
->FindB("Acquire::Source-Symlinks",true) == false ||
3110 Cnf
->Removable
== true)
3112 Desc
.URI
= "copy:" + FileName
;
3117 // Erase the file if it is a symlink so we can overwrite it
3119 if (lstat(DestFile
.c_str(),&St
) == 0)
3121 if (S_ISLNK(St
.st_mode
) != 0)
3122 unlink(DestFile
.c_str());
3126 if (symlink(FileName
.c_str(),DestFile
.c_str()) != 0)
3128 _error
->PushToStack();
3129 _error
->Errno("pkgAcqFile::Done", "Symlinking file %s failed", DestFile
.c_str());
3130 std::stringstream msg
;
3131 _error
->DumpErrors(msg
);
3132 _error
->RevertToStack();
3133 ErrorText
= msg
.str();
3140 // AcqFile::Failed - Failure handler /*{{{*/
3141 // ---------------------------------------------------------------------
3142 /* Here we try other sources */
3143 void pkgAcqFile::Failed(string
const &Message
, pkgAcquire::MethodConfig
const * const Cnf
)
3145 Item::Failed(Message
,Cnf
);
3147 // This is the retry counter
3149 Cnf
->LocalOnly
== false &&
3150 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
3160 string
pkgAcqFile::Custom600Headers() const /*{{{*/
3163 return "\nIndex-File: true";
3167 pkgAcqFile::~pkgAcqFile() {}