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 UsedMirror
= LookupTag(Message
,"UsedMirror");
525 unsigned long long const downloadedSize
= Hashes
.FileSize();
526 if (downloadedSize
!= 0)
528 FileSize
= downloadedSize
;
532 ErrorText
= string();
533 Owner
->Dequeue(this);
536 // Acquire::Item::Rename - Rename a file /*{{{*/
537 // ---------------------------------------------------------------------
538 /* This helper function is used by a lot of item methods as their final
540 bool pkgAcquire::Item::Rename(string
const &From
,string
const &To
)
542 if (From
== To
|| rename(From
.c_str(),To
.c_str()) == 0)
546 strprintf(S
, _("rename failed, %s (%s -> %s)."), strerror(errno
),
547 From
.c_str(),To
.c_str());
549 if (ErrorText
.empty())
552 ErrorText
= ErrorText
+ ": " + S
;
556 void pkgAcquire::Item::Dequeue() /*{{{*/
558 Owner
->Dequeue(this);
561 bool pkgAcquire::Item::RenameOnError(pkgAcquire::Item::RenameOnErrorState
const error
)/*{{{*/
563 if (RealFileExists(DestFile
))
564 Rename(DestFile
, DestFile
+ ".FAILED");
569 case HashSumMismatch
:
570 errtext
= _("Hash Sum mismatch");
571 Status
= StatAuthError
;
572 ReportMirrorFailure("HashChecksumFailure");
575 errtext
= _("Size mismatch");
576 Status
= StatAuthError
;
577 ReportMirrorFailure("SizeFailure");
580 errtext
= _("Invalid file format");
582 // do not report as usually its not the mirrors fault, but Portal/Proxy
585 errtext
= _("Signature error");
589 errtext
= _("Does not start with a cleartext signature");
592 case MaximumSizeExceeded
:
593 // the method is expected to report a good error for this
597 // no handling here, done by callers
600 if (ErrorText
.empty())
605 void pkgAcquire::Item::SetActiveSubprocess(const std::string
&subprocess
)/*{{{*/
607 ActiveSubprocess
= subprocess
;
608 APT_IGNORE_DEPRECATED(Mode
= ActiveSubprocess
.c_str();)
611 // Acquire::Item::ReportMirrorFailure /*{{{*/
612 void pkgAcquire::Item::ReportMirrorFailure(string
const &FailCode
)
614 // we only act if a mirror was used at all
615 if(UsedMirror
.empty())
618 std::cerr
<< "\nReportMirrorFailure: "
620 << " Uri: " << DescURI()
622 << FailCode
<< std::endl
;
624 string report
= _config
->Find("Methods::Mirror::ProblemReporting",
625 "/usr/lib/apt/apt-report-mirror-failure");
626 if(!FileExists(report
))
629 std::vector
<char const*> Args
;
630 Args
.push_back(report
.c_str());
631 Args
.push_back(UsedMirror
.c_str());
632 Args
.push_back(DescURI().c_str());
633 Args
.push_back(FailCode
.c_str());
634 Args
.push_back(NULL
);
636 pid_t pid
= ExecFork();
639 _error
->Error("ReportMirrorFailure Fork failed");
644 execvp(Args
[0], (char**)Args
.data());
645 std::cerr
<< "Could not exec " << Args
[0] << std::endl
;
648 if(!ExecWait(pid
, "report-mirror-failure"))
650 _error
->Warning("Couldn't report problem to '%s'",
651 _config
->Find("Methods::Mirror::ProblemReporting").c_str());
655 std::string
pkgAcquire::Item::HashSum() const /*{{{*/
657 HashStringList
const hashes
= GetExpectedHashes();
658 HashString
const * const hs
= hashes
.find(NULL
);
659 return hs
!= NULL
? hs
->toStr() : "";
663 pkgAcqTransactionItem::pkgAcqTransactionItem(pkgAcquire
* const Owner
, /*{{{*/
664 pkgAcqMetaBase
* const TransactionManager
, IndexTarget
const Target
) :
665 pkgAcquire::Item(Owner
), Target(Target
), TransactionManager(TransactionManager
)
667 if (TransactionManager
!= this)
668 TransactionManager
->Add(this);
671 pkgAcqTransactionItem::~pkgAcqTransactionItem() /*{{{*/
675 HashStringList
pkgAcqTransactionItem::GetExpectedHashesFor(std::string
const MetaKey
) const /*{{{*/
677 return GetExpectedHashesFromFor(TransactionManager
->MetaIndexParser
, MetaKey
);
681 // AcqMetaBase - Constructor /*{{{*/
682 pkgAcqMetaBase::pkgAcqMetaBase(pkgAcquire
* const Owner
,
683 pkgAcqMetaBase
* const TransactionManager
,
684 std::vector
<IndexTarget
> const IndexTargets
,
685 IndexTarget
const &DataTarget
,
686 indexRecords
* const MetaIndexParser
)
687 : pkgAcqTransactionItem(Owner
, TransactionManager
, DataTarget
),
688 MetaIndexParser(MetaIndexParser
), LastMetaIndexParser(NULL
), IndexTargets(IndexTargets
),
689 AuthPass(false), IMSHit(false)
693 // AcqMetaBase::Add - Add a item to the current Transaction /*{{{*/
694 void pkgAcqMetaBase::Add(pkgAcqTransactionItem
* const I
)
696 Transaction
.push_back(I
);
699 // AcqMetaBase::AbortTransaction - Abort the current Transaction /*{{{*/
700 void pkgAcqMetaBase::AbortTransaction()
702 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
703 std::clog
<< "AbortTransaction: " << TransactionManager
<< std::endl
;
705 // ensure the toplevel is in error state too
706 for (std::vector
<pkgAcqTransactionItem
*>::iterator I
= Transaction
.begin();
707 I
!= Transaction
.end(); ++I
)
709 (*I
)->TransactionState(TransactionAbort
);
714 // AcqMetaBase::TransactionHasError - Check for errors in Transaction /*{{{*/
715 APT_PURE
bool pkgAcqMetaBase::TransactionHasError() const
717 for (std::vector
<pkgAcqTransactionItem
*>::const_iterator I
= Transaction
.begin();
718 I
!= Transaction
.end(); ++I
)
720 switch((*I
)->Status
) {
721 case StatDone
: break;
722 case StatIdle
: break;
723 case StatAuthError
: return true;
724 case StatError
: return true;
725 case StatTransientNetworkError
: return true;
726 case StatFetching
: break;
732 // AcqMetaBase::CommitTransaction - Commit a transaction /*{{{*/
733 void pkgAcqMetaBase::CommitTransaction()
735 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
736 std::clog
<< "CommitTransaction: " << this << std::endl
;
738 // move new files into place *and* remove files that are not
739 // part of the transaction but are still on disk
740 for (std::vector
<pkgAcqTransactionItem
*>::iterator I
= Transaction
.begin();
741 I
!= Transaction
.end(); ++I
)
743 (*I
)->TransactionState(TransactionCommit
);
748 // AcqMetaBase::TransactionStageCopy - Stage a file for copying /*{{{*/
749 void pkgAcqMetaBase::TransactionStageCopy(pkgAcqTransactionItem
* const I
,
750 const std::string
&From
,
751 const std::string
&To
)
753 I
->PartialFile
= From
;
757 // AcqMetaBase::TransactionStageRemoval - Stage a file for removal /*{{{*/
758 void pkgAcqMetaBase::TransactionStageRemoval(pkgAcqTransactionItem
* const I
,
759 const std::string
&FinalFile
)
762 I
->DestFile
= FinalFile
;
765 // AcqMetaBase::GenerateAuthWarning - Check gpg authentication error /*{{{*/
766 bool pkgAcqMetaBase::CheckStopAuthentication(pkgAcquire::Item
* const I
, const std::string
&Message
)
768 // FIXME: this entire function can do now that we disallow going to
769 // a unauthenticated state and can cleanly rollback
771 string
const Final
= I
->GetFinalFilename();
772 if(FileExists(Final
))
774 I
->Status
= StatTransientNetworkError
;
775 _error
->Warning(_("An error occurred during the signature "
776 "verification. The repository is not updated "
777 "and the previous index files will be used. "
778 "GPG error: %s: %s\n"),
779 Desc
.Description
.c_str(),
780 LookupTag(Message
,"Message").c_str());
781 RunScripts("APT::Update::Auth-Failure");
783 } else if (LookupTag(Message
,"Message").find("NODATA") != string::npos
) {
784 /* Invalid signature file, reject (LP: #346386) (Closes: #627642) */
785 _error
->Error(_("GPG error: %s: %s"),
786 Desc
.Description
.c_str(),
787 LookupTag(Message
,"Message").c_str());
788 I
->Status
= StatError
;
791 _error
->Warning(_("GPG error: %s: %s"),
792 Desc
.Description
.c_str(),
793 LookupTag(Message
,"Message").c_str());
795 // gpgv method failed
796 ReportMirrorFailure("GPGFailure");
800 // AcqMetaBase::Custom600Headers - Get header for AcqMetaBase /*{{{*/
801 // ---------------------------------------------------------------------
802 string
pkgAcqMetaBase::Custom600Headers() const
804 std::string Header
= "\nIndex-File: true";
805 std::string MaximumSize
;
806 strprintf(MaximumSize
, "\nMaximum-Size: %i",
807 _config
->FindI("Acquire::MaxReleaseFileSize", 10*1000*1000));
808 Header
+= MaximumSize
;
810 string
const FinalFile
= GetFinalFilename();
813 if (stat(FinalFile
.c_str(),&Buf
) == 0)
814 Header
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
819 // AcqMetaBase::QueueForSignatureVerify /*{{{*/
820 void pkgAcqMetaBase::QueueForSignatureVerify(pkgAcqTransactionItem
* const I
, std::string
const &File
, std::string
const &Signature
)
823 I
->Desc
.URI
= "gpgv:" + Signature
;
826 I
->SetActiveSubprocess("gpgv");
829 // AcqMetaBase::CheckDownloadDone /*{{{*/
830 bool pkgAcqMetaBase::CheckDownloadDone(pkgAcqTransactionItem
* const I
, const std::string
&Message
, HashStringList
const &Hashes
) const
832 // We have just finished downloading a Release file (it is not
835 string
const FileName
= LookupTag(Message
,"Filename");
836 if (FileName
.empty() == true)
838 I
->Status
= StatError
;
839 I
->ErrorText
= "Method gave a blank filename";
843 if (FileName
!= I
->DestFile
&& RealFileExists(I
->DestFile
) == false)
846 I
->Desc
.URI
= "copy:" + FileName
;
847 I
->QueueURI(I
->Desc
);
851 // make sure to verify against the right file on I-M-S hit
852 bool IMSHit
= StringToBool(LookupTag(Message
,"IMS-Hit"), false);
853 if (IMSHit
== false && Hashes
.usable())
855 // detect IMS-Hits servers haven't detected by Hash comparison
856 std::string
const FinalFile
= I
->GetFinalFilename();
857 if (RealFileExists(FinalFile
) && Hashes
.VerifyFile(FinalFile
) == true)
860 unlink(I
->DestFile
.c_str());
866 // for simplicity, the transaction manager is always InRelease
867 // even if it doesn't exist.
868 if (TransactionManager
!= NULL
)
869 TransactionManager
->IMSHit
= true;
870 I
->PartialFile
= I
->DestFile
= I
->GetFinalFilename();
873 // set Item to complete as the remaining work is all local (verify etc)
879 bool pkgAcqMetaBase::CheckAuthDone(string
const &Message
) /*{{{*/
881 // At this point, the gpgv method has succeeded, so there is a
882 // valid signature from a key in the trusted keyring. We
883 // perform additional verification of its contents, and use them
884 // to verify the indexes we are about to download
886 if (TransactionManager
->IMSHit
== false)
888 // open the last (In)Release if we have it
889 std::string
const FinalFile
= GetFinalFilename();
890 std::string FinalRelease
;
891 std::string FinalInRelease
;
892 if (APT::String::Endswith(FinalFile
, "InRelease"))
894 FinalInRelease
= FinalFile
;
895 FinalRelease
= FinalFile
.substr(0, FinalFile
.length() - strlen("InRelease")) + "Release";
899 FinalInRelease
= FinalFile
.substr(0, FinalFile
.length() - strlen("Release")) + "InRelease";
900 FinalRelease
= FinalFile
;
902 if (RealFileExists(FinalInRelease
) || RealFileExists(FinalRelease
))
904 TransactionManager
->LastMetaIndexParser
= new indexRecords
;
905 _error
->PushToStack();
906 if (RealFileExists(FinalInRelease
))
907 TransactionManager
->LastMetaIndexParser
->Load(FinalInRelease
);
909 TransactionManager
->LastMetaIndexParser
->Load(FinalRelease
);
910 // its unlikely to happen, but if what we have is bad ignore it
911 if (_error
->PendingError())
913 delete TransactionManager
->LastMetaIndexParser
;
914 TransactionManager
->LastMetaIndexParser
= NULL
;
916 _error
->RevertToStack();
920 if (TransactionManager
->MetaIndexParser
->Load(DestFile
) == false)
922 Status
= StatAuthError
;
923 ErrorText
= TransactionManager
->MetaIndexParser
->ErrorText
;
927 if (!VerifyVendor(Message
))
929 Status
= StatAuthError
;
933 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
934 std::cerr
<< "Signature verification succeeded: "
935 << DestFile
<< std::endl
;
937 // Download further indexes with verification
943 void pkgAcqMetaBase::QueueIndexes(bool const verify
) /*{{{*/
945 // at this point the real Items are loaded in the fetcher
946 ExpectedAdditionalItems
= 0;
948 for (std::vector
<IndexTarget
>::const_iterator Target
= IndexTargets
.begin();
949 Target
!= IndexTargets
.end();
952 bool trypdiff
= _config
->FindB("Acquire::PDiffs", true);
955 if (TransactionManager
->MetaIndexParser
->Exists(Target
->MetaKey
) == false)
957 // optional targets that we do not have in the Release file are skipped
958 if (Target
->IsOptional
)
961 Status
= StatAuthError
;
962 strprintf(ErrorText
, _("Unable to find expected entry '%s' in Release file (Wrong sources.list entry or malformed file)"), Target
->MetaKey
.c_str());
966 if (RealFileExists(GetFinalFileNameFromURI(Target
->URI
)))
968 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
970 HashStringList
const newFile
= GetExpectedHashesFromFor(TransactionManager
->MetaIndexParser
, Target
->MetaKey
);
971 HashStringList
const oldFile
= GetExpectedHashesFromFor(TransactionManager
->LastMetaIndexParser
, Target
->MetaKey
);
972 if (newFile
== oldFile
)
974 // we have the file already, no point in trying to acquire it again
975 new NoActionItem(Owner
, *Target
);
981 trypdiff
= false; // no file to patch
983 // check if we have patches available
984 trypdiff
&= TransactionManager
->MetaIndexParser
->Exists(Target
->MetaKey
+ ".diff/Index");
986 // if we have no file to patch, no point in trying
987 trypdiff
&= RealFileExists(GetFinalFileNameFromURI(Target
->URI
));
989 // no point in patching from local sources
992 std::string
const proto
= Target
->URI
.substr(0, strlen("file:/"));
993 if (proto
== "file:/" || proto
== "copy:/" || proto
== "cdrom:")
997 // Queue the Index file (Packages, Sources, Translation-$foo, …)
999 new pkgAcqDiffIndex(Owner
, TransactionManager
, *Target
);
1001 new pkgAcqIndex(Owner
, TransactionManager
, *Target
);
1005 bool pkgAcqMetaBase::VerifyVendor(string
const &Message
) /*{{{*/
1007 string::size_type pos
;
1009 // check for missing sigs (that where not fatal because otherwise we had
1012 string msg
= _("There is no public key available for the "
1013 "following key IDs:\n");
1014 pos
= Message
.find("NO_PUBKEY ");
1015 if (pos
!= std::string::npos
)
1017 string::size_type start
= pos
+strlen("NO_PUBKEY ");
1018 string Fingerprint
= Message
.substr(start
, Message
.find("\n")-start
);
1019 missingkeys
+= (Fingerprint
);
1021 if(!missingkeys
.empty())
1022 _error
->Warning("%s", (msg
+ missingkeys
).c_str());
1024 string Transformed
= TransactionManager
->MetaIndexParser
->GetExpectedDist();
1026 if (Transformed
== "../project/experimental")
1028 Transformed
= "experimental";
1031 pos
= Transformed
.rfind('/');
1032 if (pos
!= string::npos
)
1034 Transformed
= Transformed
.substr(0, pos
);
1037 if (Transformed
== ".")
1042 if (_config
->FindB("Acquire::Check-Valid-Until", true) == true &&
1043 TransactionManager
->MetaIndexParser
->GetValidUntil() > 0) {
1044 time_t const invalid_since
= time(NULL
) - TransactionManager
->MetaIndexParser
->GetValidUntil();
1045 if (invalid_since
> 0)
1049 // TRANSLATOR: The first %s is the URL of the bad Release file, the second is
1050 // the time since then the file is invalid - formated in the same way as in
1051 // the download progress display (e.g. 7d 3h 42min 1s)
1052 _("Release file for %s is expired (invalid since %s). "
1053 "Updates for this repository will not be applied."),
1054 Target
.URI
.c_str(), TimeToStr(invalid_since
).c_str());
1055 if (ErrorText
.empty())
1057 return _error
->Error("%s", errmsg
.c_str());
1061 /* Did we get a file older than what we have? This is a last minute IMS hit and doubles
1062 as a prevention of downgrading us to older (still valid) files */
1063 if (TransactionManager
->IMSHit
== false && TransactionManager
->LastMetaIndexParser
!= NULL
&&
1064 TransactionManager
->LastMetaIndexParser
->GetDate() > TransactionManager
->MetaIndexParser
->GetDate())
1066 TransactionManager
->IMSHit
= true;
1067 unlink(DestFile
.c_str());
1068 PartialFile
= DestFile
= GetFinalFilename();
1069 delete TransactionManager
->MetaIndexParser
;
1070 TransactionManager
->MetaIndexParser
= TransactionManager
->LastMetaIndexParser
;
1071 TransactionManager
->LastMetaIndexParser
= NULL
;
1074 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1076 std::cerr
<< "Got Codename: " << TransactionManager
->MetaIndexParser
->GetDist() << std::endl
;
1077 std::cerr
<< "Expecting Dist: " << TransactionManager
->MetaIndexParser
->GetExpectedDist() << std::endl
;
1078 std::cerr
<< "Transformed Dist: " << Transformed
<< std::endl
;
1081 if (TransactionManager
->MetaIndexParser
->CheckDist(Transformed
) == false)
1083 // This might become fatal one day
1084 // Status = StatAuthError;
1085 // ErrorText = "Conflicting distribution; expected "
1086 // + MetaIndexParser->GetExpectedDist() + " but got "
1087 // + MetaIndexParser->GetDist();
1089 if (!Transformed
.empty())
1091 _error
->Warning(_("Conflicting distribution: %s (expected %s but got %s)"),
1092 Desc
.Description
.c_str(),
1093 Transformed
.c_str(),
1094 TransactionManager
->MetaIndexParser
->GetDist().c_str());
1102 pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire
* const Owner
, /*{{{*/
1103 IndexTarget
const &ClearsignedTarget
,
1104 IndexTarget
const &DetachedDataTarget
, IndexTarget
const &DetachedSigTarget
,
1105 std::vector
<IndexTarget
> const IndexTargets
,
1106 indexRecords
* const MetaIndexParser
) :
1107 pkgAcqMetaIndex(Owner
, this, ClearsignedTarget
, DetachedSigTarget
, IndexTargets
, MetaIndexParser
),
1108 ClearsignedTarget(ClearsignedTarget
),
1109 DetachedDataTarget(DetachedDataTarget
), DetachedSigTarget(DetachedSigTarget
)
1111 // index targets + (worst case:) Release/Release.gpg
1112 ExpectedAdditionalItems
= IndexTargets
.size() + 2;
1113 TransactionManager
->Add(this);
1116 pkgAcqMetaClearSig::~pkgAcqMetaClearSig() /*{{{*/
1120 // pkgAcqMetaClearSig::Custom600Headers - Insert custom request headers /*{{{*/
1121 string
pkgAcqMetaClearSig::Custom600Headers() const
1123 string Header
= pkgAcqMetaBase::Custom600Headers();
1124 Header
+= "\nFail-Ignore: true";
1128 // pkgAcqMetaClearSig::Done - We got a file /*{{{*/
1129 void pkgAcqMetaClearSig::Done(std::string
const &Message
,
1130 HashStringList
const &Hashes
,
1131 pkgAcquire::MethodConfig
const * const Cnf
)
1133 Item::Done(Message
, Hashes
, Cnf
);
1135 // if we expect a ClearTextSignature (InRelease), ensure that
1136 // this is what we get and if not fail to queue a
1137 // Release/Release.gpg, see #346386
1138 if (FileExists(DestFile
) && !StartsWithGPGClearTextSignature(DestFile
))
1140 pkgAcquire::Item::Failed(Message
, Cnf
);
1141 RenameOnError(NotClearsigned
);
1142 TransactionManager
->AbortTransaction();
1146 if(AuthPass
== false)
1148 if(CheckDownloadDone(this, Message
, Hashes
) == true)
1149 QueueForSignatureVerify(this, DestFile
, DestFile
);
1152 else if(CheckAuthDone(Message
) == true)
1154 if (TransactionManager
->IMSHit
== false)
1155 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
1156 else if (RealFileExists(GetFinalFilename()) == false)
1158 // We got an InRelease file IMSHit, but we haven't one, which means
1159 // we had a valid Release/Release.gpg combo stepping in, which we have
1160 // to 'acquire' now to ensure list cleanup isn't removing them
1161 new NoActionItem(Owner
, DetachedDataTarget
);
1162 new NoActionItem(Owner
, DetachedSigTarget
);
1167 void pkgAcqMetaClearSig::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
) /*{{{*/
1169 Item::Failed(Message
, Cnf
);
1171 // we failed, we will not get additional items from this method
1172 ExpectedAdditionalItems
= 0;
1174 if (AuthPass
== false)
1176 // Queue the 'old' InRelease file for removal if we try Release.gpg
1177 // as otherwise the file will stay around and gives a false-auth
1178 // impression (CVE-2012-0214)
1179 TransactionManager
->TransactionStageRemoval(this, GetFinalFilename());
1182 new pkgAcqMetaIndex(Owner
, TransactionManager
, DetachedDataTarget
, DetachedSigTarget
, IndexTargets
, TransactionManager
->MetaIndexParser
);
1186 if(CheckStopAuthentication(this, Message
))
1189 _error
->Warning(_("The data from '%s' is not signed. Packages "
1190 "from that repository can not be authenticated."),
1191 ClearsignedTarget
.Description
.c_str());
1193 // No Release file was present, or verification failed, so fall
1194 // back to queueing Packages files without verification
1195 // only allow going further if the users explicitely wants it
1196 if(AllowInsecureRepositories(TransactionManager
->MetaIndexParser
, TransactionManager
, this) == true)
1200 /* InRelease files become Release files, otherwise
1201 * they would be considered as trusted later on */
1202 string
const FinalRelease
= GetFinalFileNameFromURI(DetachedDataTarget
.URI
);
1203 string
const PartialRelease
= GetPartialFileNameFromURI(DetachedDataTarget
.URI
);
1204 string
const FinalReleasegpg
= GetFinalFileNameFromURI(DetachedSigTarget
.URI
);
1205 string
const FinalInRelease
= GetFinalFilename();
1206 Rename(DestFile
, PartialRelease
);
1207 TransactionManager
->TransactionStageCopy(this, PartialRelease
, FinalRelease
);
1209 if (RealFileExists(FinalReleasegpg
) || RealFileExists(FinalInRelease
))
1211 // open the last Release if we have it
1212 if (TransactionManager
->IMSHit
== false)
1214 TransactionManager
->LastMetaIndexParser
= new indexRecords
;
1215 _error
->PushToStack();
1216 if (RealFileExists(FinalInRelease
))
1217 TransactionManager
->LastMetaIndexParser
->Load(FinalInRelease
);
1219 TransactionManager
->LastMetaIndexParser
->Load(FinalRelease
);
1220 // its unlikely to happen, but if what we have is bad ignore it
1221 if (_error
->PendingError())
1223 delete TransactionManager
->LastMetaIndexParser
;
1224 TransactionManager
->LastMetaIndexParser
= NULL
;
1226 _error
->RevertToStack();
1230 // we parse the indexes here because at this point the user wanted
1231 // a repository that may potentially harm him
1232 if (TransactionManager
->MetaIndexParser
->Load(PartialRelease
) == false || VerifyVendor(Message
) == false)
1233 /* expired Release files are still a problem you need extra force for */;
1241 pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire
* const Owner
, /*{{{*/
1242 pkgAcqMetaBase
* const TransactionManager
,
1243 IndexTarget
const &DataTarget
,
1244 IndexTarget
const &DetachedSigTarget
,
1245 vector
<IndexTarget
> const IndexTargets
,
1246 indexRecords
* const MetaIndexParser
) :
1247 pkgAcqMetaBase(Owner
, TransactionManager
, IndexTargets
, DataTarget
, MetaIndexParser
),
1248 DetachedSigTarget(DetachedSigTarget
)
1250 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1251 std::clog
<< "New pkgAcqMetaIndex with TransactionManager "
1252 << this->TransactionManager
<< std::endl
;
1254 DestFile
= GetPartialFileNameFromURI(DataTarget
.URI
);
1257 Desc
.Description
= DataTarget
.Description
;
1259 Desc
.ShortDesc
= DataTarget
.ShortDesc
;
1260 Desc
.URI
= DataTarget
.URI
;
1262 // we expect more item
1263 ExpectedAdditionalItems
= IndexTargets
.size();
1267 void pkgAcqMetaIndex::Done(string
const &Message
, /*{{{*/
1268 HashStringList
const &Hashes
,
1269 pkgAcquire::MethodConfig
const * const Cfg
)
1271 Item::Done(Message
,Hashes
,Cfg
);
1273 if(CheckDownloadDone(this, Message
, Hashes
))
1275 // we have a Release file, now download the Signature, all further
1276 // verify/queue for additional downloads will be done in the
1277 // pkgAcqMetaSig::Done() code
1278 new pkgAcqMetaSig(Owner
, TransactionManager
, DetachedSigTarget
, this);
1282 // pkgAcqMetaIndex::Failed - no Release file present /*{{{*/
1283 void pkgAcqMetaIndex::Failed(string
const &Message
,
1284 pkgAcquire::MethodConfig
const * const Cnf
)
1286 pkgAcquire::Item::Failed(Message
, Cnf
);
1289 _error
->Warning(_("The repository '%s' does not have a Release file. "
1290 "This is deprecated, please contact the owner of the "
1291 "repository."), Target
.Description
.c_str());
1293 // No Release file was present so fall
1294 // back to queueing Packages files without verification
1295 // only allow going further if the users explicitely wants it
1296 if(AllowInsecureRepositories(TransactionManager
->MetaIndexParser
, TransactionManager
, this) == true)
1298 // ensure old Release files are removed
1299 TransactionManager
->TransactionStageRemoval(this, GetFinalFilename());
1300 delete TransactionManager
->MetaIndexParser
;
1301 TransactionManager
->MetaIndexParser
= NULL
;
1303 // queue without any kind of hashsum support
1304 QueueIndexes(false);
1308 void pkgAcqMetaIndex::Finished() /*{{{*/
1310 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1311 std::clog
<< "Finished: " << DestFile
<<std::endl
;
1312 if(TransactionManager
!= NULL
&&
1313 TransactionManager
->TransactionHasError() == false)
1314 TransactionManager
->CommitTransaction();
1317 std::string
pkgAcqMetaIndex::DescURI() const /*{{{*/
1323 // AcqMetaSig::AcqMetaSig - Constructor /*{{{*/
1324 pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire
* const Owner
,
1325 pkgAcqMetaBase
* const TransactionManager
,
1326 IndexTarget
const Target
,
1327 pkgAcqMetaIndex
* const MetaIndex
) :
1328 pkgAcqTransactionItem(Owner
, TransactionManager
, Target
), MetaIndex(MetaIndex
)
1330 DestFile
= GetPartialFileNameFromURI(Target
.URI
);
1332 // remove any partial downloaded sig-file in partial/.
1333 // it may confuse proxies and is too small to warrant a
1334 // partial download anyway
1335 unlink(DestFile
.c_str());
1337 // set the TransactionManager
1338 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1339 std::clog
<< "New pkgAcqMetaSig with TransactionManager "
1340 << TransactionManager
<< std::endl
;
1343 Desc
.Description
= Target
.Description
;
1345 Desc
.ShortDesc
= Target
.ShortDesc
;
1346 Desc
.URI
= Target
.URI
;
1348 // If we got a hit for Release, we will get one for Release.gpg too (or obscure errors),
1349 // so we skip the download step and go instantly to verification
1350 if (TransactionManager
->IMSHit
== true && RealFileExists(GetFinalFilename()))
1354 PartialFile
= DestFile
= GetFinalFilename();
1355 MetaIndexFileSignature
= DestFile
;
1356 MetaIndex
->QueueForSignatureVerify(this, MetaIndex
->DestFile
, DestFile
);
1362 pkgAcqMetaSig::~pkgAcqMetaSig() /*{{{*/
1366 // AcqMetaSig::Done - The signature was downloaded/verified /*{{{*/
1367 void pkgAcqMetaSig::Done(string
const &Message
, HashStringList
const &Hashes
,
1368 pkgAcquire::MethodConfig
const * const Cfg
)
1370 if (MetaIndexFileSignature
.empty() == false)
1372 DestFile
= MetaIndexFileSignature
;
1373 MetaIndexFileSignature
.clear();
1375 Item::Done(Message
, Hashes
, Cfg
);
1377 if(MetaIndex
->AuthPass
== false)
1379 if(MetaIndex
->CheckDownloadDone(this, Message
, Hashes
) == true)
1381 // destfile will be modified to point to MetaIndexFile for the
1382 // gpgv method, so we need to save it here
1383 MetaIndexFileSignature
= DestFile
;
1384 MetaIndex
->QueueForSignatureVerify(this, MetaIndex
->DestFile
, DestFile
);
1388 else if(MetaIndex
->CheckAuthDone(Message
) == true)
1390 if (TransactionManager
->IMSHit
== false)
1392 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
1393 TransactionManager
->TransactionStageCopy(MetaIndex
, MetaIndex
->DestFile
, MetaIndex
->GetFinalFilename());
1398 void pkgAcqMetaSig::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
1400 Item::Failed(Message
,Cnf
);
1402 // check if we need to fail at this point
1403 if (MetaIndex
->AuthPass
== true && MetaIndex
->CheckStopAuthentication(this, Message
))
1406 string
const FinalRelease
= MetaIndex
->GetFinalFilename();
1407 string
const FinalReleasegpg
= GetFinalFilename();
1408 string
const FinalInRelease
= TransactionManager
->GetFinalFilename();
1410 if (RealFileExists(FinalReleasegpg
) || RealFileExists(FinalInRelease
))
1412 std::string downgrade_msg
;
1413 strprintf(downgrade_msg
, _("The repository '%s' is no longer signed."),
1414 MetaIndex
->Target
.Description
.c_str());
1415 if(_config
->FindB("Acquire::AllowDowngradeToInsecureRepositories"))
1417 // meh, the users wants to take risks (we still mark the packages
1418 // from this repository as unauthenticated)
1419 _error
->Warning("%s", downgrade_msg
.c_str());
1420 _error
->Warning(_("This is normally not allowed, but the option "
1421 "Acquire::AllowDowngradeToInsecureRepositories was "
1422 "given to override it."));
1425 _error
->Error("%s", downgrade_msg
.c_str());
1426 if (TransactionManager
->IMSHit
== false)
1427 Rename(MetaIndex
->DestFile
, MetaIndex
->DestFile
+ ".FAILED");
1428 Item::Failed("Message: " + downgrade_msg
, Cnf
);
1429 TransactionManager
->AbortTransaction();
1434 _error
->Warning(_("The data from '%s' is not signed. Packages "
1435 "from that repository can not be authenticated."),
1436 MetaIndex
->Target
.Description
.c_str());
1438 // ensures that a Release.gpg file in the lists/ is removed by the transaction
1439 TransactionManager
->TransactionStageRemoval(this, DestFile
);
1441 // only allow going further if the users explicitely wants it
1442 if(AllowInsecureRepositories(TransactionManager
->MetaIndexParser
, TransactionManager
, this) == true)
1444 if (RealFileExists(FinalReleasegpg
) || RealFileExists(FinalInRelease
))
1446 // open the last Release if we have it
1447 if (TransactionManager
->IMSHit
== false)
1449 TransactionManager
->LastMetaIndexParser
= new indexRecords
;
1450 _error
->PushToStack();
1451 if (RealFileExists(FinalInRelease
))
1452 TransactionManager
->LastMetaIndexParser
->Load(FinalInRelease
);
1454 TransactionManager
->LastMetaIndexParser
->Load(FinalRelease
);
1455 // its unlikely to happen, but if what we have is bad ignore it
1456 if (_error
->PendingError())
1458 delete TransactionManager
->LastMetaIndexParser
;
1459 TransactionManager
->LastMetaIndexParser
= NULL
;
1461 _error
->RevertToStack();
1465 // we parse the indexes here because at this point the user wanted
1466 // a repository that may potentially harm him
1467 if (TransactionManager
->MetaIndexParser
->Load(MetaIndex
->DestFile
) == false || MetaIndex
->VerifyVendor(Message
) == false)
1468 /* expired Release files are still a problem you need extra force for */;
1470 MetaIndex
->QueueIndexes(true);
1472 TransactionManager
->TransactionStageCopy(MetaIndex
, MetaIndex
->DestFile
, MetaIndex
->GetFinalFilename());
1475 // FIXME: this is used often (e.g. in pkgAcqIndexTrans) so refactor
1476 if (Cnf
->LocalOnly
== true ||
1477 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1486 // AcqBaseIndex - Constructor /*{{{*/
1487 pkgAcqBaseIndex::pkgAcqBaseIndex(pkgAcquire
* const Owner
,
1488 pkgAcqMetaBase
* const TransactionManager
,
1489 IndexTarget
const Target
)
1490 : pkgAcqTransactionItem(Owner
, TransactionManager
, Target
)
1495 // AcqDiffIndex::AcqDiffIndex - Constructor /*{{{*/
1496 // ---------------------------------------------------------------------
1497 /* Get the DiffIndex file first and see if there are patches available
1498 * If so, create a pkgAcqIndexDiffs fetcher that will get and apply the
1499 * patches. If anything goes wrong in that process, it will fall back to
1500 * the original packages file
1502 pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire
* const Owner
,
1503 pkgAcqMetaBase
* const TransactionManager
,
1504 IndexTarget
const Target
)
1505 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
)
1507 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
1510 Desc
.Description
= Target
.Description
+ ".diff/Index";
1511 Desc
.ShortDesc
= Target
.ShortDesc
;
1512 Desc
.URI
= Target
.URI
+ ".diff/Index";
1514 DestFile
= GetPartialFileNameFromURI(Desc
.URI
);
1517 std::clog
<< "pkgAcqDiffIndex: " << Desc
.URI
<< std::endl
;
1522 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
1523 // ---------------------------------------------------------------------
1524 /* The only header we use is the last-modified header. */
1525 string
pkgAcqDiffIndex::Custom600Headers() const
1527 string
const Final
= GetFinalFilename();
1530 std::clog
<< "Custom600Header-IMS: " << Final
<< std::endl
;
1533 if (stat(Final
.c_str(),&Buf
) != 0)
1534 return "\nIndex-File: true";
1536 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1539 void pkgAcqDiffIndex::QueueOnIMSHit() const /*{{{*/
1541 // list cleanup needs to know that this file as well as the already
1542 // present index is ours, so we create an empty diff to save it for us
1543 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
);
1546 bool pkgAcqDiffIndex::ParseDiffIndex(string
const &IndexDiffFile
) /*{{{*/
1548 // failing here is fine: our caller will take care of trying to
1549 // get the complete file if patching fails
1551 std::clog
<< "pkgAcqDiffIndex::ParseIndexDiff() " << IndexDiffFile
1554 FileFd
Fd(IndexDiffFile
,FileFd::ReadOnly
);
1556 if (_error
->PendingError() == true)
1560 if(unlikely(TF
.Step(Tags
) == false))
1563 HashStringList ServerHashes
;
1564 unsigned long long ServerSize
= 0;
1566 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
1568 std::string tagname
= *type
;
1569 tagname
.append("-Current");
1570 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1571 if (tmp
.empty() == true)
1575 unsigned long long size
;
1576 std::stringstream
ss(tmp
);
1578 if (unlikely(hash
.empty() == true))
1580 if (unlikely(ServerSize
!= 0 && ServerSize
!= size
))
1582 ServerHashes
.push_back(HashString(*type
, hash
));
1586 if (ServerHashes
.usable() == false)
1589 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": Did not find a good hashsum in the index" << std::endl
;
1593 std::string
const CurrentPackagesFile
= GetFinalFileNameFromURI(Target
.URI
);
1594 HashStringList
const TargetFileHashes
= GetExpectedHashesFor(Target
.MetaKey
);
1595 if (TargetFileHashes
.usable() == false || ServerHashes
!= TargetFileHashes
)
1599 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": Index has different hashes than parser, probably older, so fail pdiffing" << std::endl
;
1600 printHashSumComparision(CurrentPackagesFile
, ServerHashes
, TargetFileHashes
);
1605 HashStringList LocalHashes
;
1606 // try avoiding calculating the hash here as this is costly
1607 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1608 LocalHashes
= GetExpectedHashesFromFor(TransactionManager
->LastMetaIndexParser
, Target
.MetaKey
);
1609 if (LocalHashes
.usable() == false)
1611 FileFd
fd(CurrentPackagesFile
, FileFd::ReadOnly
);
1612 Hashes
LocalHashesCalc(ServerHashes
);
1613 LocalHashesCalc
.AddFD(fd
);
1614 LocalHashes
= LocalHashesCalc
.GetHashStringList();
1617 if (ServerHashes
== LocalHashes
)
1619 // we have the same sha1 as the server so we are done here
1621 std::clog
<< "pkgAcqDiffIndex: Package file " << CurrentPackagesFile
<< " is up-to-date" << std::endl
;
1627 std::clog
<< "Server-Current: " << ServerHashes
.find(NULL
)->toStr() << " and we start at "
1628 << CurrentPackagesFile
<< " " << LocalHashes
.FileSize() << " " << LocalHashes
.find(NULL
)->toStr() << std::endl
;
1630 // parse all of (provided) history
1631 vector
<DiffInfo
> available_patches
;
1632 bool firstAcceptedHashes
= true;
1633 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
1635 if (LocalHashes
.find(*type
) == NULL
)
1638 std::string tagname
= *type
;
1639 tagname
.append("-History");
1640 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1641 if (tmp
.empty() == true)
1644 string hash
, filename
;
1645 unsigned long long size
;
1646 std::stringstream
ss(tmp
);
1648 while (ss
>> hash
>> size
>> filename
)
1650 if (unlikely(hash
.empty() == true || filename
.empty() == true))
1653 // see if we have a record for this file already
1654 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
1655 for (; cur
!= available_patches
.end(); ++cur
)
1657 if (cur
->file
!= filename
)
1659 cur
->result_hashes
.push_back(HashString(*type
, hash
));
1662 if (cur
!= available_patches
.end())
1664 if (firstAcceptedHashes
== true)
1667 next
.file
= filename
;
1668 next
.result_hashes
.push_back(HashString(*type
, hash
));
1669 next
.result_hashes
.FileSize(size
);
1670 available_patches
.push_back(next
);
1675 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
1676 << " wasn't in the list for the first parsed hash! (history)" << std::endl
;
1680 firstAcceptedHashes
= false;
1683 if (unlikely(available_patches
.empty() == true))
1686 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": "
1687 << "Couldn't find any patches for the patch series." << std::endl
;
1691 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
1693 if (LocalHashes
.find(*type
) == NULL
)
1696 std::string tagname
= *type
;
1697 tagname
.append("-Patches");
1698 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1699 if (tmp
.empty() == true)
1702 string hash
, filename
;
1703 unsigned long long size
;
1704 std::stringstream
ss(tmp
);
1706 while (ss
>> hash
>> size
>> filename
)
1708 if (unlikely(hash
.empty() == true || filename
.empty() == true))
1711 // see if we have a record for this file already
1712 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
1713 for (; cur
!= available_patches
.end(); ++cur
)
1715 if (cur
->file
!= filename
)
1717 if (cur
->patch_hashes
.empty())
1718 cur
->patch_hashes
.FileSize(size
);
1719 cur
->patch_hashes
.push_back(HashString(*type
, hash
));
1722 if (cur
!= available_patches
.end())
1725 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
1726 << " wasn't in the list for the first parsed hash! (patches)" << std::endl
;
1731 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
1733 std::string tagname
= *type
;
1734 tagname
.append("-Download");
1735 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1736 if (tmp
.empty() == true)
1739 string hash
, filename
;
1740 unsigned long long size
;
1741 std::stringstream
ss(tmp
);
1743 // FIXME: all of pdiff supports only .gz compressed patches
1744 while (ss
>> hash
>> size
>> filename
)
1746 if (unlikely(hash
.empty() == true || filename
.empty() == true))
1748 if (unlikely(APT::String::Endswith(filename
, ".gz") == false))
1750 filename
.erase(filename
.length() - 3);
1752 // see if we have a record for this file already
1753 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
1754 for (; cur
!= available_patches
.end(); ++cur
)
1756 if (cur
->file
!= filename
)
1758 if (cur
->download_hashes
.empty())
1759 cur
->download_hashes
.FileSize(size
);
1760 cur
->download_hashes
.push_back(HashString(*type
, hash
));
1763 if (cur
!= available_patches
.end())
1766 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
1767 << " wasn't in the list for the first parsed hash! (download)" << std::endl
;
1773 bool foundStart
= false;
1774 for (std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
1775 cur
!= available_patches
.end(); ++cur
)
1777 if (LocalHashes
!= cur
->result_hashes
)
1780 available_patches
.erase(available_patches
.begin(), cur
);
1785 if (foundStart
== false || unlikely(available_patches
.empty() == true))
1788 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": "
1789 << "Couldn't find the start of the patch series." << std::endl
;
1793 // patching with too many files is rather slow compared to a fast download
1794 unsigned long const fileLimit
= _config
->FindI("Acquire::PDiffs::FileLimit", 0);
1795 if (fileLimit
!= 0 && fileLimit
< available_patches
.size())
1798 std::clog
<< "Need " << available_patches
.size() << " diffs (Limit is " << fileLimit
1799 << ") so fallback to complete download" << std::endl
;
1803 // calculate the size of all patches we have to get
1804 // note that all sizes are uncompressed, while we download compressed files
1805 unsigned long long patchesSize
= 0;
1806 for (std::vector
<DiffInfo
>::const_iterator cur
= available_patches
.begin();
1807 cur
!= available_patches
.end(); ++cur
)
1808 patchesSize
+= cur
->patch_hashes
.FileSize();
1809 unsigned long long const sizeLimit
= ServerSize
* _config
->FindI("Acquire::PDiffs::SizeLimit", 100);
1810 if (sizeLimit
> 0 && (sizeLimit
/100) < patchesSize
)
1813 std::clog
<< "Need " << patchesSize
<< " bytes (Limit is " << sizeLimit
/100
1814 << ") so fallback to complete download" << std::endl
;
1818 // we have something, queue the diffs
1819 string::size_type
const last_space
= Description
.rfind(" ");
1820 if(last_space
!= string::npos
)
1821 Description
.erase(last_space
, Description
.size()-last_space
);
1823 /* decide if we should download patches one by one or in one go:
1824 The first is good if the server merges patches, but many don't so client
1825 based merging can be attempt in which case the second is better.
1826 "bad things" will happen if patches are merged on the server,
1827 but client side merging is attempt as well */
1828 bool pdiff_merge
= _config
->FindB("Acquire::PDiffs::Merge", true);
1829 if (pdiff_merge
== true)
1831 // reprepro adds this flag if it has merged patches on the server
1832 std::string
const precedence
= Tags
.FindS("X-Patch-Precedence");
1833 pdiff_merge
= (precedence
!= "merged");
1836 if (pdiff_merge
== false)
1837 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
, available_patches
);
1840 std::vector
<pkgAcqIndexMergeDiffs
*> *diffs
= new std::vector
<pkgAcqIndexMergeDiffs
*>(available_patches
.size());
1841 for(size_t i
= 0; i
< available_patches
.size(); ++i
)
1842 (*diffs
)[i
] = new pkgAcqIndexMergeDiffs(Owner
, TransactionManager
,
1844 available_patches
[i
],
1854 void pkgAcqDiffIndex::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
1856 Item::Failed(Message
,Cnf
);
1860 std::clog
<< "pkgAcqDiffIndex failed: " << Desc
.URI
<< " with " << Message
<< std::endl
1861 << "Falling back to normal index file acquire" << std::endl
;
1863 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
1866 void pkgAcqDiffIndex::Done(string
const &Message
,HashStringList
const &Hashes
, /*{{{*/
1867 pkgAcquire::MethodConfig
const * const Cnf
)
1870 std::clog
<< "pkgAcqDiffIndex::Done(): " << Desc
.URI
<< std::endl
;
1872 Item::Done(Message
, Hashes
, Cnf
);
1874 string
const FinalFile
= GetFinalFilename();
1875 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false))
1876 DestFile
= FinalFile
;
1878 if(ParseDiffIndex(DestFile
) == false)
1880 Failed("Message: Couldn't parse pdiff index", Cnf
);
1881 // queue for final move - this should happen even if we fail
1882 // while parsing (e.g. on sizelimit) and download the complete file.
1883 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
1887 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
1897 // AcqIndexDiffs::AcqIndexDiffs - Constructor /*{{{*/
1898 // ---------------------------------------------------------------------
1899 /* The package diff is added to the queue. one object is constructed
1900 * for each diff and the index
1902 pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire
* const Owner
,
1903 pkgAcqMetaBase
* const TransactionManager
,
1904 IndexTarget
const Target
,
1905 vector
<DiffInfo
> const &diffs
)
1906 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
),
1907 available_patches(diffs
)
1909 DestFile
= GetPartialFileNameFromURI(Target
.URI
);
1911 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
1914 Description
= Target
.Description
;
1915 Desc
.ShortDesc
= Target
.ShortDesc
;
1917 if(available_patches
.empty() == true)
1919 // we are done (yeah!), check hashes against the final file
1920 DestFile
= GetFinalFileNameFromURI(Target
.URI
);
1925 // patching needs to be bootstrapped with the 'old' version
1926 std::string
const PartialFile
= GetPartialFileNameFromURI(Target
.URI
);
1927 if (RealFileExists(PartialFile
) == false)
1929 if (symlink(GetFinalFilename().c_str(), PartialFile
.c_str()) != 0)
1931 Failed("Link creation of " + PartialFile
+ " to " + GetFinalFilename() + " failed", NULL
);
1936 // get the next diff
1937 State
= StateFetchDiff
;
1942 void pkgAcqIndexDiffs::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
1944 Item::Failed(Message
,Cnf
);
1948 std::clog
<< "pkgAcqIndexDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
1949 << "Falling back to normal index file acquire" << std::endl
;
1950 DestFile
= GetPartialFileNameFromURI(Target
.URI
);
1951 RenameOnError(PDiffError
);
1952 std::string
const patchname
= GetDiffsPatchFileName(DestFile
);
1953 if (RealFileExists(patchname
))
1954 rename(patchname
.c_str(), std::string(patchname
+ ".FAILED").c_str());
1955 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
1959 // Finish - helper that cleans the item out of the fetcher queue /*{{{*/
1960 void pkgAcqIndexDiffs::Finish(bool allDone
)
1963 std::clog
<< "pkgAcqIndexDiffs::Finish(): "
1965 << Desc
.URI
<< std::endl
;
1967 // we restore the original name, this is required, otherwise
1968 // the file will be cleaned
1971 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
1973 // this is for the "real" finish
1978 std::clog
<< "\n\nallDone: " << DestFile
<< "\n" << std::endl
;
1983 std::clog
<< "Finishing: " << Desc
.URI
<< std::endl
;
1990 bool pkgAcqIndexDiffs::QueueNextDiff() /*{{{*/
1992 // calc sha1 of the just patched file
1993 std::string
const FinalFile
= GetPartialFileNameFromURI(Target
.URI
);
1995 if(!FileExists(FinalFile
))
1997 Failed("Message: No FinalFile " + FinalFile
+ " available", NULL
);
2001 FileFd
fd(FinalFile
, FileFd::ReadOnly
);
2002 Hashes LocalHashesCalc
;
2003 LocalHashesCalc
.AddFD(fd
);
2004 HashStringList
const LocalHashes
= LocalHashesCalc
.GetHashStringList();
2007 std::clog
<< "QueueNextDiff: " << FinalFile
<< " (" << LocalHashes
.find(NULL
)->toStr() << ")" << std::endl
;
2009 HashStringList
const TargetFileHashes
= GetExpectedHashesFor(Target
.MetaKey
);
2010 if (unlikely(LocalHashes
.usable() == false || TargetFileHashes
.usable() == false))
2012 Failed("Local/Expected hashes are not usable", NULL
);
2017 // final file reached before all patches are applied
2018 if(LocalHashes
== TargetFileHashes
)
2024 // remove all patches until the next matching patch is found
2025 // this requires the Index file to be ordered
2026 for(vector
<DiffInfo
>::iterator I
= available_patches
.begin();
2027 available_patches
.empty() == false &&
2028 I
!= available_patches
.end() &&
2029 I
->result_hashes
!= LocalHashes
;
2032 available_patches
.erase(I
);
2035 // error checking and falling back if no patch was found
2036 if(available_patches
.empty() == true)
2038 Failed("No patches left to reach target", NULL
);
2042 // queue the right diff
2043 Desc
.URI
= Target
.URI
+ ".diff/" + available_patches
[0].file
+ ".gz";
2044 Desc
.Description
= Description
+ " " + available_patches
[0].file
+ string(".pdiff");
2045 DestFile
= GetPartialFileNameFromURI(Target
.URI
+ ".diff/" + available_patches
[0].file
);
2048 std::clog
<< "pkgAcqIndexDiffs::QueueNextDiff(): " << Desc
.URI
<< std::endl
;
2055 void pkgAcqIndexDiffs::Done(string
const &Message
, HashStringList
const &Hashes
, /*{{{*/
2056 pkgAcquire::MethodConfig
const * const Cnf
)
2059 std::clog
<< "pkgAcqIndexDiffs::Done(): " << Desc
.URI
<< std::endl
;
2061 Item::Done(Message
, Hashes
, Cnf
);
2063 std::string
const FinalFile
= GetPartialFileNameFromURI(Target
.URI
);
2064 std::string
const PatchFile
= GetDiffsPatchFileName(FinalFile
);
2066 // success in downloading a diff, enter ApplyDiff state
2067 if(State
== StateFetchDiff
)
2069 Rename(DestFile
, PatchFile
);
2072 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
2074 State
= StateApplyDiff
;
2076 Desc
.URI
= "rred:" + FinalFile
;
2078 SetActiveSubprocess("rred");
2082 // success in download/apply a diff, queue next (if needed)
2083 if(State
== StateApplyDiff
)
2085 // remove the just applied patch
2086 available_patches
.erase(available_patches
.begin());
2087 unlink(PatchFile
.c_str());
2092 std::clog
<< "Moving patched file in place: " << std::endl
2093 << DestFile
<< " -> " << FinalFile
<< std::endl
;
2095 Rename(DestFile
,FinalFile
);
2096 chmod(FinalFile
.c_str(),0644);
2098 // see if there is more to download
2099 if(available_patches
.empty() == false) {
2100 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
,
2105 DestFile
= FinalFile
;
2106 return Finish(true);
2110 std::string
pkgAcqIndexDiffs::Custom600Headers() const /*{{{*/
2112 if(State
!= StateApplyDiff
)
2113 return pkgAcqBaseIndex::Custom600Headers();
2114 std::ostringstream patchhashes
;
2115 HashStringList
const ExpectedHashes
= available_patches
[0].patch_hashes
;
2116 for (HashStringList::const_iterator hs
= ExpectedHashes
.begin(); hs
!= ExpectedHashes
.end(); ++hs
)
2117 patchhashes
<< "\nPatch-0-" << hs
->HashType() << "-Hash: " << hs
->HashValue();
2118 patchhashes
<< pkgAcqBaseIndex::Custom600Headers();
2119 return patchhashes
.str();
2123 // AcqIndexMergeDiffs::AcqIndexMergeDiffs - Constructor /*{{{*/
2124 pkgAcqIndexMergeDiffs::pkgAcqIndexMergeDiffs(pkgAcquire
* const Owner
,
2125 pkgAcqMetaBase
* const TransactionManager
,
2126 IndexTarget
const Target
,
2127 DiffInfo
const &patch
,
2128 std::vector
<pkgAcqIndexMergeDiffs
*> const * const allPatches
)
2129 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
),
2130 patch(patch
), allPatches(allPatches
), State(StateFetchDiff
)
2132 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
2135 Description
= Target
.Description
;
2136 Desc
.ShortDesc
= Target
.ShortDesc
;
2138 Desc
.URI
= Target
.URI
+ ".diff/" + patch
.file
+ ".gz";
2139 Desc
.Description
= Description
+ " " + patch
.file
+ string(".pdiff");
2141 DestFile
= GetPartialFileNameFromURI(Target
.URI
+ ".diff/" + patch
.file
);
2144 std::clog
<< "pkgAcqIndexMergeDiffs: " << Desc
.URI
<< std::endl
;
2149 void pkgAcqIndexMergeDiffs::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
2152 std::clog
<< "pkgAcqIndexMergeDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
;
2154 Item::Failed(Message
,Cnf
);
2157 // check if we are the first to fail, otherwise we are done here
2158 State
= StateDoneDiff
;
2159 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2160 I
!= allPatches
->end(); ++I
)
2161 if ((*I
)->State
== StateErrorDiff
)
2164 // first failure means we should fallback
2165 State
= StateErrorDiff
;
2167 std::clog
<< "Falling back to normal index file acquire" << std::endl
;
2168 DestFile
= GetPartialFileNameFromURI(Target
.URI
);
2169 RenameOnError(PDiffError
);
2170 std::string
const patchname
= GetMergeDiffsPatchFileName(DestFile
, patch
.file
);
2171 if (RealFileExists(patchname
))
2172 rename(patchname
.c_str(), std::string(patchname
+ ".FAILED").c_str());
2173 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
2176 void pkgAcqIndexMergeDiffs::Done(string
const &Message
, HashStringList
const &Hashes
, /*{{{*/
2177 pkgAcquire::MethodConfig
const * const Cnf
)
2180 std::clog
<< "pkgAcqIndexMergeDiffs::Done(): " << Desc
.URI
<< std::endl
;
2182 Item::Done(Message
, Hashes
, Cnf
);
2184 string
const FinalFile
= GetPartialFileNameFromURI(Target
.URI
);
2185 if (State
== StateFetchDiff
)
2187 Rename(DestFile
, GetMergeDiffsPatchFileName(FinalFile
, patch
.file
));
2189 // check if this is the last completed diff
2190 State
= StateDoneDiff
;
2191 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2192 I
!= allPatches
->end(); ++I
)
2193 if ((*I
)->State
!= StateDoneDiff
)
2196 std::clog
<< "Not the last done diff in the batch: " << Desc
.URI
<< std::endl
;
2200 // this is the last completed diff, so we are ready to apply now
2201 State
= StateApplyDiff
;
2203 // patching needs to be bootstrapped with the 'old' version
2204 if (symlink(GetFinalFilename().c_str(), FinalFile
.c_str()) != 0)
2206 Failed("Link creation of " + FinalFile
+ " to " + GetFinalFilename() + " failed", NULL
);
2211 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
2214 Desc
.URI
= "rred:" + FinalFile
;
2216 SetActiveSubprocess("rred");
2219 // success in download/apply all diffs, clean up
2220 else if (State
== StateApplyDiff
)
2222 // move the result into place
2223 std::string
const Final
= GetFinalFilename();
2225 std::clog
<< "Queue patched file in place: " << std::endl
2226 << DestFile
<< " -> " << Final
<< std::endl
;
2228 // queue for copy by the transaction manager
2229 TransactionManager
->TransactionStageCopy(this, DestFile
, Final
);
2231 // ensure the ed's are gone regardless of list-cleanup
2232 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2233 I
!= allPatches
->end(); ++I
)
2235 std::string
const PartialFile
= GetPartialFileNameFromURI(Target
.URI
);
2236 std::string
const patch
= GetMergeDiffsPatchFileName(PartialFile
, (*I
)->patch
.file
);
2237 unlink(patch
.c_str());
2239 unlink(FinalFile
.c_str());
2244 std::clog
<< "allDone: " << DestFile
<< "\n" << std::endl
;
2248 std::string
pkgAcqIndexMergeDiffs::Custom600Headers() const /*{{{*/
2250 if(State
!= StateApplyDiff
)
2251 return pkgAcqBaseIndex::Custom600Headers();
2252 std::ostringstream patchhashes
;
2253 unsigned int seen_patches
= 0;
2254 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2255 I
!= allPatches
->end(); ++I
)
2257 HashStringList
const ExpectedHashes
= (*I
)->patch
.patch_hashes
;
2258 for (HashStringList::const_iterator hs
= ExpectedHashes
.begin(); hs
!= ExpectedHashes
.end(); ++hs
)
2259 patchhashes
<< "\nPatch-" << seen_patches
<< "-" << hs
->HashType() << "-Hash: " << hs
->HashValue();
2262 patchhashes
<< pkgAcqBaseIndex::Custom600Headers();
2263 return patchhashes
.str();
2267 // AcqIndex::AcqIndex - Constructor /*{{{*/
2268 pkgAcqIndex::pkgAcqIndex(pkgAcquire
* const Owner
,
2269 pkgAcqMetaBase
* const TransactionManager
,
2270 IndexTarget
const Target
)
2271 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
)
2273 // autoselect the compression method
2274 AutoSelectCompression();
2275 Init(Target
.URI
, Target
.Description
, Target
.ShortDesc
);
2277 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
2278 std::clog
<< "New pkgIndex with TransactionManager "
2279 << TransactionManager
<< std::endl
;
2282 // AcqIndex::AutoSelectCompression - Select compression /*{{{*/
2283 void pkgAcqIndex::AutoSelectCompression()
2285 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
2286 CompressionExtensions
= "";
2287 if (TransactionManager
->MetaIndexParser
!= NULL
&& TransactionManager
->MetaIndexParser
->Exists(Target
.MetaKey
))
2289 for (std::vector
<std::string
>::const_iterator t
= types
.begin();
2290 t
!= types
.end(); ++t
)
2292 std::string CompressedMetaKey
= string(Target
.MetaKey
).append(".").append(*t
);
2293 if (*t
== "uncompressed" ||
2294 TransactionManager
->MetaIndexParser
->Exists(CompressedMetaKey
) == true)
2295 CompressionExtensions
.append(*t
).append(" ");
2300 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
2301 CompressionExtensions
.append(*t
).append(" ");
2303 if (CompressionExtensions
.empty() == false)
2304 CompressionExtensions
.erase(CompressionExtensions
.end()-1);
2307 // AcqIndex::Init - defered Constructor /*{{{*/
2308 void pkgAcqIndex::Init(string
const &URI
, string
const &URIDesc
,
2309 string
const &ShortDesc
)
2311 Stage
= STAGE_DOWNLOAD
;
2313 DestFile
= GetPartialFileNameFromURI(URI
);
2315 size_t const nextExt
= CompressionExtensions
.find(' ');
2316 if (nextExt
== std::string::npos
)
2318 CurrentCompressionExtension
= CompressionExtensions
;
2319 CompressionExtensions
.clear();
2323 CurrentCompressionExtension
= CompressionExtensions
.substr(0, nextExt
);
2324 CompressionExtensions
= CompressionExtensions
.substr(nextExt
+1);
2327 if (CurrentCompressionExtension
== "uncompressed")
2331 else if (unlikely(CurrentCompressionExtension
.empty()))
2335 Desc
.URI
= URI
+ '.' + CurrentCompressionExtension
;
2336 DestFile
= DestFile
+ '.' + CurrentCompressionExtension
;
2339 if(TransactionManager
->MetaIndexParser
!= NULL
)
2340 InitByHashIfNeeded();
2342 Desc
.Description
= URIDesc
;
2344 Desc
.ShortDesc
= ShortDesc
;
2349 // AcqIndex::AdjustForByHash - modify URI for by-hash support /*{{{*/
2350 void pkgAcqIndex::InitByHashIfNeeded()
2353 // - (maybe?) add support for by-hash into the sources.list as flag
2354 // - make apt-ftparchive generate the hashes (and expire?)
2355 std::string HostKnob
= "APT::Acquire::" + ::URI(Desc
.URI
).Host
+ "::By-Hash";
2356 if(_config
->FindB("APT::Acquire::By-Hash", false) == true ||
2357 _config
->FindB(HostKnob
, false) == true ||
2358 TransactionManager
->MetaIndexParser
->GetSupportsAcquireByHash())
2360 HashStringList
const Hashes
= GetExpectedHashes();
2363 // FIXME: should we really use the best hash here? or a fixed one?
2364 HashString
const * const TargetHash
= Hashes
.find("");
2365 std::string
const ByHash
= "/by-hash/" + TargetHash
->HashType() + "/" + TargetHash
->HashValue();
2366 size_t const trailing_slash
= Desc
.URI
.find_last_of("/");
2367 Desc
.URI
= Desc
.URI
.replace(
2369 Desc
.URI
.substr(trailing_slash
+1).size()+1,
2373 "Fetching ByHash requested but can not find record for %s",
2374 GetMetaKey().c_str());
2379 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
2380 // ---------------------------------------------------------------------
2381 /* The only header we use is the last-modified header. */
2382 string
pkgAcqIndex::Custom600Headers() const
2384 string Final
= GetFinalFilename();
2386 string msg
= "\nIndex-File: true";
2388 if (stat(Final
.c_str(),&Buf
) == 0)
2389 msg
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
2391 if(Target
.IsOptional
)
2392 msg
+= "\nFail-Ignore: true";
2397 // AcqIndex::Failed - getting the indexfile failed /*{{{*/
2398 void pkgAcqIndex::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)
2400 Item::Failed(Message
,Cnf
);
2402 // authorisation matches will not be fixed by other compression types
2403 if (Status
!= StatAuthError
)
2405 if (CompressionExtensions
.empty() == false)
2407 Init(Target
.URI
, Desc
.Description
, Desc
.ShortDesc
);
2413 if(Target
.IsOptional
&& GetExpectedHashes().empty() && Stage
== STAGE_DOWNLOAD
)
2416 TransactionManager
->AbortTransaction();
2419 // AcqIndex::ReverifyAfterIMS - Reverify index after an ims-hit /*{{{*/
2420 void pkgAcqIndex::ReverifyAfterIMS()
2422 // update destfile to *not* include the compression extension when doing
2423 // a reverify (as its uncompressed on disk already)
2424 DestFile
= GetCompressedFileName(Target
.URI
, GetPartialFileNameFromURI(Target
.URI
), CurrentCompressionExtension
);
2426 // copy FinalFile into partial/ so that we check the hash again
2427 string FinalFile
= GetFinalFilename();
2428 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
2429 Desc
.URI
= "copy:" + FinalFile
;
2433 // AcqIndex::Done - Finished a fetch /*{{{*/
2434 // ---------------------------------------------------------------------
2435 /* This goes through a number of states.. On the initial fetch the
2436 method could possibly return an alternate filename which points
2437 to the uncompressed version of the file. If this is so the file
2438 is copied into the partial directory. In all other cases the file
2439 is decompressed with a compressed uri. */
2440 void pkgAcqIndex::Done(string
const &Message
,
2441 HashStringList
const &Hashes
,
2442 pkgAcquire::MethodConfig
const * const Cfg
)
2444 Item::Done(Message
,Hashes
,Cfg
);
2448 case STAGE_DOWNLOAD
:
2449 StageDownloadDone(Message
, Hashes
, Cfg
);
2451 case STAGE_DECOMPRESS_AND_VERIFY
:
2452 StageDecompressDone(Message
, Hashes
, Cfg
);
2457 // AcqIndex::StageDownloadDone - Queue for decompress and verify /*{{{*/
2458 void pkgAcqIndex::StageDownloadDone(string
const &Message
, HashStringList
const &,
2459 pkgAcquire::MethodConfig
const * const)
2463 // Handle the unzipd case
2464 string FileName
= LookupTag(Message
,"Alt-Filename");
2465 if (FileName
.empty() == false)
2467 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
2469 DestFile
+= ".decomp";
2470 Desc
.URI
= "copy:" + FileName
;
2472 SetActiveSubprocess("copy");
2476 FileName
= LookupTag(Message
,"Filename");
2477 if (FileName
.empty() == true)
2480 ErrorText
= "Method gave a blank filename";
2483 // Methods like e.g. "file:" will give us a (compressed) FileName that is
2484 // not the "DestFile" we set, in this case we uncompress from the local file
2485 if (FileName
!= DestFile
&& RealFileExists(DestFile
) == false)
2488 EraseFileName
= FileName
;
2490 // we need to verify the file against the current Release file again
2491 // on if-modfied-since hit to avoid a stale attack against us
2492 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
2494 // The files timestamp matches, reverify by copy into partial/
2500 // If we have compressed indexes enabled, queue for hash verification
2501 if (_config
->FindB("Acquire::GzipIndexes",false))
2503 DestFile
= GetPartialFileNameFromURI(Target
.URI
+ '.' + CurrentCompressionExtension
);
2505 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
2506 Desc
.URI
= "copy:" + FileName
;
2508 SetActiveSubprocess("copy");
2512 // get the binary name for your used compression type
2514 if(CurrentCompressionExtension
== "uncompressed")
2515 decompProg
= "copy";
2517 decompProg
= _config
->Find(string("Acquire::CompressionTypes::").append(CurrentCompressionExtension
),"");
2518 if(decompProg
.empty() == true)
2520 _error
->Error("Unsupported extension: %s", CurrentCompressionExtension
.c_str());
2524 // queue uri for the next stage
2525 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
2526 DestFile
+= ".decomp";
2527 Desc
.URI
= decompProg
+ ":" + FileName
;
2529 SetActiveSubprocess(decompProg
);
2532 // AcqIndex::StageDecompressDone - Final verification /*{{{*/
2533 void pkgAcqIndex::StageDecompressDone(string
const &,
2534 HashStringList
const &,
2535 pkgAcquire::MethodConfig
const * const)
2537 // Done, queue for rename on transaction finished
2538 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
2544 // AcqArchive::AcqArchive - Constructor /*{{{*/
2545 // ---------------------------------------------------------------------
2546 /* This just sets up the initial fetch environment and queues the first
2548 pkgAcqArchive::pkgAcqArchive(pkgAcquire
* const Owner
,pkgSourceList
* const Sources
,
2549 pkgRecords
* const Recs
,pkgCache::VerIterator
const &Version
,
2550 string
&StoreFilename
) :
2551 Item(Owner
), LocalSource(false), Version(Version
), Sources(Sources
), Recs(Recs
),
2552 StoreFilename(StoreFilename
), Vf(Version
.FileList()),
2555 Retries
= _config
->FindI("Acquire::Retries",0);
2557 if (Version
.Arch() == 0)
2559 _error
->Error(_("I wasn't able to locate a file for the %s package. "
2560 "This might mean you need to manually fix this package. "
2561 "(due to missing arch)"),
2562 Version
.ParentPkg().FullName().c_str());
2566 /* We need to find a filename to determine the extension. We make the
2567 assumption here that all the available sources for this version share
2568 the same extension.. */
2569 // Skip not source sources, they do not have file fields.
2570 for (; Vf
.end() == false; ++Vf
)
2572 if (Vf
.File().Flagged(pkgCache::Flag::NotSource
))
2577 // Does not really matter here.. we are going to fail out below
2578 if (Vf
.end() != true)
2580 // If this fails to get a file name we will bomb out below.
2581 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2582 if (_error
->PendingError() == true)
2585 // Generate the final file name as: package_version_arch.foo
2586 StoreFilename
= QuoteString(Version
.ParentPkg().Name(),"_:") + '_' +
2587 QuoteString(Version
.VerStr(),"_:") + '_' +
2588 QuoteString(Version
.Arch(),"_:.") +
2589 "." + flExtension(Parse
.FileName());
2592 // check if we have one trusted source for the package. if so, switch
2593 // to "TrustedOnly" mode - but only if not in AllowUnauthenticated mode
2594 bool const allowUnauth
= _config
->FindB("APT::Get::AllowUnauthenticated", false);
2595 bool const debugAuth
= _config
->FindB("Debug::pkgAcquire::Auth", false);
2596 bool seenUntrusted
= false;
2597 for (pkgCache::VerFileIterator i
= Version
.FileList(); i
.end() == false; ++i
)
2599 pkgIndexFile
*Index
;
2600 if (Sources
->FindIndex(i
.File(),Index
) == false)
2603 if (debugAuth
== true)
2604 std::cerr
<< "Checking index: " << Index
->Describe()
2605 << "(Trusted=" << Index
->IsTrusted() << ")" << std::endl
;
2607 if (Index
->IsTrusted() == true)
2610 if (allowUnauth
== false)
2614 seenUntrusted
= true;
2617 // "allow-unauthenticated" restores apts old fetching behaviour
2618 // that means that e.g. unauthenticated file:// uris are higher
2619 // priority than authenticated http:// uris
2620 if (allowUnauth
== true && seenUntrusted
== true)
2624 if (QueueNext() == false && _error
->PendingError() == false)
2625 _error
->Error(_("Can't find a source to download version '%s' of '%s'"),
2626 Version
.VerStr(), Version
.ParentPkg().FullName(false).c_str());
2629 // AcqArchive::QueueNext - Queue the next file source /*{{{*/
2630 // ---------------------------------------------------------------------
2631 /* This queues the next available file version for download. It checks if
2632 the archive is already available in the cache and stashs the MD5 for
2634 bool pkgAcqArchive::QueueNext()
2636 for (; Vf
.end() == false; ++Vf
)
2638 pkgCache::PkgFileIterator
const PkgF
= Vf
.File();
2639 // Ignore not source sources
2640 if (PkgF
.Flagged(pkgCache::Flag::NotSource
))
2643 // Try to cross match against the source list
2644 pkgIndexFile
*Index
;
2645 if (Sources
->FindIndex(PkgF
, Index
) == false)
2647 LocalSource
= PkgF
.Flagged(pkgCache::Flag::LocalSource
);
2649 // only try to get a trusted package from another source if that source
2651 if(Trusted
&& !Index
->IsTrusted())
2654 // Grab the text package record
2655 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2656 if (_error
->PendingError() == true)
2659 string PkgFile
= Parse
.FileName();
2660 ExpectedHashes
= Parse
.Hashes();
2662 if (PkgFile
.empty() == true)
2663 return _error
->Error(_("The package index files are corrupted. No Filename: "
2664 "field for package %s."),
2665 Version
.ParentPkg().Name());
2667 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
2668 Desc
.Description
= Index
->ArchiveInfo(Version
);
2670 Desc
.ShortDesc
= Version
.ParentPkg().FullName(true);
2672 // See if we already have the file. (Legacy filenames)
2673 FileSize
= Version
->Size
;
2674 string FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile
);
2676 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2678 // Make sure the size matches
2679 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2684 StoreFilename
= DestFile
= FinalFile
;
2688 /* Hmm, we have a file and its size does not match, this means it is
2689 an old style mismatched arch */
2690 unlink(FinalFile
.c_str());
2693 // Check it again using the new style output filenames
2694 FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
2695 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2697 // Make sure the size matches
2698 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2703 StoreFilename
= DestFile
= FinalFile
;
2707 /* Hmm, we have a file and its size does not match, this shouldn't
2709 unlink(FinalFile
.c_str());
2712 DestFile
= _config
->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename
);
2714 // Check the destination file
2715 if (stat(DestFile
.c_str(),&Buf
) == 0)
2717 // Hmm, the partial file is too big, erase it
2718 if ((unsigned long long)Buf
.st_size
> Version
->Size
)
2719 unlink(DestFile
.c_str());
2721 PartialSize
= Buf
.st_size
;
2724 // Disables download of archives - useful if no real installation follows,
2725 // e.g. if we are just interested in proposed installation order
2726 if (_config
->FindB("Debug::pkgAcqArchive::NoQueue", false) == true)
2731 StoreFilename
= DestFile
= FinalFile
;
2745 // AcqArchive::Done - Finished fetching /*{{{*/
2746 // ---------------------------------------------------------------------
2748 void pkgAcqArchive::Done(string
const &Message
, HashStringList
const &Hashes
,
2749 pkgAcquire::MethodConfig
const * const Cfg
)
2751 Item::Done(Message
, Hashes
, Cfg
);
2753 // Grab the output filename
2754 string FileName
= LookupTag(Message
,"Filename");
2755 if (FileName
.empty() == true)
2758 ErrorText
= "Method gave a blank filename";
2762 // Reference filename
2763 if (DestFile
!= FileName
&& RealFileExists(DestFile
) == false)
2765 StoreFilename
= DestFile
= FileName
;
2771 // Done, move it into position
2772 string
const FinalFile
= GetFinalFilename();
2773 Rename(DestFile
,FinalFile
);
2774 StoreFilename
= DestFile
= FinalFile
;
2778 // AcqArchive::Failed - Failure handler /*{{{*/
2779 // ---------------------------------------------------------------------
2780 /* Here we try other sources */
2781 void pkgAcqArchive::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)
2783 Item::Failed(Message
,Cnf
);
2785 /* We don't really want to retry on failed media swaps, this prevents
2786 that. An interesting observation is that permanent failures are not
2788 if (Cnf
->Removable
== true &&
2789 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2791 // Vf = Version.FileList();
2792 while (Vf
.end() == false) ++Vf
;
2793 StoreFilename
= string();
2798 if (QueueNext() == false)
2800 // This is the retry counter
2802 Cnf
->LocalOnly
== false &&
2803 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2806 Vf
= Version
.FileList();
2807 if (QueueNext() == true)
2811 StoreFilename
= string();
2816 APT_PURE
bool pkgAcqArchive::IsTrusted() const /*{{{*/
2821 void pkgAcqArchive::Finished() /*{{{*/
2823 if (Status
== pkgAcquire::Item::StatDone
&&
2826 StoreFilename
= string();
2829 std::string
pkgAcqArchive::DescURI() const /*{{{*/
2834 std::string
pkgAcqArchive::ShortDesc() const /*{{{*/
2836 return Desc
.ShortDesc
;
2840 // AcqChangelog::pkgAcqChangelog - Constructors /*{{{*/
2841 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire
* const Owner
, pkgCache::VerIterator
const &Ver
,
2842 std::string
const &DestDir
, std::string
const &DestFilename
) :
2843 pkgAcquire::Item(Owner
), d(NULL
), SrcName(Ver
.SourcePkgName()), SrcVersion(Ver
.SourceVerStr())
2845 Desc
.URI
= URI(Ver
);
2846 Init(DestDir
, DestFilename
);
2848 // some parameters are char* here as they come likely from char* interfaces – which can also return NULL
2849 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire
* const Owner
, pkgCache::RlsFileIterator
const &RlsFile
,
2850 char const * const Component
, char const * const SrcName
, char const * const SrcVersion
,
2851 const string
&DestDir
, const string
&DestFilename
) :
2852 pkgAcquire::Item(Owner
), d(NULL
), SrcName(SrcName
), SrcVersion(SrcVersion
)
2854 Desc
.URI
= URI(RlsFile
, Component
, SrcName
, SrcVersion
);
2855 Init(DestDir
, DestFilename
);
2857 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire
* const Owner
,
2858 std::string
const &URI
, char const * const SrcName
, char const * const SrcVersion
,
2859 const string
&DestDir
, const string
&DestFilename
) :
2860 pkgAcquire::Item(Owner
), d(NULL
), SrcName(SrcName
), SrcVersion(SrcVersion
)
2863 Init(DestDir
, DestFilename
);
2865 void pkgAcqChangelog::Init(std::string
const &DestDir
, std::string
const &DestFilename
)
2867 if (Desc
.URI
.empty())
2870 // TRANSLATOR: %s=%s is sourcename=sourceversion, e.g. apt=1.1
2871 strprintf(ErrorText
, _("Changelog unavailable for %s=%s"), SrcName
.c_str(), SrcVersion
.c_str());
2872 // Let the error message print something sensible rather than "Failed to fetch /"
2873 if (DestFilename
.empty())
2874 DestFile
= SrcName
+ ".changelog";
2876 DestFile
= DestFilename
;
2877 Desc
.URI
= "changelog:/" + DestFile
;
2881 if (DestDir
.empty())
2883 std::string
const systemTemp
= GetTempDir();
2885 snprintf(tmpname
, sizeof(tmpname
), "%s/apt-changelog-XXXXXX", systemTemp
.c_str());
2886 if (NULL
== mkdtemp(tmpname
))
2888 _error
->Errno("mkdtemp", "mkdtemp failed in changelog acquire of %s %s", SrcName
.c_str(), SrcVersion
.c_str());
2892 DestFile
= TemporaryDirectory
= tmpname
;
2897 if (DestFilename
.empty())
2898 DestFile
= flCombine(DestFile
, SrcName
+ ".changelog");
2900 DestFile
= flCombine(DestFile
, DestFilename
);
2902 Desc
.ShortDesc
= "Changelog";
2903 strprintf(Desc
.Description
, "%s %s %s Changelog", URI::SiteOnly(Desc
.URI
).c_str(), SrcName
.c_str(), SrcVersion
.c_str());
2908 std::string
pkgAcqChangelog::URI(pkgCache::VerIterator
const &Ver
) /*{{{*/
2910 char const * const SrcName
= Ver
.SourcePkgName();
2911 char const * const SrcVersion
= Ver
.SourceVerStr();
2912 pkgCache::PkgFileIterator PkgFile
;
2913 // find the first source for this version which promises a changelog
2914 for (pkgCache::VerFileIterator VF
= Ver
.FileList(); VF
.end() == false; ++VF
)
2916 pkgCache::PkgFileIterator
const PF
= VF
.File();
2917 if (PF
.Flagged(pkgCache::Flag::NotSource
) || PF
->Release
== 0)
2920 pkgCache::RlsFileIterator
const RF
= PF
.ReleaseFile();
2921 std::string
const uri
= URI(RF
, PF
.Component(), SrcName
, SrcVersion
);
2928 std::string
pkgAcqChangelog::URITemplate(pkgCache::RlsFileIterator
const &Rls
)
2930 if (Rls
.end() == true || (Rls
->Label
== 0 && Rls
->Origin
== 0))
2932 std::string
const serverConfig
= "Acquire::Changelogs::URI";
2934 #define APT_EMPTY_SERVER \
2935 if (server.empty() == false) \
2937 if (server != "no") \
2941 #define APT_CHECK_SERVER(X, Y) \
2944 std::string const specialServerConfig = serverConfig + "::" + Y + #X + "::" + Rls.X(); \
2945 server = _config->Find(specialServerConfig); \
2948 // this way e.g. Debian-Security can fallback to Debian
2949 APT_CHECK_SERVER(Label
, "Override::")
2950 APT_CHECK_SERVER(Origin
, "Override::")
2952 if (RealFileExists(Rls
.FileName()))
2954 _error
->PushToStack();
2956 /* This can be costly. A caller wanting to get millions of URIs might
2957 want to do this on its own once and use Override settings.
2958 We don't do this here as Origin/Label are not as unique as they
2959 should be so this could produce request order-dependent anomalies */
2960 if (OpenMaybeClearSignedFile(Rls
.FileName(), rf
) == true)
2962 pkgTagFile
TagFile(&rf
, rf
.Size());
2963 pkgTagSection Section
;
2964 if (TagFile
.Step(Section
) == true)
2965 server
= Section
.FindS("Changelogs");
2967 _error
->RevertToStack();
2971 APT_CHECK_SERVER(Label
, "")
2972 APT_CHECK_SERVER(Origin
, "")
2973 #undef APT_CHECK_SERVER
2974 #undef APT_EMPTY_SERVER
2977 std::string
pkgAcqChangelog::URI(pkgCache::RlsFileIterator
const &Rls
,
2978 char const * const Component
, char const * const SrcName
,
2979 char const * const SrcVersion
)
2981 return URI(URITemplate(Rls
), Component
, SrcName
, SrcVersion
);
2983 std::string
pkgAcqChangelog::URI(std::string
const &Template
,
2984 char const * const Component
, char const * const SrcName
,
2985 char const * const SrcVersion
)
2987 if (Template
.find("CHANGEPATH") == std::string::npos
)
2990 // the path is: COMPONENT/SRC/SRCNAME/SRCNAME_SRCVER, e.g. main/a/apt/1.1 or contrib/liba/libapt/2.0
2991 std::string Src
= SrcName
;
2992 std::string path
= APT::String::Startswith(SrcName
, "lib") ? Src
.substr(0, 4) : Src
.substr(0,1);
2993 path
.append("/").append(Src
).append("/");
2994 path
.append(Src
).append("_").append(StripEpoch(SrcVersion
));
2995 // we omit component for releases without one (= flat-style repositories)
2996 if (Component
!= NULL
&& strlen(Component
) != 0)
2997 path
= std::string(Component
) + "/" + path
;
2999 return SubstVar(Template
, "CHANGEPATH", path
);
3002 // AcqChangelog::Failed - Failure handler /*{{{*/
3003 void pkgAcqChangelog::Failed(string
const &Message
, pkgAcquire::MethodConfig
const * const Cnf
)
3005 Item::Failed(Message
,Cnf
);
3007 std::string errText
;
3008 // TRANSLATOR: %s=%s is sourcename=sourceversion, e.g. apt=1.1
3009 strprintf(errText
, _("Changelog unavailable for %s=%s"), SrcName
.c_str(), SrcVersion
.c_str());
3011 // Error is probably something techy like 404 Not Found
3012 if (ErrorText
.empty())
3013 ErrorText
= errText
;
3015 ErrorText
= errText
+ " (" + ErrorText
+ ")";
3019 // AcqChangelog::Done - Item downloaded OK /*{{{*/
3020 void pkgAcqChangelog::Done(string
const &Message
,HashStringList
const &CalcHashes
,
3021 pkgAcquire::MethodConfig
const * const Cnf
)
3023 Item::Done(Message
,CalcHashes
,Cnf
);
3028 pkgAcqChangelog::~pkgAcqChangelog() /*{{{*/
3030 if (TemporaryDirectory
.empty() == false)
3032 unlink(DestFile
.c_str());
3033 rmdir(TemporaryDirectory
.c_str());
3038 // AcqFile::pkgAcqFile - Constructor /*{{{*/
3039 pkgAcqFile::pkgAcqFile(pkgAcquire
* const Owner
,string
const &URI
, HashStringList
const &Hashes
,
3040 unsigned long long const Size
,string
const &Dsc
,string
const &ShortDesc
,
3041 const string
&DestDir
, const string
&DestFilename
,
3042 bool const IsIndexFile
) :
3043 Item(Owner
), IsIndexFile(IsIndexFile
), ExpectedHashes(Hashes
)
3045 Retries
= _config
->FindI("Acquire::Retries",0);
3047 if(!DestFilename
.empty())
3048 DestFile
= DestFilename
;
3049 else if(!DestDir
.empty())
3050 DestFile
= DestDir
+ "/" + flNotDir(URI
);
3052 DestFile
= flNotDir(URI
);
3056 Desc
.Description
= Dsc
;
3059 // Set the short description to the archive component
3060 Desc
.ShortDesc
= ShortDesc
;
3062 // Get the transfer sizes
3065 if (stat(DestFile
.c_str(),&Buf
) == 0)
3067 // Hmm, the partial file is too big, erase it
3068 if ((Size
> 0) && (unsigned long long)Buf
.st_size
> Size
)
3069 unlink(DestFile
.c_str());
3071 PartialSize
= Buf
.st_size
;
3077 // AcqFile::Done - Item downloaded OK /*{{{*/
3078 void pkgAcqFile::Done(string
const &Message
,HashStringList
const &CalcHashes
,
3079 pkgAcquire::MethodConfig
const * const Cnf
)
3081 Item::Done(Message
,CalcHashes
,Cnf
);
3083 string FileName
= LookupTag(Message
,"Filename");
3084 if (FileName
.empty() == true)
3087 ErrorText
= "Method gave a blank filename";
3093 // The files timestamp matches
3094 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
3097 // We have to copy it into place
3098 if (RealFileExists(DestFile
.c_str()) == false)
3101 if (_config
->FindB("Acquire::Source-Symlinks",true) == false ||
3102 Cnf
->Removable
== true)
3104 Desc
.URI
= "copy:" + FileName
;
3109 // Erase the file if it is a symlink so we can overwrite it
3111 if (lstat(DestFile
.c_str(),&St
) == 0)
3113 if (S_ISLNK(St
.st_mode
) != 0)
3114 unlink(DestFile
.c_str());
3118 if (symlink(FileName
.c_str(),DestFile
.c_str()) != 0)
3120 _error
->PushToStack();
3121 _error
->Errno("pkgAcqFile::Done", "Symlinking file %s failed", DestFile
.c_str());
3122 std::stringstream msg
;
3123 _error
->DumpErrors(msg
);
3124 _error
->RevertToStack();
3125 ErrorText
= msg
.str();
3132 // AcqFile::Failed - Failure handler /*{{{*/
3133 // ---------------------------------------------------------------------
3134 /* Here we try other sources */
3135 void pkgAcqFile::Failed(string
const &Message
, pkgAcquire::MethodConfig
const * const Cnf
)
3137 Item::Failed(Message
,Cnf
);
3139 // This is the retry counter
3141 Cnf
->LocalOnly
== false &&
3142 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
3152 string
pkgAcqFile::Custom600Headers() const /*{{{*/
3155 return "\nIndex-File: true";