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/tagfile.h>
26 #include <apt-pkg/metaindex.h>
27 #include <apt-pkg/acquire.h>
28 #include <apt-pkg/hashes.h>
29 #include <apt-pkg/indexfile.h>
30 #include <apt-pkg/pkgcache.h>
31 #include <apt-pkg/cacheiterators.h>
32 #include <apt-pkg/pkgrecords.h>
33 #include <apt-pkg/gpgv.h>
53 static void printHashSumComparision(std::string
const &URI
, HashStringList
const &Expected
, HashStringList
const &Actual
) /*{{{*/
55 if (_config
->FindB("Debug::Acquire::HashSumMismatch", false) == false)
57 std::cerr
<< std::endl
<< URI
<< ":" << std::endl
<< " Expected Hash: " << std::endl
;
58 for (HashStringList::const_iterator hs
= Expected
.begin(); hs
!= Expected
.end(); ++hs
)
59 std::cerr
<< "\t- " << hs
->toStr() << std::endl
;
60 std::cerr
<< " Actual Hash: " << std::endl
;
61 for (HashStringList::const_iterator hs
= Actual
.begin(); hs
!= Actual
.end(); ++hs
)
62 std::cerr
<< "\t- " << hs
->toStr() << std::endl
;
65 static std::string
GetPartialFileName(std::string
const &file
) /*{{{*/
67 std::string DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
72 static std::string
GetPartialFileNameFromURI(std::string
const &uri
) /*{{{*/
74 return GetPartialFileName(URItoFileName(uri
));
77 static std::string
GetFinalFileNameFromURI(std::string
const &uri
) /*{{{*/
79 return _config
->FindDir("Dir::State::lists") + URItoFileName(uri
);
82 static std::string
GetCompressedFileName(IndexTarget
const &Target
, std::string
const &Name
, std::string
const &Ext
) /*{{{*/
84 if (Ext
.empty() || Ext
== "uncompressed")
87 // do not reverify cdrom sources as apt-cdrom may rewrite the Packages
88 // file when its doing the indexcopy
89 if (Target
.URI
.substr(0,6) == "cdrom:")
92 // adjust DestFile if its compressed on disk
93 if (Target
.KeepCompressed
== true)
94 return Name
+ '.' + Ext
;
98 static std::string
GetMergeDiffsPatchFileName(std::string
const &Final
, std::string
const &Patch
)/*{{{*/
100 // rred expects the patch as $FinalFile.ed.$patchname.gz
101 return Final
+ ".ed." + Patch
+ ".gz";
104 static std::string
GetDiffsPatchFileName(std::string
const &Final
) /*{{{*/
106 // rred expects the patch as $FinalFile.ed
107 return Final
+ ".ed";
111 static bool AllowInsecureRepositories(metaIndex
const * const MetaIndexParser
, pkgAcqMetaClearSig
* const TransactionManager
, pkgAcquire::Item
* const I
) /*{{{*/
113 if(MetaIndexParser
->GetTrusted() == metaIndex::TRI_YES
|| _config
->FindB("Acquire::AllowInsecureRepositories") == true)
116 _error
->Error(_("Use --allow-insecure-repositories to force the update"));
117 TransactionManager
->AbortTransaction();
118 I
->Status
= pkgAcquire::Item::StatError
;
122 static HashStringList
GetExpectedHashesFromFor(metaIndex
* const Parser
, std::string
const &MetaKey
)/*{{{*/
125 return HashStringList();
126 metaIndex::checkSum
* const R
= Parser
->Lookup(MetaKey
);
128 return HashStringList();
133 // all ::HashesRequired and ::GetExpectedHashes implementations /*{{{*/
134 /* ::GetExpectedHashes is abstract and has to be implemented by all subclasses.
135 It is best to implement it as broadly as possible, while ::HashesRequired defaults
136 to true and should be as restrictive as possible for false cases. Note that if
137 a hash is returned by ::GetExpectedHashes it must match. Only if it doesn't
138 ::HashesRequired is called to evaluate if its okay to have no hashes. */
139 APT_CONST
bool pkgAcqTransactionItem::HashesRequired() const
141 /* signed repositories obviously have a parser and good hashes.
142 unsigned repositories, too, as even if we can't trust them for security,
143 we can at least trust them for integrity of the download itself.
144 Only repositories without a Release file can (obviously) not have
145 hashes – and they are very uncommon and strongly discouraged */
146 return TransactionManager
->MetaIndexParser
!= NULL
&&
147 TransactionManager
->MetaIndexParser
->GetLoadedSuccessfully() != metaIndex::TRI_UNSET
;
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
, 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 APT_OVERRIDE
{return Target
.URI
;};
394 virtual HashStringList
GetExpectedHashes() const APT_OVERRIDE
{return HashStringList();};
396 NoActionItem(pkgAcquire
* const Owner
, IndexTarget
const &Target
) :
397 pkgAcquire::Item(Owner
), Target(Target
)
400 DestFile
= GetFinalFileNameFromURI(Target
.URI
);
405 // Acquire::Item::Item - Constructor /*{{{*/
406 APT_IGNORE_DEPRECATED_PUSH
407 pkgAcquire::Item::Item(pkgAcquire
* const owner
) :
408 FileSize(0), PartialSize(0), Mode(0), ID(0), Complete(false), Local(false),
409 QueueCounter(0), ExpectedAdditionalItems(0), Owner(owner
), d(NULL
)
414 APT_IGNORE_DEPRECATED_POP
416 // Acquire::Item::~Item - Destructor /*{{{*/
417 pkgAcquire::Item::~Item()
422 std::string
pkgAcquire::Item::Custom600Headers() const /*{{{*/
424 return std::string();
427 std::string
pkgAcquire::Item::ShortDesc() const /*{{{*/
432 APT_CONST
void pkgAcquire::Item::Finished() /*{{{*/
436 APT_PURE pkgAcquire
* pkgAcquire::Item::GetOwner() const /*{{{*/
441 APT_CONST
pkgAcquire::ItemDesc
&pkgAcquire::Item::GetItemDesc() /*{{{*/
446 APT_CONST
bool pkgAcquire::Item::IsTrusted() const /*{{{*/
451 // Acquire::Item::Failed - Item failed to download /*{{{*/
452 // ---------------------------------------------------------------------
453 /* We return to an idle state if there are still other queues that could
455 void pkgAcquire::Item::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)
457 if(ErrorText
.empty())
458 ErrorText
= LookupTag(Message
,"Message");
459 if (QueueCounter
<= 1)
461 /* This indicates that the file is not available right now but might
462 be sometime later. If we do a retry cycle then this should be
464 if (Cnf
!= NULL
&& Cnf
->LocalOnly
== true &&
465 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
481 case StatTransientNetworkError
:
488 string
const FailReason
= LookupTag(Message
, "FailReason");
489 if (FailReason
== "MaximumSizeExceeded")
490 RenameOnError(MaximumSizeExceeded
);
491 else if (Status
== StatAuthError
)
492 RenameOnError(HashSumMismatch
);
494 // report mirror failure back to LP if we actually use a mirror
495 if (FailReason
.empty() == false)
496 ReportMirrorFailure(FailReason
);
498 ReportMirrorFailure(ErrorText
);
500 if (QueueCounter
> 1)
504 // Acquire::Item::Start - Item has begun to download /*{{{*/
505 // ---------------------------------------------------------------------
506 /* Stash status and the file size. Note that setting Complete means
507 sub-phases of the acquire process such as decompresion are operating */
508 void pkgAcquire::Item::Start(string
const &/*Message*/, unsigned long long const Size
)
510 Status
= StatFetching
;
512 if (FileSize
== 0 && Complete
== false)
516 // Acquire::Item::VerifyDone - check if Item was downloaded OK /*{{{*/
517 /* Note that hash-verification is 'hardcoded' in acquire-worker and has
518 * already passed if this method is called. */
519 bool pkgAcquire::Item::VerifyDone(std::string
const &Message
,
520 pkgAcquire::MethodConfig
const * const /*Cnf*/)
522 std::string
const FileName
= LookupTag(Message
,"Filename");
523 if (FileName
.empty() == true)
526 ErrorText
= "Method gave a blank filename";
533 // Acquire::Item::Done - Item downloaded OK /*{{{*/
534 void pkgAcquire::Item::Done(string
const &/*Message*/, HashStringList
const &Hashes
,
535 pkgAcquire::MethodConfig
const * const /*Cnf*/)
537 // We just downloaded something..
540 unsigned long long const downloadedSize
= Hashes
.FileSize();
541 if (downloadedSize
!= 0)
543 FileSize
= downloadedSize
;
547 ErrorText
= string();
548 Owner
->Dequeue(this);
551 // Acquire::Item::Rename - Rename a file /*{{{*/
552 // ---------------------------------------------------------------------
553 /* This helper function is used by a lot of item methods as their final
555 bool pkgAcquire::Item::Rename(string
const &From
,string
const &To
)
557 if (From
== To
|| rename(From
.c_str(),To
.c_str()) == 0)
561 strprintf(S
, _("rename failed, %s (%s -> %s)."), strerror(errno
),
562 From
.c_str(),To
.c_str());
564 if (ErrorText
.empty())
567 ErrorText
= ErrorText
+ ": " + S
;
571 void pkgAcquire::Item::Dequeue() /*{{{*/
573 Owner
->Dequeue(this);
576 bool pkgAcquire::Item::RenameOnError(pkgAcquire::Item::RenameOnErrorState
const error
)/*{{{*/
578 if (RealFileExists(DestFile
))
579 Rename(DestFile
, DestFile
+ ".FAILED");
584 case HashSumMismatch
:
585 errtext
= _("Hash Sum mismatch");
586 Status
= StatAuthError
;
587 ReportMirrorFailure("HashChecksumFailure");
590 errtext
= _("Size mismatch");
591 Status
= StatAuthError
;
592 ReportMirrorFailure("SizeFailure");
595 errtext
= _("Invalid file format");
597 // do not report as usually its not the mirrors fault, but Portal/Proxy
600 errtext
= _("Signature error");
604 strprintf(errtext
, _("Clearsigned file isn't valid, got '%s' (does the network require authentication?)"), "NOSPLIT");
605 Status
= StatAuthError
;
607 case MaximumSizeExceeded
:
608 // the method is expected to report a good error for this
612 // no handling here, done by callers
615 if (ErrorText
.empty())
620 void pkgAcquire::Item::SetActiveSubprocess(const std::string
&subprocess
)/*{{{*/
622 ActiveSubprocess
= subprocess
;
623 APT_IGNORE_DEPRECATED(Mode
= ActiveSubprocess
.c_str();)
626 // Acquire::Item::ReportMirrorFailure /*{{{*/
627 void pkgAcquire::Item::ReportMirrorFailure(string
const &FailCode
)
629 // we only act if a mirror was used at all
630 if(UsedMirror
.empty())
633 std::cerr
<< "\nReportMirrorFailure: "
635 << " Uri: " << DescURI()
637 << FailCode
<< std::endl
;
639 string report
= _config
->Find("Methods::Mirror::ProblemReporting",
640 "/usr/lib/apt/apt-report-mirror-failure");
641 if(!FileExists(report
))
644 std::vector
<char const*> Args
;
645 Args
.push_back(report
.c_str());
646 Args
.push_back(UsedMirror
.c_str());
647 Args
.push_back(DescURI().c_str());
648 Args
.push_back(FailCode
.c_str());
649 Args
.push_back(NULL
);
651 pid_t pid
= ExecFork();
654 _error
->Error("ReportMirrorFailure Fork failed");
659 execvp(Args
[0], (char**)Args
.data());
660 std::cerr
<< "Could not exec " << Args
[0] << std::endl
;
663 if(!ExecWait(pid
, "report-mirror-failure"))
665 _error
->Warning("Couldn't report problem to '%s'",
666 _config
->Find("Methods::Mirror::ProblemReporting").c_str());
670 std::string
pkgAcquire::Item::HashSum() const /*{{{*/
672 HashStringList
const hashes
= GetExpectedHashes();
673 HashString
const * const hs
= hashes
.find(NULL
);
674 return hs
!= NULL
? hs
->toStr() : "";
678 pkgAcqTransactionItem::pkgAcqTransactionItem(pkgAcquire
* const Owner
, /*{{{*/
679 pkgAcqMetaClearSig
* const transactionManager
, IndexTarget
const &target
) :
680 pkgAcquire::Item(Owner
), d(NULL
), Target(target
), TransactionManager(transactionManager
)
682 if (TransactionManager
!= this)
683 TransactionManager
->Add(this);
686 pkgAcqTransactionItem::~pkgAcqTransactionItem() /*{{{*/
690 HashStringList
pkgAcqTransactionItem::GetExpectedHashesFor(std::string
const &MetaKey
) const /*{{{*/
692 return GetExpectedHashesFromFor(TransactionManager
->MetaIndexParser
, MetaKey
);
696 // AcqMetaBase - Constructor /*{{{*/
697 pkgAcqMetaBase::pkgAcqMetaBase(pkgAcquire
* const Owner
,
698 pkgAcqMetaClearSig
* const TransactionManager
,
699 std::vector
<IndexTarget
> const &IndexTargets
,
700 IndexTarget
const &DataTarget
)
701 : pkgAcqTransactionItem(Owner
, TransactionManager
, DataTarget
), d(NULL
),
702 IndexTargets(IndexTargets
),
703 AuthPass(false), IMSHit(false)
707 // AcqMetaBase::Add - Add a item to the current Transaction /*{{{*/
708 void pkgAcqMetaBase::Add(pkgAcqTransactionItem
* const I
)
710 Transaction
.push_back(I
);
713 // AcqMetaBase::AbortTransaction - Abort the current Transaction /*{{{*/
714 void pkgAcqMetaBase::AbortTransaction()
716 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
717 std::clog
<< "AbortTransaction: " << TransactionManager
<< std::endl
;
719 // ensure the toplevel is in error state too
720 for (std::vector
<pkgAcqTransactionItem
*>::iterator I
= Transaction
.begin();
721 I
!= Transaction
.end(); ++I
)
723 (*I
)->TransactionState(TransactionAbort
);
728 // AcqMetaBase::TransactionHasError - Check for errors in Transaction /*{{{*/
729 APT_PURE
bool pkgAcqMetaBase::TransactionHasError() const
731 for (std::vector
<pkgAcqTransactionItem
*>::const_iterator I
= Transaction
.begin();
732 I
!= Transaction
.end(); ++I
)
734 switch((*I
)->Status
) {
735 case StatDone
: break;
736 case StatIdle
: break;
737 case StatAuthError
: return true;
738 case StatError
: return true;
739 case StatTransientNetworkError
: return true;
740 case StatFetching
: break;
746 // AcqMetaBase::CommitTransaction - Commit a transaction /*{{{*/
747 void pkgAcqMetaBase::CommitTransaction()
749 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
750 std::clog
<< "CommitTransaction: " << this << std::endl
;
752 // move new files into place *and* remove files that are not
753 // part of the transaction but are still on disk
754 for (std::vector
<pkgAcqTransactionItem
*>::iterator I
= Transaction
.begin();
755 I
!= Transaction
.end(); ++I
)
757 (*I
)->TransactionState(TransactionCommit
);
762 // AcqMetaBase::TransactionStageCopy - Stage a file for copying /*{{{*/
763 void pkgAcqMetaBase::TransactionStageCopy(pkgAcqTransactionItem
* const I
,
764 const std::string
&From
,
765 const std::string
&To
)
767 I
->PartialFile
= From
;
771 // AcqMetaBase::TransactionStageRemoval - Stage a file for removal /*{{{*/
772 void pkgAcqMetaBase::TransactionStageRemoval(pkgAcqTransactionItem
* const I
,
773 const std::string
&FinalFile
)
776 I
->DestFile
= FinalFile
;
779 // AcqMetaBase::GenerateAuthWarning - Check gpg authentication error /*{{{*/
780 bool pkgAcqMetaBase::CheckStopAuthentication(pkgAcquire::Item
* const I
, const std::string
&Message
)
782 // FIXME: this entire function can do now that we disallow going to
783 // a unauthenticated state and can cleanly rollback
785 string
const Final
= I
->GetFinalFilename();
786 if(FileExists(Final
))
788 I
->Status
= StatTransientNetworkError
;
789 _error
->Warning(_("An error occurred during the signature "
790 "verification. The repository is not updated "
791 "and the previous index files will be used. "
792 "GPG error: %s: %s"),
793 Desc
.Description
.c_str(),
794 LookupTag(Message
,"Message").c_str());
795 RunScripts("APT::Update::Auth-Failure");
797 } else if (LookupTag(Message
,"Message").find("NODATA") != string::npos
) {
798 /* Invalid signature file, reject (LP: #346386) (Closes: #627642) */
799 _error
->Error(_("GPG error: %s: %s"),
800 Desc
.Description
.c_str(),
801 LookupTag(Message
,"Message").c_str());
802 I
->Status
= StatAuthError
;
805 _error
->Warning(_("GPG error: %s: %s"),
806 Desc
.Description
.c_str(),
807 LookupTag(Message
,"Message").c_str());
809 // gpgv method failed
810 ReportMirrorFailure("GPGFailure");
814 // AcqMetaBase::Custom600Headers - Get header for AcqMetaBase /*{{{*/
815 // ---------------------------------------------------------------------
816 string
pkgAcqMetaBase::Custom600Headers() const
818 std::string Header
= "\nIndex-File: true";
819 std::string MaximumSize
;
820 strprintf(MaximumSize
, "\nMaximum-Size: %i",
821 _config
->FindI("Acquire::MaxReleaseFileSize", 10*1000*1000));
822 Header
+= MaximumSize
;
824 string
const FinalFile
= GetFinalFilename();
826 if (stat(FinalFile
.c_str(),&Buf
) == 0)
827 Header
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
832 // AcqMetaBase::QueueForSignatureVerify /*{{{*/
833 void pkgAcqMetaBase::QueueForSignatureVerify(pkgAcqTransactionItem
* const I
, std::string
const &File
, std::string
const &Signature
)
836 I
->Desc
.URI
= "gpgv:" + Signature
;
839 I
->SetActiveSubprocess("gpgv");
842 // AcqMetaBase::CheckDownloadDone /*{{{*/
843 bool pkgAcqMetaBase::CheckDownloadDone(pkgAcqTransactionItem
* const I
, const std::string
&Message
, HashStringList
const &Hashes
) const
845 // We have just finished downloading a Release file (it is not
848 std::string
const FileName
= LookupTag(Message
,"Filename");
849 if (FileName
!= I
->DestFile
&& RealFileExists(I
->DestFile
) == false)
852 I
->Desc
.URI
= "copy:" + FileName
;
853 I
->QueueURI(I
->Desc
);
857 // make sure to verify against the right file on I-M-S hit
858 bool IMSHit
= StringToBool(LookupTag(Message
,"IMS-Hit"), false);
859 if (IMSHit
== false && Hashes
.usable())
861 // detect IMS-Hits servers haven't detected by Hash comparison
862 std::string
const FinalFile
= I
->GetFinalFilename();
863 if (RealFileExists(FinalFile
) && Hashes
.VerifyFile(FinalFile
) == true)
866 unlink(I
->DestFile
.c_str());
872 // for simplicity, the transaction manager is always InRelease
873 // even if it doesn't exist.
874 if (TransactionManager
!= NULL
)
875 TransactionManager
->IMSHit
= true;
876 I
->PartialFile
= I
->DestFile
= I
->GetFinalFilename();
879 // set Item to complete as the remaining work is all local (verify etc)
885 bool pkgAcqMetaBase::CheckAuthDone(string
const &Message
) /*{{{*/
887 // At this point, the gpgv method has succeeded, so there is a
888 // valid signature from a key in the trusted keyring. We
889 // perform additional verification of its contents, and use them
890 // to verify the indexes we are about to download
892 if (TransactionManager
->IMSHit
== false)
894 // open the last (In)Release if we have it
895 std::string
const FinalFile
= GetFinalFilename();
896 std::string FinalRelease
;
897 std::string FinalInRelease
;
898 if (APT::String::Endswith(FinalFile
, "InRelease"))
900 FinalInRelease
= FinalFile
;
901 FinalRelease
= FinalFile
.substr(0, FinalFile
.length() - strlen("InRelease")) + "Release";
905 FinalInRelease
= FinalFile
.substr(0, FinalFile
.length() - strlen("Release")) + "InRelease";
906 FinalRelease
= FinalFile
;
908 if (RealFileExists(FinalInRelease
) || RealFileExists(FinalRelease
))
910 TransactionManager
->LastMetaIndexParser
= TransactionManager
->MetaIndexParser
->UnloadedClone();
911 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
913 _error
->PushToStack();
914 if (RealFileExists(FinalInRelease
))
915 TransactionManager
->LastMetaIndexParser
->Load(FinalInRelease
, NULL
);
917 TransactionManager
->LastMetaIndexParser
->Load(FinalRelease
, NULL
);
918 // its unlikely to happen, but if what we have is bad ignore it
919 if (_error
->PendingError())
921 delete TransactionManager
->LastMetaIndexParser
;
922 TransactionManager
->LastMetaIndexParser
= NULL
;
924 _error
->RevertToStack();
929 if (TransactionManager
->MetaIndexParser
->Load(DestFile
, &ErrorText
) == false)
931 Status
= StatAuthError
;
935 if (!VerifyVendor(Message
))
937 Status
= StatAuthError
;
941 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
942 std::cerr
<< "Signature verification succeeded: "
943 << DestFile
<< std::endl
;
945 // Download further indexes with verification
951 void pkgAcqMetaBase::QueueIndexes(bool const verify
) /*{{{*/
953 // at this point the real Items are loaded in the fetcher
954 ExpectedAdditionalItems
= 0;
956 for (std::vector
<IndexTarget
>::const_iterator Target
= IndexTargets
.begin();
957 Target
!= IndexTargets
.end();
960 bool trypdiff
= _config
->FindB("Acquire::PDiffs", true);
963 if (TransactionManager
->MetaIndexParser
->Exists(Target
->MetaKey
) == false)
965 // optional targets that we do not have in the Release file are skipped
966 if (Target
->IsOptional
)
969 Status
= StatAuthError
;
970 strprintf(ErrorText
, _("Unable to find expected entry '%s' in Release file (Wrong sources.list entry or malformed file)"), Target
->MetaKey
.c_str());
974 if (RealFileExists(GetFinalFileNameFromURI(Target
->URI
)))
976 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
978 HashStringList
const newFile
= GetExpectedHashesFromFor(TransactionManager
->MetaIndexParser
, Target
->MetaKey
);
979 HashStringList
const oldFile
= GetExpectedHashesFromFor(TransactionManager
->LastMetaIndexParser
, Target
->MetaKey
);
980 if (newFile
== oldFile
)
982 // we have the file already, no point in trying to acquire it again
983 new NoActionItem(Owner
, *Target
);
987 else if (TransactionManager
->IMSHit
== true)
989 // we have the file already, no point in trying to acquire it again
990 new NoActionItem(Owner
, *Target
);
995 trypdiff
= false; // no file to patch
997 // check if we have patches available
998 trypdiff
&= TransactionManager
->MetaIndexParser
->Exists(Target
->MetaKey
+ ".diff/Index");
1000 // if we have no file to patch, no point in trying
1001 trypdiff
&= RealFileExists(GetFinalFileNameFromURI(Target
->URI
));
1003 // no point in patching from local sources
1006 std::string
const proto
= Target
->URI
.substr(0, strlen("file:/"));
1007 if (proto
== "file:/" || proto
== "copy:/" || proto
== "cdrom:")
1011 // Queue the Index file (Packages, Sources, Translation-$foo, …)
1013 new pkgAcqDiffIndex(Owner
, TransactionManager
, *Target
);
1015 new pkgAcqIndex(Owner
, TransactionManager
, *Target
);
1019 bool pkgAcqMetaBase::VerifyVendor(string
const &Message
) /*{{{*/
1021 string::size_type pos
;
1023 // check for missing sigs (that where not fatal because otherwise we had
1026 string msg
= _("There is no public key available for the "
1027 "following key IDs:\n");
1028 pos
= Message
.find("NO_PUBKEY ");
1029 if (pos
!= std::string::npos
)
1031 string::size_type start
= pos
+strlen("NO_PUBKEY ");
1032 string Fingerprint
= Message
.substr(start
, Message
.find("\n")-start
);
1033 missingkeys
+= (Fingerprint
);
1035 if(!missingkeys
.empty())
1036 _error
->Warning("%s", (msg
+ missingkeys
).c_str());
1038 string Transformed
= TransactionManager
->MetaIndexParser
->GetExpectedDist();
1040 if (Transformed
== "../project/experimental")
1042 Transformed
= "experimental";
1045 pos
= Transformed
.rfind('/');
1046 if (pos
!= string::npos
)
1048 Transformed
= Transformed
.substr(0, pos
);
1051 if (Transformed
== ".")
1056 if (TransactionManager
->MetaIndexParser
->GetValidUntil() > 0)
1058 time_t const invalid_since
= time(NULL
) - TransactionManager
->MetaIndexParser
->GetValidUntil();
1059 if (invalid_since
> 0)
1063 // TRANSLATOR: The first %s is the URL of the bad Release file, the second is
1064 // the time since then the file is invalid - formatted in the same way as in
1065 // the download progress display (e.g. 7d 3h 42min 1s)
1066 _("Release file for %s is expired (invalid since %s). "
1067 "Updates for this repository will not be applied."),
1068 Target
.URI
.c_str(), TimeToStr(invalid_since
).c_str());
1069 if (ErrorText
.empty())
1071 return _error
->Error("%s", errmsg
.c_str());
1075 /* Did we get a file older than what we have? This is a last minute IMS hit and doubles
1076 as a prevention of downgrading us to older (still valid) files */
1077 if (TransactionManager
->IMSHit
== false && TransactionManager
->LastMetaIndexParser
!= NULL
&&
1078 TransactionManager
->LastMetaIndexParser
->GetDate() > TransactionManager
->MetaIndexParser
->GetDate())
1080 TransactionManager
->IMSHit
= true;
1081 unlink(DestFile
.c_str());
1082 PartialFile
= DestFile
= GetFinalFilename();
1083 // load the 'old' file in the 'new' one instead of flipping pointers as
1084 // the new one isn't owned by us, while the old one is so cleanup would be confused.
1085 TransactionManager
->MetaIndexParser
->swapLoad(TransactionManager
->LastMetaIndexParser
);
1086 delete TransactionManager
->LastMetaIndexParser
;
1087 TransactionManager
->LastMetaIndexParser
= NULL
;
1090 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1092 std::cerr
<< "Got Codename: " << TransactionManager
->MetaIndexParser
->GetCodename() << std::endl
;
1093 std::cerr
<< "Expecting Dist: " << TransactionManager
->MetaIndexParser
->GetExpectedDist() << std::endl
;
1094 std::cerr
<< "Transformed Dist: " << Transformed
<< std::endl
;
1097 if (TransactionManager
->MetaIndexParser
->CheckDist(Transformed
) == false)
1099 // This might become fatal one day
1100 // Status = StatAuthError;
1101 // ErrorText = "Conflicting distribution; expected "
1102 // + MetaIndexParser->GetExpectedDist() + " but got "
1103 // + MetaIndexParser->GetCodename();
1105 if (!Transformed
.empty())
1107 _error
->Warning(_("Conflicting distribution: %s (expected %s but got %s)"),
1108 Desc
.Description
.c_str(),
1109 Transformed
.c_str(),
1110 TransactionManager
->MetaIndexParser
->GetCodename().c_str());
1117 pkgAcqMetaBase::~pkgAcqMetaBase()
1121 pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire
* const Owner
, /*{{{*/
1122 IndexTarget
const &ClearsignedTarget
,
1123 IndexTarget
const &DetachedDataTarget
, IndexTarget
const &DetachedSigTarget
,
1124 std::vector
<IndexTarget
> const &IndexTargets
,
1125 metaIndex
* const MetaIndexParser
) :
1126 pkgAcqMetaIndex(Owner
, this, ClearsignedTarget
, DetachedSigTarget
, IndexTargets
),
1127 d(NULL
), ClearsignedTarget(ClearsignedTarget
),
1128 DetachedDataTarget(DetachedDataTarget
),
1129 MetaIndexParser(MetaIndexParser
), LastMetaIndexParser(NULL
)
1131 // index targets + (worst case:) Release/Release.gpg
1132 ExpectedAdditionalItems
= IndexTargets
.size() + 2;
1133 TransactionManager
->Add(this);
1136 pkgAcqMetaClearSig::~pkgAcqMetaClearSig() /*{{{*/
1138 if (LastMetaIndexParser
!= NULL
)
1139 delete LastMetaIndexParser
;
1142 // pkgAcqMetaClearSig::Custom600Headers - Insert custom request headers /*{{{*/
1143 string
pkgAcqMetaClearSig::Custom600Headers() const
1145 string Header
= pkgAcqMetaBase::Custom600Headers();
1146 Header
+= "\nFail-Ignore: true";
1147 std::string
const key
= TransactionManager
->MetaIndexParser
->GetSignedBy();
1148 if (key
.empty() == false)
1149 Header
+= "\nSigned-By: " + key
;
1154 bool pkgAcqMetaClearSig::VerifyDone(std::string
const &Message
,
1155 pkgAcquire::MethodConfig
const * const Cnf
)
1157 Item::VerifyDone(Message
, Cnf
);
1159 if (FileExists(DestFile
) && !StartsWithGPGClearTextSignature(DestFile
))
1160 return RenameOnError(NotClearsigned
);
1164 // pkgAcqMetaClearSig::Done - We got a file /*{{{*/
1165 void pkgAcqMetaClearSig::Done(std::string
const &Message
,
1166 HashStringList
const &Hashes
,
1167 pkgAcquire::MethodConfig
const * const Cnf
)
1169 Item::Done(Message
, Hashes
, Cnf
);
1171 if(AuthPass
== false)
1173 if(CheckDownloadDone(this, Message
, Hashes
) == true)
1174 QueueForSignatureVerify(this, DestFile
, DestFile
);
1177 else if(CheckAuthDone(Message
) == true)
1179 if (TransactionManager
->IMSHit
== false)
1180 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
1181 else if (RealFileExists(GetFinalFilename()) == false)
1183 // We got an InRelease file IMSHit, but we haven't one, which means
1184 // we had a valid Release/Release.gpg combo stepping in, which we have
1185 // to 'acquire' now to ensure list cleanup isn't removing them
1186 new NoActionItem(Owner
, DetachedDataTarget
);
1187 new NoActionItem(Owner
, DetachedSigTarget
);
1192 void pkgAcqMetaClearSig::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
) /*{{{*/
1194 Item::Failed(Message
, Cnf
);
1196 // we failed, we will not get additional items from this method
1197 ExpectedAdditionalItems
= 0;
1199 if (AuthPass
== false)
1201 if (Status
== StatAuthError
)
1203 // if we expected a ClearTextSignature (InRelease) and got a file,
1204 // but it wasn't valid we end up here (see VerifyDone).
1205 // As these is usually called by web-portals we do not try Release/Release.gpg
1206 // as this is gonna fail anyway and instead abort our try (LP#346386)
1207 TransactionManager
->AbortTransaction();
1211 // Queue the 'old' InRelease file for removal if we try Release.gpg
1212 // as otherwise the file will stay around and gives a false-auth
1213 // impression (CVE-2012-0214)
1214 TransactionManager
->TransactionStageRemoval(this, GetFinalFilename());
1217 new pkgAcqMetaIndex(Owner
, TransactionManager
, DetachedDataTarget
, DetachedSigTarget
, IndexTargets
);
1221 if(CheckStopAuthentication(this, Message
))
1224 _error
->Warning(_("The data from '%s' is not signed. Packages "
1225 "from that repository can not be authenticated."),
1226 ClearsignedTarget
.Description
.c_str());
1228 // No Release file was present, or verification failed, so fall
1229 // back to queueing Packages files without verification
1230 // only allow going further if the users explicitely wants it
1231 if(AllowInsecureRepositories(TransactionManager
->MetaIndexParser
, TransactionManager
, this) == true)
1235 /* InRelease files become Release files, otherwise
1236 * they would be considered as trusted later on */
1237 string
const FinalRelease
= GetFinalFileNameFromURI(DetachedDataTarget
.URI
);
1238 string
const PartialRelease
= GetPartialFileNameFromURI(DetachedDataTarget
.URI
);
1239 string
const FinalReleasegpg
= GetFinalFileNameFromURI(DetachedSigTarget
.URI
);
1240 string
const FinalInRelease
= GetFinalFilename();
1241 Rename(DestFile
, PartialRelease
);
1242 TransactionManager
->TransactionStageCopy(this, PartialRelease
, FinalRelease
);
1244 if (RealFileExists(FinalReleasegpg
) || RealFileExists(FinalInRelease
))
1246 // open the last Release if we have it
1247 if (TransactionManager
->IMSHit
== false)
1249 TransactionManager
->LastMetaIndexParser
= TransactionManager
->MetaIndexParser
->UnloadedClone();
1250 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1252 _error
->PushToStack();
1253 if (RealFileExists(FinalInRelease
))
1254 TransactionManager
->LastMetaIndexParser
->Load(FinalInRelease
, NULL
);
1256 TransactionManager
->LastMetaIndexParser
->Load(FinalRelease
, NULL
);
1257 // its unlikely to happen, but if what we have is bad ignore it
1258 if (_error
->PendingError())
1260 delete TransactionManager
->LastMetaIndexParser
;
1261 TransactionManager
->LastMetaIndexParser
= NULL
;
1263 _error
->RevertToStack();
1268 // we parse the indexes here because at this point the user wanted
1269 // a repository that may potentially harm him
1270 if (TransactionManager
->MetaIndexParser
->Load(PartialRelease
, &ErrorText
) == false || VerifyVendor(Message
) == false)
1271 /* expired Release files are still a problem you need extra force for */;
1279 pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire
* const Owner
, /*{{{*/
1280 pkgAcqMetaClearSig
* const TransactionManager
,
1281 IndexTarget
const &DataTarget
,
1282 IndexTarget
const &DetachedSigTarget
,
1283 vector
<IndexTarget
> const &IndexTargets
) :
1284 pkgAcqMetaBase(Owner
, TransactionManager
, IndexTargets
, DataTarget
), d(NULL
),
1285 DetachedSigTarget(DetachedSigTarget
)
1287 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1288 std::clog
<< "New pkgAcqMetaIndex with TransactionManager "
1289 << this->TransactionManager
<< std::endl
;
1291 DestFile
= GetPartialFileNameFromURI(DataTarget
.URI
);
1294 Desc
.Description
= DataTarget
.Description
;
1296 Desc
.ShortDesc
= DataTarget
.ShortDesc
;
1297 Desc
.URI
= DataTarget
.URI
;
1299 // we expect more item
1300 ExpectedAdditionalItems
= IndexTargets
.size();
1304 void pkgAcqMetaIndex::Done(string
const &Message
, /*{{{*/
1305 HashStringList
const &Hashes
,
1306 pkgAcquire::MethodConfig
const * const Cfg
)
1308 Item::Done(Message
,Hashes
,Cfg
);
1310 if(CheckDownloadDone(this, Message
, Hashes
))
1312 // we have a Release file, now download the Signature, all further
1313 // verify/queue for additional downloads will be done in the
1314 // pkgAcqMetaSig::Done() code
1315 new pkgAcqMetaSig(Owner
, TransactionManager
, DetachedSigTarget
, this);
1319 // pkgAcqMetaIndex::Failed - no Release file present /*{{{*/
1320 void pkgAcqMetaIndex::Failed(string
const &Message
,
1321 pkgAcquire::MethodConfig
const * const Cnf
)
1323 pkgAcquire::Item::Failed(Message
, Cnf
);
1326 _error
->Warning(_("The repository '%s' does not have a Release file. "
1327 "This is deprecated, please contact the owner of the "
1328 "repository."), Target
.Description
.c_str());
1330 // No Release file was present so fall
1331 // back to queueing Packages files without verification
1332 // only allow going further if the users explicitely wants it
1333 if(AllowInsecureRepositories(TransactionManager
->MetaIndexParser
, TransactionManager
, this) == true)
1335 // ensure old Release files are removed
1336 TransactionManager
->TransactionStageRemoval(this, GetFinalFilename());
1338 // queue without any kind of hashsum support
1339 QueueIndexes(false);
1343 void pkgAcqMetaIndex::Finished() /*{{{*/
1345 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1346 std::clog
<< "Finished: " << DestFile
<<std::endl
;
1347 if(TransactionManager
!= NULL
&&
1348 TransactionManager
->TransactionHasError() == false)
1349 TransactionManager
->CommitTransaction();
1352 std::string
pkgAcqMetaIndex::DescURI() const /*{{{*/
1357 pkgAcqMetaIndex::~pkgAcqMetaIndex() {}
1359 // AcqMetaSig::AcqMetaSig - Constructor /*{{{*/
1360 pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire
* const Owner
,
1361 pkgAcqMetaClearSig
* const TransactionManager
,
1362 IndexTarget
const &Target
,
1363 pkgAcqMetaIndex
* const MetaIndex
) :
1364 pkgAcqTransactionItem(Owner
, TransactionManager
, Target
), d(NULL
), MetaIndex(MetaIndex
)
1366 DestFile
= GetPartialFileNameFromURI(Target
.URI
);
1368 // remove any partial downloaded sig-file in partial/.
1369 // it may confuse proxies and is too small to warrant a
1370 // partial download anyway
1371 unlink(DestFile
.c_str());
1373 // set the TransactionManager
1374 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1375 std::clog
<< "New pkgAcqMetaSig with TransactionManager "
1376 << TransactionManager
<< std::endl
;
1379 Desc
.Description
= Target
.Description
;
1381 Desc
.ShortDesc
= Target
.ShortDesc
;
1382 Desc
.URI
= Target
.URI
;
1384 // If we got a hit for Release, we will get one for Release.gpg too (or obscure errors),
1385 // so we skip the download step and go instantly to verification
1386 if (TransactionManager
->IMSHit
== true && RealFileExists(GetFinalFilename()))
1390 PartialFile
= DestFile
= GetFinalFilename();
1391 MetaIndexFileSignature
= DestFile
;
1392 MetaIndex
->QueueForSignatureVerify(this, MetaIndex
->DestFile
, DestFile
);
1398 pkgAcqMetaSig::~pkgAcqMetaSig() /*{{{*/
1402 // pkgAcqMetaSig::Custom600Headers - Insert custom request headers /*{{{*/
1403 std::string
pkgAcqMetaSig::Custom600Headers() const
1405 std::string Header
= pkgAcqTransactionItem::Custom600Headers();
1406 std::string
const key
= TransactionManager
->MetaIndexParser
->GetSignedBy();
1407 if (key
.empty() == false)
1408 Header
+= "\nSigned-By: " + key
;
1412 // AcqMetaSig::Done - The signature was downloaded/verified /*{{{*/
1413 void pkgAcqMetaSig::Done(string
const &Message
, HashStringList
const &Hashes
,
1414 pkgAcquire::MethodConfig
const * const Cfg
)
1416 if (MetaIndexFileSignature
.empty() == false)
1418 DestFile
= MetaIndexFileSignature
;
1419 MetaIndexFileSignature
.clear();
1421 Item::Done(Message
, Hashes
, Cfg
);
1423 if(MetaIndex
->AuthPass
== false)
1425 if(MetaIndex
->CheckDownloadDone(this, Message
, Hashes
) == true)
1427 // destfile will be modified to point to MetaIndexFile for the
1428 // gpgv method, so we need to save it here
1429 MetaIndexFileSignature
= DestFile
;
1430 MetaIndex
->QueueForSignatureVerify(this, MetaIndex
->DestFile
, DestFile
);
1434 else if(MetaIndex
->CheckAuthDone(Message
) == true)
1436 if (TransactionManager
->IMSHit
== false)
1438 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
1439 TransactionManager
->TransactionStageCopy(MetaIndex
, MetaIndex
->DestFile
, MetaIndex
->GetFinalFilename());
1444 void pkgAcqMetaSig::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
1446 Item::Failed(Message
,Cnf
);
1448 // check if we need to fail at this point
1449 if (MetaIndex
->AuthPass
== true && MetaIndex
->CheckStopAuthentication(this, Message
))
1452 string
const FinalRelease
= MetaIndex
->GetFinalFilename();
1453 string
const FinalReleasegpg
= GetFinalFilename();
1454 string
const FinalInRelease
= TransactionManager
->GetFinalFilename();
1456 if (RealFileExists(FinalReleasegpg
) || RealFileExists(FinalInRelease
))
1458 std::string downgrade_msg
;
1459 strprintf(downgrade_msg
, _("The repository '%s' is no longer signed."),
1460 MetaIndex
->Target
.Description
.c_str());
1461 if(_config
->FindB("Acquire::AllowDowngradeToInsecureRepositories"))
1463 // meh, the users wants to take risks (we still mark the packages
1464 // from this repository as unauthenticated)
1465 _error
->Warning("%s", downgrade_msg
.c_str());
1466 _error
->Warning(_("This is normally not allowed, but the option "
1467 "Acquire::AllowDowngradeToInsecureRepositories was "
1468 "given to override it."));
1471 _error
->Error("%s", downgrade_msg
.c_str());
1472 if (TransactionManager
->IMSHit
== false)
1473 Rename(MetaIndex
->DestFile
, MetaIndex
->DestFile
+ ".FAILED");
1474 Item::Failed("Message: " + downgrade_msg
, Cnf
);
1475 TransactionManager
->AbortTransaction();
1480 _error
->Warning(_("The data from '%s' is not signed. Packages "
1481 "from that repository can not be authenticated."),
1482 MetaIndex
->Target
.Description
.c_str());
1484 // ensures that a Release.gpg file in the lists/ is removed by the transaction
1485 TransactionManager
->TransactionStageRemoval(this, DestFile
);
1487 // only allow going further if the users explicitely wants it
1488 if(AllowInsecureRepositories(TransactionManager
->MetaIndexParser
, TransactionManager
, this) == true)
1490 if (RealFileExists(FinalReleasegpg
) || RealFileExists(FinalInRelease
))
1492 // open the last Release if we have it
1493 if (TransactionManager
->IMSHit
== false)
1495 TransactionManager
->LastMetaIndexParser
= TransactionManager
->MetaIndexParser
->UnloadedClone();
1496 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1498 _error
->PushToStack();
1499 if (RealFileExists(FinalInRelease
))
1500 TransactionManager
->LastMetaIndexParser
->Load(FinalInRelease
, NULL
);
1502 TransactionManager
->LastMetaIndexParser
->Load(FinalRelease
, NULL
);
1503 // its unlikely to happen, but if what we have is bad ignore it
1504 if (_error
->PendingError())
1506 delete TransactionManager
->LastMetaIndexParser
;
1507 TransactionManager
->LastMetaIndexParser
= NULL
;
1509 _error
->RevertToStack();
1514 // we parse the indexes here because at this point the user wanted
1515 // a repository that may potentially harm him
1516 if (TransactionManager
->MetaIndexParser
->Load(MetaIndex
->DestFile
, &ErrorText
) == false || MetaIndex
->VerifyVendor(Message
) == false)
1517 /* expired Release files are still a problem you need extra force for */;
1519 MetaIndex
->QueueIndexes(true);
1521 TransactionManager
->TransactionStageCopy(MetaIndex
, MetaIndex
->DestFile
, MetaIndex
->GetFinalFilename());
1524 // FIXME: this is used often (e.g. in pkgAcqIndexTrans) so refactor
1525 if (Cnf
->LocalOnly
== true ||
1526 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1535 // AcqBaseIndex - Constructor /*{{{*/
1536 pkgAcqBaseIndex::pkgAcqBaseIndex(pkgAcquire
* const Owner
,
1537 pkgAcqMetaClearSig
* const TransactionManager
,
1538 IndexTarget
const &Target
)
1539 : pkgAcqTransactionItem(Owner
, TransactionManager
, Target
), d(NULL
)
1543 pkgAcqBaseIndex::~pkgAcqBaseIndex() {}
1545 // AcqDiffIndex::AcqDiffIndex - Constructor /*{{{*/
1546 // ---------------------------------------------------------------------
1547 /* Get the DiffIndex file first and see if there are patches available
1548 * If so, create a pkgAcqIndexDiffs fetcher that will get and apply the
1549 * patches. If anything goes wrong in that process, it will fall back to
1550 * the original packages file
1552 pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire
* const Owner
,
1553 pkgAcqMetaClearSig
* const TransactionManager
,
1554 IndexTarget
const &Target
)
1555 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
), diffs(NULL
)
1557 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
1560 Desc
.Description
= Target
.Description
+ ".diff/Index";
1561 Desc
.ShortDesc
= Target
.ShortDesc
;
1562 Desc
.URI
= Target
.URI
+ ".diff/Index";
1564 DestFile
= GetPartialFileNameFromURI(Desc
.URI
);
1567 std::clog
<< "pkgAcqDiffIndex: " << Desc
.URI
<< std::endl
;
1572 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
1573 // ---------------------------------------------------------------------
1574 /* The only header we use is the last-modified header. */
1575 string
pkgAcqDiffIndex::Custom600Headers() const
1577 string
const Final
= GetFinalFilename();
1580 std::clog
<< "Custom600Header-IMS: " << Final
<< std::endl
;
1583 if (stat(Final
.c_str(),&Buf
) != 0)
1584 return "\nIndex-File: true";
1586 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1589 void pkgAcqDiffIndex::QueueOnIMSHit() const /*{{{*/
1591 // list cleanup needs to know that this file as well as the already
1592 // present index is ours, so we create an empty diff to save it for us
1593 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
);
1596 bool pkgAcqDiffIndex::ParseDiffIndex(string
const &IndexDiffFile
) /*{{{*/
1598 // failing here is fine: our caller will take care of trying to
1599 // get the complete file if patching fails
1601 std::clog
<< "pkgAcqDiffIndex::ParseIndexDiff() " << IndexDiffFile
1604 FileFd
Fd(IndexDiffFile
,FileFd::ReadOnly
);
1606 if (_error
->PendingError() == true)
1610 if(unlikely(TF
.Step(Tags
) == false))
1613 HashStringList ServerHashes
;
1614 unsigned long long ServerSize
= 0;
1616 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
1618 std::string tagname
= *type
;
1619 tagname
.append("-Current");
1620 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1621 if (tmp
.empty() == true)
1625 unsigned long long size
;
1626 std::stringstream
ss(tmp
);
1628 if (unlikely(hash
.empty() == true))
1630 if (unlikely(ServerSize
!= 0 && ServerSize
!= size
))
1632 ServerHashes
.push_back(HashString(*type
, hash
));
1636 if (ServerHashes
.usable() == false)
1639 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": Did not find a good hashsum in the index" << std::endl
;
1643 std::string
const CurrentPackagesFile
= GetFinalFileNameFromURI(Target
.URI
);
1644 HashStringList
const TargetFileHashes
= GetExpectedHashesFor(Target
.MetaKey
);
1645 if (TargetFileHashes
.usable() == false || ServerHashes
!= TargetFileHashes
)
1649 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": Index has different hashes than parser, probably older, so fail pdiffing" << std::endl
;
1650 printHashSumComparision(CurrentPackagesFile
, ServerHashes
, TargetFileHashes
);
1655 HashStringList LocalHashes
;
1656 // try avoiding calculating the hash here as this is costly
1657 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1658 LocalHashes
= GetExpectedHashesFromFor(TransactionManager
->LastMetaIndexParser
, Target
.MetaKey
);
1659 if (LocalHashes
.usable() == false)
1661 FileFd
fd(CurrentPackagesFile
, FileFd::ReadOnly
);
1662 Hashes
LocalHashesCalc(ServerHashes
);
1663 LocalHashesCalc
.AddFD(fd
);
1664 LocalHashes
= LocalHashesCalc
.GetHashStringList();
1667 if (ServerHashes
== LocalHashes
)
1669 // we have the same sha1 as the server so we are done here
1671 std::clog
<< "pkgAcqDiffIndex: Package file " << CurrentPackagesFile
<< " is up-to-date" << std::endl
;
1677 std::clog
<< "Server-Current: " << ServerHashes
.find(NULL
)->toStr() << " and we start at "
1678 << CurrentPackagesFile
<< " " << LocalHashes
.FileSize() << " " << LocalHashes
.find(NULL
)->toStr() << std::endl
;
1680 // parse all of (provided) history
1681 vector
<DiffInfo
> available_patches
;
1682 bool firstAcceptedHashes
= true;
1683 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
1685 if (LocalHashes
.find(*type
) == NULL
)
1688 std::string tagname
= *type
;
1689 tagname
.append("-History");
1690 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1691 if (tmp
.empty() == true)
1694 string hash
, filename
;
1695 unsigned long long size
;
1696 std::stringstream
ss(tmp
);
1698 while (ss
>> hash
>> size
>> filename
)
1700 if (unlikely(hash
.empty() == true || filename
.empty() == true))
1703 // see if we have a record for this file already
1704 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
1705 for (; cur
!= available_patches
.end(); ++cur
)
1707 if (cur
->file
!= filename
)
1709 cur
->result_hashes
.push_back(HashString(*type
, hash
));
1712 if (cur
!= available_patches
.end())
1714 if (firstAcceptedHashes
== true)
1717 next
.file
= filename
;
1718 next
.result_hashes
.push_back(HashString(*type
, hash
));
1719 next
.result_hashes
.FileSize(size
);
1720 available_patches
.push_back(next
);
1725 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
1726 << " wasn't in the list for the first parsed hash! (history)" << std::endl
;
1730 firstAcceptedHashes
= false;
1733 if (unlikely(available_patches
.empty() == true))
1736 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": "
1737 << "Couldn't find any patches for the patch series." << std::endl
;
1741 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
1743 if (LocalHashes
.find(*type
) == NULL
)
1746 std::string tagname
= *type
;
1747 tagname
.append("-Patches");
1748 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1749 if (tmp
.empty() == true)
1752 string hash
, filename
;
1753 unsigned long long size
;
1754 std::stringstream
ss(tmp
);
1756 while (ss
>> hash
>> size
>> filename
)
1758 if (unlikely(hash
.empty() == true || filename
.empty() == true))
1761 // see if we have a record for this file already
1762 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
1763 for (; cur
!= available_patches
.end(); ++cur
)
1765 if (cur
->file
!= filename
)
1767 if (cur
->patch_hashes
.empty())
1768 cur
->patch_hashes
.FileSize(size
);
1769 cur
->patch_hashes
.push_back(HashString(*type
, hash
));
1772 if (cur
!= available_patches
.end())
1775 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
1776 << " wasn't in the list for the first parsed hash! (patches)" << std::endl
;
1781 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
1783 std::string tagname
= *type
;
1784 tagname
.append("-Download");
1785 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1786 if (tmp
.empty() == true)
1789 string hash
, filename
;
1790 unsigned long long size
;
1791 std::stringstream
ss(tmp
);
1793 // FIXME: all of pdiff supports only .gz compressed patches
1794 while (ss
>> hash
>> size
>> filename
)
1796 if (unlikely(hash
.empty() == true || filename
.empty() == true))
1798 if (unlikely(APT::String::Endswith(filename
, ".gz") == false))
1800 filename
.erase(filename
.length() - 3);
1802 // see if we have a record for this file already
1803 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
1804 for (; cur
!= available_patches
.end(); ++cur
)
1806 if (cur
->file
!= filename
)
1808 if (cur
->download_hashes
.empty())
1809 cur
->download_hashes
.FileSize(size
);
1810 cur
->download_hashes
.push_back(HashString(*type
, hash
));
1813 if (cur
!= available_patches
.end())
1816 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
1817 << " wasn't in the list for the first parsed hash! (download)" << std::endl
;
1823 bool foundStart
= false;
1824 for (std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
1825 cur
!= available_patches
.end(); ++cur
)
1827 if (LocalHashes
!= cur
->result_hashes
)
1830 available_patches
.erase(available_patches
.begin(), cur
);
1835 if (foundStart
== false || unlikely(available_patches
.empty() == true))
1838 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": "
1839 << "Couldn't find the start of the patch series." << std::endl
;
1843 // patching with too many files is rather slow compared to a fast download
1844 unsigned long const fileLimit
= _config
->FindI("Acquire::PDiffs::FileLimit", 0);
1845 if (fileLimit
!= 0 && fileLimit
< available_patches
.size())
1848 std::clog
<< "Need " << available_patches
.size() << " diffs (Limit is " << fileLimit
1849 << ") so fallback to complete download" << std::endl
;
1853 // calculate the size of all patches we have to get
1854 // note that all sizes are uncompressed, while we download compressed files
1855 unsigned long long patchesSize
= 0;
1856 for (std::vector
<DiffInfo
>::const_iterator cur
= available_patches
.begin();
1857 cur
!= available_patches
.end(); ++cur
)
1858 patchesSize
+= cur
->patch_hashes
.FileSize();
1859 unsigned long long const sizeLimit
= ServerSize
* _config
->FindI("Acquire::PDiffs::SizeLimit", 100);
1860 if (sizeLimit
> 0 && (sizeLimit
/100) < patchesSize
)
1863 std::clog
<< "Need " << patchesSize
<< " bytes (Limit is " << sizeLimit
/100
1864 << ") so fallback to complete download" << std::endl
;
1868 // we have something, queue the diffs
1869 string::size_type
const last_space
= Description
.rfind(" ");
1870 if(last_space
!= string::npos
)
1871 Description
.erase(last_space
, Description
.size()-last_space
);
1873 /* decide if we should download patches one by one or in one go:
1874 The first is good if the server merges patches, but many don't so client
1875 based merging can be attempt in which case the second is better.
1876 "bad things" will happen if patches are merged on the server,
1877 but client side merging is attempt as well */
1878 bool pdiff_merge
= _config
->FindB("Acquire::PDiffs::Merge", true);
1879 if (pdiff_merge
== true)
1881 // reprepro adds this flag if it has merged patches on the server
1882 std::string
const precedence
= Tags
.FindS("X-Patch-Precedence");
1883 pdiff_merge
= (precedence
!= "merged");
1886 if (pdiff_merge
== false)
1887 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
, available_patches
);
1890 diffs
= new std::vector
<pkgAcqIndexMergeDiffs
*>(available_patches
.size());
1891 for(size_t i
= 0; i
< available_patches
.size(); ++i
)
1892 (*diffs
)[i
] = new pkgAcqIndexMergeDiffs(Owner
, TransactionManager
,
1894 available_patches
[i
],
1904 void pkgAcqDiffIndex::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
1906 Item::Failed(Message
,Cnf
);
1910 std::clog
<< "pkgAcqDiffIndex failed: " << Desc
.URI
<< " with " << Message
<< std::endl
1911 << "Falling back to normal index file acquire" << std::endl
;
1913 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
1916 void pkgAcqDiffIndex::Done(string
const &Message
,HashStringList
const &Hashes
, /*{{{*/
1917 pkgAcquire::MethodConfig
const * const Cnf
)
1920 std::clog
<< "pkgAcqDiffIndex::Done(): " << Desc
.URI
<< std::endl
;
1922 Item::Done(Message
, Hashes
, Cnf
);
1924 string
const FinalFile
= GetFinalFilename();
1925 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false))
1926 DestFile
= FinalFile
;
1928 if(ParseDiffIndex(DestFile
) == false)
1930 Failed("Message: Couldn't parse pdiff index", Cnf
);
1931 // queue for final move - this should happen even if we fail
1932 // while parsing (e.g. on sizelimit) and download the complete file.
1933 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
1937 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
1946 pkgAcqDiffIndex::~pkgAcqDiffIndex()
1952 // AcqIndexDiffs::AcqIndexDiffs - Constructor /*{{{*/
1953 // ---------------------------------------------------------------------
1954 /* The package diff is added to the queue. one object is constructed
1955 * for each diff and the index
1957 pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire
* const Owner
,
1958 pkgAcqMetaClearSig
* const TransactionManager
,
1959 IndexTarget
const &Target
,
1960 vector
<DiffInfo
> const &diffs
)
1961 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
),
1962 available_patches(diffs
)
1964 DestFile
= GetPartialFileNameFromURI(Target
.URI
);
1966 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
1969 Description
= Target
.Description
;
1970 Desc
.ShortDesc
= Target
.ShortDesc
;
1972 if(available_patches
.empty() == true)
1974 // we are done (yeah!), check hashes against the final file
1975 DestFile
= GetFinalFileNameFromURI(Target
.URI
);
1980 // patching needs to be bootstrapped with the 'old' version
1981 std::string
const PartialFile
= GetPartialFileNameFromURI(Target
.URI
);
1982 if (RealFileExists(PartialFile
) == false)
1984 if (symlink(GetFinalFilename().c_str(), PartialFile
.c_str()) != 0)
1986 Failed("Link creation of " + PartialFile
+ " to " + GetFinalFilename() + " failed", NULL
);
1991 // get the next diff
1992 State
= StateFetchDiff
;
1997 void pkgAcqIndexDiffs::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
1999 Item::Failed(Message
,Cnf
);
2003 std::clog
<< "pkgAcqIndexDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
2004 << "Falling back to normal index file acquire" << std::endl
;
2005 DestFile
= GetPartialFileNameFromURI(Target
.URI
);
2006 RenameOnError(PDiffError
);
2007 std::string
const patchname
= GetDiffsPatchFileName(DestFile
);
2008 if (RealFileExists(patchname
))
2009 rename(patchname
.c_str(), std::string(patchname
+ ".FAILED").c_str());
2010 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
2014 // Finish - helper that cleans the item out of the fetcher queue /*{{{*/
2015 void pkgAcqIndexDiffs::Finish(bool allDone
)
2018 std::clog
<< "pkgAcqIndexDiffs::Finish(): "
2020 << Desc
.URI
<< std::endl
;
2022 // we restore the original name, this is required, otherwise
2023 // the file will be cleaned
2026 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
2028 // this is for the "real" finish
2033 std::clog
<< "\n\nallDone: " << DestFile
<< "\n" << std::endl
;
2038 std::clog
<< "Finishing: " << Desc
.URI
<< std::endl
;
2045 bool pkgAcqIndexDiffs::QueueNextDiff() /*{{{*/
2047 // calc sha1 of the just patched file
2048 std::string
const FinalFile
= GetPartialFileNameFromURI(Target
.URI
);
2050 if(!FileExists(FinalFile
))
2052 Failed("Message: No FinalFile " + FinalFile
+ " available", NULL
);
2056 FileFd
fd(FinalFile
, FileFd::ReadOnly
);
2057 Hashes LocalHashesCalc
;
2058 LocalHashesCalc
.AddFD(fd
);
2059 HashStringList
const LocalHashes
= LocalHashesCalc
.GetHashStringList();
2062 std::clog
<< "QueueNextDiff: " << FinalFile
<< " (" << LocalHashes
.find(NULL
)->toStr() << ")" << std::endl
;
2064 HashStringList
const TargetFileHashes
= GetExpectedHashesFor(Target
.MetaKey
);
2065 if (unlikely(LocalHashes
.usable() == false || TargetFileHashes
.usable() == false))
2067 Failed("Local/Expected hashes are not usable", NULL
);
2072 // final file reached before all patches are applied
2073 if(LocalHashes
== TargetFileHashes
)
2079 // remove all patches until the next matching patch is found
2080 // this requires the Index file to be ordered
2081 for(vector
<DiffInfo
>::iterator I
= available_patches
.begin();
2082 available_patches
.empty() == false &&
2083 I
!= available_patches
.end() &&
2084 I
->result_hashes
!= LocalHashes
;
2087 available_patches
.erase(I
);
2090 // error checking and falling back if no patch was found
2091 if(available_patches
.empty() == true)
2093 Failed("No patches left to reach target", NULL
);
2097 // queue the right diff
2098 Desc
.URI
= Target
.URI
+ ".diff/" + available_patches
[0].file
+ ".gz";
2099 Desc
.Description
= Description
+ " " + available_patches
[0].file
+ string(".pdiff");
2100 DestFile
= GetPartialFileNameFromURI(Target
.URI
+ ".diff/" + available_patches
[0].file
);
2103 std::clog
<< "pkgAcqIndexDiffs::QueueNextDiff(): " << Desc
.URI
<< std::endl
;
2110 void pkgAcqIndexDiffs::Done(string
const &Message
, HashStringList
const &Hashes
, /*{{{*/
2111 pkgAcquire::MethodConfig
const * const Cnf
)
2114 std::clog
<< "pkgAcqIndexDiffs::Done(): " << Desc
.URI
<< std::endl
;
2116 Item::Done(Message
, Hashes
, Cnf
);
2118 std::string
const FinalFile
= GetPartialFileNameFromURI(Target
.URI
);
2119 std::string
const PatchFile
= GetDiffsPatchFileName(FinalFile
);
2121 // success in downloading a diff, enter ApplyDiff state
2122 if(State
== StateFetchDiff
)
2124 Rename(DestFile
, PatchFile
);
2127 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
2129 State
= StateApplyDiff
;
2131 Desc
.URI
= "rred:" + FinalFile
;
2133 SetActiveSubprocess("rred");
2137 // success in download/apply a diff, queue next (if needed)
2138 if(State
== StateApplyDiff
)
2140 // remove the just applied patch
2141 available_patches
.erase(available_patches
.begin());
2142 unlink(PatchFile
.c_str());
2147 std::clog
<< "Moving patched file in place: " << std::endl
2148 << DestFile
<< " -> " << FinalFile
<< std::endl
;
2150 Rename(DestFile
,FinalFile
);
2151 chmod(FinalFile
.c_str(),0644);
2153 // see if there is more to download
2154 if(available_patches
.empty() == false) {
2155 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
,
2160 DestFile
= FinalFile
;
2161 return Finish(true);
2165 std::string
pkgAcqIndexDiffs::Custom600Headers() const /*{{{*/
2167 if(State
!= StateApplyDiff
)
2168 return pkgAcqBaseIndex::Custom600Headers();
2169 std::ostringstream patchhashes
;
2170 HashStringList
const ExpectedHashes
= available_patches
[0].patch_hashes
;
2171 for (HashStringList::const_iterator hs
= ExpectedHashes
.begin(); hs
!= ExpectedHashes
.end(); ++hs
)
2172 patchhashes
<< "\nPatch-0-" << hs
->HashType() << "-Hash: " << hs
->HashValue();
2173 patchhashes
<< pkgAcqBaseIndex::Custom600Headers();
2174 return patchhashes
.str();
2177 pkgAcqIndexDiffs::~pkgAcqIndexDiffs() {}
2179 // AcqIndexMergeDiffs::AcqIndexMergeDiffs - Constructor /*{{{*/
2180 pkgAcqIndexMergeDiffs::pkgAcqIndexMergeDiffs(pkgAcquire
* const Owner
,
2181 pkgAcqMetaClearSig
* const TransactionManager
,
2182 IndexTarget
const &Target
,
2183 DiffInfo
const &patch
,
2184 std::vector
<pkgAcqIndexMergeDiffs
*> const * const allPatches
)
2185 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
),
2186 patch(patch
), allPatches(allPatches
), State(StateFetchDiff
)
2188 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
2191 Description
= Target
.Description
;
2192 Desc
.ShortDesc
= Target
.ShortDesc
;
2194 Desc
.URI
= Target
.URI
+ ".diff/" + patch
.file
+ ".gz";
2195 Desc
.Description
= Description
+ " " + patch
.file
+ string(".pdiff");
2197 DestFile
= GetPartialFileNameFromURI(Target
.URI
+ ".diff/" + patch
.file
);
2200 std::clog
<< "pkgAcqIndexMergeDiffs: " << Desc
.URI
<< std::endl
;
2205 void pkgAcqIndexMergeDiffs::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
2208 std::clog
<< "pkgAcqIndexMergeDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
;
2210 Item::Failed(Message
,Cnf
);
2213 // check if we are the first to fail, otherwise we are done here
2214 State
= StateDoneDiff
;
2215 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2216 I
!= allPatches
->end(); ++I
)
2217 if ((*I
)->State
== StateErrorDiff
)
2220 // first failure means we should fallback
2221 State
= StateErrorDiff
;
2223 std::clog
<< "Falling back to normal index file acquire" << std::endl
;
2224 DestFile
= GetPartialFileNameFromURI(Target
.URI
);
2225 RenameOnError(PDiffError
);
2226 std::string
const patchname
= GetMergeDiffsPatchFileName(DestFile
, patch
.file
);
2227 if (RealFileExists(patchname
))
2228 rename(patchname
.c_str(), std::string(patchname
+ ".FAILED").c_str());
2229 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
2232 void pkgAcqIndexMergeDiffs::Done(string
const &Message
, HashStringList
const &Hashes
, /*{{{*/
2233 pkgAcquire::MethodConfig
const * const Cnf
)
2236 std::clog
<< "pkgAcqIndexMergeDiffs::Done(): " << Desc
.URI
<< std::endl
;
2238 Item::Done(Message
, Hashes
, Cnf
);
2240 string
const FinalFile
= GetPartialFileNameFromURI(Target
.URI
);
2241 if (State
== StateFetchDiff
)
2243 Rename(DestFile
, GetMergeDiffsPatchFileName(FinalFile
, patch
.file
));
2245 // check if this is the last completed diff
2246 State
= StateDoneDiff
;
2247 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2248 I
!= allPatches
->end(); ++I
)
2249 if ((*I
)->State
!= StateDoneDiff
)
2252 std::clog
<< "Not the last done diff in the batch: " << Desc
.URI
<< std::endl
;
2256 // this is the last completed diff, so we are ready to apply now
2257 State
= StateApplyDiff
;
2259 // patching needs to be bootstrapped with the 'old' version
2260 if (symlink(GetFinalFilename().c_str(), FinalFile
.c_str()) != 0)
2262 Failed("Link creation of " + FinalFile
+ " to " + GetFinalFilename() + " failed", NULL
);
2267 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
2270 Desc
.URI
= "rred:" + FinalFile
;
2272 SetActiveSubprocess("rred");
2275 // success in download/apply all diffs, clean up
2276 else if (State
== StateApplyDiff
)
2278 // move the result into place
2279 std::string
const Final
= GetFinalFilename();
2281 std::clog
<< "Queue patched file in place: " << std::endl
2282 << DestFile
<< " -> " << Final
<< std::endl
;
2284 // queue for copy by the transaction manager
2285 TransactionManager
->TransactionStageCopy(this, DestFile
, Final
);
2287 // ensure the ed's are gone regardless of list-cleanup
2288 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2289 I
!= allPatches
->end(); ++I
)
2291 std::string
const PartialFile
= GetPartialFileNameFromURI(Target
.URI
);
2292 std::string
const patch
= GetMergeDiffsPatchFileName(PartialFile
, (*I
)->patch
.file
);
2293 unlink(patch
.c_str());
2295 unlink(FinalFile
.c_str());
2300 std::clog
<< "allDone: " << DestFile
<< "\n" << std::endl
;
2304 std::string
pkgAcqIndexMergeDiffs::Custom600Headers() const /*{{{*/
2306 if(State
!= StateApplyDiff
)
2307 return pkgAcqBaseIndex::Custom600Headers();
2308 std::ostringstream patchhashes
;
2309 unsigned int seen_patches
= 0;
2310 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2311 I
!= allPatches
->end(); ++I
)
2313 HashStringList
const ExpectedHashes
= (*I
)->patch
.patch_hashes
;
2314 for (HashStringList::const_iterator hs
= ExpectedHashes
.begin(); hs
!= ExpectedHashes
.end(); ++hs
)
2315 patchhashes
<< "\nPatch-" << seen_patches
<< "-" << hs
->HashType() << "-Hash: " << hs
->HashValue();
2318 patchhashes
<< pkgAcqBaseIndex::Custom600Headers();
2319 return patchhashes
.str();
2322 pkgAcqIndexMergeDiffs::~pkgAcqIndexMergeDiffs() {}
2324 // AcqIndex::AcqIndex - Constructor /*{{{*/
2325 pkgAcqIndex::pkgAcqIndex(pkgAcquire
* const Owner
,
2326 pkgAcqMetaClearSig
* const TransactionManager
,
2327 IndexTarget
const &Target
)
2328 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
), Stage(STAGE_DOWNLOAD
)
2330 // autoselect the compression method
2331 AutoSelectCompression();
2332 Init(Target
.URI
, Target
.Description
, Target
.ShortDesc
);
2334 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
2335 std::clog
<< "New pkgIndex with TransactionManager "
2336 << TransactionManager
<< std::endl
;
2339 // AcqIndex::AutoSelectCompression - Select compression /*{{{*/
2340 void pkgAcqIndex::AutoSelectCompression()
2342 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
2343 CompressionExtensions
= "";
2344 if (TransactionManager
->MetaIndexParser
!= NULL
&& TransactionManager
->MetaIndexParser
->Exists(Target
.MetaKey
))
2346 for (std::vector
<std::string
>::const_iterator t
= types
.begin();
2347 t
!= types
.end(); ++t
)
2349 std::string CompressedMetaKey
= string(Target
.MetaKey
).append(".").append(*t
);
2350 if (*t
== "uncompressed" ||
2351 TransactionManager
->MetaIndexParser
->Exists(CompressedMetaKey
) == true)
2352 CompressionExtensions
.append(*t
).append(" ");
2357 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
2358 CompressionExtensions
.append(*t
).append(" ");
2360 if (CompressionExtensions
.empty() == false)
2361 CompressionExtensions
.erase(CompressionExtensions
.end()-1);
2364 // AcqIndex::Init - defered Constructor /*{{{*/
2365 void pkgAcqIndex::Init(string
const &URI
, string
const &URIDesc
,
2366 string
const &ShortDesc
)
2368 Stage
= STAGE_DOWNLOAD
;
2370 DestFile
= GetPartialFileNameFromURI(URI
);
2372 size_t const nextExt
= CompressionExtensions
.find(' ');
2373 if (nextExt
== std::string::npos
)
2375 CurrentCompressionExtension
= CompressionExtensions
;
2376 CompressionExtensions
.clear();
2380 CurrentCompressionExtension
= CompressionExtensions
.substr(0, nextExt
);
2381 CompressionExtensions
= CompressionExtensions
.substr(nextExt
+1);
2384 if (CurrentCompressionExtension
== "uncompressed")
2388 else if (unlikely(CurrentCompressionExtension
.empty()))
2392 Desc
.URI
= URI
+ '.' + CurrentCompressionExtension
;
2393 DestFile
= DestFile
+ '.' + CurrentCompressionExtension
;
2396 if(TransactionManager
->MetaIndexParser
!= NULL
)
2397 InitByHashIfNeeded();
2399 Desc
.Description
= URIDesc
;
2401 Desc
.ShortDesc
= ShortDesc
;
2406 // AcqIndex::AdjustForByHash - modify URI for by-hash support /*{{{*/
2407 void pkgAcqIndex::InitByHashIfNeeded()
2410 // - (maybe?) add support for by-hash into the sources.list as flag
2411 // - make apt-ftparchive generate the hashes (and expire?)
2412 std::string HostKnob
= "APT::Acquire::" + ::URI(Desc
.URI
).Host
+ "::By-Hash";
2413 if(_config
->FindB("APT::Acquire::By-Hash", false) == true ||
2414 _config
->FindB(HostKnob
, false) == true ||
2415 TransactionManager
->MetaIndexParser
->GetSupportsAcquireByHash())
2417 HashStringList
const Hashes
= GetExpectedHashes();
2420 // FIXME: should we really use the best hash here? or a fixed one?
2421 HashString
const * const TargetHash
= Hashes
.find("");
2422 std::string
const ByHash
= "/by-hash/" + TargetHash
->HashType() + "/" + TargetHash
->HashValue();
2423 size_t const trailing_slash
= Desc
.URI
.find_last_of("/");
2424 Desc
.URI
= Desc
.URI
.replace(
2426 Desc
.URI
.substr(trailing_slash
+1).size()+1,
2430 "Fetching ByHash requested but can not find record for %s",
2431 GetMetaKey().c_str());
2436 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
2437 // ---------------------------------------------------------------------
2438 /* The only header we use is the last-modified header. */
2439 string
pkgAcqIndex::Custom600Headers() const
2441 string Final
= GetFinalFilename();
2443 string msg
= "\nIndex-File: true";
2445 if (stat(Final
.c_str(),&Buf
) == 0)
2446 msg
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
2448 if(Target
.IsOptional
)
2449 msg
+= "\nFail-Ignore: true";
2454 // AcqIndex::Failed - getting the indexfile failed /*{{{*/
2455 void pkgAcqIndex::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)
2457 Item::Failed(Message
,Cnf
);
2459 // authorisation matches will not be fixed by other compression types
2460 if (Status
!= StatAuthError
)
2462 if (CompressionExtensions
.empty() == false)
2464 Init(Target
.URI
, Desc
.Description
, Desc
.ShortDesc
);
2470 if(Target
.IsOptional
&& GetExpectedHashes().empty() && Stage
== STAGE_DOWNLOAD
)
2473 TransactionManager
->AbortTransaction();
2476 // AcqIndex::ReverifyAfterIMS - Reverify index after an ims-hit /*{{{*/
2477 void pkgAcqIndex::ReverifyAfterIMS()
2479 // update destfile to *not* include the compression extension when doing
2480 // a reverify (as its uncompressed on disk already)
2481 DestFile
= GetCompressedFileName(Target
, GetPartialFileNameFromURI(Target
.URI
), CurrentCompressionExtension
);
2483 // copy FinalFile into partial/ so that we check the hash again
2484 string FinalFile
= GetFinalFilename();
2485 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
2486 Desc
.URI
= "copy:" + FinalFile
;
2490 // AcqIndex::Done - Finished a fetch /*{{{*/
2491 // ---------------------------------------------------------------------
2492 /* This goes through a number of states.. On the initial fetch the
2493 method could possibly return an alternate filename which points
2494 to the uncompressed version of the file. If this is so the file
2495 is copied into the partial directory. In all other cases the file
2496 is decompressed with a compressed uri. */
2497 void pkgAcqIndex::Done(string
const &Message
,
2498 HashStringList
const &Hashes
,
2499 pkgAcquire::MethodConfig
const * const Cfg
)
2501 Item::Done(Message
,Hashes
,Cfg
);
2505 case STAGE_DOWNLOAD
:
2506 StageDownloadDone(Message
, Hashes
, Cfg
);
2508 case STAGE_DECOMPRESS_AND_VERIFY
:
2509 StageDecompressDone(Message
, Hashes
, Cfg
);
2514 // AcqIndex::StageDownloadDone - Queue for decompress and verify /*{{{*/
2515 void pkgAcqIndex::StageDownloadDone(string
const &Message
, HashStringList
const &,
2516 pkgAcquire::MethodConfig
const * const)
2520 // Handle the unzipd case
2521 std::string FileName
= LookupTag(Message
,"Alt-Filename");
2522 if (FileName
.empty() == false)
2524 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
2526 DestFile
+= ".decomp";
2527 Desc
.URI
= "copy:" + FileName
;
2529 SetActiveSubprocess("copy");
2532 FileName
= LookupTag(Message
,"Filename");
2534 // Methods like e.g. "file:" will give us a (compressed) FileName that is
2535 // not the "DestFile" we set, in this case we uncompress from the local file
2536 if (FileName
!= DestFile
&& RealFileExists(DestFile
) == false)
2539 EraseFileName
= FileName
;
2541 // we need to verify the file against the current Release file again
2542 // on if-modfied-since hit to avoid a stale attack against us
2543 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
2545 // The files timestamp matches, reverify by copy into partial/
2551 // If we want compressed indexes, just copy in place for hash verification
2552 if (Target
.KeepCompressed
== true)
2554 DestFile
= GetPartialFileNameFromURI(Target
.URI
+ '.' + CurrentCompressionExtension
);
2556 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
2557 Desc
.URI
= "copy:" + FileName
;
2559 SetActiveSubprocess("copy");
2563 // get the binary name for your used compression type
2565 if(CurrentCompressionExtension
== "uncompressed")
2566 decompProg
= "copy";
2568 decompProg
= _config
->Find(string("Acquire::CompressionTypes::").append(CurrentCompressionExtension
),"");
2569 if(decompProg
.empty() == true)
2571 _error
->Error("Unsupported extension: %s", CurrentCompressionExtension
.c_str());
2575 // queue uri for the next stage
2576 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
2577 DestFile
+= ".decomp";
2578 Desc
.URI
= decompProg
+ ":" + FileName
;
2580 SetActiveSubprocess(decompProg
);
2583 // AcqIndex::StageDecompressDone - Final verification /*{{{*/
2584 void pkgAcqIndex::StageDecompressDone(string
const &,
2585 HashStringList
const &,
2586 pkgAcquire::MethodConfig
const * const)
2588 // Done, queue for rename on transaction finished
2589 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
2593 pkgAcqIndex::~pkgAcqIndex() {}
2596 // AcqArchive::AcqArchive - Constructor /*{{{*/
2597 // ---------------------------------------------------------------------
2598 /* This just sets up the initial fetch environment and queues the first
2600 pkgAcqArchive::pkgAcqArchive(pkgAcquire
* const Owner
,pkgSourceList
* const Sources
,
2601 pkgRecords
* const Recs
,pkgCache::VerIterator
const &Version
,
2602 string
&StoreFilename
) :
2603 Item(Owner
), d(NULL
), LocalSource(false), Version(Version
), Sources(Sources
), Recs(Recs
),
2604 StoreFilename(StoreFilename
), Vf(Version
.FileList()),
2607 Retries
= _config
->FindI("Acquire::Retries",0);
2609 if (Version
.Arch() == 0)
2611 _error
->Error(_("I wasn't able to locate a file for the %s package. "
2612 "This might mean you need to manually fix this package. "
2613 "(due to missing arch)"),
2614 Version
.ParentPkg().FullName().c_str());
2618 /* We need to find a filename to determine the extension. We make the
2619 assumption here that all the available sources for this version share
2620 the same extension.. */
2621 // Skip not source sources, they do not have file fields.
2622 for (; Vf
.end() == false; ++Vf
)
2624 if (Vf
.File().Flagged(pkgCache::Flag::NotSource
))
2629 // Does not really matter here.. we are going to fail out below
2630 if (Vf
.end() != true)
2632 // If this fails to get a file name we will bomb out below.
2633 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2634 if (_error
->PendingError() == true)
2637 // Generate the final file name as: package_version_arch.foo
2638 StoreFilename
= QuoteString(Version
.ParentPkg().Name(),"_:") + '_' +
2639 QuoteString(Version
.VerStr(),"_:") + '_' +
2640 QuoteString(Version
.Arch(),"_:.") +
2641 "." + flExtension(Parse
.FileName());
2644 // check if we have one trusted source for the package. if so, switch
2645 // to "TrustedOnly" mode - but only if not in AllowUnauthenticated mode
2646 bool const allowUnauth
= _config
->FindB("APT::Get::AllowUnauthenticated", false);
2647 bool const debugAuth
= _config
->FindB("Debug::pkgAcquire::Auth", false);
2648 bool seenUntrusted
= false;
2649 for (pkgCache::VerFileIterator i
= Version
.FileList(); i
.end() == false; ++i
)
2651 pkgIndexFile
*Index
;
2652 if (Sources
->FindIndex(i
.File(),Index
) == false)
2655 if (debugAuth
== true)
2656 std::cerr
<< "Checking index: " << Index
->Describe()
2657 << "(Trusted=" << Index
->IsTrusted() << ")" << std::endl
;
2659 if (Index
->IsTrusted() == true)
2662 if (allowUnauth
== false)
2666 seenUntrusted
= true;
2669 // "allow-unauthenticated" restores apts old fetching behaviour
2670 // that means that e.g. unauthenticated file:// uris are higher
2671 // priority than authenticated http:// uris
2672 if (allowUnauth
== true && seenUntrusted
== true)
2676 if (QueueNext() == false && _error
->PendingError() == false)
2677 _error
->Error(_("Can't find a source to download version '%s' of '%s'"),
2678 Version
.VerStr(), Version
.ParentPkg().FullName(false).c_str());
2681 // AcqArchive::QueueNext - Queue the next file source /*{{{*/
2682 // ---------------------------------------------------------------------
2683 /* This queues the next available file version for download. It checks if
2684 the archive is already available in the cache and stashs the MD5 for
2686 bool pkgAcqArchive::QueueNext()
2688 for (; Vf
.end() == false; ++Vf
)
2690 pkgCache::PkgFileIterator
const PkgF
= Vf
.File();
2691 // Ignore not source sources
2692 if (PkgF
.Flagged(pkgCache::Flag::NotSource
))
2695 // Try to cross match against the source list
2696 pkgIndexFile
*Index
;
2697 if (Sources
->FindIndex(PkgF
, Index
) == false)
2699 LocalSource
= PkgF
.Flagged(pkgCache::Flag::LocalSource
);
2701 // only try to get a trusted package from another source if that source
2703 if(Trusted
&& !Index
->IsTrusted())
2706 // Grab the text package record
2707 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2708 if (_error
->PendingError() == true)
2711 string PkgFile
= Parse
.FileName();
2712 ExpectedHashes
= Parse
.Hashes();
2714 if (PkgFile
.empty() == true)
2715 return _error
->Error(_("The package index files are corrupted. No Filename: "
2716 "field for package %s."),
2717 Version
.ParentPkg().Name());
2719 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
2720 Desc
.Description
= Index
->ArchiveInfo(Version
);
2722 Desc
.ShortDesc
= Version
.ParentPkg().FullName(true);
2724 // See if we already have the file. (Legacy filenames)
2725 FileSize
= Version
->Size
;
2726 string FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile
);
2728 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2730 // Make sure the size matches
2731 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2736 StoreFilename
= DestFile
= FinalFile
;
2740 /* Hmm, we have a file and its size does not match, this means it is
2741 an old style mismatched arch */
2742 unlink(FinalFile
.c_str());
2745 // Check it again using the new style output filenames
2746 FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
2747 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2749 // Make sure the size matches
2750 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2755 StoreFilename
= DestFile
= FinalFile
;
2759 /* Hmm, we have a file and its size does not match, this shouldn't
2761 unlink(FinalFile
.c_str());
2764 DestFile
= _config
->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename
);
2766 // Check the destination file
2767 if (stat(DestFile
.c_str(),&Buf
) == 0)
2769 // Hmm, the partial file is too big, erase it
2770 if ((unsigned long long)Buf
.st_size
> Version
->Size
)
2771 unlink(DestFile
.c_str());
2773 PartialSize
= Buf
.st_size
;
2776 // Disables download of archives - useful if no real installation follows,
2777 // e.g. if we are just interested in proposed installation order
2778 if (_config
->FindB("Debug::pkgAcqArchive::NoQueue", false) == true)
2783 StoreFilename
= DestFile
= FinalFile
;
2797 // AcqArchive::Done - Finished fetching /*{{{*/
2798 // ---------------------------------------------------------------------
2800 void pkgAcqArchive::Done(string
const &Message
, HashStringList
const &Hashes
,
2801 pkgAcquire::MethodConfig
const * const Cfg
)
2803 Item::Done(Message
, Hashes
, Cfg
);
2805 // Grab the output filename
2806 std::string
const FileName
= LookupTag(Message
,"Filename");
2807 if (DestFile
!= FileName
&& RealFileExists(DestFile
) == false)
2809 StoreFilename
= DestFile
= FileName
;
2815 // Done, move it into position
2816 string
const FinalFile
= GetFinalFilename();
2817 Rename(DestFile
,FinalFile
);
2818 StoreFilename
= DestFile
= FinalFile
;
2822 // AcqArchive::Failed - Failure handler /*{{{*/
2823 // ---------------------------------------------------------------------
2824 /* Here we try other sources */
2825 void pkgAcqArchive::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)
2827 Item::Failed(Message
,Cnf
);
2829 /* We don't really want to retry on failed media swaps, this prevents
2830 that. An interesting observation is that permanent failures are not
2832 if (Cnf
->Removable
== true &&
2833 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2835 // Vf = Version.FileList();
2836 while (Vf
.end() == false) ++Vf
;
2837 StoreFilename
= string();
2842 if (QueueNext() == false)
2844 // This is the retry counter
2846 Cnf
->LocalOnly
== false &&
2847 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2850 Vf
= Version
.FileList();
2851 if (QueueNext() == true)
2855 StoreFilename
= string();
2860 APT_PURE
bool pkgAcqArchive::IsTrusted() const /*{{{*/
2865 void pkgAcqArchive::Finished() /*{{{*/
2867 if (Status
== pkgAcquire::Item::StatDone
&&
2870 StoreFilename
= string();
2873 std::string
pkgAcqArchive::DescURI() const /*{{{*/
2878 std::string
pkgAcqArchive::ShortDesc() const /*{{{*/
2880 return Desc
.ShortDesc
;
2883 pkgAcqArchive::~pkgAcqArchive() {}
2885 // AcqChangelog::pkgAcqChangelog - Constructors /*{{{*/
2886 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire
* const Owner
, pkgCache::VerIterator
const &Ver
,
2887 std::string
const &DestDir
, std::string
const &DestFilename
) :
2888 pkgAcquire::Item(Owner
), d(NULL
), SrcName(Ver
.SourcePkgName()), SrcVersion(Ver
.SourceVerStr())
2890 Desc
.URI
= URI(Ver
);
2891 Init(DestDir
, DestFilename
);
2893 // some parameters are char* here as they come likely from char* interfaces – which can also return NULL
2894 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire
* const Owner
, pkgCache::RlsFileIterator
const &RlsFile
,
2895 char const * const Component
, char const * const SrcName
, char const * const SrcVersion
,
2896 const string
&DestDir
, const string
&DestFilename
) :
2897 pkgAcquire::Item(Owner
), d(NULL
), SrcName(SrcName
), SrcVersion(SrcVersion
)
2899 Desc
.URI
= URI(RlsFile
, Component
, SrcName
, SrcVersion
);
2900 Init(DestDir
, DestFilename
);
2902 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire
* const Owner
,
2903 std::string
const &URI
, char const * const SrcName
, char const * const SrcVersion
,
2904 const string
&DestDir
, const string
&DestFilename
) :
2905 pkgAcquire::Item(Owner
), d(NULL
), SrcName(SrcName
), SrcVersion(SrcVersion
)
2908 Init(DestDir
, DestFilename
);
2910 void pkgAcqChangelog::Init(std::string
const &DestDir
, std::string
const &DestFilename
)
2912 if (Desc
.URI
.empty())
2915 // TRANSLATOR: %s=%s is sourcename=sourceversion, e.g. apt=1.1
2916 strprintf(ErrorText
, _("Changelog unavailable for %s=%s"), SrcName
.c_str(), SrcVersion
.c_str());
2917 // Let the error message print something sensible rather than "Failed to fetch /"
2918 if (DestFilename
.empty())
2919 DestFile
= SrcName
+ ".changelog";
2921 DestFile
= DestFilename
;
2922 Desc
.URI
= "changelog:/" + DestFile
;
2926 if (DestDir
.empty())
2928 std::string
const systemTemp
= GetTempDir();
2930 snprintf(tmpname
, sizeof(tmpname
), "%s/apt-changelog-XXXXXX", systemTemp
.c_str());
2931 if (NULL
== mkdtemp(tmpname
))
2933 _error
->Errno("mkdtemp", "mkdtemp failed in changelog acquire of %s %s", SrcName
.c_str(), SrcVersion
.c_str());
2937 DestFile
= TemporaryDirectory
= tmpname
;
2939 std::string SandboxUser
= _config
->Find("APT::Sandbox::User");
2940 ChangeOwnerAndPermissionOfFile("Item::QueueURI", DestFile
.c_str(),
2941 SandboxUser
.c_str(), "root", 0700);
2946 if (DestFilename
.empty())
2947 DestFile
= flCombine(DestFile
, SrcName
+ ".changelog");
2949 DestFile
= flCombine(DestFile
, DestFilename
);
2951 Desc
.ShortDesc
= "Changelog";
2952 strprintf(Desc
.Description
, "%s %s %s Changelog", URI::SiteOnly(Desc
.URI
).c_str(), SrcName
.c_str(), SrcVersion
.c_str());
2957 std::string
pkgAcqChangelog::URI(pkgCache::VerIterator
const &Ver
) /*{{{*/
2959 char const * const SrcName
= Ver
.SourcePkgName();
2960 char const * const SrcVersion
= Ver
.SourceVerStr();
2961 pkgCache::PkgFileIterator PkgFile
;
2962 // find the first source for this version which promises a changelog
2963 for (pkgCache::VerFileIterator VF
= Ver
.FileList(); VF
.end() == false; ++VF
)
2965 pkgCache::PkgFileIterator
const PF
= VF
.File();
2966 if (PF
.Flagged(pkgCache::Flag::NotSource
) || PF
->Release
== 0)
2969 pkgCache::RlsFileIterator
const RF
= PF
.ReleaseFile();
2970 std::string
const uri
= URI(RF
, PF
.Component(), SrcName
, SrcVersion
);
2977 std::string
pkgAcqChangelog::URITemplate(pkgCache::RlsFileIterator
const &Rls
)
2979 if (Rls
.end() == true || (Rls
->Label
== 0 && Rls
->Origin
== 0))
2981 std::string
const serverConfig
= "Acquire::Changelogs::URI";
2983 #define APT_EMPTY_SERVER \
2984 if (server.empty() == false) \
2986 if (server != "no") \
2990 #define APT_CHECK_SERVER(X, Y) \
2993 std::string const specialServerConfig = serverConfig + "::" + Y + #X + "::" + Rls.X(); \
2994 server = _config->Find(specialServerConfig); \
2997 // this way e.g. Debian-Security can fallback to Debian
2998 APT_CHECK_SERVER(Label
, "Override::")
2999 APT_CHECK_SERVER(Origin
, "Override::")
3001 if (RealFileExists(Rls
.FileName()))
3003 _error
->PushToStack();
3005 /* This can be costly. A caller wanting to get millions of URIs might
3006 want to do this on its own once and use Override settings.
3007 We don't do this here as Origin/Label are not as unique as they
3008 should be so this could produce request order-dependent anomalies */
3009 if (OpenMaybeClearSignedFile(Rls
.FileName(), rf
) == true)
3011 pkgTagFile
TagFile(&rf
, rf
.Size());
3012 pkgTagSection Section
;
3013 if (TagFile
.Step(Section
) == true)
3014 server
= Section
.FindS("Changelogs");
3016 _error
->RevertToStack();
3020 APT_CHECK_SERVER(Label
, "")
3021 APT_CHECK_SERVER(Origin
, "")
3022 #undef APT_CHECK_SERVER
3023 #undef APT_EMPTY_SERVER
3026 std::string
pkgAcqChangelog::URI(pkgCache::RlsFileIterator
const &Rls
,
3027 char const * const Component
, char const * const SrcName
,
3028 char const * const SrcVersion
)
3030 return URI(URITemplate(Rls
), Component
, SrcName
, SrcVersion
);
3032 std::string
pkgAcqChangelog::URI(std::string
const &Template
,
3033 char const * const Component
, char const * const SrcName
,
3034 char const * const SrcVersion
)
3036 if (Template
.find("CHANGEPATH") == std::string::npos
)
3039 // the path is: COMPONENT/SRC/SRCNAME/SRCNAME_SRCVER, e.g. main/a/apt/1.1 or contrib/liba/libapt/2.0
3040 std::string Src
= SrcName
;
3041 std::string path
= APT::String::Startswith(SrcName
, "lib") ? Src
.substr(0, 4) : Src
.substr(0,1);
3042 path
.append("/").append(Src
).append("/");
3043 path
.append(Src
).append("_").append(StripEpoch(SrcVersion
));
3044 // we omit component for releases without one (= flat-style repositories)
3045 if (Component
!= NULL
&& strlen(Component
) != 0)
3046 path
= std::string(Component
) + "/" + path
;
3048 return SubstVar(Template
, "CHANGEPATH", path
);
3051 // AcqChangelog::Failed - Failure handler /*{{{*/
3052 void pkgAcqChangelog::Failed(string
const &Message
, pkgAcquire::MethodConfig
const * const Cnf
)
3054 Item::Failed(Message
,Cnf
);
3056 std::string errText
;
3057 // TRANSLATOR: %s=%s is sourcename=sourceversion, e.g. apt=1.1
3058 strprintf(errText
, _("Changelog unavailable for %s=%s"), SrcName
.c_str(), SrcVersion
.c_str());
3060 // Error is probably something techy like 404 Not Found
3061 if (ErrorText
.empty())
3062 ErrorText
= errText
;
3064 ErrorText
= errText
+ " (" + ErrorText
+ ")";
3068 // AcqChangelog::Done - Item downloaded OK /*{{{*/
3069 void pkgAcqChangelog::Done(string
const &Message
,HashStringList
const &CalcHashes
,
3070 pkgAcquire::MethodConfig
const * const Cnf
)
3072 Item::Done(Message
,CalcHashes
,Cnf
);
3077 pkgAcqChangelog::~pkgAcqChangelog() /*{{{*/
3079 if (TemporaryDirectory
.empty() == false)
3081 unlink(DestFile
.c_str());
3082 rmdir(TemporaryDirectory
.c_str());
3087 // AcqFile::pkgAcqFile - Constructor /*{{{*/
3088 pkgAcqFile::pkgAcqFile(pkgAcquire
* const Owner
,string
const &URI
, HashStringList
const &Hashes
,
3089 unsigned long long const Size
,string
const &Dsc
,string
const &ShortDesc
,
3090 const string
&DestDir
, const string
&DestFilename
,
3091 bool const IsIndexFile
) :
3092 Item(Owner
), d(NULL
), IsIndexFile(IsIndexFile
), ExpectedHashes(Hashes
)
3094 Retries
= _config
->FindI("Acquire::Retries",0);
3096 if(!DestFilename
.empty())
3097 DestFile
= DestFilename
;
3098 else if(!DestDir
.empty())
3099 DestFile
= DestDir
+ "/" + flNotDir(URI
);
3101 DestFile
= flNotDir(URI
);
3105 Desc
.Description
= Dsc
;
3108 // Set the short description to the archive component
3109 Desc
.ShortDesc
= ShortDesc
;
3111 // Get the transfer sizes
3114 if (stat(DestFile
.c_str(),&Buf
) == 0)
3116 // Hmm, the partial file is too big, erase it
3117 if ((Size
> 0) && (unsigned long long)Buf
.st_size
> Size
)
3118 unlink(DestFile
.c_str());
3120 PartialSize
= Buf
.st_size
;
3126 // AcqFile::Done - Item downloaded OK /*{{{*/
3127 void pkgAcqFile::Done(string
const &Message
,HashStringList
const &CalcHashes
,
3128 pkgAcquire::MethodConfig
const * const Cnf
)
3130 Item::Done(Message
,CalcHashes
,Cnf
);
3132 std::string
const FileName
= LookupTag(Message
,"Filename");
3135 // The files timestamp matches
3136 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
3139 // We have to copy it into place
3140 if (RealFileExists(DestFile
.c_str()) == false)
3143 if (_config
->FindB("Acquire::Source-Symlinks",true) == false ||
3144 Cnf
->Removable
== true)
3146 Desc
.URI
= "copy:" + FileName
;
3151 // Erase the file if it is a symlink so we can overwrite it
3153 if (lstat(DestFile
.c_str(),&St
) == 0)
3155 if (S_ISLNK(St
.st_mode
) != 0)
3156 unlink(DestFile
.c_str());
3160 if (symlink(FileName
.c_str(),DestFile
.c_str()) != 0)
3162 _error
->PushToStack();
3163 _error
->Errno("pkgAcqFile::Done", "Symlinking file %s failed", DestFile
.c_str());
3164 std::stringstream msg
;
3165 _error
->DumpErrors(msg
);
3166 _error
->RevertToStack();
3167 ErrorText
= msg
.str();
3174 // AcqFile::Failed - Failure handler /*{{{*/
3175 // ---------------------------------------------------------------------
3176 /* Here we try other sources */
3177 void pkgAcqFile::Failed(string
const &Message
, pkgAcquire::MethodConfig
const * const Cnf
)
3179 Item::Failed(Message
,Cnf
);
3181 // This is the retry counter
3183 Cnf
->LocalOnly
== false &&
3184 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
3194 string
pkgAcqFile::Custom600Headers() const /*{{{*/
3197 return "\nIndex-File: true";
3201 pkgAcqFile::~pkgAcqFile() {}