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), Complete(false), Local(false),
409 QueueCounter(0), ExpectedAdditionalItems(0), Owner(Owner
)
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 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 string FileName
= LookupTag(Message
,"Filename");
523 UsedMirror
= LookupTag(Message
,"UsedMirror");
524 unsigned long long const downloadedSize
= Hashes
.FileSize();
525 if (downloadedSize
!= 0)
527 if (Complete
== false && !Local
&& FileName
== DestFile
)
530 Owner
->Log
->Fetched(Hashes
.FileSize(),atoi(LookupTag(Message
,"Resume-Point","0").c_str()));
534 FileSize
= downloadedSize
;
537 ErrorText
= string();
538 Owner
->Dequeue(this);
541 // Acquire::Item::Rename - Rename a file /*{{{*/
542 // ---------------------------------------------------------------------
543 /* This helper function is used by a lot of item methods as their final
545 bool pkgAcquire::Item::Rename(string
const &From
,string
const &To
)
547 if (From
== To
|| rename(From
.c_str(),To
.c_str()) == 0)
551 strprintf(S
, _("rename failed, %s (%s -> %s)."), strerror(errno
),
552 From
.c_str(),To
.c_str());
554 if (ErrorText
.empty())
557 ErrorText
= ErrorText
+ ": " + S
;
561 void pkgAcquire::Item::Dequeue() /*{{{*/
563 Owner
->Dequeue(this);
566 bool pkgAcquire::Item::RenameOnError(pkgAcquire::Item::RenameOnErrorState
const error
)/*{{{*/
568 if (RealFileExists(DestFile
))
569 Rename(DestFile
, DestFile
+ ".FAILED");
574 case HashSumMismatch
:
575 errtext
= _("Hash Sum mismatch");
576 Status
= StatAuthError
;
577 ReportMirrorFailure("HashChecksumFailure");
580 errtext
= _("Size mismatch");
581 Status
= StatAuthError
;
582 ReportMirrorFailure("SizeFailure");
585 errtext
= _("Invalid file format");
587 // do not report as usually its not the mirrors fault, but Portal/Proxy
590 errtext
= _("Signature error");
594 errtext
= _("Does not start with a cleartext signature");
597 case MaximumSizeExceeded
:
598 // the method is expected to report a good error for this
602 // no handling here, done by callers
605 if (ErrorText
.empty())
610 void pkgAcquire::Item::SetActiveSubprocess(const std::string
&subprocess
)/*{{{*/
612 ActiveSubprocess
= subprocess
;
613 APT_IGNORE_DEPRECATED(Mode
= ActiveSubprocess
.c_str();)
616 // Acquire::Item::ReportMirrorFailure /*{{{*/
617 void pkgAcquire::Item::ReportMirrorFailure(string
const &FailCode
)
619 // we only act if a mirror was used at all
620 if(UsedMirror
.empty())
623 std::cerr
<< "\nReportMirrorFailure: "
625 << " Uri: " << DescURI()
627 << FailCode
<< std::endl
;
629 string report
= _config
->Find("Methods::Mirror::ProblemReporting",
630 "/usr/lib/apt/apt-report-mirror-failure");
631 if(!FileExists(report
))
634 std::vector
<char const*> Args
;
635 Args
.push_back(report
.c_str());
636 Args
.push_back(UsedMirror
.c_str());
637 Args
.push_back(DescURI().c_str());
638 Args
.push_back(FailCode
.c_str());
639 Args
.push_back(NULL
);
641 pid_t pid
= ExecFork();
644 _error
->Error("ReportMirrorFailure Fork failed");
649 execvp(Args
[0], (char**)Args
.data());
650 std::cerr
<< "Could not exec " << Args
[0] << std::endl
;
653 if(!ExecWait(pid
, "report-mirror-failure"))
655 _error
->Warning("Couldn't report problem to '%s'",
656 _config
->Find("Methods::Mirror::ProblemReporting").c_str());
660 std::string
pkgAcquire::Item::HashSum() const /*{{{*/
662 HashStringList
const hashes
= GetExpectedHashes();
663 HashString
const * const hs
= hashes
.find(NULL
);
664 return hs
!= NULL
? hs
->toStr() : "";
668 pkgAcqTransactionItem::pkgAcqTransactionItem(pkgAcquire
* const Owner
, /*{{{*/
669 pkgAcqMetaBase
* const TransactionManager
, IndexTarget
const Target
) :
670 pkgAcquire::Item(Owner
), Target(Target
), TransactionManager(TransactionManager
)
672 if (TransactionManager
!= this)
673 TransactionManager
->Add(this);
676 pkgAcqTransactionItem::~pkgAcqTransactionItem() /*{{{*/
680 HashStringList
pkgAcqTransactionItem::GetExpectedHashesFor(std::string
const MetaKey
) const /*{{{*/
682 return GetExpectedHashesFromFor(TransactionManager
->MetaIndexParser
, MetaKey
);
686 // AcqMetaBase - Constructor /*{{{*/
687 pkgAcqMetaBase::pkgAcqMetaBase(pkgAcquire
* const Owner
,
688 pkgAcqMetaBase
* const TransactionManager
,
689 std::vector
<IndexTarget
> const IndexTargets
,
690 IndexTarget
const &DataTarget
,
691 indexRecords
* const MetaIndexParser
)
692 : pkgAcqTransactionItem(Owner
, TransactionManager
, DataTarget
),
693 MetaIndexParser(MetaIndexParser
), LastMetaIndexParser(NULL
), IndexTargets(IndexTargets
),
694 AuthPass(false), IMSHit(false)
698 // AcqMetaBase::Add - Add a item to the current Transaction /*{{{*/
699 void pkgAcqMetaBase::Add(pkgAcqTransactionItem
* const I
)
701 Transaction
.push_back(I
);
704 // AcqMetaBase::AbortTransaction - Abort the current Transaction /*{{{*/
705 void pkgAcqMetaBase::AbortTransaction()
707 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
708 std::clog
<< "AbortTransaction: " << TransactionManager
<< std::endl
;
710 // ensure the toplevel is in error state too
711 for (std::vector
<pkgAcqTransactionItem
*>::iterator I
= Transaction
.begin();
712 I
!= Transaction
.end(); ++I
)
714 (*I
)->TransactionState(TransactionAbort
);
719 // AcqMetaBase::TransactionHasError - Check for errors in Transaction /*{{{*/
720 APT_PURE
bool pkgAcqMetaBase::TransactionHasError() const
722 for (std::vector
<pkgAcqTransactionItem
*>::const_iterator I
= Transaction
.begin();
723 I
!= Transaction
.end(); ++I
)
725 switch((*I
)->Status
) {
726 case StatDone
: break;
727 case StatIdle
: break;
728 case StatAuthError
: return true;
729 case StatError
: return true;
730 case StatTransientNetworkError
: return true;
731 case StatFetching
: break;
737 // AcqMetaBase::CommitTransaction - Commit a transaction /*{{{*/
738 void pkgAcqMetaBase::CommitTransaction()
740 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
741 std::clog
<< "CommitTransaction: " << this << std::endl
;
743 // move new files into place *and* remove files that are not
744 // part of the transaction but are still on disk
745 for (std::vector
<pkgAcqTransactionItem
*>::iterator I
= Transaction
.begin();
746 I
!= Transaction
.end(); ++I
)
748 (*I
)->TransactionState(TransactionCommit
);
753 // AcqMetaBase::TransactionStageCopy - Stage a file for copying /*{{{*/
754 void pkgAcqMetaBase::TransactionStageCopy(pkgAcqTransactionItem
* const I
,
755 const std::string
&From
,
756 const std::string
&To
)
758 I
->PartialFile
= From
;
762 // AcqMetaBase::TransactionStageRemoval - Stage a file for removal /*{{{*/
763 void pkgAcqMetaBase::TransactionStageRemoval(pkgAcqTransactionItem
* const I
,
764 const std::string
&FinalFile
)
767 I
->DestFile
= FinalFile
;
770 // AcqMetaBase::GenerateAuthWarning - Check gpg authentication error /*{{{*/
771 bool pkgAcqMetaBase::CheckStopAuthentication(pkgAcquire::Item
* const I
, const std::string
&Message
)
773 // FIXME: this entire function can do now that we disallow going to
774 // a unauthenticated state and can cleanly rollback
776 string
const Final
= I
->GetFinalFilename();
777 if(FileExists(Final
))
779 I
->Status
= StatTransientNetworkError
;
780 _error
->Warning(_("An error occurred during the signature "
781 "verification. The repository is not updated "
782 "and the previous index files will be used. "
783 "GPG error: %s: %s\n"),
784 Desc
.Description
.c_str(),
785 LookupTag(Message
,"Message").c_str());
786 RunScripts("APT::Update::Auth-Failure");
788 } else if (LookupTag(Message
,"Message").find("NODATA") != string::npos
) {
789 /* Invalid signature file, reject (LP: #346386) (Closes: #627642) */
790 _error
->Error(_("GPG error: %s: %s"),
791 Desc
.Description
.c_str(),
792 LookupTag(Message
,"Message").c_str());
793 I
->Status
= StatError
;
796 _error
->Warning(_("GPG error: %s: %s"),
797 Desc
.Description
.c_str(),
798 LookupTag(Message
,"Message").c_str());
800 // gpgv method failed
801 ReportMirrorFailure("GPGFailure");
805 // AcqMetaBase::Custom600Headers - Get header for AcqMetaBase /*{{{*/
806 // ---------------------------------------------------------------------
807 string
pkgAcqMetaBase::Custom600Headers() const
809 std::string Header
= "\nIndex-File: true";
810 std::string MaximumSize
;
811 strprintf(MaximumSize
, "\nMaximum-Size: %i",
812 _config
->FindI("Acquire::MaxReleaseFileSize", 10*1000*1000));
813 Header
+= MaximumSize
;
815 string
const FinalFile
= GetFinalFilename();
818 if (stat(FinalFile
.c_str(),&Buf
) == 0)
819 Header
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
824 // AcqMetaBase::QueueForSignatureVerify /*{{{*/
825 void pkgAcqMetaBase::QueueForSignatureVerify(pkgAcqTransactionItem
* const I
, std::string
const &File
, std::string
const &Signature
)
828 I
->Desc
.URI
= "gpgv:" + Signature
;
831 I
->SetActiveSubprocess("gpgv");
834 // AcqMetaBase::CheckDownloadDone /*{{{*/
835 bool pkgAcqMetaBase::CheckDownloadDone(pkgAcqTransactionItem
* const I
, const std::string
&Message
, HashStringList
const &Hashes
) const
837 // We have just finished downloading a Release file (it is not
840 string
const FileName
= LookupTag(Message
,"Filename");
841 if (FileName
.empty() == true)
843 I
->Status
= StatError
;
844 I
->ErrorText
= "Method gave a blank filename";
848 if (FileName
!= I
->DestFile
&& RealFileExists(I
->DestFile
) == false)
851 I
->Desc
.URI
= "copy:" + FileName
;
852 I
->QueueURI(I
->Desc
);
856 // make sure to verify against the right file on I-M-S hit
857 bool IMSHit
= StringToBool(LookupTag(Message
,"IMS-Hit"), false);
858 if (IMSHit
== false && Hashes
.usable())
860 // detect IMS-Hits servers haven't detected by Hash comparison
861 std::string
const FinalFile
= I
->GetFinalFilename();
862 if (RealFileExists(FinalFile
) && Hashes
.VerifyFile(FinalFile
) == true)
865 unlink(I
->DestFile
.c_str());
871 // for simplicity, the transaction manager is always InRelease
872 // even if it doesn't exist.
873 if (TransactionManager
!= NULL
)
874 TransactionManager
->IMSHit
= true;
875 I
->PartialFile
= I
->DestFile
= I
->GetFinalFilename();
878 // set Item to complete as the remaining work is all local (verify etc)
884 bool pkgAcqMetaBase::CheckAuthDone(string
const &Message
) /*{{{*/
886 // At this point, the gpgv method has succeeded, so there is a
887 // valid signature from a key in the trusted keyring. We
888 // perform additional verification of its contents, and use them
889 // to verify the indexes we are about to download
891 if (TransactionManager
->IMSHit
== false)
893 // open the last (In)Release if we have it
894 std::string
const FinalFile
= GetFinalFilename();
895 std::string FinalRelease
;
896 std::string FinalInRelease
;
897 if (APT::String::Endswith(FinalFile
, "InRelease"))
899 FinalInRelease
= FinalFile
;
900 FinalRelease
= FinalFile
.substr(0, FinalFile
.length() - strlen("InRelease")) + "Release";
904 FinalInRelease
= FinalFile
.substr(0, FinalFile
.length() - strlen("Release")) + "InRelease";
905 FinalRelease
= FinalFile
;
907 if (RealFileExists(FinalInRelease
) || RealFileExists(FinalRelease
))
909 TransactionManager
->LastMetaIndexParser
= new indexRecords
;
910 _error
->PushToStack();
911 if (RealFileExists(FinalInRelease
))
912 TransactionManager
->LastMetaIndexParser
->Load(FinalInRelease
);
914 TransactionManager
->LastMetaIndexParser
->Load(FinalRelease
);
915 // its unlikely to happen, but if what we have is bad ignore it
916 if (_error
->PendingError())
918 delete TransactionManager
->LastMetaIndexParser
;
919 TransactionManager
->LastMetaIndexParser
= NULL
;
921 _error
->RevertToStack();
925 if (TransactionManager
->MetaIndexParser
->Load(DestFile
) == false)
927 Status
= StatAuthError
;
928 ErrorText
= TransactionManager
->MetaIndexParser
->ErrorText
;
932 if (!VerifyVendor(Message
))
934 Status
= StatAuthError
;
938 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
939 std::cerr
<< "Signature verification succeeded: "
940 << DestFile
<< std::endl
;
942 // Download further indexes with verification
948 void pkgAcqMetaBase::QueueIndexes(bool const verify
) /*{{{*/
950 // at this point the real Items are loaded in the fetcher
951 ExpectedAdditionalItems
= 0;
953 for (std::vector
<IndexTarget
>::const_iterator Target
= IndexTargets
.begin();
954 Target
!= IndexTargets
.end();
957 bool trypdiff
= _config
->FindB("Acquire::PDiffs", true);
960 if (TransactionManager
->MetaIndexParser
->Exists(Target
->MetaKey
) == false)
962 // optional targets that we do not have in the Release file are skipped
963 if (Target
->IsOptional
)
966 Status
= StatAuthError
;
967 strprintf(ErrorText
, _("Unable to find expected entry '%s' in Release file (Wrong sources.list entry or malformed file)"), Target
->MetaKey
.c_str());
971 if (RealFileExists(GetFinalFileNameFromURI(Target
->URI
)))
973 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
975 HashStringList
const newFile
= GetExpectedHashesFromFor(TransactionManager
->MetaIndexParser
, Target
->MetaKey
);
976 HashStringList
const oldFile
= GetExpectedHashesFromFor(TransactionManager
->LastMetaIndexParser
, Target
->MetaKey
);
977 if (newFile
== oldFile
)
979 // we have the file already, no point in trying to acquire it again
980 new NoActionItem(Owner
, *Target
);
986 trypdiff
= false; // no file to patch
988 // check if we have patches available
989 trypdiff
&= TransactionManager
->MetaIndexParser
->Exists(Target
->MetaKey
+ ".diff/Index");
991 // if we have no file to patch, no point in trying
992 trypdiff
&= RealFileExists(GetFinalFileNameFromURI(Target
->URI
));
994 // no point in patching from local sources
997 std::string
const proto
= Target
->URI
.substr(0, strlen("file:/"));
998 if (proto
== "file:/" || proto
== "copy:/" || proto
== "cdrom:")
1002 // Queue the Index file (Packages, Sources, Translation-$foo, …)
1004 new pkgAcqDiffIndex(Owner
, TransactionManager
, *Target
);
1006 new pkgAcqIndex(Owner
, TransactionManager
, *Target
);
1010 bool pkgAcqMetaBase::VerifyVendor(string
const &Message
) /*{{{*/
1012 string::size_type pos
;
1014 // check for missing sigs (that where not fatal because otherwise we had
1017 string msg
= _("There is no public key available for the "
1018 "following key IDs:\n");
1019 pos
= Message
.find("NO_PUBKEY ");
1020 if (pos
!= std::string::npos
)
1022 string::size_type start
= pos
+strlen("NO_PUBKEY ");
1023 string Fingerprint
= Message
.substr(start
, Message
.find("\n")-start
);
1024 missingkeys
+= (Fingerprint
);
1026 if(!missingkeys
.empty())
1027 _error
->Warning("%s", (msg
+ missingkeys
).c_str());
1029 string Transformed
= TransactionManager
->MetaIndexParser
->GetExpectedDist();
1031 if (Transformed
== "../project/experimental")
1033 Transformed
= "experimental";
1036 pos
= Transformed
.rfind('/');
1037 if (pos
!= string::npos
)
1039 Transformed
= Transformed
.substr(0, pos
);
1042 if (Transformed
== ".")
1047 if (_config
->FindB("Acquire::Check-Valid-Until", true) == true &&
1048 TransactionManager
->MetaIndexParser
->GetValidUntil() > 0) {
1049 time_t const invalid_since
= time(NULL
) - TransactionManager
->MetaIndexParser
->GetValidUntil();
1050 if (invalid_since
> 0)
1054 // TRANSLATOR: The first %s is the URL of the bad Release file, the second is
1055 // the time since then the file is invalid - formated in the same way as in
1056 // the download progress display (e.g. 7d 3h 42min 1s)
1057 _("Release file for %s is expired (invalid since %s). "
1058 "Updates for this repository will not be applied."),
1059 Target
.URI
.c_str(), TimeToStr(invalid_since
).c_str());
1060 if (ErrorText
.empty())
1062 return _error
->Error("%s", errmsg
.c_str());
1066 /* Did we get a file older than what we have? This is a last minute IMS hit and doubles
1067 as a prevention of downgrading us to older (still valid) files */
1068 if (TransactionManager
->IMSHit
== false && TransactionManager
->LastMetaIndexParser
!= NULL
&&
1069 TransactionManager
->LastMetaIndexParser
->GetDate() > TransactionManager
->MetaIndexParser
->GetDate())
1071 TransactionManager
->IMSHit
= true;
1072 unlink(DestFile
.c_str());
1073 PartialFile
= DestFile
= GetFinalFilename();
1074 delete TransactionManager
->MetaIndexParser
;
1075 TransactionManager
->MetaIndexParser
= TransactionManager
->LastMetaIndexParser
;
1076 TransactionManager
->LastMetaIndexParser
= NULL
;
1079 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1081 std::cerr
<< "Got Codename: " << TransactionManager
->MetaIndexParser
->GetDist() << std::endl
;
1082 std::cerr
<< "Expecting Dist: " << TransactionManager
->MetaIndexParser
->GetExpectedDist() << std::endl
;
1083 std::cerr
<< "Transformed Dist: " << Transformed
<< std::endl
;
1086 if (TransactionManager
->MetaIndexParser
->CheckDist(Transformed
) == false)
1088 // This might become fatal one day
1089 // Status = StatAuthError;
1090 // ErrorText = "Conflicting distribution; expected "
1091 // + MetaIndexParser->GetExpectedDist() + " but got "
1092 // + MetaIndexParser->GetDist();
1094 if (!Transformed
.empty())
1096 _error
->Warning(_("Conflicting distribution: %s (expected %s but got %s)"),
1097 Desc
.Description
.c_str(),
1098 Transformed
.c_str(),
1099 TransactionManager
->MetaIndexParser
->GetDist().c_str());
1107 pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire
* const Owner
, /*{{{*/
1108 IndexTarget
const &ClearsignedTarget
,
1109 IndexTarget
const &DetachedDataTarget
, IndexTarget
const &DetachedSigTarget
,
1110 std::vector
<IndexTarget
> const IndexTargets
,
1111 indexRecords
* const MetaIndexParser
) :
1112 pkgAcqMetaIndex(Owner
, this, ClearsignedTarget
, DetachedSigTarget
, IndexTargets
, MetaIndexParser
),
1113 ClearsignedTarget(ClearsignedTarget
),
1114 DetachedDataTarget(DetachedDataTarget
), DetachedSigTarget(DetachedSigTarget
)
1116 // index targets + (worst case:) Release/Release.gpg
1117 ExpectedAdditionalItems
= IndexTargets
.size() + 2;
1118 TransactionManager
->Add(this);
1121 pkgAcqMetaClearSig::~pkgAcqMetaClearSig() /*{{{*/
1125 // pkgAcqMetaClearSig::Custom600Headers - Insert custom request headers /*{{{*/
1126 string
pkgAcqMetaClearSig::Custom600Headers() const
1128 string Header
= pkgAcqMetaBase::Custom600Headers();
1129 Header
+= "\nFail-Ignore: true";
1133 // pkgAcqMetaClearSig::Done - We got a file /*{{{*/
1134 void pkgAcqMetaClearSig::Done(std::string
const &Message
,
1135 HashStringList
const &Hashes
,
1136 pkgAcquire::MethodConfig
const * const Cnf
)
1138 Item::Done(Message
, Hashes
, Cnf
);
1140 // if we expect a ClearTextSignature (InRelease), ensure that
1141 // this is what we get and if not fail to queue a
1142 // Release/Release.gpg, see #346386
1143 if (FileExists(DestFile
) && !StartsWithGPGClearTextSignature(DestFile
))
1145 pkgAcquire::Item::Failed(Message
, Cnf
);
1146 RenameOnError(NotClearsigned
);
1147 TransactionManager
->AbortTransaction();
1151 if(AuthPass
== false)
1153 if(CheckDownloadDone(this, Message
, Hashes
) == true)
1154 QueueForSignatureVerify(this, DestFile
, DestFile
);
1157 else if(CheckAuthDone(Message
) == true)
1159 if (TransactionManager
->IMSHit
== false)
1160 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
1161 else if (RealFileExists(GetFinalFilename()) == false)
1163 // We got an InRelease file IMSHit, but we haven't one, which means
1164 // we had a valid Release/Release.gpg combo stepping in, which we have
1165 // to 'acquire' now to ensure list cleanup isn't removing them
1166 new NoActionItem(Owner
, DetachedDataTarget
);
1167 new NoActionItem(Owner
, DetachedSigTarget
);
1172 void pkgAcqMetaClearSig::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
) /*{{{*/
1174 Item::Failed(Message
, Cnf
);
1176 // we failed, we will not get additional items from this method
1177 ExpectedAdditionalItems
= 0;
1179 if (AuthPass
== false)
1181 // Queue the 'old' InRelease file for removal if we try Release.gpg
1182 // as otherwise the file will stay around and gives a false-auth
1183 // impression (CVE-2012-0214)
1184 TransactionManager
->TransactionStageRemoval(this, GetFinalFilename());
1187 new pkgAcqMetaIndex(Owner
, TransactionManager
, DetachedDataTarget
, DetachedSigTarget
, IndexTargets
, TransactionManager
->MetaIndexParser
);
1191 if(CheckStopAuthentication(this, Message
))
1194 _error
->Warning(_("The data from '%s' is not signed. Packages "
1195 "from that repository can not be authenticated."),
1196 ClearsignedTarget
.Description
.c_str());
1198 // No Release file was present, or verification failed, so fall
1199 // back to queueing Packages files without verification
1200 // only allow going further if the users explicitely wants it
1201 if(AllowInsecureRepositories(TransactionManager
->MetaIndexParser
, TransactionManager
, this) == true)
1205 /* InRelease files become Release files, otherwise
1206 * they would be considered as trusted later on */
1207 string
const FinalRelease
= GetFinalFileNameFromURI(DetachedDataTarget
.URI
);
1208 string
const PartialRelease
= GetPartialFileNameFromURI(DetachedDataTarget
.URI
);
1209 string
const FinalReleasegpg
= GetFinalFileNameFromURI(DetachedSigTarget
.URI
);
1210 string
const FinalInRelease
= GetFinalFilename();
1211 Rename(DestFile
, PartialRelease
);
1212 TransactionManager
->TransactionStageCopy(this, PartialRelease
, FinalRelease
);
1214 if (RealFileExists(FinalReleasegpg
) || RealFileExists(FinalInRelease
))
1216 // open the last Release if we have it
1217 if (TransactionManager
->IMSHit
== false)
1219 TransactionManager
->LastMetaIndexParser
= new indexRecords
;
1220 _error
->PushToStack();
1221 if (RealFileExists(FinalInRelease
))
1222 TransactionManager
->LastMetaIndexParser
->Load(FinalInRelease
);
1224 TransactionManager
->LastMetaIndexParser
->Load(FinalRelease
);
1225 // its unlikely to happen, but if what we have is bad ignore it
1226 if (_error
->PendingError())
1228 delete TransactionManager
->LastMetaIndexParser
;
1229 TransactionManager
->LastMetaIndexParser
= NULL
;
1231 _error
->RevertToStack();
1235 // we parse the indexes here because at this point the user wanted
1236 // a repository that may potentially harm him
1237 if (TransactionManager
->MetaIndexParser
->Load(PartialRelease
) == false || VerifyVendor(Message
) == false)
1238 /* expired Release files are still a problem you need extra force for */;
1246 pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire
* const Owner
, /*{{{*/
1247 pkgAcqMetaBase
* const TransactionManager
,
1248 IndexTarget
const &DataTarget
,
1249 IndexTarget
const &DetachedSigTarget
,
1250 vector
<IndexTarget
> const IndexTargets
,
1251 indexRecords
* const MetaIndexParser
) :
1252 pkgAcqMetaBase(Owner
, TransactionManager
, IndexTargets
, DataTarget
, MetaIndexParser
),
1253 DetachedSigTarget(DetachedSigTarget
)
1255 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1256 std::clog
<< "New pkgAcqMetaIndex with TransactionManager "
1257 << this->TransactionManager
<< std::endl
;
1259 DestFile
= GetPartialFileNameFromURI(DataTarget
.URI
);
1262 Desc
.Description
= DataTarget
.Description
;
1264 Desc
.ShortDesc
= DataTarget
.ShortDesc
;
1265 Desc
.URI
= DataTarget
.URI
;
1267 // we expect more item
1268 ExpectedAdditionalItems
= IndexTargets
.size();
1272 void pkgAcqMetaIndex::Done(string
const &Message
, /*{{{*/
1273 HashStringList
const &Hashes
,
1274 pkgAcquire::MethodConfig
const * const Cfg
)
1276 Item::Done(Message
,Hashes
,Cfg
);
1278 if(CheckDownloadDone(this, Message
, Hashes
))
1280 // we have a Release file, now download the Signature, all further
1281 // verify/queue for additional downloads will be done in the
1282 // pkgAcqMetaSig::Done() code
1283 new pkgAcqMetaSig(Owner
, TransactionManager
, DetachedSigTarget
, this);
1287 // pkgAcqMetaIndex::Failed - no Release file present /*{{{*/
1288 void pkgAcqMetaIndex::Failed(string
const &Message
,
1289 pkgAcquire::MethodConfig
const * const Cnf
)
1291 pkgAcquire::Item::Failed(Message
, Cnf
);
1294 _error
->Warning(_("The repository '%s' does not have a Release file. "
1295 "This is deprecated, please contact the owner of the "
1296 "repository."), Target
.Description
.c_str());
1298 // No Release file was present so fall
1299 // back to queueing Packages files without verification
1300 // only allow going further if the users explicitely wants it
1301 if(AllowInsecureRepositories(TransactionManager
->MetaIndexParser
, TransactionManager
, this) == true)
1303 // ensure old Release files are removed
1304 TransactionManager
->TransactionStageRemoval(this, GetFinalFilename());
1305 delete TransactionManager
->MetaIndexParser
;
1306 TransactionManager
->MetaIndexParser
= NULL
;
1308 // queue without any kind of hashsum support
1309 QueueIndexes(false);
1313 void pkgAcqMetaIndex::Finished() /*{{{*/
1315 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1316 std::clog
<< "Finished: " << DestFile
<<std::endl
;
1317 if(TransactionManager
!= NULL
&&
1318 TransactionManager
->TransactionHasError() == false)
1319 TransactionManager
->CommitTransaction();
1322 std::string
pkgAcqMetaIndex::DescURI() const /*{{{*/
1328 // AcqMetaSig::AcqMetaSig - Constructor /*{{{*/
1329 pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire
* const Owner
,
1330 pkgAcqMetaBase
* const TransactionManager
,
1331 IndexTarget
const Target
,
1332 pkgAcqMetaIndex
* const MetaIndex
) :
1333 pkgAcqTransactionItem(Owner
, TransactionManager
, Target
), MetaIndex(MetaIndex
)
1335 DestFile
= GetPartialFileNameFromURI(Target
.URI
);
1337 // remove any partial downloaded sig-file in partial/.
1338 // it may confuse proxies and is too small to warrant a
1339 // partial download anyway
1340 unlink(DestFile
.c_str());
1342 // set the TransactionManager
1343 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1344 std::clog
<< "New pkgAcqMetaSig with TransactionManager "
1345 << TransactionManager
<< std::endl
;
1348 Desc
.Description
= Target
.Description
;
1350 Desc
.ShortDesc
= Target
.ShortDesc
;
1351 Desc
.URI
= Target
.URI
;
1353 // If we got a hit for Release, we will get one for Release.gpg too (or obscure errors),
1354 // so we skip the download step and go instantly to verification
1355 if (TransactionManager
->IMSHit
== true && RealFileExists(GetFinalFilename()))
1359 PartialFile
= DestFile
= GetFinalFilename();
1360 MetaIndexFileSignature
= DestFile
;
1361 MetaIndex
->QueueForSignatureVerify(this, MetaIndex
->DestFile
, DestFile
);
1367 pkgAcqMetaSig::~pkgAcqMetaSig() /*{{{*/
1371 // AcqMetaSig::Done - The signature was downloaded/verified /*{{{*/
1372 void pkgAcqMetaSig::Done(string
const &Message
, HashStringList
const &Hashes
,
1373 pkgAcquire::MethodConfig
const * const Cfg
)
1375 if (MetaIndexFileSignature
.empty() == false)
1377 DestFile
= MetaIndexFileSignature
;
1378 MetaIndexFileSignature
.clear();
1380 Item::Done(Message
, Hashes
, Cfg
);
1382 if(MetaIndex
->AuthPass
== false)
1384 if(MetaIndex
->CheckDownloadDone(this, Message
, Hashes
) == true)
1386 // destfile will be modified to point to MetaIndexFile for the
1387 // gpgv method, so we need to save it here
1388 MetaIndexFileSignature
= DestFile
;
1389 MetaIndex
->QueueForSignatureVerify(this, MetaIndex
->DestFile
, DestFile
);
1393 else if(MetaIndex
->CheckAuthDone(Message
) == true)
1395 if (TransactionManager
->IMSHit
== false)
1397 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
1398 TransactionManager
->TransactionStageCopy(MetaIndex
, MetaIndex
->DestFile
, MetaIndex
->GetFinalFilename());
1403 void pkgAcqMetaSig::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
1405 Item::Failed(Message
,Cnf
);
1407 // check if we need to fail at this point
1408 if (MetaIndex
->AuthPass
== true && MetaIndex
->CheckStopAuthentication(this, Message
))
1411 string
const FinalRelease
= MetaIndex
->GetFinalFilename();
1412 string
const FinalReleasegpg
= GetFinalFilename();
1413 string
const FinalInRelease
= TransactionManager
->GetFinalFilename();
1415 if (RealFileExists(FinalReleasegpg
) || RealFileExists(FinalInRelease
))
1417 std::string downgrade_msg
;
1418 strprintf(downgrade_msg
, _("The repository '%s' is no longer signed."),
1419 MetaIndex
->Target
.Description
.c_str());
1420 if(_config
->FindB("Acquire::AllowDowngradeToInsecureRepositories"))
1422 // meh, the users wants to take risks (we still mark the packages
1423 // from this repository as unauthenticated)
1424 _error
->Warning("%s", downgrade_msg
.c_str());
1425 _error
->Warning(_("This is normally not allowed, but the option "
1426 "Acquire::AllowDowngradeToInsecureRepositories was "
1427 "given to override it."));
1430 _error
->Error("%s", downgrade_msg
.c_str());
1431 if (TransactionManager
->IMSHit
== false)
1432 Rename(MetaIndex
->DestFile
, MetaIndex
->DestFile
+ ".FAILED");
1433 Item::Failed("Message: " + downgrade_msg
, Cnf
);
1434 TransactionManager
->AbortTransaction();
1439 _error
->Warning(_("The data from '%s' is not signed. Packages "
1440 "from that repository can not be authenticated."),
1441 MetaIndex
->Target
.Description
.c_str());
1443 // ensures that a Release.gpg file in the lists/ is removed by the transaction
1444 TransactionManager
->TransactionStageRemoval(this, DestFile
);
1446 // only allow going further if the users explicitely wants it
1447 if(AllowInsecureRepositories(TransactionManager
->MetaIndexParser
, TransactionManager
, this) == true)
1449 if (RealFileExists(FinalReleasegpg
) || RealFileExists(FinalInRelease
))
1451 // open the last Release if we have it
1452 if (TransactionManager
->IMSHit
== false)
1454 TransactionManager
->LastMetaIndexParser
= new indexRecords
;
1455 _error
->PushToStack();
1456 if (RealFileExists(FinalInRelease
))
1457 TransactionManager
->LastMetaIndexParser
->Load(FinalInRelease
);
1459 TransactionManager
->LastMetaIndexParser
->Load(FinalRelease
);
1460 // its unlikely to happen, but if what we have is bad ignore it
1461 if (_error
->PendingError())
1463 delete TransactionManager
->LastMetaIndexParser
;
1464 TransactionManager
->LastMetaIndexParser
= NULL
;
1466 _error
->RevertToStack();
1470 // we parse the indexes here because at this point the user wanted
1471 // a repository that may potentially harm him
1472 if (TransactionManager
->MetaIndexParser
->Load(MetaIndex
->DestFile
) == false || MetaIndex
->VerifyVendor(Message
) == false)
1473 /* expired Release files are still a problem you need extra force for */;
1475 MetaIndex
->QueueIndexes(true);
1477 TransactionManager
->TransactionStageCopy(MetaIndex
, MetaIndex
->DestFile
, MetaIndex
->GetFinalFilename());
1480 // FIXME: this is used often (e.g. in pkgAcqIndexTrans) so refactor
1481 if (Cnf
->LocalOnly
== true ||
1482 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1491 // AcqBaseIndex - Constructor /*{{{*/
1492 pkgAcqBaseIndex::pkgAcqBaseIndex(pkgAcquire
* const Owner
,
1493 pkgAcqMetaBase
* const TransactionManager
,
1494 IndexTarget
const Target
)
1495 : pkgAcqTransactionItem(Owner
, TransactionManager
, Target
)
1500 // AcqDiffIndex::AcqDiffIndex - Constructor /*{{{*/
1501 // ---------------------------------------------------------------------
1502 /* Get the DiffIndex file first and see if there are patches available
1503 * If so, create a pkgAcqIndexDiffs fetcher that will get and apply the
1504 * patches. If anything goes wrong in that process, it will fall back to
1505 * the original packages file
1507 pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire
* const Owner
,
1508 pkgAcqMetaBase
* const TransactionManager
,
1509 IndexTarget
const Target
)
1510 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
)
1512 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
1515 Desc
.Description
= Target
.Description
+ ".diff/Index";
1516 Desc
.ShortDesc
= Target
.ShortDesc
;
1517 Desc
.URI
= Target
.URI
+ ".diff/Index";
1519 DestFile
= GetPartialFileNameFromURI(Desc
.URI
);
1522 std::clog
<< "pkgAcqDiffIndex: " << Desc
.URI
<< std::endl
;
1527 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
1528 // ---------------------------------------------------------------------
1529 /* The only header we use is the last-modified header. */
1530 string
pkgAcqDiffIndex::Custom600Headers() const
1532 string
const Final
= GetFinalFilename();
1535 std::clog
<< "Custom600Header-IMS: " << Final
<< std::endl
;
1538 if (stat(Final
.c_str(),&Buf
) != 0)
1539 return "\nIndex-File: true";
1541 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1544 void pkgAcqDiffIndex::QueueOnIMSHit() const /*{{{*/
1546 // list cleanup needs to know that this file as well as the already
1547 // present index is ours, so we create an empty diff to save it for us
1548 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
);
1551 bool pkgAcqDiffIndex::ParseDiffIndex(string
const &IndexDiffFile
) /*{{{*/
1553 // failing here is fine: our caller will take care of trying to
1554 // get the complete file if patching fails
1556 std::clog
<< "pkgAcqDiffIndex::ParseIndexDiff() " << IndexDiffFile
1559 FileFd
Fd(IndexDiffFile
,FileFd::ReadOnly
);
1561 if (_error
->PendingError() == true)
1565 if(unlikely(TF
.Step(Tags
) == false))
1568 HashStringList ServerHashes
;
1569 unsigned long long ServerSize
= 0;
1571 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
1573 std::string tagname
= *type
;
1574 tagname
.append("-Current");
1575 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1576 if (tmp
.empty() == true)
1580 unsigned long long size
;
1581 std::stringstream
ss(tmp
);
1583 if (unlikely(hash
.empty() == true))
1585 if (unlikely(ServerSize
!= 0 && ServerSize
!= size
))
1587 ServerHashes
.push_back(HashString(*type
, hash
));
1591 if (ServerHashes
.usable() == false)
1594 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": Did not find a good hashsum in the index" << std::endl
;
1598 std::string
const CurrentPackagesFile
= GetFinalFileNameFromURI(Target
.URI
);
1599 HashStringList
const TargetFileHashes
= GetExpectedHashesFor(Target
.MetaKey
);
1600 if (TargetFileHashes
.usable() == false || ServerHashes
!= TargetFileHashes
)
1604 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": Index has different hashes than parser, probably older, so fail pdiffing" << std::endl
;
1605 printHashSumComparision(CurrentPackagesFile
, ServerHashes
, TargetFileHashes
);
1610 HashStringList LocalHashes
;
1611 // try avoiding calculating the hash here as this is costly
1612 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1613 LocalHashes
= GetExpectedHashesFromFor(TransactionManager
->LastMetaIndexParser
, Target
.MetaKey
);
1614 if (LocalHashes
.usable() == false)
1616 FileFd
fd(CurrentPackagesFile
, FileFd::ReadOnly
);
1617 Hashes
LocalHashesCalc(ServerHashes
);
1618 LocalHashesCalc
.AddFD(fd
);
1619 LocalHashes
= LocalHashesCalc
.GetHashStringList();
1622 if (ServerHashes
== LocalHashes
)
1624 // we have the same sha1 as the server so we are done here
1626 std::clog
<< "pkgAcqDiffIndex: Package file " << CurrentPackagesFile
<< " is up-to-date" << std::endl
;
1632 std::clog
<< "Server-Current: " << ServerHashes
.find(NULL
)->toStr() << " and we start at "
1633 << CurrentPackagesFile
<< " " << LocalHashes
.FileSize() << " " << LocalHashes
.find(NULL
)->toStr() << std::endl
;
1635 // parse all of (provided) history
1636 vector
<DiffInfo
> available_patches
;
1637 bool firstAcceptedHashes
= true;
1638 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
1640 if (LocalHashes
.find(*type
) == NULL
)
1643 std::string tagname
= *type
;
1644 tagname
.append("-History");
1645 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1646 if (tmp
.empty() == true)
1649 string hash
, filename
;
1650 unsigned long long size
;
1651 std::stringstream
ss(tmp
);
1653 while (ss
>> hash
>> size
>> filename
)
1655 if (unlikely(hash
.empty() == true || filename
.empty() == true))
1658 // see if we have a record for this file already
1659 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
1660 for (; cur
!= available_patches
.end(); ++cur
)
1662 if (cur
->file
!= filename
)
1664 cur
->result_hashes
.push_back(HashString(*type
, hash
));
1667 if (cur
!= available_patches
.end())
1669 if (firstAcceptedHashes
== true)
1672 next
.file
= filename
;
1673 next
.result_hashes
.push_back(HashString(*type
, hash
));
1674 next
.result_hashes
.FileSize(size
);
1675 available_patches
.push_back(next
);
1680 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
1681 << " wasn't in the list for the first parsed hash! (history)" << std::endl
;
1685 firstAcceptedHashes
= false;
1688 if (unlikely(available_patches
.empty() == true))
1691 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": "
1692 << "Couldn't find any patches for the patch series." << std::endl
;
1696 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
1698 if (LocalHashes
.find(*type
) == NULL
)
1701 std::string tagname
= *type
;
1702 tagname
.append("-Patches");
1703 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1704 if (tmp
.empty() == true)
1707 string hash
, filename
;
1708 unsigned long long size
;
1709 std::stringstream
ss(tmp
);
1711 while (ss
>> hash
>> size
>> filename
)
1713 if (unlikely(hash
.empty() == true || filename
.empty() == true))
1716 // see if we have a record for this file already
1717 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
1718 for (; cur
!= available_patches
.end(); ++cur
)
1720 if (cur
->file
!= filename
)
1722 if (cur
->patch_hashes
.empty())
1723 cur
->patch_hashes
.FileSize(size
);
1724 cur
->patch_hashes
.push_back(HashString(*type
, hash
));
1727 if (cur
!= available_patches
.end())
1730 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
1731 << " wasn't in the list for the first parsed hash! (patches)" << std::endl
;
1736 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
1738 std::string tagname
= *type
;
1739 tagname
.append("-Download");
1740 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1741 if (tmp
.empty() == true)
1744 string hash
, filename
;
1745 unsigned long long size
;
1746 std::stringstream
ss(tmp
);
1748 // FIXME: all of pdiff supports only .gz compressed patches
1749 while (ss
>> hash
>> size
>> filename
)
1751 if (unlikely(hash
.empty() == true || filename
.empty() == true))
1753 if (unlikely(APT::String::Endswith(filename
, ".gz") == false))
1755 filename
.erase(filename
.length() - 3);
1757 // see if we have a record for this file already
1758 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
1759 for (; cur
!= available_patches
.end(); ++cur
)
1761 if (cur
->file
!= filename
)
1763 if (cur
->download_hashes
.empty())
1764 cur
->download_hashes
.FileSize(size
);
1765 cur
->download_hashes
.push_back(HashString(*type
, hash
));
1768 if (cur
!= available_patches
.end())
1771 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
1772 << " wasn't in the list for the first parsed hash! (download)" << std::endl
;
1778 bool foundStart
= false;
1779 for (std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
1780 cur
!= available_patches
.end(); ++cur
)
1782 if (LocalHashes
!= cur
->result_hashes
)
1785 available_patches
.erase(available_patches
.begin(), cur
);
1790 if (foundStart
== false || unlikely(available_patches
.empty() == true))
1793 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": "
1794 << "Couldn't find the start of the patch series." << std::endl
;
1798 // patching with too many files is rather slow compared to a fast download
1799 unsigned long const fileLimit
= _config
->FindI("Acquire::PDiffs::FileLimit", 0);
1800 if (fileLimit
!= 0 && fileLimit
< available_patches
.size())
1803 std::clog
<< "Need " << available_patches
.size() << " diffs (Limit is " << fileLimit
1804 << ") so fallback to complete download" << std::endl
;
1808 // calculate the size of all patches we have to get
1809 // note that all sizes are uncompressed, while we download compressed files
1810 unsigned long long patchesSize
= 0;
1811 for (std::vector
<DiffInfo
>::const_iterator cur
= available_patches
.begin();
1812 cur
!= available_patches
.end(); ++cur
)
1813 patchesSize
+= cur
->patch_hashes
.FileSize();
1814 unsigned long long const sizeLimit
= ServerSize
* _config
->FindI("Acquire::PDiffs::SizeLimit", 100);
1815 if (sizeLimit
> 0 && (sizeLimit
/100) < patchesSize
)
1818 std::clog
<< "Need " << patchesSize
<< " bytes (Limit is " << sizeLimit
/100
1819 << ") so fallback to complete download" << std::endl
;
1823 // we have something, queue the diffs
1824 string::size_type
const last_space
= Description
.rfind(" ");
1825 if(last_space
!= string::npos
)
1826 Description
.erase(last_space
, Description
.size()-last_space
);
1828 /* decide if we should download patches one by one or in one go:
1829 The first is good if the server merges patches, but many don't so client
1830 based merging can be attempt in which case the second is better.
1831 "bad things" will happen if patches are merged on the server,
1832 but client side merging is attempt as well */
1833 bool pdiff_merge
= _config
->FindB("Acquire::PDiffs::Merge", true);
1834 if (pdiff_merge
== true)
1836 // reprepro adds this flag if it has merged patches on the server
1837 std::string
const precedence
= Tags
.FindS("X-Patch-Precedence");
1838 pdiff_merge
= (precedence
!= "merged");
1841 if (pdiff_merge
== false)
1842 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
, available_patches
);
1845 std::vector
<pkgAcqIndexMergeDiffs
*> *diffs
= new std::vector
<pkgAcqIndexMergeDiffs
*>(available_patches
.size());
1846 for(size_t i
= 0; i
< available_patches
.size(); ++i
)
1847 (*diffs
)[i
] = new pkgAcqIndexMergeDiffs(Owner
, TransactionManager
,
1849 available_patches
[i
],
1859 void pkgAcqDiffIndex::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
1861 Item::Failed(Message
,Cnf
);
1865 std::clog
<< "pkgAcqDiffIndex failed: " << Desc
.URI
<< " with " << Message
<< std::endl
1866 << "Falling back to normal index file acquire" << std::endl
;
1868 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
1871 void pkgAcqDiffIndex::Done(string
const &Message
,HashStringList
const &Hashes
, /*{{{*/
1872 pkgAcquire::MethodConfig
const * const Cnf
)
1875 std::clog
<< "pkgAcqDiffIndex::Done(): " << Desc
.URI
<< std::endl
;
1877 Item::Done(Message
, Hashes
, Cnf
);
1879 string
const FinalFile
= GetFinalFilename();
1880 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false))
1881 DestFile
= FinalFile
;
1883 if(ParseDiffIndex(DestFile
) == false)
1885 Failed("Message: Couldn't parse pdiff index", Cnf
);
1886 // queue for final move - this should happen even if we fail
1887 // while parsing (e.g. on sizelimit) and download the complete file.
1888 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
1892 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
1902 // AcqIndexDiffs::AcqIndexDiffs - Constructor /*{{{*/
1903 // ---------------------------------------------------------------------
1904 /* The package diff is added to the queue. one object is constructed
1905 * for each diff and the index
1907 pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire
* const Owner
,
1908 pkgAcqMetaBase
* const TransactionManager
,
1909 IndexTarget
const Target
,
1910 vector
<DiffInfo
> const &diffs
)
1911 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
),
1912 available_patches(diffs
)
1914 DestFile
= GetPartialFileNameFromURI(Target
.URI
);
1916 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
1919 Description
= Target
.Description
;
1920 Desc
.ShortDesc
= Target
.ShortDesc
;
1922 if(available_patches
.empty() == true)
1924 // we are done (yeah!), check hashes against the final file
1925 DestFile
= GetFinalFileNameFromURI(Target
.URI
);
1930 // patching needs to be bootstrapped with the 'old' version
1931 std::string
const PartialFile
= GetPartialFileNameFromURI(Target
.URI
);
1932 if (RealFileExists(PartialFile
) == false)
1934 if (symlink(GetFinalFilename().c_str(), PartialFile
.c_str()) != 0)
1936 Failed("Link creation of " + PartialFile
+ " to " + GetFinalFilename() + " failed", NULL
);
1941 // get the next diff
1942 State
= StateFetchDiff
;
1947 void pkgAcqIndexDiffs::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
1949 Item::Failed(Message
,Cnf
);
1953 std::clog
<< "pkgAcqIndexDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
1954 << "Falling back to normal index file acquire" << std::endl
;
1955 DestFile
= GetPartialFileNameFromURI(Target
.URI
);
1956 RenameOnError(PDiffError
);
1957 std::string
const patchname
= GetDiffsPatchFileName(DestFile
);
1958 if (RealFileExists(patchname
))
1959 rename(patchname
.c_str(), std::string(patchname
+ ".FAILED").c_str());
1960 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
1964 // Finish - helper that cleans the item out of the fetcher queue /*{{{*/
1965 void pkgAcqIndexDiffs::Finish(bool allDone
)
1968 std::clog
<< "pkgAcqIndexDiffs::Finish(): "
1970 << Desc
.URI
<< std::endl
;
1972 // we restore the original name, this is required, otherwise
1973 // the file will be cleaned
1976 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
1978 // this is for the "real" finish
1983 std::clog
<< "\n\nallDone: " << DestFile
<< "\n" << std::endl
;
1988 std::clog
<< "Finishing: " << Desc
.URI
<< std::endl
;
1995 bool pkgAcqIndexDiffs::QueueNextDiff() /*{{{*/
1997 // calc sha1 of the just patched file
1998 std::string
const FinalFile
= GetPartialFileNameFromURI(Target
.URI
);
2000 if(!FileExists(FinalFile
))
2002 Failed("Message: No FinalFile " + FinalFile
+ " available", NULL
);
2006 FileFd
fd(FinalFile
, FileFd::ReadOnly
);
2007 Hashes LocalHashesCalc
;
2008 LocalHashesCalc
.AddFD(fd
);
2009 HashStringList
const LocalHashes
= LocalHashesCalc
.GetHashStringList();
2012 std::clog
<< "QueueNextDiff: " << FinalFile
<< " (" << LocalHashes
.find(NULL
)->toStr() << ")" << std::endl
;
2014 HashStringList
const TargetFileHashes
= GetExpectedHashesFor(Target
.MetaKey
);
2015 if (unlikely(LocalHashes
.usable() == false || TargetFileHashes
.usable() == false))
2017 Failed("Local/Expected hashes are not usable", NULL
);
2022 // final file reached before all patches are applied
2023 if(LocalHashes
== TargetFileHashes
)
2029 // remove all patches until the next matching patch is found
2030 // this requires the Index file to be ordered
2031 for(vector
<DiffInfo
>::iterator I
= available_patches
.begin();
2032 available_patches
.empty() == false &&
2033 I
!= available_patches
.end() &&
2034 I
->result_hashes
!= LocalHashes
;
2037 available_patches
.erase(I
);
2040 // error checking and falling back if no patch was found
2041 if(available_patches
.empty() == true)
2043 Failed("No patches left to reach target", NULL
);
2047 // queue the right diff
2048 Desc
.URI
= Target
.URI
+ ".diff/" + available_patches
[0].file
+ ".gz";
2049 Desc
.Description
= Description
+ " " + available_patches
[0].file
+ string(".pdiff");
2050 DestFile
= GetPartialFileNameFromURI(Target
.URI
+ ".diff/" + available_patches
[0].file
);
2053 std::clog
<< "pkgAcqIndexDiffs::QueueNextDiff(): " << Desc
.URI
<< std::endl
;
2060 void pkgAcqIndexDiffs::Done(string
const &Message
, HashStringList
const &Hashes
, /*{{{*/
2061 pkgAcquire::MethodConfig
const * const Cnf
)
2064 std::clog
<< "pkgAcqIndexDiffs::Done(): " << Desc
.URI
<< std::endl
;
2066 Item::Done(Message
, Hashes
, Cnf
);
2068 std::string
const FinalFile
= GetPartialFileNameFromURI(Target
.URI
);
2069 std::string
const PatchFile
= GetDiffsPatchFileName(FinalFile
);
2071 // success in downloading a diff, enter ApplyDiff state
2072 if(State
== StateFetchDiff
)
2074 Rename(DestFile
, PatchFile
);
2077 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
2079 State
= StateApplyDiff
;
2081 Desc
.URI
= "rred:" + FinalFile
;
2083 SetActiveSubprocess("rred");
2087 // success in download/apply a diff, queue next (if needed)
2088 if(State
== StateApplyDiff
)
2090 // remove the just applied patch
2091 available_patches
.erase(available_patches
.begin());
2092 unlink(PatchFile
.c_str());
2097 std::clog
<< "Moving patched file in place: " << std::endl
2098 << DestFile
<< " -> " << FinalFile
<< std::endl
;
2100 Rename(DestFile
,FinalFile
);
2101 chmod(FinalFile
.c_str(),0644);
2103 // see if there is more to download
2104 if(available_patches
.empty() == false) {
2105 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
,
2110 DestFile
= FinalFile
;
2111 return Finish(true);
2115 std::string
pkgAcqIndexDiffs::Custom600Headers() const /*{{{*/
2117 if(State
!= StateApplyDiff
)
2118 return pkgAcqBaseIndex::Custom600Headers();
2119 std::ostringstream patchhashes
;
2120 HashStringList
const ExpectedHashes
= available_patches
[0].patch_hashes
;
2121 for (HashStringList::const_iterator hs
= ExpectedHashes
.begin(); hs
!= ExpectedHashes
.end(); ++hs
)
2122 patchhashes
<< "\nPatch-0-" << hs
->HashType() << "-Hash: " << hs
->HashValue();
2123 patchhashes
<< pkgAcqBaseIndex::Custom600Headers();
2124 return patchhashes
.str();
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
),
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();
2272 // AcqIndex::AcqIndex - Constructor /*{{{*/
2273 pkgAcqIndex::pkgAcqIndex(pkgAcquire
* const Owner
,
2274 pkgAcqMetaBase
* const TransactionManager
,
2275 IndexTarget
const Target
)
2276 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
)
2278 // autoselect the compression method
2279 AutoSelectCompression();
2280 Init(Target
.URI
, Target
.Description
, Target
.ShortDesc
);
2282 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
2283 std::clog
<< "New pkgIndex with TransactionManager "
2284 << TransactionManager
<< std::endl
;
2287 // AcqIndex::AutoSelectCompression - Select compression /*{{{*/
2288 void pkgAcqIndex::AutoSelectCompression()
2290 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
2291 CompressionExtensions
= "";
2292 if (TransactionManager
->MetaIndexParser
!= NULL
&& TransactionManager
->MetaIndexParser
->Exists(Target
.MetaKey
))
2294 for (std::vector
<std::string
>::const_iterator t
= types
.begin();
2295 t
!= types
.end(); ++t
)
2297 std::string CompressedMetaKey
= string(Target
.MetaKey
).append(".").append(*t
);
2298 if (*t
== "uncompressed" ||
2299 TransactionManager
->MetaIndexParser
->Exists(CompressedMetaKey
) == true)
2300 CompressionExtensions
.append(*t
).append(" ");
2305 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
2306 CompressionExtensions
.append(*t
).append(" ");
2308 if (CompressionExtensions
.empty() == false)
2309 CompressionExtensions
.erase(CompressionExtensions
.end()-1);
2312 // AcqIndex::Init - defered Constructor /*{{{*/
2313 void pkgAcqIndex::Init(string
const &URI
, string
const &URIDesc
,
2314 string
const &ShortDesc
)
2316 Stage
= STAGE_DOWNLOAD
;
2318 DestFile
= GetPartialFileNameFromURI(URI
);
2320 size_t const nextExt
= CompressionExtensions
.find(' ');
2321 if (nextExt
== std::string::npos
)
2323 CurrentCompressionExtension
= CompressionExtensions
;
2324 CompressionExtensions
.clear();
2328 CurrentCompressionExtension
= CompressionExtensions
.substr(0, nextExt
);
2329 CompressionExtensions
= CompressionExtensions
.substr(nextExt
+1);
2332 if (CurrentCompressionExtension
== "uncompressed")
2336 else if (unlikely(CurrentCompressionExtension
.empty()))
2340 Desc
.URI
= URI
+ '.' + CurrentCompressionExtension
;
2341 DestFile
= DestFile
+ '.' + CurrentCompressionExtension
;
2344 if(TransactionManager
->MetaIndexParser
!= NULL
)
2345 InitByHashIfNeeded();
2347 Desc
.Description
= URIDesc
;
2349 Desc
.ShortDesc
= ShortDesc
;
2354 // AcqIndex::AdjustForByHash - modify URI for by-hash support /*{{{*/
2355 void pkgAcqIndex::InitByHashIfNeeded()
2358 // - (maybe?) add support for by-hash into the sources.list as flag
2359 // - make apt-ftparchive generate the hashes (and expire?)
2360 std::string HostKnob
= "APT::Acquire::" + ::URI(Desc
.URI
).Host
+ "::By-Hash";
2361 if(_config
->FindB("APT::Acquire::By-Hash", false) == true ||
2362 _config
->FindB(HostKnob
, false) == true ||
2363 TransactionManager
->MetaIndexParser
->GetSupportsAcquireByHash())
2365 HashStringList
const Hashes
= GetExpectedHashes();
2368 // FIXME: should we really use the best hash here? or a fixed one?
2369 HashString
const * const TargetHash
= Hashes
.find("");
2370 std::string
const ByHash
= "/by-hash/" + TargetHash
->HashType() + "/" + TargetHash
->HashValue();
2371 size_t const trailing_slash
= Desc
.URI
.find_last_of("/");
2372 Desc
.URI
= Desc
.URI
.replace(
2374 Desc
.URI
.substr(trailing_slash
+1).size()+1,
2378 "Fetching ByHash requested but can not find record for %s",
2379 GetMetaKey().c_str());
2384 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
2385 // ---------------------------------------------------------------------
2386 /* The only header we use is the last-modified header. */
2387 string
pkgAcqIndex::Custom600Headers() const
2389 string Final
= GetFinalFilename();
2391 string msg
= "\nIndex-File: true";
2393 if (stat(Final
.c_str(),&Buf
) == 0)
2394 msg
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
2396 if(Target
.IsOptional
)
2397 msg
+= "\nFail-Ignore: true";
2402 // AcqIndex::Failed - getting the indexfile failed /*{{{*/
2403 void pkgAcqIndex::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)
2405 Item::Failed(Message
,Cnf
);
2407 // authorisation matches will not be fixed by other compression types
2408 if (Status
!= StatAuthError
)
2410 if (CompressionExtensions
.empty() == false)
2412 Init(Target
.URI
, Desc
.Description
, Desc
.ShortDesc
);
2418 if(Target
.IsOptional
&& GetExpectedHashes().empty() && Stage
== STAGE_DOWNLOAD
)
2421 TransactionManager
->AbortTransaction();
2424 // AcqIndex::ReverifyAfterIMS - Reverify index after an ims-hit /*{{{*/
2425 void pkgAcqIndex::ReverifyAfterIMS()
2427 // update destfile to *not* include the compression extension when doing
2428 // a reverify (as its uncompressed on disk already)
2429 DestFile
= GetCompressedFileName(Target
.URI
, GetPartialFileNameFromURI(Target
.URI
), CurrentCompressionExtension
);
2431 // copy FinalFile into partial/ so that we check the hash again
2432 string FinalFile
= GetFinalFilename();
2433 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
2434 Desc
.URI
= "copy:" + FinalFile
;
2438 // AcqIndex::Done - Finished a fetch /*{{{*/
2439 // ---------------------------------------------------------------------
2440 /* This goes through a number of states.. On the initial fetch the
2441 method could possibly return an alternate filename which points
2442 to the uncompressed version of the file. If this is so the file
2443 is copied into the partial directory. In all other cases the file
2444 is decompressed with a compressed uri. */
2445 void pkgAcqIndex::Done(string
const &Message
,
2446 HashStringList
const &Hashes
,
2447 pkgAcquire::MethodConfig
const * const Cfg
)
2449 Item::Done(Message
,Hashes
,Cfg
);
2453 case STAGE_DOWNLOAD
:
2454 StageDownloadDone(Message
, Hashes
, Cfg
);
2456 case STAGE_DECOMPRESS_AND_VERIFY
:
2457 StageDecompressDone(Message
, Hashes
, Cfg
);
2462 // AcqIndex::StageDownloadDone - Queue for decompress and verify /*{{{*/
2463 void pkgAcqIndex::StageDownloadDone(string
const &Message
, HashStringList
const &,
2464 pkgAcquire::MethodConfig
const * const)
2468 // Handle the unzipd case
2469 string FileName
= LookupTag(Message
,"Alt-Filename");
2470 if (FileName
.empty() == false)
2472 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
2474 DestFile
+= ".decomp";
2475 Desc
.URI
= "copy:" + FileName
;
2477 SetActiveSubprocess("copy");
2481 FileName
= LookupTag(Message
,"Filename");
2482 if (FileName
.empty() == true)
2485 ErrorText
= "Method gave a blank filename";
2488 // Methods like e.g. "file:" will give us a (compressed) FileName that is
2489 // not the "DestFile" we set, in this case we uncompress from the local file
2490 if (FileName
!= DestFile
&& RealFileExists(DestFile
) == false)
2493 EraseFileName
= FileName
;
2495 // we need to verify the file against the current Release file again
2496 // on if-modfied-since hit to avoid a stale attack against us
2497 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
2499 // The files timestamp matches, reverify by copy into partial/
2505 // If we have compressed indexes enabled, queue for hash verification
2506 if (_config
->FindB("Acquire::GzipIndexes",false))
2508 DestFile
= GetPartialFileNameFromURI(Target
.URI
+ '.' + CurrentCompressionExtension
);
2510 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
2511 Desc
.URI
= "copy:" + FileName
;
2513 SetActiveSubprocess("copy");
2517 // get the binary name for your used compression type
2519 if(CurrentCompressionExtension
== "uncompressed")
2520 decompProg
= "copy";
2522 decompProg
= _config
->Find(string("Acquire::CompressionTypes::").append(CurrentCompressionExtension
),"");
2523 if(decompProg
.empty() == true)
2525 _error
->Error("Unsupported extension: %s", CurrentCompressionExtension
.c_str());
2529 // queue uri for the next stage
2530 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
2531 DestFile
+= ".decomp";
2532 Desc
.URI
= decompProg
+ ":" + FileName
;
2534 SetActiveSubprocess(decompProg
);
2537 // AcqIndex::StageDecompressDone - Final verification /*{{{*/
2538 void pkgAcqIndex::StageDecompressDone(string
const &,
2539 HashStringList
const &,
2540 pkgAcquire::MethodConfig
const * const)
2542 // Done, queue for rename on transaction finished
2543 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
2549 // AcqArchive::AcqArchive - Constructor /*{{{*/
2550 // ---------------------------------------------------------------------
2551 /* This just sets up the initial fetch environment and queues the first
2553 pkgAcqArchive::pkgAcqArchive(pkgAcquire
* const Owner
,pkgSourceList
* const Sources
,
2554 pkgRecords
* const Recs
,pkgCache::VerIterator
const &Version
,
2555 string
&StoreFilename
) :
2556 Item(Owner
), LocalSource(false), Version(Version
), Sources(Sources
), Recs(Recs
),
2557 StoreFilename(StoreFilename
), Vf(Version
.FileList()),
2560 Retries
= _config
->FindI("Acquire::Retries",0);
2562 if (Version
.Arch() == 0)
2564 _error
->Error(_("I wasn't able to locate a file for the %s package. "
2565 "This might mean you need to manually fix this package. "
2566 "(due to missing arch)"),
2567 Version
.ParentPkg().FullName().c_str());
2571 /* We need to find a filename to determine the extension. We make the
2572 assumption here that all the available sources for this version share
2573 the same extension.. */
2574 // Skip not source sources, they do not have file fields.
2575 for (; Vf
.end() == false; ++Vf
)
2577 if (Vf
.File().Flagged(pkgCache::Flag::NotSource
))
2582 // Does not really matter here.. we are going to fail out below
2583 if (Vf
.end() != true)
2585 // If this fails to get a file name we will bomb out below.
2586 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2587 if (_error
->PendingError() == true)
2590 // Generate the final file name as: package_version_arch.foo
2591 StoreFilename
= QuoteString(Version
.ParentPkg().Name(),"_:") + '_' +
2592 QuoteString(Version
.VerStr(),"_:") + '_' +
2593 QuoteString(Version
.Arch(),"_:.") +
2594 "." + flExtension(Parse
.FileName());
2597 // check if we have one trusted source for the package. if so, switch
2598 // to "TrustedOnly" mode - but only if not in AllowUnauthenticated mode
2599 bool const allowUnauth
= _config
->FindB("APT::Get::AllowUnauthenticated", false);
2600 bool const debugAuth
= _config
->FindB("Debug::pkgAcquire::Auth", false);
2601 bool seenUntrusted
= false;
2602 for (pkgCache::VerFileIterator i
= Version
.FileList(); i
.end() == false; ++i
)
2604 pkgIndexFile
*Index
;
2605 if (Sources
->FindIndex(i
.File(),Index
) == false)
2608 if (debugAuth
== true)
2609 std::cerr
<< "Checking index: " << Index
->Describe()
2610 << "(Trusted=" << Index
->IsTrusted() << ")" << std::endl
;
2612 if (Index
->IsTrusted() == true)
2615 if (allowUnauth
== false)
2619 seenUntrusted
= true;
2622 // "allow-unauthenticated" restores apts old fetching behaviour
2623 // that means that e.g. unauthenticated file:// uris are higher
2624 // priority than authenticated http:// uris
2625 if (allowUnauth
== true && seenUntrusted
== true)
2629 if (QueueNext() == false && _error
->PendingError() == false)
2630 _error
->Error(_("Can't find a source to download version '%s' of '%s'"),
2631 Version
.VerStr(), Version
.ParentPkg().FullName(false).c_str());
2634 // AcqArchive::QueueNext - Queue the next file source /*{{{*/
2635 // ---------------------------------------------------------------------
2636 /* This queues the next available file version for download. It checks if
2637 the archive is already available in the cache and stashs the MD5 for
2639 bool pkgAcqArchive::QueueNext()
2641 for (; Vf
.end() == false; ++Vf
)
2643 pkgCache::PkgFileIterator
const PkgF
= Vf
.File();
2644 // Ignore not source sources
2645 if (PkgF
.Flagged(pkgCache::Flag::NotSource
))
2648 // Try to cross match against the source list
2649 pkgIndexFile
*Index
;
2650 if (Sources
->FindIndex(PkgF
, Index
) == false)
2652 LocalSource
= PkgF
.Flagged(pkgCache::Flag::LocalSource
);
2654 // only try to get a trusted package from another source if that source
2656 if(Trusted
&& !Index
->IsTrusted())
2659 // Grab the text package record
2660 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2661 if (_error
->PendingError() == true)
2664 string PkgFile
= Parse
.FileName();
2665 ExpectedHashes
= Parse
.Hashes();
2667 if (PkgFile
.empty() == true)
2668 return _error
->Error(_("The package index files are corrupted. No Filename: "
2669 "field for package %s."),
2670 Version
.ParentPkg().Name());
2672 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
2673 Desc
.Description
= Index
->ArchiveInfo(Version
);
2675 Desc
.ShortDesc
= Version
.ParentPkg().FullName(true);
2677 // See if we already have the file. (Legacy filenames)
2678 FileSize
= Version
->Size
;
2679 string FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile
);
2681 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2683 // Make sure the size matches
2684 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2689 StoreFilename
= DestFile
= FinalFile
;
2693 /* Hmm, we have a file and its size does not match, this means it is
2694 an old style mismatched arch */
2695 unlink(FinalFile
.c_str());
2698 // Check it again using the new style output filenames
2699 FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
2700 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2702 // Make sure the size matches
2703 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2708 StoreFilename
= DestFile
= FinalFile
;
2712 /* Hmm, we have a file and its size does not match, this shouldn't
2714 unlink(FinalFile
.c_str());
2717 DestFile
= _config
->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename
);
2719 // Check the destination file
2720 if (stat(DestFile
.c_str(),&Buf
) == 0)
2722 // Hmm, the partial file is too big, erase it
2723 if ((unsigned long long)Buf
.st_size
> Version
->Size
)
2724 unlink(DestFile
.c_str());
2726 PartialSize
= Buf
.st_size
;
2729 // Disables download of archives - useful if no real installation follows,
2730 // e.g. if we are just interested in proposed installation order
2731 if (_config
->FindB("Debug::pkgAcqArchive::NoQueue", false) == true)
2736 StoreFilename
= DestFile
= FinalFile
;
2750 // AcqArchive::Done - Finished fetching /*{{{*/
2751 // ---------------------------------------------------------------------
2753 void pkgAcqArchive::Done(string
const &Message
, HashStringList
const &Hashes
,
2754 pkgAcquire::MethodConfig
const * const Cfg
)
2756 Item::Done(Message
, Hashes
, Cfg
);
2758 // Grab the output filename
2759 string FileName
= LookupTag(Message
,"Filename");
2760 if (FileName
.empty() == true)
2763 ErrorText
= "Method gave a blank filename";
2767 // Reference filename
2768 if (DestFile
!= FileName
&& RealFileExists(DestFile
) == false)
2770 StoreFilename
= DestFile
= FileName
;
2776 // Done, move it into position
2777 string
const FinalFile
= GetFinalFilename();
2778 Rename(DestFile
,FinalFile
);
2779 StoreFilename
= DestFile
= FinalFile
;
2783 // AcqArchive::Failed - Failure handler /*{{{*/
2784 // ---------------------------------------------------------------------
2785 /* Here we try other sources */
2786 void pkgAcqArchive::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)
2788 Item::Failed(Message
,Cnf
);
2790 /* We don't really want to retry on failed media swaps, this prevents
2791 that. An interesting observation is that permanent failures are not
2793 if (Cnf
->Removable
== true &&
2794 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2796 // Vf = Version.FileList();
2797 while (Vf
.end() == false) ++Vf
;
2798 StoreFilename
= string();
2803 if (QueueNext() == false)
2805 // This is the retry counter
2807 Cnf
->LocalOnly
== false &&
2808 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2811 Vf
= Version
.FileList();
2812 if (QueueNext() == true)
2816 StoreFilename
= string();
2821 APT_PURE
bool pkgAcqArchive::IsTrusted() const /*{{{*/
2826 void pkgAcqArchive::Finished() /*{{{*/
2828 if (Status
== pkgAcquire::Item::StatDone
&&
2831 StoreFilename
= string();
2834 std::string
pkgAcqArchive::DescURI() const /*{{{*/
2839 std::string
pkgAcqArchive::ShortDesc() const /*{{{*/
2841 return Desc
.ShortDesc
;
2845 // AcqChangelog::pkgAcqChangelog - Constructors /*{{{*/
2846 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire
* const Owner
, pkgCache::VerIterator
const &Ver
,
2847 std::string
const &DestDir
, std::string
const &DestFilename
) :
2848 pkgAcquire::Item(Owner
), d(NULL
), SrcName(Ver
.SourcePkgName()), SrcVersion(Ver
.SourceVerStr())
2850 Desc
.URI
= URI(Ver
);
2851 Init(DestDir
, DestFilename
);
2853 // some parameters are char* here as they come likely from char* interfaces – which can also return NULL
2854 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire
* const Owner
, pkgCache::RlsFileIterator
const &RlsFile
,
2855 char const * const Component
, char const * const SrcName
, char const * const SrcVersion
,
2856 const string
&DestDir
, const string
&DestFilename
) :
2857 pkgAcquire::Item(Owner
), d(NULL
), SrcName(SrcName
), SrcVersion(SrcVersion
)
2859 Desc
.URI
= URI(RlsFile
, Component
, SrcName
, SrcVersion
);
2860 Init(DestDir
, DestFilename
);
2862 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire
* const Owner
,
2863 std::string
const &URI
, char const * const SrcName
, char const * const SrcVersion
,
2864 const string
&DestDir
, const string
&DestFilename
) :
2865 pkgAcquire::Item(Owner
), d(NULL
), SrcName(SrcName
), SrcVersion(SrcVersion
)
2868 Init(DestDir
, DestFilename
);
2870 void pkgAcqChangelog::Init(std::string
const &DestDir
, std::string
const &DestFilename
)
2872 if (Desc
.URI
.empty())
2875 // TRANSLATOR: %s=%s is sourcename=sourceversion, e.g. apt=1.1
2876 strprintf(ErrorText
, _("Changelog unavailable for %s=%s"), SrcName
.c_str(), SrcVersion
.c_str());
2877 // Let the error message print something sensible rather than "Failed to fetch /"
2878 if (DestFilename
.empty())
2879 DestFile
= SrcName
+ ".changelog";
2881 DestFile
= DestFilename
;
2882 Desc
.URI
= "changelog:/" + DestFile
;
2886 if (DestDir
.empty())
2888 std::string
const systemTemp
= GetTempDir();
2890 snprintf(tmpname
, sizeof(tmpname
), "%s/apt-changelog-XXXXXX", systemTemp
.c_str());
2891 if (NULL
== mkdtemp(tmpname
))
2893 _error
->Errno("mkdtemp", "mkdtemp failed in changelog acquire of %s %s", SrcName
.c_str(), SrcVersion
.c_str());
2897 DestFile
= TemporaryDirectory
= tmpname
;
2902 if (DestFilename
.empty())
2903 DestFile
= flCombine(DestFile
, SrcName
+ ".changelog");
2905 DestFile
= flCombine(DestFile
, DestFilename
);
2907 Desc
.ShortDesc
= "Changelog";
2908 strprintf(Desc
.Description
, "%s %s %s Changelog", URI::SiteOnly(Desc
.URI
).c_str(), SrcName
.c_str(), SrcVersion
.c_str());
2913 std::string
pkgAcqChangelog::URI(pkgCache::VerIterator
const &Ver
) /*{{{*/
2915 char const * const SrcName
= Ver
.SourcePkgName();
2916 char const * const SrcVersion
= Ver
.SourceVerStr();
2917 pkgCache::PkgFileIterator PkgFile
;
2918 // find the first source for this version which promises a changelog
2919 for (pkgCache::VerFileIterator VF
= Ver
.FileList(); VF
.end() == false; ++VF
)
2921 pkgCache::PkgFileIterator
const PF
= VF
.File();
2922 if (PF
.Flagged(pkgCache::Flag::NotSource
) || PF
->Release
== 0)
2925 pkgCache::RlsFileIterator
const RF
= PF
.ReleaseFile();
2926 std::string
const uri
= URI(RF
, PF
.Component(), SrcName
, SrcVersion
);
2933 std::string
pkgAcqChangelog::URITemplate(pkgCache::RlsFileIterator
const &Rls
)
2935 if (Rls
.end() == true || (Rls
->Label
== 0 && Rls
->Origin
== 0))
2937 std::string
const serverConfig
= "Acquire::Changelogs::URI";
2939 #define APT_EMPTY_SERVER \
2940 if (server.empty() == false) \
2942 if (server != "no") \
2946 #define APT_CHECK_SERVER(X, Y) \
2949 std::string const specialServerConfig = serverConfig + "::" + Y + #X + "::" + Rls.X(); \
2950 server = _config->Find(specialServerConfig); \
2953 // this way e.g. Debian-Security can fallback to Debian
2954 APT_CHECK_SERVER(Label
, "Override::")
2955 APT_CHECK_SERVER(Origin
, "Override::")
2957 if (RealFileExists(Rls
.FileName()))
2959 _error
->PushToStack();
2961 /* This can be costly. A caller wanting to get millions of URIs might
2962 want to do this on its own once and use Override settings.
2963 We don't do this here as Origin/Label are not as unique as they
2964 should be so this could produce request order-dependent anomalies */
2965 if (OpenMaybeClearSignedFile(Rls
.FileName(), rf
) == true)
2967 pkgTagFile
TagFile(&rf
, rf
.Size());
2968 pkgTagSection Section
;
2969 if (TagFile
.Step(Section
) == true)
2970 server
= Section
.FindS("Changelogs");
2972 _error
->RevertToStack();
2976 APT_CHECK_SERVER(Label
, "")
2977 APT_CHECK_SERVER(Origin
, "")
2978 #undef APT_CHECK_SERVER
2979 #undef APT_EMPTY_SERVER
2982 std::string
pkgAcqChangelog::URI(pkgCache::RlsFileIterator
const &Rls
,
2983 char const * const Component
, char const * const SrcName
,
2984 char const * const SrcVersion
)
2986 return URI(URITemplate(Rls
), Component
, SrcName
, SrcVersion
);
2988 std::string
pkgAcqChangelog::URI(std::string
const &Template
,
2989 char const * const Component
, char const * const SrcName
,
2990 char const * const SrcVersion
)
2992 if (Template
.find("CHANGEPATH") == std::string::npos
)
2995 // the path is: COMPONENT/SRC/SRCNAME/SRCNAME_SRCVER, e.g. main/a/apt/1.1 or contrib/liba/libapt/2.0
2996 std::string Src
= SrcName
;
2997 std::string path
= APT::String::Startswith(SrcName
, "lib") ? Src
.substr(0, 4) : Src
.substr(0,1);
2998 path
.append("/").append(Src
).append("/");
2999 path
.append(Src
).append("_").append(StripEpoch(SrcVersion
));
3000 // we omit component for releases without one (= flat-style repositories)
3001 if (Component
!= NULL
&& strlen(Component
) != 0)
3002 path
= std::string(Component
) + "/" + path
;
3004 return SubstVar(Template
, "CHANGEPATH", path
);
3007 // AcqChangelog::Failed - Failure handler /*{{{*/
3008 void pkgAcqChangelog::Failed(string
const &Message
, pkgAcquire::MethodConfig
const * const Cnf
)
3010 Item::Failed(Message
,Cnf
);
3012 std::string errText
;
3013 // TRANSLATOR: %s=%s is sourcename=sourceversion, e.g. apt=1.1
3014 strprintf(errText
, _("Changelog unavailable for %s=%s"), SrcName
.c_str(), SrcVersion
.c_str());
3016 // Error is probably something techy like 404 Not Found
3017 if (ErrorText
.empty())
3018 ErrorText
= errText
;
3020 ErrorText
= errText
+ " (" + ErrorText
+ ")";
3024 // AcqChangelog::Done - Item downloaded OK /*{{{*/
3025 void pkgAcqChangelog::Done(string
const &Message
,HashStringList
const &CalcHashes
,
3026 pkgAcquire::MethodConfig
const * const Cnf
)
3028 Item::Done(Message
,CalcHashes
,Cnf
);
3033 pkgAcqChangelog::~pkgAcqChangelog() /*{{{*/
3035 if (TemporaryDirectory
.empty() == false)
3037 unlink(DestFile
.c_str());
3038 rmdir(TemporaryDirectory
.c_str());
3043 // AcqFile::pkgAcqFile - Constructor /*{{{*/
3044 pkgAcqFile::pkgAcqFile(pkgAcquire
* const Owner
,string
const &URI
, HashStringList
const &Hashes
,
3045 unsigned long long const Size
,string
const &Dsc
,string
const &ShortDesc
,
3046 const string
&DestDir
, const string
&DestFilename
,
3047 bool const IsIndexFile
) :
3048 Item(Owner
), IsIndexFile(IsIndexFile
), ExpectedHashes(Hashes
)
3050 Retries
= _config
->FindI("Acquire::Retries",0);
3052 if(!DestFilename
.empty())
3053 DestFile
= DestFilename
;
3054 else if(!DestDir
.empty())
3055 DestFile
= DestDir
+ "/" + flNotDir(URI
);
3057 DestFile
= flNotDir(URI
);
3061 Desc
.Description
= Dsc
;
3064 // Set the short description to the archive component
3065 Desc
.ShortDesc
= ShortDesc
;
3067 // Get the transfer sizes
3070 if (stat(DestFile
.c_str(),&Buf
) == 0)
3072 // Hmm, the partial file is too big, erase it
3073 if ((Size
> 0) && (unsigned long long)Buf
.st_size
> Size
)
3074 unlink(DestFile
.c_str());
3076 PartialSize
= Buf
.st_size
;
3082 // AcqFile::Done - Item downloaded OK /*{{{*/
3083 void pkgAcqFile::Done(string
const &Message
,HashStringList
const &CalcHashes
,
3084 pkgAcquire::MethodConfig
const * const Cnf
)
3086 Item::Done(Message
,CalcHashes
,Cnf
);
3088 string FileName
= LookupTag(Message
,"Filename");
3089 if (FileName
.empty() == true)
3092 ErrorText
= "Method gave a blank filename";
3098 // The files timestamp matches
3099 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
3102 // We have to copy it into place
3103 if (RealFileExists(DestFile
.c_str()) == false)
3106 if (_config
->FindB("Acquire::Source-Symlinks",true) == false ||
3107 Cnf
->Removable
== true)
3109 Desc
.URI
= "copy:" + FileName
;
3114 // Erase the file if it is a symlink so we can overwrite it
3116 if (lstat(DestFile
.c_str(),&St
) == 0)
3118 if (S_ISLNK(St
.st_mode
) != 0)
3119 unlink(DestFile
.c_str());
3123 if (symlink(FileName
.c_str(),DestFile
.c_str()) != 0)
3125 _error
->PushToStack();
3126 _error
->Errno("pkgAcqFile::Done", "Symlinking file %s failed", DestFile
.c_str());
3127 std::stringstream msg
;
3128 _error
->DumpErrors(msg
);
3129 _error
->RevertToStack();
3130 ErrorText
= msg
.str();
3137 // AcqFile::Failed - Failure handler /*{{{*/
3138 // ---------------------------------------------------------------------
3139 /* Here we try other sources */
3140 void pkgAcqFile::Failed(string
const &Message
, pkgAcquire::MethodConfig
const * const Cnf
)
3142 Item::Failed(Message
,Cnf
);
3144 // This is the retry counter
3146 Cnf
->LocalOnly
== false &&
3147 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
3157 string
pkgAcqFile::Custom600Headers() const /*{{{*/
3160 return "\nIndex-File: true";