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>
54 static void printHashSumComparision(std::string
const &URI
, HashStringList
const &Expected
, HashStringList
const &Actual
) /*{{{*/
56 if (_config
->FindB("Debug::Acquire::HashSumMismatch", false) == false)
58 std::cerr
<< std::endl
<< URI
<< ":" << std::endl
<< " Expected Hash: " << std::endl
;
59 for (HashStringList::const_iterator hs
= Expected
.begin(); hs
!= Expected
.end(); ++hs
)
60 std::cerr
<< "\t- " << hs
->toStr() << std::endl
;
61 std::cerr
<< " Actual Hash: " << std::endl
;
62 for (HashStringList::const_iterator hs
= Actual
.begin(); hs
!= Actual
.end(); ++hs
)
63 std::cerr
<< "\t- " << hs
->toStr() << std::endl
;
66 static std::string
GetPartialFileName(std::string
const &file
) /*{{{*/
68 std::string DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
73 static std::string
GetPartialFileNameFromURI(std::string
const &uri
) /*{{{*/
75 return GetPartialFileName(URItoFileName(uri
));
78 static std::string
GetFinalFileNameFromURI(std::string
const &uri
) /*{{{*/
80 return _config
->FindDir("Dir::State::lists") + URItoFileName(uri
);
83 static std::string
GetKeepCompressedFileName(std::string file
, IndexTarget
const &Target
)/*{{{*/
85 if (Target
.KeepCompressed
== false)
88 std::string
const CompressionTypes
= Target
.Option(IndexTarget::COMPRESSIONTYPES
);
89 if (CompressionTypes
.empty() == false)
91 std::string
const ext
= CompressionTypes
.substr(0, CompressionTypes
.find(' '));
92 if (ext
!= "uncompressed")
93 file
.append(".").append(ext
);
98 static std::string
GetCompressedFileName(IndexTarget
const &Target
, std::string
const &Name
, std::string
const &Ext
) /*{{{*/
100 if (Ext
.empty() || Ext
== "uncompressed")
103 // do not reverify cdrom sources as apt-cdrom may rewrite the Packages
104 // file when its doing the indexcopy
105 if (Target
.URI
.substr(0,6) == "cdrom:")
108 // adjust DestFile if its compressed on disk
109 if (Target
.KeepCompressed
== true)
110 return Name
+ '.' + Ext
;
114 static std::string
GetMergeDiffsPatchFileName(std::string
const &Final
, std::string
const &Patch
)/*{{{*/
116 // rred expects the patch as $FinalFile.ed.$patchname.gz
117 return Final
+ ".ed." + Patch
+ ".gz";
120 static std::string
GetDiffsPatchFileName(std::string
const &Final
) /*{{{*/
122 // rred expects the patch as $FinalFile.ed
123 return Final
+ ".ed";
126 static bool BootstrapPDiffWith(std::string
const &PartialFile
, std::string
const &FinalFile
, IndexTarget
const &Target
)/*{{{*/
128 // patching needs to be bootstrapped with the 'old' version
129 std::vector
<std::string
> types
= VectorizeString(Target
.Option(IndexTarget::COMPRESSIONTYPES
), ' ');
130 auto typeItr
= types
.cbegin();
131 for (; typeItr
!= types
.cend(); ++typeItr
)
133 std::string Final
= FinalFile
;
134 if (*typeItr
!= "uncompressed")
135 Final
.append(".").append(*typeItr
);
136 if (RealFileExists(Final
) == false)
138 std::string Partial
= PartialFile
;
139 if (*typeItr
!= "uncompressed")
140 Partial
.append(".").append(*typeItr
);
141 if (FileExists(Partial
.c_str()) == true)
143 if (symlink(Final
.c_str(), Partial
.c_str()) != 0)
147 return typeItr
!= types
.cend();
151 static bool MessageInsecureRepository(bool const isError
, std::string
const &msg
)/*{{{*/
155 _error
->Error("%s", msg
.c_str());
156 _error
->Notice("%s", _("Updating from such a repository can't be done securely, and is therefore disabled by default."));
160 _error
->Warning("%s", msg
.c_str());
161 _error
->Notice("%s", _("Data from such a repository can't be authenticated and is therefore potentially dangerous to use."));
163 _error
->Notice("%s", _("See apt-secure(8) manpage for repository creation and user configuration details."));
166 static bool MessageInsecureRepository(bool const isError
, char const * const msg
, std::string
const &repo
)
169 strprintf(m
, msg
, repo
.c_str());
170 return MessageInsecureRepository(isError
, m
);
173 static bool AllowInsecureRepositories(char const * const msg
, std::string
const &repo
,/*{{{*/
174 metaIndex
const * const MetaIndexParser
, pkgAcqMetaClearSig
* const TransactionManager
, pkgAcquire::Item
* const I
)
176 if(MetaIndexParser
->GetTrusted() == metaIndex::TRI_YES
)
179 if (_config
->FindB("Acquire::AllowInsecureRepositories") == true)
181 MessageInsecureRepository(false, msg
, repo
);
185 MessageInsecureRepository(true, msg
, repo
);
186 TransactionManager
->AbortTransaction();
187 I
->Status
= pkgAcquire::Item::StatError
;
191 static HashStringList
GetExpectedHashesFromFor(metaIndex
* const Parser
, std::string
const &MetaKey
)/*{{{*/
194 return HashStringList();
195 metaIndex::checkSum
* const R
= Parser
->Lookup(MetaKey
);
197 return HashStringList();
202 // all ::HashesRequired and ::GetExpectedHashes implementations /*{{{*/
203 /* ::GetExpectedHashes is abstract and has to be implemented by all subclasses.
204 It is best to implement it as broadly as possible, while ::HashesRequired defaults
205 to true and should be as restrictive as possible for false cases. Note that if
206 a hash is returned by ::GetExpectedHashes it must match. Only if it doesn't
207 ::HashesRequired is called to evaluate if its okay to have no hashes. */
208 APT_CONST
bool pkgAcqTransactionItem::HashesRequired() const
210 /* signed repositories obviously have a parser and good hashes.
211 unsigned repositories, too, as even if we can't trust them for security,
212 we can at least trust them for integrity of the download itself.
213 Only repositories without a Release file can (obviously) not have
214 hashes – and they are very uncommon and strongly discouraged */
215 return TransactionManager
->MetaIndexParser
!= NULL
&&
216 TransactionManager
->MetaIndexParser
->GetLoadedSuccessfully() == metaIndex::TRI_YES
;
218 HashStringList
pkgAcqTransactionItem::GetExpectedHashes() const
220 return GetExpectedHashesFor(GetMetaKey());
223 APT_CONST
bool pkgAcqMetaBase::HashesRequired() const
225 // Release and co have no hashes 'by design'.
228 HashStringList
pkgAcqMetaBase::GetExpectedHashes() const
230 return HashStringList();
233 APT_CONST
bool pkgAcqIndexDiffs::HashesRequired() const
235 /* We don't always have the diff of the downloaded pdiff file.
236 What we have for sure is hashes for the uncompressed file,
237 but rred uncompresses them on the fly while parsing, so not handled here.
238 Hashes are (also) checked while searching for (next) patch to apply. */
239 if (State
== StateFetchDiff
)
240 return available_patches
[0].download_hashes
.empty() == false;
243 HashStringList
pkgAcqIndexDiffs::GetExpectedHashes() const
245 if (State
== StateFetchDiff
)
246 return available_patches
[0].download_hashes
;
247 return HashStringList();
250 APT_CONST
bool pkgAcqIndexMergeDiffs::HashesRequired() const
252 /* @see #pkgAcqIndexDiffs::HashesRequired, with the difference that
253 we can check the rred result after all patches are applied as
254 we know the expected result rather than potentially apply more patches */
255 if (State
== StateFetchDiff
)
256 return patch
.download_hashes
.empty() == false;
257 return State
== StateApplyDiff
;
259 HashStringList
pkgAcqIndexMergeDiffs::GetExpectedHashes() const
261 if (State
== StateFetchDiff
)
262 return patch
.download_hashes
;
263 else if (State
== StateApplyDiff
)
264 return GetExpectedHashesFor(Target
.MetaKey
);
265 return HashStringList();
268 APT_CONST
bool pkgAcqArchive::HashesRequired() const
270 return LocalSource
== false;
272 HashStringList
pkgAcqArchive::GetExpectedHashes() const
274 // figured out while parsing the records
275 return ExpectedHashes
;
278 APT_CONST
bool pkgAcqFile::HashesRequired() const
280 // supplied as parameter at creation time, so the caller decides
281 return ExpectedHashes
.usable();
283 HashStringList
pkgAcqFile::GetExpectedHashes() const
285 return ExpectedHashes
;
288 // Acquire::Item::QueueURI and specialisations from child classes /*{{{*/
289 bool pkgAcquire::Item::QueueURI(pkgAcquire::ItemDesc
&Item
)
291 Owner
->Enqueue(Item
);
294 /* The idea here is that an item isn't queued if it exists on disk and the
295 transition manager was a hit as this means that the files it contains
296 the checksums for can't be updated either (or they are and we are asking
297 for a hashsum mismatch to happen which helps nobody) */
298 bool pkgAcqTransactionItem::QueueURI(pkgAcquire::ItemDesc
&Item
)
300 std::string
const FinalFile
= GetFinalFilename();
301 if (TransactionManager
!= NULL
&& TransactionManager
->IMSHit
== true &&
302 FileExists(FinalFile
) == true)
304 PartialFile
= DestFile
= FinalFile
;
308 return pkgAcquire::Item::QueueURI(Item
);
310 /* The transition manager InRelease itself (or its older sisters-in-law
311 Release & Release.gpg) is always queued as this allows us to rerun gpgv
312 on it to verify that we aren't stalled with old files */
313 bool pkgAcqMetaBase::QueueURI(pkgAcquire::ItemDesc
&Item
)
315 return pkgAcquire::Item::QueueURI(Item
);
317 /* the Diff/Index needs to queue also the up-to-date complete index file
318 to ensure that the list cleaner isn't eating it */
319 bool pkgAcqDiffIndex::QueueURI(pkgAcquire::ItemDesc
&Item
)
321 if (pkgAcqTransactionItem::QueueURI(Item
) == true)
327 // Acquire::Item::GetFinalFilename and specialisations for child classes /*{{{*/
328 std::string
pkgAcquire::Item::GetFinalFilename() const
330 return GetFinalFileNameFromURI(Desc
.URI
);
332 std::string
pkgAcqDiffIndex::GetFinalFilename() const
334 // the logic we inherent from pkgAcqBaseIndex isn't what we need here
335 return pkgAcquire::Item::GetFinalFilename();
337 std::string
pkgAcqIndex::GetFinalFilename() const
339 std::string
const FinalFile
= GetFinalFileNameFromURI(Target
.URI
);
340 return GetCompressedFileName(Target
, FinalFile
, CurrentCompressionExtension
);
342 std::string
pkgAcqMetaSig::GetFinalFilename() const
344 return GetFinalFileNameFromURI(Target
.URI
);
346 std::string
pkgAcqBaseIndex::GetFinalFilename() const
348 return GetFinalFileNameFromURI(Target
.URI
);
350 std::string
pkgAcqMetaBase::GetFinalFilename() const
352 return GetFinalFileNameFromURI(Target
.URI
);
354 std::string
pkgAcqArchive::GetFinalFilename() const
356 return _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
359 // pkgAcqTransactionItem::GetMetaKey and specialisations for child classes /*{{{*/
360 std::string
pkgAcqTransactionItem::GetMetaKey() const
362 return Target
.MetaKey
;
364 std::string
pkgAcqIndex::GetMetaKey() const
366 if (Stage
== STAGE_DECOMPRESS_AND_VERIFY
|| CurrentCompressionExtension
== "uncompressed")
367 return Target
.MetaKey
;
368 return Target
.MetaKey
+ "." + CurrentCompressionExtension
;
370 std::string
pkgAcqDiffIndex::GetMetaKey() const
372 return Target
.MetaKey
+ ".diff/Index";
375 //pkgAcqTransactionItem::TransactionState and specialisations for child classes /*{{{*/
376 bool pkgAcqTransactionItem::TransactionState(TransactionStates
const state
)
378 bool const Debug
= _config
->FindB("Debug::Acquire::Transaction", false);
381 case TransactionAbort
:
383 std::clog
<< " Cancel: " << DestFile
<< std::endl
;
384 if (Status
== pkgAcquire::Item::StatIdle
)
386 Status
= pkgAcquire::Item::StatDone
;
390 case TransactionCommit
:
391 if(PartialFile
!= "")
394 std::clog
<< "mv " << PartialFile
<< " -> "<< DestFile
<< " # " << DescURI() << std::endl
;
396 Rename(PartialFile
, DestFile
);
399 std::clog
<< "rm " << DestFile
<< " # " << DescURI() << std::endl
;
400 RemoveFile("TransactionCommit", DestFile
);
406 bool pkgAcqMetaBase::TransactionState(TransactionStates
const state
)
408 // Do not remove InRelease on IMSHit of Release.gpg [yes, this is very edgecasey]
409 if (TransactionManager
->IMSHit
== false)
410 return pkgAcqTransactionItem::TransactionState(state
);
413 bool pkgAcqIndex::TransactionState(TransactionStates
const state
)
415 if (pkgAcqTransactionItem::TransactionState(state
) == false)
420 case TransactionAbort
:
421 if (Stage
== STAGE_DECOMPRESS_AND_VERIFY
)
423 // keep the compressed file, but drop the decompressed
424 EraseFileName
.clear();
425 if (PartialFile
.empty() == false && flExtension(PartialFile
) == "decomp")
426 RemoveFile("TransactionAbort", PartialFile
);
429 case TransactionCommit
:
430 if (EraseFileName
.empty() == false)
431 RemoveFile("TransactionCommit", EraseFileName
);
436 bool pkgAcqDiffIndex::TransactionState(TransactionStates
const state
)
438 if (pkgAcqTransactionItem::TransactionState(state
) == false)
443 case TransactionCommit
:
445 case TransactionAbort
:
446 std::string
const Partial
= GetPartialFileNameFromURI(Target
.URI
);
447 RemoveFile("TransactionAbort", Partial
);
455 class APT_HIDDEN NoActionItem
: public pkgAcquire::Item
/*{{{*/
456 /* The sole purpose of this class is having an item which does nothing to
457 reach its done state to prevent cleanup deleting the mentioned file.
458 Handy in cases in which we know we have the file already, like IMS-Hits. */
460 IndexTarget
const Target
;
462 virtual std::string
DescURI() const APT_OVERRIDE
{return Target
.URI
;};
463 virtual HashStringList
GetExpectedHashes() const APT_OVERRIDE
{return HashStringList();};
465 NoActionItem(pkgAcquire
* const Owner
, IndexTarget
const &Target
) :
466 pkgAcquire::Item(Owner
), Target(Target
)
469 DestFile
= GetFinalFileNameFromURI(Target
.URI
);
471 NoActionItem(pkgAcquire
* const Owner
, IndexTarget
const &Target
, std::string
const &FinalFile
) :
472 pkgAcquire::Item(Owner
), Target(Target
)
475 DestFile
= FinalFile
;
480 // Acquire::Item::Item - Constructor /*{{{*/
481 APT_IGNORE_DEPRECATED_PUSH
482 pkgAcquire::Item::Item(pkgAcquire
* const owner
) :
483 FileSize(0), PartialSize(0), Mode(0), ID(0), Complete(false), Local(false),
484 QueueCounter(0), ExpectedAdditionalItems(0), Owner(owner
), d(NULL
)
489 APT_IGNORE_DEPRECATED_POP
491 // Acquire::Item::~Item - Destructor /*{{{*/
492 pkgAcquire::Item::~Item()
497 std::string
pkgAcquire::Item::Custom600Headers() const /*{{{*/
499 return std::string();
502 std::string
pkgAcquire::Item::ShortDesc() const /*{{{*/
507 APT_CONST
void pkgAcquire::Item::Finished() /*{{{*/
511 APT_PURE pkgAcquire
* pkgAcquire::Item::GetOwner() const /*{{{*/
516 APT_CONST
pkgAcquire::ItemDesc
&pkgAcquire::Item::GetItemDesc() /*{{{*/
521 APT_CONST
bool pkgAcquire::Item::IsTrusted() const /*{{{*/
526 // Acquire::Item::Failed - Item failed to download /*{{{*/
527 // ---------------------------------------------------------------------
528 /* We return to an idle state if there are still other queues that could
530 void pkgAcquire::Item::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)
532 if(ErrorText
.empty())
533 ErrorText
= LookupTag(Message
,"Message");
534 if (QueueCounter
<= 1)
536 /* This indicates that the file is not available right now but might
537 be sometime later. If we do a retry cycle then this should be
539 if (Cnf
!= NULL
&& Cnf
->LocalOnly
== true &&
540 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
556 case StatTransientNetworkError
:
563 string
const FailReason
= LookupTag(Message
, "FailReason");
564 if (FailReason
== "MaximumSizeExceeded")
565 RenameOnError(MaximumSizeExceeded
);
566 else if (Status
== StatAuthError
)
567 RenameOnError(HashSumMismatch
);
569 // report mirror failure back to LP if we actually use a mirror
570 if (FailReason
.empty() == false)
571 ReportMirrorFailure(FailReason
);
573 ReportMirrorFailure(ErrorText
);
575 if (QueueCounter
> 1)
579 // Acquire::Item::Start - Item has begun to download /*{{{*/
580 // ---------------------------------------------------------------------
581 /* Stash status and the file size. Note that setting Complete means
582 sub-phases of the acquire process such as decompresion are operating */
583 void pkgAcquire::Item::Start(string
const &/*Message*/, unsigned long long const Size
)
585 Status
= StatFetching
;
587 if (FileSize
== 0 && Complete
== false)
591 // Acquire::Item::VerifyDone - check if Item was downloaded OK /*{{{*/
592 /* Note that hash-verification is 'hardcoded' in acquire-worker and has
593 * already passed if this method is called. */
594 bool pkgAcquire::Item::VerifyDone(std::string
const &Message
,
595 pkgAcquire::MethodConfig
const * const /*Cnf*/)
597 std::string
const FileName
= LookupTag(Message
,"Filename");
598 if (FileName
.empty() == true)
601 ErrorText
= "Method gave a blank filename";
608 // Acquire::Item::Done - Item downloaded OK /*{{{*/
609 void pkgAcquire::Item::Done(string
const &/*Message*/, HashStringList
const &Hashes
,
610 pkgAcquire::MethodConfig
const * const /*Cnf*/)
612 // We just downloaded something..
615 unsigned long long const downloadedSize
= Hashes
.FileSize();
616 if (downloadedSize
!= 0)
618 FileSize
= downloadedSize
;
622 ErrorText
= string();
623 Owner
->Dequeue(this);
626 // Acquire::Item::Rename - Rename a file /*{{{*/
627 // ---------------------------------------------------------------------
628 /* This helper function is used by a lot of item methods as their final
630 bool pkgAcquire::Item::Rename(string
const &From
,string
const &To
)
632 if (From
== To
|| rename(From
.c_str(),To
.c_str()) == 0)
636 strprintf(S
, _("rename failed, %s (%s -> %s)."), strerror(errno
),
637 From
.c_str(),To
.c_str());
639 if (ErrorText
.empty())
642 ErrorText
= ErrorText
+ ": " + S
;
646 void pkgAcquire::Item::Dequeue() /*{{{*/
648 Owner
->Dequeue(this);
651 bool pkgAcquire::Item::RenameOnError(pkgAcquire::Item::RenameOnErrorState
const error
)/*{{{*/
653 if (RealFileExists(DestFile
))
654 Rename(DestFile
, DestFile
+ ".FAILED");
659 case HashSumMismatch
:
660 errtext
= _("Hash Sum mismatch");
661 Status
= StatAuthError
;
662 ReportMirrorFailure("HashChecksumFailure");
665 errtext
= _("Size mismatch");
666 Status
= StatAuthError
;
667 ReportMirrorFailure("SizeFailure");
670 errtext
= _("Invalid file format");
672 // do not report as usually its not the mirrors fault, but Portal/Proxy
675 errtext
= _("Signature error");
679 strprintf(errtext
, _("Clearsigned file isn't valid, got '%s' (does the network require authentication?)"), "NOSPLIT");
680 Status
= StatAuthError
;
682 case MaximumSizeExceeded
:
683 // the method is expected to report a good error for this
687 // no handling here, done by callers
690 if (ErrorText
.empty())
695 void pkgAcquire::Item::SetActiveSubprocess(const std::string
&subprocess
)/*{{{*/
697 ActiveSubprocess
= subprocess
;
698 APT_IGNORE_DEPRECATED(Mode
= ActiveSubprocess
.c_str();)
701 // Acquire::Item::ReportMirrorFailure /*{{{*/
702 void pkgAcquire::Item::ReportMirrorFailure(string
const &FailCode
)
704 // we only act if a mirror was used at all
705 if(UsedMirror
.empty())
708 std::cerr
<< "\nReportMirrorFailure: "
710 << " Uri: " << DescURI()
712 << FailCode
<< std::endl
;
714 string report
= _config
->Find("Methods::Mirror::ProblemReporting",
715 "/usr/lib/apt/apt-report-mirror-failure");
716 if(!FileExists(report
))
719 std::vector
<char const*> Args
;
720 Args
.push_back(report
.c_str());
721 Args
.push_back(UsedMirror
.c_str());
722 Args
.push_back(DescURI().c_str());
723 Args
.push_back(FailCode
.c_str());
724 Args
.push_back(NULL
);
726 pid_t pid
= ExecFork();
729 _error
->Error("ReportMirrorFailure Fork failed");
734 execvp(Args
[0], (char**)Args
.data());
735 std::cerr
<< "Could not exec " << Args
[0] << std::endl
;
738 if(!ExecWait(pid
, "report-mirror-failure"))
740 _error
->Warning("Couldn't report problem to '%s'",
741 _config
->Find("Methods::Mirror::ProblemReporting").c_str());
745 std::string
pkgAcquire::Item::HashSum() const /*{{{*/
747 HashStringList
const hashes
= GetExpectedHashes();
748 HashString
const * const hs
= hashes
.find(NULL
);
749 return hs
!= NULL
? hs
->toStr() : "";
753 pkgAcqTransactionItem::pkgAcqTransactionItem(pkgAcquire
* const Owner
, /*{{{*/
754 pkgAcqMetaClearSig
* const transactionManager
, IndexTarget
const &target
) :
755 pkgAcquire::Item(Owner
), d(NULL
), Target(target
), TransactionManager(transactionManager
)
757 if (TransactionManager
!= this)
758 TransactionManager
->Add(this);
761 pkgAcqTransactionItem::~pkgAcqTransactionItem() /*{{{*/
765 HashStringList
pkgAcqTransactionItem::GetExpectedHashesFor(std::string
const &MetaKey
) const /*{{{*/
767 return GetExpectedHashesFromFor(TransactionManager
->MetaIndexParser
, MetaKey
);
771 // AcqMetaBase - Constructor /*{{{*/
772 pkgAcqMetaBase::pkgAcqMetaBase(pkgAcquire
* const Owner
,
773 pkgAcqMetaClearSig
* const TransactionManager
,
774 std::vector
<IndexTarget
> const &IndexTargets
,
775 IndexTarget
const &DataTarget
)
776 : pkgAcqTransactionItem(Owner
, TransactionManager
, DataTarget
), d(NULL
),
777 IndexTargets(IndexTargets
),
778 AuthPass(false), IMSHit(false)
782 // AcqMetaBase::Add - Add a item to the current Transaction /*{{{*/
783 void pkgAcqMetaBase::Add(pkgAcqTransactionItem
* const I
)
785 Transaction
.push_back(I
);
788 // AcqMetaBase::AbortTransaction - Abort the current Transaction /*{{{*/
789 void pkgAcqMetaBase::AbortTransaction()
791 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
792 std::clog
<< "AbortTransaction: " << TransactionManager
<< std::endl
;
794 // ensure the toplevel is in error state too
795 for (std::vector
<pkgAcqTransactionItem
*>::iterator I
= Transaction
.begin();
796 I
!= Transaction
.end(); ++I
)
798 (*I
)->TransactionState(TransactionAbort
);
803 // AcqMetaBase::TransactionHasError - Check for errors in Transaction /*{{{*/
804 APT_PURE
bool pkgAcqMetaBase::TransactionHasError() const
806 for (std::vector
<pkgAcqTransactionItem
*>::const_iterator I
= Transaction
.begin();
807 I
!= Transaction
.end(); ++I
)
809 switch((*I
)->Status
) {
810 case StatDone
: break;
811 case StatIdle
: break;
812 case StatAuthError
: return true;
813 case StatError
: return true;
814 case StatTransientNetworkError
: return true;
815 case StatFetching
: break;
821 // AcqMetaBase::CommitTransaction - Commit a transaction /*{{{*/
822 void pkgAcqMetaBase::CommitTransaction()
824 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
825 std::clog
<< "CommitTransaction: " << this << std::endl
;
827 // move new files into place *and* remove files that are not
828 // part of the transaction but are still on disk
829 for (std::vector
<pkgAcqTransactionItem
*>::iterator I
= Transaction
.begin();
830 I
!= Transaction
.end(); ++I
)
832 (*I
)->TransactionState(TransactionCommit
);
837 // AcqMetaBase::TransactionStageCopy - Stage a file for copying /*{{{*/
838 void pkgAcqMetaBase::TransactionStageCopy(pkgAcqTransactionItem
* const I
,
839 const std::string
&From
,
840 const std::string
&To
)
842 I
->PartialFile
= From
;
846 // AcqMetaBase::TransactionStageRemoval - Stage a file for removal /*{{{*/
847 void pkgAcqMetaBase::TransactionStageRemoval(pkgAcqTransactionItem
* const I
,
848 const std::string
&FinalFile
)
851 I
->DestFile
= FinalFile
;
854 // AcqMetaBase::GenerateAuthWarning - Check gpg authentication error /*{{{*/
855 bool pkgAcqMetaBase::CheckStopAuthentication(pkgAcquire::Item
* const I
, const std::string
&Message
)
857 // FIXME: this entire function can do now that we disallow going to
858 // a unauthenticated state and can cleanly rollback
860 string
const Final
= I
->GetFinalFilename();
861 if(FileExists(Final
))
863 I
->Status
= StatTransientNetworkError
;
864 _error
->Warning(_("An error occurred during the signature "
865 "verification. The repository is not updated "
866 "and the previous index files will be used. "
867 "GPG error: %s: %s"),
868 Desc
.Description
.c_str(),
869 LookupTag(Message
,"Message").c_str());
870 RunScripts("APT::Update::Auth-Failure");
872 } else if (LookupTag(Message
,"Message").find("NODATA") != string::npos
) {
873 /* Invalid signature file, reject (LP: #346386) (Closes: #627642) */
874 _error
->Error(_("GPG error: %s: %s"),
875 Desc
.Description
.c_str(),
876 LookupTag(Message
,"Message").c_str());
877 I
->Status
= StatAuthError
;
880 _error
->Warning(_("GPG error: %s: %s"),
881 Desc
.Description
.c_str(),
882 LookupTag(Message
,"Message").c_str());
884 // gpgv method failed
885 ReportMirrorFailure("GPGFailure");
889 // AcqMetaBase::Custom600Headers - Get header for AcqMetaBase /*{{{*/
890 // ---------------------------------------------------------------------
891 string
pkgAcqMetaBase::Custom600Headers() const
893 std::string Header
= "\nIndex-File: true";
894 std::string MaximumSize
;
895 strprintf(MaximumSize
, "\nMaximum-Size: %i",
896 _config
->FindI("Acquire::MaxReleaseFileSize", 10*1000*1000));
897 Header
+= MaximumSize
;
899 string
const FinalFile
= GetFinalFilename();
901 if (stat(FinalFile
.c_str(),&Buf
) == 0)
902 Header
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
907 // AcqMetaBase::QueueForSignatureVerify /*{{{*/
908 void pkgAcqMetaBase::QueueForSignatureVerify(pkgAcqTransactionItem
* const I
, std::string
const &File
, std::string
const &Signature
)
911 I
->Desc
.URI
= "gpgv:" + Signature
;
914 I
->SetActiveSubprocess("gpgv");
917 // AcqMetaBase::CheckDownloadDone /*{{{*/
918 bool pkgAcqMetaBase::CheckDownloadDone(pkgAcqTransactionItem
* const I
, const std::string
&Message
, HashStringList
const &Hashes
) const
920 // We have just finished downloading a Release file (it is not
923 std::string
const FileName
= LookupTag(Message
,"Filename");
924 if (FileName
!= I
->DestFile
&& RealFileExists(I
->DestFile
) == false)
927 I
->Desc
.URI
= "copy:" + FileName
;
928 I
->QueueURI(I
->Desc
);
932 // make sure to verify against the right file on I-M-S hit
933 bool IMSHit
= StringToBool(LookupTag(Message
,"IMS-Hit"), false);
934 if (IMSHit
== false && Hashes
.usable())
936 // detect IMS-Hits servers haven't detected by Hash comparison
937 std::string
const FinalFile
= I
->GetFinalFilename();
938 if (RealFileExists(FinalFile
) && Hashes
.VerifyFile(FinalFile
) == true)
941 RemoveFile("CheckDownloadDone", I
->DestFile
);
947 // for simplicity, the transaction manager is always InRelease
948 // even if it doesn't exist.
949 if (TransactionManager
!= NULL
)
950 TransactionManager
->IMSHit
= true;
951 I
->PartialFile
= I
->DestFile
= I
->GetFinalFilename();
954 // set Item to complete as the remaining work is all local (verify etc)
960 bool pkgAcqMetaBase::CheckAuthDone(string
const &Message
) /*{{{*/
962 // At this point, the gpgv method has succeeded, so there is a
963 // valid signature from a key in the trusted keyring. We
964 // perform additional verification of its contents, and use them
965 // to verify the indexes we are about to download
967 if (TransactionManager
->IMSHit
== false)
969 // open the last (In)Release if we have it
970 std::string
const FinalFile
= GetFinalFilename();
971 std::string FinalRelease
;
972 std::string FinalInRelease
;
973 if (APT::String::Endswith(FinalFile
, "InRelease"))
975 FinalInRelease
= FinalFile
;
976 FinalRelease
= FinalFile
.substr(0, FinalFile
.length() - strlen("InRelease")) + "Release";
980 FinalInRelease
= FinalFile
.substr(0, FinalFile
.length() - strlen("Release")) + "InRelease";
981 FinalRelease
= FinalFile
;
983 if (RealFileExists(FinalInRelease
) || RealFileExists(FinalRelease
))
985 TransactionManager
->LastMetaIndexParser
= TransactionManager
->MetaIndexParser
->UnloadedClone();
986 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
988 _error
->PushToStack();
989 if (RealFileExists(FinalInRelease
))
990 TransactionManager
->LastMetaIndexParser
->Load(FinalInRelease
, NULL
);
992 TransactionManager
->LastMetaIndexParser
->Load(FinalRelease
, NULL
);
993 // its unlikely to happen, but if what we have is bad ignore it
994 if (_error
->PendingError())
996 delete TransactionManager
->LastMetaIndexParser
;
997 TransactionManager
->LastMetaIndexParser
= NULL
;
999 _error
->RevertToStack();
1004 if (TransactionManager
->MetaIndexParser
->Load(DestFile
, &ErrorText
) == false)
1006 Status
= StatAuthError
;
1010 if (!VerifyVendor(Message
))
1012 Status
= StatAuthError
;
1016 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1017 std::cerr
<< "Signature verification succeeded: "
1018 << DestFile
<< std::endl
;
1020 // Download further indexes with verification
1026 void pkgAcqMetaBase::QueueIndexes(bool const verify
) /*{{{*/
1028 // at this point the real Items are loaded in the fetcher
1029 ExpectedAdditionalItems
= 0;
1031 bool metaBaseSupportsByHash
= false;
1032 if (TransactionManager
!= NULL
&& TransactionManager
->MetaIndexParser
!= NULL
)
1033 metaBaseSupportsByHash
= TransactionManager
->MetaIndexParser
->GetSupportsAcquireByHash();
1035 for (std::vector
<IndexTarget
>::iterator Target
= IndexTargets
.begin();
1036 Target
!= IndexTargets
.end();
1039 // all is an implementation detail. Users shouldn't use this as arch
1040 // We need this support trickery here as e.g. Debian has binary-all files already,
1041 // but arch:all packages are still in the arch:any files, so we would waste precious
1042 // download time, bandwidth and diskspace for nothing, BUT Debian doesn't feature all
1043 // in the set of supported architectures, so we can filter based on this property rather
1044 // than invent an entirely new flag we would need to carry for all of eternity.
1045 if (Target
->Option(IndexTarget::ARCHITECTURE
) == "all" &&
1046 TransactionManager
->MetaIndexParser
->IsArchitectureSupported("all") == false)
1049 bool trypdiff
= Target
->OptionBool(IndexTarget::PDIFFS
);
1052 if (TransactionManager
->MetaIndexParser
->Exists(Target
->MetaKey
) == false)
1054 // optional targets that we do not have in the Release file are skipped
1055 if (Target
->IsOptional
)
1058 std::string
const &arch
= Target
->Option(IndexTarget::ARCHITECTURE
);
1059 if (arch
.empty() == false)
1061 if (TransactionManager
->MetaIndexParser
->IsArchitectureSupported(arch
) == false)
1063 _error
->Notice(_("Skipping acquire of configured file '%s' as repository '%s' doesn't support architecture '%s'"),
1064 Target
->MetaKey
.c_str(), TransactionManager
->Target
.Description
.c_str(), arch
.c_str());
1067 // if the architecture is officially supported but currently no packages for it available,
1068 // ignore silently as this is pretty much the same as just shipping an empty file.
1069 // if we don't know which architectures are supported, we do NOT ignore it to notify user about this
1070 if (TransactionManager
->MetaIndexParser
->IsArchitectureSupported("*undefined*") == false)
1074 Status
= StatAuthError
;
1075 strprintf(ErrorText
, _("Unable to find expected entry '%s' in Release file (Wrong sources.list entry or malformed file)"), Target
->MetaKey
.c_str());
1080 auto const hashes
= GetExpectedHashesFor(Target
->MetaKey
);
1081 if (hashes
.usable() == false && hashes
.empty() == false)
1083 _error
->Warning(_("Skipping acquire of configured file '%s' as repository '%s' provides only weak security information for it"),
1084 Target
->MetaKey
.c_str(), TransactionManager
->Target
.Description
.c_str());
1089 // autoselect the compression method
1090 std::vector
<std::string
> types
= VectorizeString(Target
->Option(IndexTarget::COMPRESSIONTYPES
), ' ');
1091 types
.erase(std::remove_if(types
.begin(), types
.end(), [&](std::string
const &t
) {
1092 if (t
== "uncompressed")
1093 return TransactionManager
->MetaIndexParser
->Exists(Target
->MetaKey
) == false;
1094 std::string
const MetaKey
= Target
->MetaKey
+ "." + t
;
1095 return TransactionManager
->MetaIndexParser
->Exists(MetaKey
) == false;
1097 if (types
.empty() == false)
1099 std::ostringstream os
;
1100 // add the special compressiontype byhash first if supported
1101 std::string
const useByHashConf
= Target
->Option(IndexTarget::BY_HASH
);
1102 bool useByHash
= false;
1103 if(useByHashConf
== "force")
1106 useByHash
= StringToBool(useByHashConf
) == true && metaBaseSupportsByHash
;
1107 if (useByHash
== true)
1109 std::copy(types
.begin(), types
.end()-1, std::ostream_iterator
<std::string
>(os
, " "));
1110 os
<< *types
.rbegin();
1111 Target
->Options
["COMPRESSIONTYPES"] = os
.str();
1114 Target
->Options
["COMPRESSIONTYPES"].clear();
1116 std::string filename
= GetFinalFileNameFromURI(Target
->URI
);
1117 if (RealFileExists(filename
) == false)
1119 if (Target
->KeepCompressed
)
1121 filename
= GetKeepCompressedFileName(filename
, *Target
);
1122 if (RealFileExists(filename
) == false)
1129 if (filename
.empty() == false)
1131 // if the Release file is a hit and we have an index it must be the current one
1132 if (TransactionManager
->IMSHit
== true)
1134 else if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1136 // see if the file changed since the last Release file
1137 // we use the uncompressed files as we might compress differently compared to the server,
1138 // so the hashes might not match, even if they contain the same data.
1139 HashStringList
const newFile
= GetExpectedHashesFromFor(TransactionManager
->MetaIndexParser
, Target
->MetaKey
);
1140 HashStringList
const oldFile
= GetExpectedHashesFromFor(TransactionManager
->LastMetaIndexParser
, Target
->MetaKey
);
1141 if (newFile
!= oldFile
)
1148 trypdiff
= false; // no file to patch
1150 if (filename
.empty() == false)
1152 new NoActionItem(Owner
, *Target
, filename
);
1153 std::string
const idxfilename
= GetFinalFileNameFromURI(Target
->URI
+ ".diff/Index");
1154 if (FileExists(idxfilename
))
1155 new NoActionItem(Owner
, *Target
, idxfilename
);
1159 // check if we have patches available
1160 trypdiff
&= TransactionManager
->MetaIndexParser
->Exists(Target
->MetaKey
+ ".diff/Index");
1164 // if we have no file to patch, no point in trying
1165 std::string filename
= GetFinalFileNameFromURI(Target
->URI
);
1166 if (RealFileExists(filename
) == false)
1168 if (Target
->KeepCompressed
)
1170 filename
= GetKeepCompressedFileName(filename
, *Target
);
1171 if (RealFileExists(filename
) == false)
1177 trypdiff
&= (filename
.empty() == false);
1180 // no point in patching from local sources
1183 std::string
const proto
= Target
->URI
.substr(0, strlen("file:/"));
1184 if (proto
== "file:/" || proto
== "copy:/" || proto
== "cdrom:")
1188 // Queue the Index file (Packages, Sources, Translation-$foo, …)
1190 new pkgAcqDiffIndex(Owner
, TransactionManager
, *Target
);
1192 new pkgAcqIndex(Owner
, TransactionManager
, *Target
);
1196 bool pkgAcqMetaBase::VerifyVendor(string
const &Message
) /*{{{*/
1198 string::size_type pos
;
1200 // check for missing sigs (that where not fatal because otherwise we had
1203 string msg
= _("There is no public key available for the "
1204 "following key IDs:\n");
1205 pos
= Message
.find("NO_PUBKEY ");
1206 if (pos
!= std::string::npos
)
1208 string::size_type start
= pos
+strlen("NO_PUBKEY ");
1209 string Fingerprint
= Message
.substr(start
, Message
.find("\n")-start
);
1210 missingkeys
+= (Fingerprint
);
1212 if(!missingkeys
.empty())
1213 _error
->Warning("%s", (msg
+ missingkeys
).c_str());
1215 string Transformed
= TransactionManager
->MetaIndexParser
->GetExpectedDist();
1217 if (Transformed
== "../project/experimental")
1219 Transformed
= "experimental";
1222 pos
= Transformed
.rfind('/');
1223 if (pos
!= string::npos
)
1225 Transformed
= Transformed
.substr(0, pos
);
1228 if (Transformed
== ".")
1233 if (TransactionManager
->MetaIndexParser
->GetValidUntil() > 0)
1235 time_t const invalid_since
= time(NULL
) - TransactionManager
->MetaIndexParser
->GetValidUntil();
1236 if (invalid_since
> 0)
1240 // TRANSLATOR: The first %s is the URL of the bad Release file, the second is
1241 // the time since then the file is invalid - formatted in the same way as in
1242 // the download progress display (e.g. 7d 3h 42min 1s)
1243 _("Release file for %s is expired (invalid since %s). "
1244 "Updates for this repository will not be applied."),
1245 Target
.URI
.c_str(), TimeToStr(invalid_since
).c_str());
1246 if (ErrorText
.empty())
1248 return _error
->Error("%s", errmsg
.c_str());
1252 /* Did we get a file older than what we have? This is a last minute IMS hit and doubles
1253 as a prevention of downgrading us to older (still valid) files */
1254 if (TransactionManager
->IMSHit
== false && TransactionManager
->LastMetaIndexParser
!= NULL
&&
1255 TransactionManager
->LastMetaIndexParser
->GetDate() > TransactionManager
->MetaIndexParser
->GetDate())
1257 TransactionManager
->IMSHit
= true;
1258 RemoveFile("VerifyVendor", DestFile
);
1259 PartialFile
= DestFile
= GetFinalFilename();
1260 // load the 'old' file in the 'new' one instead of flipping pointers as
1261 // the new one isn't owned by us, while the old one is so cleanup would be confused.
1262 TransactionManager
->MetaIndexParser
->swapLoad(TransactionManager
->LastMetaIndexParser
);
1263 delete TransactionManager
->LastMetaIndexParser
;
1264 TransactionManager
->LastMetaIndexParser
= NULL
;
1267 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1269 std::cerr
<< "Got Codename: " << TransactionManager
->MetaIndexParser
->GetCodename() << std::endl
;
1270 std::cerr
<< "Expecting Dist: " << TransactionManager
->MetaIndexParser
->GetExpectedDist() << std::endl
;
1271 std::cerr
<< "Transformed Dist: " << Transformed
<< std::endl
;
1274 if (TransactionManager
->MetaIndexParser
->CheckDist(Transformed
) == false)
1276 // This might become fatal one day
1277 // Status = StatAuthError;
1278 // ErrorText = "Conflicting distribution; expected "
1279 // + MetaIndexParser->GetExpectedDist() + " but got "
1280 // + MetaIndexParser->GetCodename();
1282 if (!Transformed
.empty())
1284 _error
->Warning(_("Conflicting distribution: %s (expected %s but got %s)"),
1285 Desc
.Description
.c_str(),
1286 Transformed
.c_str(),
1287 TransactionManager
->MetaIndexParser
->GetCodename().c_str());
1294 pkgAcqMetaBase::~pkgAcqMetaBase()
1298 pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire
* const Owner
, /*{{{*/
1299 IndexTarget
const &ClearsignedTarget
,
1300 IndexTarget
const &DetachedDataTarget
, IndexTarget
const &DetachedSigTarget
,
1301 std::vector
<IndexTarget
> const &IndexTargets
,
1302 metaIndex
* const MetaIndexParser
) :
1303 pkgAcqMetaIndex(Owner
, this, ClearsignedTarget
, DetachedSigTarget
, IndexTargets
),
1304 d(NULL
), ClearsignedTarget(ClearsignedTarget
),
1305 DetachedDataTarget(DetachedDataTarget
),
1306 MetaIndexParser(MetaIndexParser
), LastMetaIndexParser(NULL
)
1308 // index targets + (worst case:) Release/Release.gpg
1309 ExpectedAdditionalItems
= IndexTargets
.size() + 2;
1310 TransactionManager
->Add(this);
1313 pkgAcqMetaClearSig::~pkgAcqMetaClearSig() /*{{{*/
1315 if (LastMetaIndexParser
!= NULL
)
1316 delete LastMetaIndexParser
;
1319 // pkgAcqMetaClearSig::Custom600Headers - Insert custom request headers /*{{{*/
1320 string
pkgAcqMetaClearSig::Custom600Headers() const
1322 string Header
= pkgAcqMetaBase::Custom600Headers();
1323 Header
+= "\nFail-Ignore: true";
1324 std::string
const key
= TransactionManager
->MetaIndexParser
->GetSignedBy();
1325 if (key
.empty() == false)
1326 Header
+= "\nSigned-By: " + key
;
1331 bool pkgAcqMetaClearSig::VerifyDone(std::string
const &Message
, /*{{{*/
1332 pkgAcquire::MethodConfig
const * const Cnf
)
1334 Item::VerifyDone(Message
, Cnf
);
1336 if (FileExists(DestFile
) && !StartsWithGPGClearTextSignature(DestFile
))
1337 return RenameOnError(NotClearsigned
);
1342 // pkgAcqMetaClearSig::Done - We got a file /*{{{*/
1343 void pkgAcqMetaClearSig::Done(std::string
const &Message
,
1344 HashStringList
const &Hashes
,
1345 pkgAcquire::MethodConfig
const * const Cnf
)
1347 Item::Done(Message
, Hashes
, Cnf
);
1349 if(AuthPass
== false)
1351 if(CheckDownloadDone(this, Message
, Hashes
) == true)
1352 QueueForSignatureVerify(this, DestFile
, DestFile
);
1355 else if(CheckAuthDone(Message
) == true)
1357 if (TransactionManager
->IMSHit
== false)
1358 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
1359 else if (RealFileExists(GetFinalFilename()) == false)
1361 // We got an InRelease file IMSHit, but we haven't one, which means
1362 // we had a valid Release/Release.gpg combo stepping in, which we have
1363 // to 'acquire' now to ensure list cleanup isn't removing them
1364 new NoActionItem(Owner
, DetachedDataTarget
);
1365 new NoActionItem(Owner
, DetachedSigTarget
);
1370 void pkgAcqMetaClearSig::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
) /*{{{*/
1372 Item::Failed(Message
, Cnf
);
1374 // we failed, we will not get additional items from this method
1375 ExpectedAdditionalItems
= 0;
1377 if (AuthPass
== false)
1379 if (Status
== StatAuthError
|| Status
== StatTransientNetworkError
)
1381 // if we expected a ClearTextSignature (InRelease) but got a network
1382 // error or got a file, but it wasn't valid, we end up here (see VerifyDone).
1383 // As these is usually called by web-portals we do not try Release/Release.gpg
1384 // as this is gonna fail anyway and instead abort our try (LP#346386)
1385 TransactionManager
->AbortTransaction();
1389 // Queue the 'old' InRelease file for removal if we try Release.gpg
1390 // as otherwise the file will stay around and gives a false-auth
1391 // impression (CVE-2012-0214)
1392 TransactionManager
->TransactionStageRemoval(this, GetFinalFilename());
1395 new pkgAcqMetaIndex(Owner
, TransactionManager
, DetachedDataTarget
, DetachedSigTarget
, IndexTargets
);
1399 if(CheckStopAuthentication(this, Message
))
1402 // No Release file was present, or verification failed, so fall
1403 // back to queueing Packages files without verification
1404 // only allow going further if the user explicitly wants it
1405 if(AllowInsecureRepositories(_("The repository '%s' is not signed."), ClearsignedTarget
.Description
, TransactionManager
->MetaIndexParser
, TransactionManager
, this) == true)
1409 /* InRelease files become Release files, otherwise
1410 * they would be considered as trusted later on */
1411 string
const FinalRelease
= GetFinalFileNameFromURI(DetachedDataTarget
.URI
);
1412 string
const PartialRelease
= GetPartialFileNameFromURI(DetachedDataTarget
.URI
);
1413 string
const FinalReleasegpg
= GetFinalFileNameFromURI(DetachedSigTarget
.URI
);
1414 string
const FinalInRelease
= GetFinalFilename();
1415 Rename(DestFile
, PartialRelease
);
1416 TransactionManager
->TransactionStageCopy(this, PartialRelease
, FinalRelease
);
1418 if (RealFileExists(FinalReleasegpg
) || RealFileExists(FinalInRelease
))
1420 // open the last Release if we have it
1421 if (TransactionManager
->IMSHit
== false)
1423 TransactionManager
->LastMetaIndexParser
= TransactionManager
->MetaIndexParser
->UnloadedClone();
1424 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1426 _error
->PushToStack();
1427 if (RealFileExists(FinalInRelease
))
1428 TransactionManager
->LastMetaIndexParser
->Load(FinalInRelease
, NULL
);
1430 TransactionManager
->LastMetaIndexParser
->Load(FinalRelease
, NULL
);
1431 // its unlikely to happen, but if what we have is bad ignore it
1432 if (_error
->PendingError())
1434 delete TransactionManager
->LastMetaIndexParser
;
1435 TransactionManager
->LastMetaIndexParser
= NULL
;
1437 _error
->RevertToStack();
1442 // we parse the indexes here because at this point the user wanted
1443 // a repository that may potentially harm him
1444 if (TransactionManager
->MetaIndexParser
->Load(PartialRelease
, &ErrorText
) == false || VerifyVendor(Message
) == false)
1445 /* expired Release files are still a problem you need extra force for */;
1453 pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire
* const Owner
, /*{{{*/
1454 pkgAcqMetaClearSig
* const TransactionManager
,
1455 IndexTarget
const &DataTarget
,
1456 IndexTarget
const &DetachedSigTarget
,
1457 vector
<IndexTarget
> const &IndexTargets
) :
1458 pkgAcqMetaBase(Owner
, TransactionManager
, IndexTargets
, DataTarget
), d(NULL
),
1459 DetachedSigTarget(DetachedSigTarget
)
1461 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1462 std::clog
<< "New pkgAcqMetaIndex with TransactionManager "
1463 << this->TransactionManager
<< std::endl
;
1465 DestFile
= GetPartialFileNameFromURI(DataTarget
.URI
);
1468 Desc
.Description
= DataTarget
.Description
;
1470 Desc
.ShortDesc
= DataTarget
.ShortDesc
;
1471 Desc
.URI
= DataTarget
.URI
;
1473 // we expect more item
1474 ExpectedAdditionalItems
= IndexTargets
.size();
1478 void pkgAcqMetaIndex::Done(string
const &Message
, /*{{{*/
1479 HashStringList
const &Hashes
,
1480 pkgAcquire::MethodConfig
const * const Cfg
)
1482 Item::Done(Message
,Hashes
,Cfg
);
1484 if(CheckDownloadDone(this, Message
, Hashes
))
1486 // we have a Release file, now download the Signature, all further
1487 // verify/queue for additional downloads will be done in the
1488 // pkgAcqMetaSig::Done() code
1489 new pkgAcqMetaSig(Owner
, TransactionManager
, DetachedSigTarget
, this);
1493 // pkgAcqMetaIndex::Failed - no Release file present /*{{{*/
1494 void pkgAcqMetaIndex::Failed(string
const &Message
,
1495 pkgAcquire::MethodConfig
const * const Cnf
)
1497 pkgAcquire::Item::Failed(Message
, Cnf
);
1500 // No Release file was present so fall
1501 // back to queueing Packages files without verification
1502 // only allow going further if the user explicitly wants it
1503 if(AllowInsecureRepositories(_("The repository '%s' does not have a Release file."), Target
.Description
, TransactionManager
->MetaIndexParser
, TransactionManager
, this) == true)
1505 // ensure old Release files are removed
1506 TransactionManager
->TransactionStageRemoval(this, GetFinalFilename());
1508 // queue without any kind of hashsum support
1509 QueueIndexes(false);
1513 void pkgAcqMetaIndex::Finished() /*{{{*/
1515 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1516 std::clog
<< "Finished: " << DestFile
<<std::endl
;
1517 if(TransactionManager
!= NULL
&&
1518 TransactionManager
->TransactionHasError() == false)
1519 TransactionManager
->CommitTransaction();
1522 std::string
pkgAcqMetaIndex::DescURI() const /*{{{*/
1527 pkgAcqMetaIndex::~pkgAcqMetaIndex() {}
1529 // AcqMetaSig::AcqMetaSig - Constructor /*{{{*/
1530 pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire
* const Owner
,
1531 pkgAcqMetaClearSig
* const TransactionManager
,
1532 IndexTarget
const &Target
,
1533 pkgAcqMetaIndex
* const MetaIndex
) :
1534 pkgAcqTransactionItem(Owner
, TransactionManager
, Target
), d(NULL
), MetaIndex(MetaIndex
)
1536 DestFile
= GetPartialFileNameFromURI(Target
.URI
);
1538 // remove any partial downloaded sig-file in partial/.
1539 // it may confuse proxies and is too small to warrant a
1540 // partial download anyway
1541 RemoveFile("pkgAcqMetaSig", DestFile
);
1543 // set the TransactionManager
1544 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1545 std::clog
<< "New pkgAcqMetaSig with TransactionManager "
1546 << TransactionManager
<< std::endl
;
1549 Desc
.Description
= Target
.Description
;
1551 Desc
.ShortDesc
= Target
.ShortDesc
;
1552 Desc
.URI
= Target
.URI
;
1554 // If we got a hit for Release, we will get one for Release.gpg too (or obscure errors),
1555 // so we skip the download step and go instantly to verification
1556 if (TransactionManager
->IMSHit
== true && RealFileExists(GetFinalFilename()))
1560 PartialFile
= DestFile
= GetFinalFilename();
1561 MetaIndexFileSignature
= DestFile
;
1562 MetaIndex
->QueueForSignatureVerify(this, MetaIndex
->DestFile
, DestFile
);
1568 pkgAcqMetaSig::~pkgAcqMetaSig() /*{{{*/
1572 // pkgAcqMetaSig::Custom600Headers - Insert custom request headers /*{{{*/
1573 std::string
pkgAcqMetaSig::Custom600Headers() const
1575 std::string Header
= pkgAcqTransactionItem::Custom600Headers();
1576 std::string
const key
= TransactionManager
->MetaIndexParser
->GetSignedBy();
1577 if (key
.empty() == false)
1578 Header
+= "\nSigned-By: " + key
;
1582 // AcqMetaSig::Done - The signature was downloaded/verified /*{{{*/
1583 void pkgAcqMetaSig::Done(string
const &Message
, HashStringList
const &Hashes
,
1584 pkgAcquire::MethodConfig
const * const Cfg
)
1586 if (MetaIndexFileSignature
.empty() == false)
1588 DestFile
= MetaIndexFileSignature
;
1589 MetaIndexFileSignature
.clear();
1591 Item::Done(Message
, Hashes
, Cfg
);
1593 if(MetaIndex
->AuthPass
== false)
1595 if(MetaIndex
->CheckDownloadDone(this, Message
, Hashes
) == true)
1597 // destfile will be modified to point to MetaIndexFile for the
1598 // gpgv method, so we need to save it here
1599 MetaIndexFileSignature
= DestFile
;
1600 MetaIndex
->QueueForSignatureVerify(this, MetaIndex
->DestFile
, DestFile
);
1604 else if(MetaIndex
->CheckAuthDone(Message
) == true)
1606 if (TransactionManager
->IMSHit
== false)
1608 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
1609 TransactionManager
->TransactionStageCopy(MetaIndex
, MetaIndex
->DestFile
, MetaIndex
->GetFinalFilename());
1614 void pkgAcqMetaSig::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
1616 Item::Failed(Message
,Cnf
);
1618 // check if we need to fail at this point
1619 if (MetaIndex
->AuthPass
== true && MetaIndex
->CheckStopAuthentication(this, Message
))
1622 string
const FinalRelease
= MetaIndex
->GetFinalFilename();
1623 string
const FinalReleasegpg
= GetFinalFilename();
1624 string
const FinalInRelease
= TransactionManager
->GetFinalFilename();
1626 if (RealFileExists(FinalReleasegpg
) || RealFileExists(FinalInRelease
))
1628 std::string downgrade_msg
;
1629 strprintf(downgrade_msg
, _("The repository '%s' is no longer signed."),
1630 MetaIndex
->Target
.Description
.c_str());
1631 if(_config
->FindB("Acquire::AllowDowngradeToInsecureRepositories"))
1633 // meh, the users wants to take risks (we still mark the packages
1634 // from this repository as unauthenticated)
1635 _error
->Warning("%s", downgrade_msg
.c_str());
1636 _error
->Warning(_("This is normally not allowed, but the option "
1637 "Acquire::AllowDowngradeToInsecureRepositories was "
1638 "given to override it."));
1641 MessageInsecureRepository(true, downgrade_msg
);
1642 if (TransactionManager
->IMSHit
== false)
1643 Rename(MetaIndex
->DestFile
, MetaIndex
->DestFile
+ ".FAILED");
1644 Item::Failed("Message: " + downgrade_msg
, Cnf
);
1645 TransactionManager
->AbortTransaction();
1650 // ensures that a Release.gpg file in the lists/ is removed by the transaction
1651 TransactionManager
->TransactionStageRemoval(this, DestFile
);
1653 // only allow going further if the user explicitly wants it
1654 if (AllowInsecureRepositories(_("The repository '%s' is not signed."), MetaIndex
->Target
.Description
, TransactionManager
->MetaIndexParser
, TransactionManager
, this) == true)
1656 if (RealFileExists(FinalReleasegpg
) || RealFileExists(FinalInRelease
))
1658 // open the last Release if we have it
1659 if (TransactionManager
->IMSHit
== false)
1661 TransactionManager
->LastMetaIndexParser
= TransactionManager
->MetaIndexParser
->UnloadedClone();
1662 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1664 _error
->PushToStack();
1665 if (RealFileExists(FinalInRelease
))
1666 TransactionManager
->LastMetaIndexParser
->Load(FinalInRelease
, NULL
);
1668 TransactionManager
->LastMetaIndexParser
->Load(FinalRelease
, NULL
);
1669 // its unlikely to happen, but if what we have is bad ignore it
1670 if (_error
->PendingError())
1672 delete TransactionManager
->LastMetaIndexParser
;
1673 TransactionManager
->LastMetaIndexParser
= NULL
;
1675 _error
->RevertToStack();
1680 // we parse the indexes here because at this point the user wanted
1681 // a repository that may potentially harm him
1682 bool const GoodLoad
= TransactionManager
->MetaIndexParser
->Load(MetaIndex
->DestFile
, &ErrorText
);
1683 if (MetaIndex
->VerifyVendor(Message
) == false)
1684 /* expired Release files are still a problem you need extra force for */;
1686 MetaIndex
->QueueIndexes(GoodLoad
);
1688 TransactionManager
->TransactionStageCopy(MetaIndex
, MetaIndex
->DestFile
, MetaIndex
->GetFinalFilename());
1691 // FIXME: this is used often (e.g. in pkgAcqIndexTrans) so refactor
1692 if (Cnf
->LocalOnly
== true ||
1693 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1702 // AcqBaseIndex - Constructor /*{{{*/
1703 pkgAcqBaseIndex::pkgAcqBaseIndex(pkgAcquire
* const Owner
,
1704 pkgAcqMetaClearSig
* const TransactionManager
,
1705 IndexTarget
const &Target
)
1706 : pkgAcqTransactionItem(Owner
, TransactionManager
, Target
), d(NULL
)
1710 pkgAcqBaseIndex::~pkgAcqBaseIndex() {}
1712 // AcqDiffIndex::AcqDiffIndex - Constructor /*{{{*/
1713 // ---------------------------------------------------------------------
1714 /* Get the DiffIndex file first and see if there are patches available
1715 * If so, create a pkgAcqIndexDiffs fetcher that will get and apply the
1716 * patches. If anything goes wrong in that process, it will fall back to
1717 * the original packages file
1719 pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire
* const Owner
,
1720 pkgAcqMetaClearSig
* const TransactionManager
,
1721 IndexTarget
const &Target
)
1722 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
), diffs(NULL
)
1724 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
1727 Desc
.Description
= Target
.Description
+ ".diff/Index";
1728 Desc
.ShortDesc
= Target
.ShortDesc
;
1729 Desc
.URI
= Target
.URI
+ ".diff/Index";
1731 DestFile
= GetPartialFileNameFromURI(Desc
.URI
);
1734 std::clog
<< "pkgAcqDiffIndex: " << Desc
.URI
<< std::endl
;
1739 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
1740 // ---------------------------------------------------------------------
1741 /* The only header we use is the last-modified header. */
1742 string
pkgAcqDiffIndex::Custom600Headers() const
1744 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1745 return "\nIndex-File: true";
1747 string
const Final
= GetFinalFilename();
1750 std::clog
<< "Custom600Header-IMS: " << Final
<< std::endl
;
1753 if (stat(Final
.c_str(),&Buf
) != 0)
1754 return "\nIndex-File: true";
1756 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1759 void pkgAcqDiffIndex::QueueOnIMSHit() const /*{{{*/
1761 // list cleanup needs to know that this file as well as the already
1762 // present index is ours, so we create an empty diff to save it for us
1763 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
);
1766 bool pkgAcqDiffIndex::ParseDiffIndex(string
const &IndexDiffFile
) /*{{{*/
1768 // failing here is fine: our caller will take care of trying to
1769 // get the complete file if patching fails
1771 std::clog
<< "pkgAcqDiffIndex::ParseIndexDiff() " << IndexDiffFile
1774 FileFd
Fd(IndexDiffFile
,FileFd::ReadOnly
);
1776 if (Fd
.IsOpen() == false || Fd
.Failed())
1780 if(unlikely(TF
.Step(Tags
) == false))
1783 HashStringList ServerHashes
;
1784 unsigned long long ServerSize
= 0;
1786 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
1788 std::string tagname
= *type
;
1789 tagname
.append("-Current");
1790 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1791 if (tmp
.empty() == true)
1795 unsigned long long size
;
1796 std::stringstream
ss(tmp
);
1798 if (unlikely(hash
.empty() == true))
1800 if (unlikely(ServerSize
!= 0 && ServerSize
!= size
))
1802 ServerHashes
.push_back(HashString(*type
, hash
));
1806 if (ServerHashes
.usable() == false)
1809 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": Did not find a good hashsum in the index" << std::endl
;
1813 std::string
const CurrentPackagesFile
= GetFinalFileNameFromURI(Target
.URI
);
1814 HashStringList
const TargetFileHashes
= GetExpectedHashesFor(Target
.MetaKey
);
1815 if (TargetFileHashes
.usable() == false || ServerHashes
!= TargetFileHashes
)
1819 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": Index has different hashes than parser, probably older, so fail pdiffing" << std::endl
;
1820 printHashSumComparision(CurrentPackagesFile
, ServerHashes
, TargetFileHashes
);
1825 HashStringList LocalHashes
;
1826 // try avoiding calculating the hash here as this is costly
1827 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1828 LocalHashes
= GetExpectedHashesFromFor(TransactionManager
->LastMetaIndexParser
, Target
.MetaKey
);
1829 if (LocalHashes
.usable() == false)
1831 FileFd
fd(CurrentPackagesFile
, FileFd::ReadOnly
, FileFd::Auto
);
1832 Hashes
LocalHashesCalc(ServerHashes
);
1833 LocalHashesCalc
.AddFD(fd
);
1834 LocalHashes
= LocalHashesCalc
.GetHashStringList();
1837 if (ServerHashes
== LocalHashes
)
1839 // we have the same sha1 as the server so we are done here
1841 std::clog
<< "pkgAcqDiffIndex: Package file " << CurrentPackagesFile
<< " is up-to-date" << std::endl
;
1847 std::clog
<< "Server-Current: " << ServerHashes
.find(NULL
)->toStr() << " and we start at "
1848 << CurrentPackagesFile
<< " " << LocalHashes
.FileSize() << " " << LocalHashes
.find(NULL
)->toStr() << std::endl
;
1850 // historically, older hashes have more info than newer ones, so start
1851 // collecting with older ones first to avoid implementing complicated
1852 // information merging techniques… a failure is after all always
1853 // recoverable with a complete file and hashes aren't changed that often.
1854 std::vector
<char const *> types
;
1855 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
1856 types
.push_back(*type
);
1858 // parse all of (provided) history
1859 vector
<DiffInfo
> available_patches
;
1860 bool firstAcceptedHashes
= true;
1861 for (auto type
= types
.crbegin(); type
!= types
.crend(); ++type
)
1863 if (LocalHashes
.find(*type
) == NULL
)
1866 std::string tagname
= *type
;
1867 tagname
.append("-History");
1868 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1869 if (tmp
.empty() == true)
1872 string hash
, filename
;
1873 unsigned long long size
;
1874 std::stringstream
ss(tmp
);
1876 while (ss
>> hash
>> size
>> filename
)
1878 if (unlikely(hash
.empty() == true || filename
.empty() == true))
1881 // see if we have a record for this file already
1882 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
1883 for (; cur
!= available_patches
.end(); ++cur
)
1885 if (cur
->file
!= filename
)
1887 cur
->result_hashes
.push_back(HashString(*type
, hash
));
1890 if (cur
!= available_patches
.end())
1892 if (firstAcceptedHashes
== true)
1895 next
.file
= filename
;
1896 next
.result_hashes
.push_back(HashString(*type
, hash
));
1897 next
.result_hashes
.FileSize(size
);
1898 available_patches
.push_back(next
);
1903 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
1904 << " wasn't in the list for the first parsed hash! (history)" << std::endl
;
1908 firstAcceptedHashes
= false;
1911 if (unlikely(available_patches
.empty() == true))
1914 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": "
1915 << "Couldn't find any patches for the patch series." << std::endl
;
1919 for (auto type
= types
.crbegin(); type
!= types
.crend(); ++type
)
1921 if (LocalHashes
.find(*type
) == NULL
)
1924 std::string tagname
= *type
;
1925 tagname
.append("-Patches");
1926 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1927 if (tmp
.empty() == true)
1930 string hash
, filename
;
1931 unsigned long long size
;
1932 std::stringstream
ss(tmp
);
1934 while (ss
>> hash
>> size
>> filename
)
1936 if (unlikely(hash
.empty() == true || filename
.empty() == true))
1939 // see if we have a record for this file already
1940 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
1941 for (; cur
!= available_patches
.end(); ++cur
)
1943 if (cur
->file
!= filename
)
1945 if (cur
->patch_hashes
.empty())
1946 cur
->patch_hashes
.FileSize(size
);
1947 cur
->patch_hashes
.push_back(HashString(*type
, hash
));
1950 if (cur
!= available_patches
.end())
1953 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
1954 << " wasn't in the list for the first parsed hash! (patches)" << std::endl
;
1959 for (auto type
= types
.crbegin(); type
!= types
.crend(); ++type
)
1961 std::string tagname
= *type
;
1962 tagname
.append("-Download");
1963 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1964 if (tmp
.empty() == true)
1967 string hash
, filename
;
1968 unsigned long long size
;
1969 std::stringstream
ss(tmp
);
1971 // FIXME: all of pdiff supports only .gz compressed patches
1972 while (ss
>> hash
>> size
>> filename
)
1974 if (unlikely(hash
.empty() == true || filename
.empty() == true))
1976 if (unlikely(APT::String::Endswith(filename
, ".gz") == false))
1978 filename
.erase(filename
.length() - 3);
1980 // see if we have a record for this file already
1981 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
1982 for (; cur
!= available_patches
.end(); ++cur
)
1984 if (cur
->file
!= filename
)
1986 if (cur
->download_hashes
.empty())
1987 cur
->download_hashes
.FileSize(size
);
1988 cur
->download_hashes
.push_back(HashString(*type
, hash
));
1991 if (cur
!= available_patches
.end())
1994 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
1995 << " wasn't in the list for the first parsed hash! (download)" << std::endl
;
2001 bool foundStart
= false;
2002 for (std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
2003 cur
!= available_patches
.end(); ++cur
)
2005 if (LocalHashes
!= cur
->result_hashes
)
2008 available_patches
.erase(available_patches
.begin(), cur
);
2013 if (foundStart
== false || unlikely(available_patches
.empty() == true))
2016 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": "
2017 << "Couldn't find the start of the patch series." << std::endl
;
2021 // patching with too many files is rather slow compared to a fast download
2022 unsigned long const fileLimit
= _config
->FindI("Acquire::PDiffs::FileLimit", 0);
2023 if (fileLimit
!= 0 && fileLimit
< available_patches
.size())
2026 std::clog
<< "Need " << available_patches
.size() << " diffs (Limit is " << fileLimit
2027 << ") so fallback to complete download" << std::endl
;
2031 // calculate the size of all patches we have to get
2032 // note that all sizes are uncompressed, while we download compressed files
2033 unsigned long long patchesSize
= 0;
2034 for (std::vector
<DiffInfo
>::const_iterator cur
= available_patches
.begin();
2035 cur
!= available_patches
.end(); ++cur
)
2036 patchesSize
+= cur
->patch_hashes
.FileSize();
2037 unsigned long long const sizeLimit
= ServerSize
* _config
->FindI("Acquire::PDiffs::SizeLimit", 100);
2038 if (sizeLimit
> 0 && (sizeLimit
/100) < patchesSize
)
2041 std::clog
<< "Need " << patchesSize
<< " bytes (Limit is " << sizeLimit
/100
2042 << ") so fallback to complete download" << std::endl
;
2046 // we have something, queue the diffs
2047 string::size_type
const last_space
= Description
.rfind(" ");
2048 if(last_space
!= string::npos
)
2049 Description
.erase(last_space
, Description
.size()-last_space
);
2051 /* decide if we should download patches one by one or in one go:
2052 The first is good if the server merges patches, but many don't so client
2053 based merging can be attempt in which case the second is better.
2054 "bad things" will happen if patches are merged on the server,
2055 but client side merging is attempt as well */
2056 bool pdiff_merge
= _config
->FindB("Acquire::PDiffs::Merge", true);
2057 if (pdiff_merge
== true)
2059 // reprepro adds this flag if it has merged patches on the server
2060 std::string
const precedence
= Tags
.FindS("X-Patch-Precedence");
2061 pdiff_merge
= (precedence
!= "merged");
2064 if (pdiff_merge
== false)
2065 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
, available_patches
);
2068 diffs
= new std::vector
<pkgAcqIndexMergeDiffs
*>(available_patches
.size());
2069 for(size_t i
= 0; i
< available_patches
.size(); ++i
)
2070 (*diffs
)[i
] = new pkgAcqIndexMergeDiffs(Owner
, TransactionManager
,
2072 available_patches
[i
],
2082 void pkgAcqDiffIndex::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
2084 Item::Failed(Message
,Cnf
);
2088 std::clog
<< "pkgAcqDiffIndex failed: " << Desc
.URI
<< " with " << Message
<< std::endl
2089 << "Falling back to normal index file acquire" << std::endl
;
2091 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
2094 void pkgAcqDiffIndex::Done(string
const &Message
,HashStringList
const &Hashes
, /*{{{*/
2095 pkgAcquire::MethodConfig
const * const Cnf
)
2098 std::clog
<< "pkgAcqDiffIndex::Done(): " << Desc
.URI
<< std::endl
;
2100 Item::Done(Message
, Hashes
, Cnf
);
2102 string
const FinalFile
= GetFinalFilename();
2103 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false))
2104 DestFile
= FinalFile
;
2106 if(ParseDiffIndex(DestFile
) == false)
2108 Failed("Message: Couldn't parse pdiff index", Cnf
);
2109 // queue for final move - this should happen even if we fail
2110 // while parsing (e.g. on sizelimit) and download the complete file.
2111 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
2115 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
2124 pkgAcqDiffIndex::~pkgAcqDiffIndex()
2130 // AcqIndexDiffs::AcqIndexDiffs - Constructor /*{{{*/
2131 // ---------------------------------------------------------------------
2132 /* The package diff is added to the queue. one object is constructed
2133 * for each diff and the index
2135 pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire
* const Owner
,
2136 pkgAcqMetaClearSig
* const TransactionManager
,
2137 IndexTarget
const &Target
,
2138 vector
<DiffInfo
> const &diffs
)
2139 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
),
2140 available_patches(diffs
)
2142 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
2144 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
2147 Description
= Target
.Description
;
2148 Desc
.ShortDesc
= Target
.ShortDesc
;
2150 if(available_patches
.empty() == true)
2152 // we are done (yeah!), check hashes against the final file
2153 DestFile
= GetKeepCompressedFileName(GetFinalFileNameFromURI(Target
.URI
), Target
);
2158 if (BootstrapPDiffWith(GetPartialFileNameFromURI(Target
.URI
), GetFinalFilename(), Target
) == false)
2160 Failed("Bootstrapping of " + DestFile
+ " failed", NULL
);
2164 // get the next diff
2165 State
= StateFetchDiff
;
2170 void pkgAcqIndexDiffs::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
2172 Item::Failed(Message
,Cnf
);
2175 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
2177 std::clog
<< "pkgAcqIndexDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
2178 << "Falling back to normal index file acquire " << std::endl
;
2179 RenameOnError(PDiffError
);
2180 std::string
const patchname
= GetDiffsPatchFileName(DestFile
);
2181 if (RealFileExists(patchname
))
2182 rename(patchname
.c_str(), std::string(patchname
+ ".FAILED").c_str());
2183 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
2187 // Finish - helper that cleans the item out of the fetcher queue /*{{{*/
2188 void pkgAcqIndexDiffs::Finish(bool allDone
)
2191 std::clog
<< "pkgAcqIndexDiffs::Finish(): "
2193 << Desc
.URI
<< std::endl
;
2195 // we restore the original name, this is required, otherwise
2196 // the file will be cleaned
2199 std::string Final
= GetFinalFilename();
2200 if (Target
.KeepCompressed
)
2202 std::string
const ext
= flExtension(DestFile
);
2203 if (ext
.empty() == false)
2204 Final
.append(".").append(ext
);
2206 TransactionManager
->TransactionStageCopy(this, DestFile
, Final
);
2208 // this is for the "real" finish
2213 std::clog
<< "\n\nallDone: " << DestFile
<< "\n" << std::endl
;
2220 std::clog
<< "Finishing: " << Desc
.URI
<< std::endl
;
2227 bool pkgAcqIndexDiffs::QueueNextDiff() /*{{{*/
2229 // calc sha1 of the just patched file
2230 std::string
const FinalFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
2231 if(!FileExists(FinalFile
))
2233 Failed("Message: No FinalFile " + FinalFile
+ " available", NULL
);
2237 FileFd
fd(FinalFile
, FileFd::ReadOnly
, FileFd::Extension
);
2238 Hashes LocalHashesCalc
;
2239 LocalHashesCalc
.AddFD(fd
);
2240 HashStringList
const LocalHashes
= LocalHashesCalc
.GetHashStringList();
2243 std::clog
<< "QueueNextDiff: " << FinalFile
<< " (" << LocalHashes
.find(NULL
)->toStr() << ")" << std::endl
;
2245 HashStringList
const TargetFileHashes
= GetExpectedHashesFor(Target
.MetaKey
);
2246 if (unlikely(LocalHashes
.usable() == false || TargetFileHashes
.usable() == false))
2248 Failed("Local/Expected hashes are not usable", NULL
);
2253 // final file reached before all patches are applied
2254 if(LocalHashes
== TargetFileHashes
)
2260 // remove all patches until the next matching patch is found
2261 // this requires the Index file to be ordered
2262 available_patches
.erase(available_patches
.begin(),
2263 std::find_if(available_patches
.begin(), available_patches
.end(), [&](DiffInfo
const &I
) {
2264 return I
.result_hashes
== LocalHashes
;
2267 // error checking and falling back if no patch was found
2268 if(available_patches
.empty() == true)
2270 Failed("No patches left to reach target", NULL
);
2274 // queue the right diff
2275 Desc
.URI
= Target
.URI
+ ".diff/" + available_patches
[0].file
+ ".gz";
2276 Desc
.Description
= Description
+ " " + available_patches
[0].file
+ string(".pdiff");
2277 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
+ ".diff/" + available_patches
[0].file
), Target
);
2280 std::clog
<< "pkgAcqIndexDiffs::QueueNextDiff(): " << Desc
.URI
<< std::endl
;
2287 void pkgAcqIndexDiffs::Done(string
const &Message
, HashStringList
const &Hashes
, /*{{{*/
2288 pkgAcquire::MethodConfig
const * const Cnf
)
2291 std::clog
<< "pkgAcqIndexDiffs::Done(): " << Desc
.URI
<< std::endl
;
2293 Item::Done(Message
, Hashes
, Cnf
);
2295 std::string
const FinalFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
2296 std::string
const PatchFile
= GetDiffsPatchFileName(FinalFile
);
2298 // success in downloading a diff, enter ApplyDiff state
2299 if(State
== StateFetchDiff
)
2301 Rename(DestFile
, PatchFile
);
2304 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
2306 State
= StateApplyDiff
;
2308 Desc
.URI
= "rred:" + FinalFile
;
2310 SetActiveSubprocess("rred");
2314 // success in download/apply a diff, queue next (if needed)
2315 if(State
== StateApplyDiff
)
2317 // remove the just applied patch
2318 available_patches
.erase(available_patches
.begin());
2319 RemoveFile("pkgAcqIndexDiffs::Done", PatchFile
);
2324 std::clog
<< "Moving patched file in place: " << std::endl
2325 << DestFile
<< " -> " << FinalFile
<< std::endl
;
2327 Rename(DestFile
,FinalFile
);
2328 chmod(FinalFile
.c_str(),0644);
2330 // see if there is more to download
2331 if(available_patches
.empty() == false) {
2332 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
,
2337 DestFile
= FinalFile
;
2338 return Finish(true);
2342 std::string
pkgAcqIndexDiffs::Custom600Headers() const /*{{{*/
2344 if(State
!= StateApplyDiff
)
2345 return pkgAcqBaseIndex::Custom600Headers();
2346 std::ostringstream patchhashes
;
2347 HashStringList
const ExpectedHashes
= available_patches
[0].patch_hashes
;
2348 for (HashStringList::const_iterator hs
= ExpectedHashes
.begin(); hs
!= ExpectedHashes
.end(); ++hs
)
2349 patchhashes
<< "\nPatch-0-" << hs
->HashType() << "-Hash: " << hs
->HashValue();
2350 patchhashes
<< pkgAcqBaseIndex::Custom600Headers();
2351 return patchhashes
.str();
2354 pkgAcqIndexDiffs::~pkgAcqIndexDiffs() {}
2356 // AcqIndexMergeDiffs::AcqIndexMergeDiffs - Constructor /*{{{*/
2357 pkgAcqIndexMergeDiffs::pkgAcqIndexMergeDiffs(pkgAcquire
* const Owner
,
2358 pkgAcqMetaClearSig
* const TransactionManager
,
2359 IndexTarget
const &Target
,
2360 DiffInfo
const &patch
,
2361 std::vector
<pkgAcqIndexMergeDiffs
*> const * const allPatches
)
2362 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
),
2363 patch(patch
), allPatches(allPatches
), State(StateFetchDiff
)
2365 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
2368 Description
= Target
.Description
;
2369 Desc
.ShortDesc
= Target
.ShortDesc
;
2371 Desc
.URI
= Target
.URI
+ ".diff/" + patch
.file
+ ".gz";
2372 Desc
.Description
= Description
+ " " + patch
.file
+ string(".pdiff");
2374 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
+ ".diff/" + patch
.file
), Target
);
2377 std::clog
<< "pkgAcqIndexMergeDiffs: " << Desc
.URI
<< std::endl
;
2382 void pkgAcqIndexMergeDiffs::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
2385 std::clog
<< "pkgAcqIndexMergeDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
;
2387 Item::Failed(Message
,Cnf
);
2390 // check if we are the first to fail, otherwise we are done here
2391 State
= StateDoneDiff
;
2392 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2393 I
!= allPatches
->end(); ++I
)
2394 if ((*I
)->State
== StateErrorDiff
)
2397 // first failure means we should fallback
2398 State
= StateErrorDiff
;
2400 std::clog
<< "Falling back to normal index file acquire" << std::endl
;
2401 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
2402 RenameOnError(PDiffError
);
2403 std::string
const patchname
= GetMergeDiffsPatchFileName(DestFile
, patch
.file
);
2404 if (RealFileExists(patchname
))
2405 rename(patchname
.c_str(), std::string(patchname
+ ".FAILED").c_str());
2406 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
2410 void pkgAcqIndexMergeDiffs::Done(string
const &Message
, HashStringList
const &Hashes
, /*{{{*/
2411 pkgAcquire::MethodConfig
const * const Cnf
)
2414 std::clog
<< "pkgAcqIndexMergeDiffs::Done(): " << Desc
.URI
<< std::endl
;
2416 Item::Done(Message
, Hashes
, Cnf
);
2418 std::string
const UncompressedFinalFile
= GetPartialFileNameFromURI(Target
.URI
);
2419 std::string
const FinalFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
2420 if (State
== StateFetchDiff
)
2422 Rename(DestFile
, GetMergeDiffsPatchFileName(FinalFile
, patch
.file
));
2424 // check if this is the last completed diff
2425 State
= StateDoneDiff
;
2426 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2427 I
!= allPatches
->end(); ++I
)
2428 if ((*I
)->State
!= StateDoneDiff
)
2431 std::clog
<< "Not the last done diff in the batch: " << Desc
.URI
<< std::endl
;
2435 // this is the last completed diff, so we are ready to apply now
2436 State
= StateApplyDiff
;
2438 if (BootstrapPDiffWith(UncompressedFinalFile
, GetFinalFilename(), Target
) == false)
2440 Failed("Bootstrapping of " + DestFile
+ " failed", NULL
);
2445 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
2448 Desc
.URI
= "rred:" + FinalFile
;
2450 SetActiveSubprocess("rred");
2453 // success in download/apply all diffs, clean up
2454 else if (State
== StateApplyDiff
)
2456 // move the result into place
2457 std::string
const Final
= GetKeepCompressedFileName(GetFinalFilename(), Target
);
2459 std::clog
<< "Queue patched file in place: " << std::endl
2460 << DestFile
<< " -> " << Final
<< std::endl
;
2462 // queue for copy by the transaction manager
2463 TransactionManager
->TransactionStageCopy(this, DestFile
, Final
);
2465 // ensure the ed's are gone regardless of list-cleanup
2466 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2467 I
!= allPatches
->end(); ++I
)
2469 std::string
const PartialFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
2470 std::string
const patch
= GetMergeDiffsPatchFileName(PartialFile
, (*I
)->patch
.file
);
2471 RemoveFile("pkgAcqIndexMergeDiffs::Done", patch
);
2473 RemoveFile("pkgAcqIndexMergeDiffs::Done", FinalFile
);
2478 std::clog
<< "allDone: " << DestFile
<< "\n" << std::endl
;
2482 std::string
pkgAcqIndexMergeDiffs::Custom600Headers() const /*{{{*/
2484 if(State
!= StateApplyDiff
)
2485 return pkgAcqBaseIndex::Custom600Headers();
2486 std::ostringstream patchhashes
;
2487 unsigned int seen_patches
= 0;
2488 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2489 I
!= allPatches
->end(); ++I
)
2491 HashStringList
const ExpectedHashes
= (*I
)->patch
.patch_hashes
;
2492 for (HashStringList::const_iterator hs
= ExpectedHashes
.begin(); hs
!= ExpectedHashes
.end(); ++hs
)
2493 patchhashes
<< "\nPatch-" << seen_patches
<< "-" << hs
->HashType() << "-Hash: " << hs
->HashValue();
2496 patchhashes
<< pkgAcqBaseIndex::Custom600Headers();
2497 return patchhashes
.str();
2500 pkgAcqIndexMergeDiffs::~pkgAcqIndexMergeDiffs() {}
2502 // AcqIndex::AcqIndex - Constructor /*{{{*/
2503 pkgAcqIndex::pkgAcqIndex(pkgAcquire
* const Owner
,
2504 pkgAcqMetaClearSig
* const TransactionManager
,
2505 IndexTarget
const &Target
)
2506 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
), Stage(STAGE_DOWNLOAD
),
2507 CompressionExtensions(Target
.Option(IndexTarget::COMPRESSIONTYPES
))
2509 Init(Target
.URI
, Target
.Description
, Target
.ShortDesc
);
2511 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
2512 std::clog
<< "New pkgIndex with TransactionManager "
2513 << TransactionManager
<< std::endl
;
2516 // AcqIndex::Init - defered Constructor /*{{{*/
2517 static void NextCompressionExtension(std::string
&CurrentCompressionExtension
, std::string
&CompressionExtensions
, bool const preview
)
2519 size_t const nextExt
= CompressionExtensions
.find(' ');
2520 if (nextExt
== std::string::npos
)
2522 CurrentCompressionExtension
= CompressionExtensions
;
2523 if (preview
== false)
2524 CompressionExtensions
.clear();
2528 CurrentCompressionExtension
= CompressionExtensions
.substr(0, nextExt
);
2529 if (preview
== false)
2530 CompressionExtensions
= CompressionExtensions
.substr(nextExt
+1);
2533 void pkgAcqIndex::Init(string
const &URI
, string
const &URIDesc
,
2534 string
const &ShortDesc
)
2536 Stage
= STAGE_DOWNLOAD
;
2538 DestFile
= GetPartialFileNameFromURI(URI
);
2539 NextCompressionExtension(CurrentCompressionExtension
, CompressionExtensions
, false);
2541 if (CurrentCompressionExtension
== "uncompressed")
2545 else if (CurrentCompressionExtension
== "by-hash")
2547 NextCompressionExtension(CurrentCompressionExtension
, CompressionExtensions
, true);
2548 if(unlikely(TransactionManager
->MetaIndexParser
== NULL
|| CurrentCompressionExtension
.empty()))
2550 if (CurrentCompressionExtension
!= "uncompressed")
2552 Desc
.URI
= URI
+ '.' + CurrentCompressionExtension
;
2553 DestFile
= DestFile
+ '.' + CurrentCompressionExtension
;
2556 HashStringList
const Hashes
= GetExpectedHashes();
2557 HashString
const * const TargetHash
= Hashes
.find(NULL
);
2558 if (unlikely(TargetHash
== nullptr))
2560 std::string
const ByHash
= "/by-hash/" + TargetHash
->HashType() + "/" + TargetHash
->HashValue();
2561 size_t const trailing_slash
= Desc
.URI
.find_last_of("/");
2562 if (unlikely(trailing_slash
== std::string::npos
))
2564 Desc
.URI
= Desc
.URI
.replace(
2566 Desc
.URI
.substr(trailing_slash
+1).size()+1,
2569 else if (unlikely(CurrentCompressionExtension
.empty()))
2573 Desc
.URI
= URI
+ '.' + CurrentCompressionExtension
;
2574 DestFile
= DestFile
+ '.' + CurrentCompressionExtension
;
2578 Desc
.Description
= URIDesc
;
2580 Desc
.ShortDesc
= ShortDesc
;
2585 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
2586 // ---------------------------------------------------------------------
2587 /* The only header we use is the last-modified header. */
2588 string
pkgAcqIndex::Custom600Headers() const
2591 string msg
= "\nIndex-File: true";
2593 if (TransactionManager
->LastMetaIndexParser
== NULL
)
2595 std::string
const Final
= GetFinalFilename();
2598 if (stat(Final
.c_str(),&Buf
) == 0)
2599 msg
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
2602 if(Target
.IsOptional
)
2603 msg
+= "\nFail-Ignore: true";
2608 // AcqIndex::Failed - getting the indexfile failed /*{{{*/
2609 void pkgAcqIndex::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)
2611 Item::Failed(Message
,Cnf
);
2613 // authorisation matches will not be fixed by other compression types
2614 if (Status
!= StatAuthError
)
2616 if (CompressionExtensions
.empty() == false)
2618 Init(Target
.URI
, Desc
.Description
, Desc
.ShortDesc
);
2624 if(Target
.IsOptional
&& GetExpectedHashes().empty() && Stage
== STAGE_DOWNLOAD
)
2627 TransactionManager
->AbortTransaction();
2630 // AcqIndex::ReverifyAfterIMS - Reverify index after an ims-hit /*{{{*/
2631 void pkgAcqIndex::ReverifyAfterIMS()
2633 // update destfile to *not* include the compression extension when doing
2634 // a reverify (as its uncompressed on disk already)
2635 DestFile
= GetCompressedFileName(Target
, GetPartialFileNameFromURI(Target
.URI
), CurrentCompressionExtension
);
2637 // copy FinalFile into partial/ so that we check the hash again
2638 string FinalFile
= GetFinalFilename();
2639 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
2640 Desc
.URI
= "copy:" + FinalFile
;
2644 // AcqIndex::Done - Finished a fetch /*{{{*/
2645 // ---------------------------------------------------------------------
2646 /* This goes through a number of states.. On the initial fetch the
2647 method could possibly return an alternate filename which points
2648 to the uncompressed version of the file. If this is so the file
2649 is copied into the partial directory. In all other cases the file
2650 is decompressed with a compressed uri. */
2651 void pkgAcqIndex::Done(string
const &Message
,
2652 HashStringList
const &Hashes
,
2653 pkgAcquire::MethodConfig
const * const Cfg
)
2655 Item::Done(Message
,Hashes
,Cfg
);
2659 case STAGE_DOWNLOAD
:
2660 StageDownloadDone(Message
, Hashes
, Cfg
);
2662 case STAGE_DECOMPRESS_AND_VERIFY
:
2663 StageDecompressDone(Message
, Hashes
, Cfg
);
2668 // AcqIndex::StageDownloadDone - Queue for decompress and verify /*{{{*/
2669 void pkgAcqIndex::StageDownloadDone(string
const &Message
, HashStringList
const &,
2670 pkgAcquire::MethodConfig
const * const)
2674 // Handle the unzipd case
2675 std::string FileName
= LookupTag(Message
,"Alt-Filename");
2676 if (FileName
.empty() == false)
2678 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
2680 DestFile
+= ".decomp";
2681 Desc
.URI
= "copy:" + FileName
;
2683 SetActiveSubprocess("copy");
2686 FileName
= LookupTag(Message
,"Filename");
2688 // Methods like e.g. "file:" will give us a (compressed) FileName that is
2689 // not the "DestFile" we set, in this case we uncompress from the local file
2690 if (FileName
!= DestFile
&& RealFileExists(DestFile
) == false)
2693 if (Target
.KeepCompressed
== true)
2695 // but if we don't keep the uncompress we copy the compressed file first
2696 Stage
= STAGE_DOWNLOAD
;
2697 Desc
.URI
= "copy:" + FileName
;
2699 SetActiveSubprocess("copy");
2704 EraseFileName
= FileName
;
2706 // we need to verify the file against the current Release file again
2707 // on if-modfied-since hit to avoid a stale attack against us
2708 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
2710 // The files timestamp matches, reverify by copy into partial/
2716 // get the binary name for your used compression type
2718 if(CurrentCompressionExtension
== "uncompressed")
2719 decompProg
= "copy";
2721 decompProg
= _config
->Find(string("Acquire::CompressionTypes::").append(CurrentCompressionExtension
),"");
2722 if(decompProg
.empty() == true)
2724 _error
->Error("Unsupported extension: %s", CurrentCompressionExtension
.c_str());
2728 if (Target
.KeepCompressed
== true)
2730 DestFile
= "/dev/null";
2731 EraseFileName
.clear();
2734 DestFile
+= ".decomp";
2736 // queue uri for the next stage
2737 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
2738 Desc
.URI
= decompProg
+ ":" + FileName
;
2740 SetActiveSubprocess(decompProg
);
2743 // AcqIndex::StageDecompressDone - Final verification /*{{{*/
2744 void pkgAcqIndex::StageDecompressDone(string
const &,
2745 HashStringList
const &,
2746 pkgAcquire::MethodConfig
const * const)
2748 if (Target
.KeepCompressed
== true && DestFile
== "/dev/null")
2749 DestFile
= GetPartialFileNameFromURI(Target
.URI
+ '.' + CurrentCompressionExtension
);
2751 // Done, queue for rename on transaction finished
2752 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
2756 pkgAcqIndex::~pkgAcqIndex() {}
2759 // AcqArchive::AcqArchive - Constructor /*{{{*/
2760 // ---------------------------------------------------------------------
2761 /* This just sets up the initial fetch environment and queues the first
2763 pkgAcqArchive::pkgAcqArchive(pkgAcquire
* const Owner
,pkgSourceList
* const Sources
,
2764 pkgRecords
* const Recs
,pkgCache::VerIterator
const &Version
,
2765 string
&StoreFilename
) :
2766 Item(Owner
), d(NULL
), LocalSource(false), Version(Version
), Sources(Sources
), Recs(Recs
),
2767 StoreFilename(StoreFilename
), Vf(Version
.FileList()),
2770 Retries
= _config
->FindI("Acquire::Retries",0);
2772 if (Version
.Arch() == 0)
2774 _error
->Error(_("I wasn't able to locate a file for the %s package. "
2775 "This might mean you need to manually fix this package. "
2776 "(due to missing arch)"),
2777 Version
.ParentPkg().FullName().c_str());
2781 /* We need to find a filename to determine the extension. We make the
2782 assumption here that all the available sources for this version share
2783 the same extension.. */
2784 // Skip not source sources, they do not have file fields.
2785 for (; Vf
.end() == false; ++Vf
)
2787 if (Vf
.File().Flagged(pkgCache::Flag::NotSource
))
2792 // Does not really matter here.. we are going to fail out below
2793 if (Vf
.end() != true)
2795 // If this fails to get a file name we will bomb out below.
2796 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2797 if (_error
->PendingError() == true)
2800 // Generate the final file name as: package_version_arch.foo
2801 StoreFilename
= QuoteString(Version
.ParentPkg().Name(),"_:") + '_' +
2802 QuoteString(Version
.VerStr(),"_:") + '_' +
2803 QuoteString(Version
.Arch(),"_:.") +
2804 "." + flExtension(Parse
.FileName());
2807 // check if we have one trusted source for the package. if so, switch
2808 // to "TrustedOnly" mode - but only if not in AllowUnauthenticated mode
2809 bool const allowUnauth
= _config
->FindB("APT::Get::AllowUnauthenticated", false);
2810 bool const debugAuth
= _config
->FindB("Debug::pkgAcquire::Auth", false);
2811 bool seenUntrusted
= false;
2812 for (pkgCache::VerFileIterator i
= Version
.FileList(); i
.end() == false; ++i
)
2814 pkgIndexFile
*Index
;
2815 if (Sources
->FindIndex(i
.File(),Index
) == false)
2818 if (debugAuth
== true)
2819 std::cerr
<< "Checking index: " << Index
->Describe()
2820 << "(Trusted=" << Index
->IsTrusted() << ")" << std::endl
;
2822 if (Index
->IsTrusted() == true)
2825 if (allowUnauth
== false)
2829 seenUntrusted
= true;
2832 // "allow-unauthenticated" restores apts old fetching behaviour
2833 // that means that e.g. unauthenticated file:// uris are higher
2834 // priority than authenticated http:// uris
2835 if (allowUnauth
== true && seenUntrusted
== true)
2839 if (QueueNext() == false && _error
->PendingError() == false)
2840 _error
->Error(_("Can't find a source to download version '%s' of '%s'"),
2841 Version
.VerStr(), Version
.ParentPkg().FullName(false).c_str());
2844 // AcqArchive::QueueNext - Queue the next file source /*{{{*/
2845 // ---------------------------------------------------------------------
2846 /* This queues the next available file version for download. It checks if
2847 the archive is already available in the cache and stashs the MD5 for
2849 bool pkgAcqArchive::QueueNext()
2851 for (; Vf
.end() == false; ++Vf
)
2853 pkgCache::PkgFileIterator
const PkgF
= Vf
.File();
2854 // Ignore not source sources
2855 if (PkgF
.Flagged(pkgCache::Flag::NotSource
))
2858 // Try to cross match against the source list
2859 pkgIndexFile
*Index
;
2860 if (Sources
->FindIndex(PkgF
, Index
) == false)
2862 LocalSource
= PkgF
.Flagged(pkgCache::Flag::LocalSource
);
2864 // only try to get a trusted package from another source if that source
2866 if(Trusted
&& !Index
->IsTrusted())
2869 // Grab the text package record
2870 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2871 if (_error
->PendingError() == true)
2874 string PkgFile
= Parse
.FileName();
2875 ExpectedHashes
= Parse
.Hashes();
2877 if (PkgFile
.empty() == true)
2878 return _error
->Error(_("The package index files are corrupted. No Filename: "
2879 "field for package %s."),
2880 Version
.ParentPkg().Name());
2882 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
2883 Desc
.Description
= Index
->ArchiveInfo(Version
);
2885 Desc
.ShortDesc
= Version
.ParentPkg().FullName(true);
2887 // See if we already have the file. (Legacy filenames)
2888 FileSize
= Version
->Size
;
2889 string FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile
);
2891 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2893 // Make sure the size matches
2894 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2899 StoreFilename
= DestFile
= FinalFile
;
2903 /* Hmm, we have a file and its size does not match, this means it is
2904 an old style mismatched arch */
2905 RemoveFile("pkgAcqArchive::QueueNext", FinalFile
);
2908 // Check it again using the new style output filenames
2909 FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
2910 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2912 // Make sure the size matches
2913 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2918 StoreFilename
= DestFile
= FinalFile
;
2922 /* Hmm, we have a file and its size does not match, this shouldn't
2924 RemoveFile("pkgAcqArchive::QueueNext", FinalFile
);
2927 DestFile
= _config
->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename
);
2929 // Check the destination file
2930 if (stat(DestFile
.c_str(),&Buf
) == 0)
2932 // Hmm, the partial file is too big, erase it
2933 if ((unsigned long long)Buf
.st_size
> Version
->Size
)
2934 RemoveFile("pkgAcqArchive::QueueNext", DestFile
);
2936 PartialSize
= Buf
.st_size
;
2939 // Disables download of archives - useful if no real installation follows,
2940 // e.g. if we are just interested in proposed installation order
2941 if (_config
->FindB("Debug::pkgAcqArchive::NoQueue", false) == true)
2946 StoreFilename
= DestFile
= FinalFile
;
2960 // AcqArchive::Done - Finished fetching /*{{{*/
2961 // ---------------------------------------------------------------------
2963 void pkgAcqArchive::Done(string
const &Message
, HashStringList
const &Hashes
,
2964 pkgAcquire::MethodConfig
const * const Cfg
)
2966 Item::Done(Message
, Hashes
, Cfg
);
2968 // Grab the output filename
2969 std::string
const FileName
= LookupTag(Message
,"Filename");
2970 if (DestFile
!= FileName
&& RealFileExists(DestFile
) == false)
2972 StoreFilename
= DestFile
= FileName
;
2978 // Done, move it into position
2979 string
const FinalFile
= GetFinalFilename();
2980 Rename(DestFile
,FinalFile
);
2981 StoreFilename
= DestFile
= FinalFile
;
2985 // AcqArchive::Failed - Failure handler /*{{{*/
2986 // ---------------------------------------------------------------------
2987 /* Here we try other sources */
2988 void pkgAcqArchive::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)
2990 Item::Failed(Message
,Cnf
);
2992 /* We don't really want to retry on failed media swaps, this prevents
2993 that. An interesting observation is that permanent failures are not
2995 if (Cnf
->Removable
== true &&
2996 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2998 // Vf = Version.FileList();
2999 while (Vf
.end() == false) ++Vf
;
3000 StoreFilename
= string();
3005 if (QueueNext() == false)
3007 // This is the retry counter
3009 Cnf
->LocalOnly
== false &&
3010 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
3013 Vf
= Version
.FileList();
3014 if (QueueNext() == true)
3018 StoreFilename
= string();
3023 APT_PURE
bool pkgAcqArchive::IsTrusted() const /*{{{*/
3028 void pkgAcqArchive::Finished() /*{{{*/
3030 if (Status
== pkgAcquire::Item::StatDone
&&
3033 StoreFilename
= string();
3036 std::string
pkgAcqArchive::DescURI() const /*{{{*/
3041 std::string
pkgAcqArchive::ShortDesc() const /*{{{*/
3043 return Desc
.ShortDesc
;
3046 pkgAcqArchive::~pkgAcqArchive() {}
3048 // AcqChangelog::pkgAcqChangelog - Constructors /*{{{*/
3049 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire
* const Owner
, pkgCache::VerIterator
const &Ver
,
3050 std::string
const &DestDir
, std::string
const &DestFilename
) :
3051 pkgAcquire::Item(Owner
), d(NULL
), SrcName(Ver
.SourcePkgName()), SrcVersion(Ver
.SourceVerStr())
3053 Desc
.URI
= URI(Ver
);
3054 Init(DestDir
, DestFilename
);
3056 // some parameters are char* here as they come likely from char* interfaces – which can also return NULL
3057 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire
* const Owner
, pkgCache::RlsFileIterator
const &RlsFile
,
3058 char const * const Component
, char const * const SrcName
, char const * const SrcVersion
,
3059 const string
&DestDir
, const string
&DestFilename
) :
3060 pkgAcquire::Item(Owner
), d(NULL
), SrcName(SrcName
), SrcVersion(SrcVersion
)
3062 Desc
.URI
= URI(RlsFile
, Component
, SrcName
, SrcVersion
);
3063 Init(DestDir
, DestFilename
);
3065 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire
* const Owner
,
3066 std::string
const &URI
, char const * const SrcName
, char const * const SrcVersion
,
3067 const string
&DestDir
, const string
&DestFilename
) :
3068 pkgAcquire::Item(Owner
), d(NULL
), SrcName(SrcName
), SrcVersion(SrcVersion
)
3071 Init(DestDir
, DestFilename
);
3073 void pkgAcqChangelog::Init(std::string
const &DestDir
, std::string
const &DestFilename
)
3075 if (Desc
.URI
.empty())
3078 // TRANSLATOR: %s=%s is sourcename=sourceversion, e.g. apt=1.1
3079 strprintf(ErrorText
, _("Changelog unavailable for %s=%s"), SrcName
.c_str(), SrcVersion
.c_str());
3080 // Let the error message print something sensible rather than "Failed to fetch /"
3081 if (DestFilename
.empty())
3082 DestFile
= SrcName
+ ".changelog";
3084 DestFile
= DestFilename
;
3085 Desc
.URI
= "changelog:/" + DestFile
;
3089 if (DestDir
.empty())
3091 std::string
const SandboxUser
= _config
->Find("APT::Sandbox::User");
3092 std::string
const systemTemp
= GetTempDir(SandboxUser
);
3094 snprintf(tmpname
, sizeof(tmpname
), "%s/apt-changelog-XXXXXX", systemTemp
.c_str());
3095 if (NULL
== mkdtemp(tmpname
))
3097 _error
->Errno("mkdtemp", "mkdtemp failed in changelog acquire of %s %s", SrcName
.c_str(), SrcVersion
.c_str());
3101 DestFile
= TemporaryDirectory
= tmpname
;
3103 ChangeOwnerAndPermissionOfFile("Item::QueueURI", DestFile
.c_str(),
3104 SandboxUser
.c_str(), "root", 0700);
3109 if (DestFilename
.empty())
3110 DestFile
= flCombine(DestFile
, SrcName
+ ".changelog");
3112 DestFile
= flCombine(DestFile
, DestFilename
);
3114 Desc
.ShortDesc
= "Changelog";
3115 strprintf(Desc
.Description
, "%s %s %s Changelog", URI::SiteOnly(Desc
.URI
).c_str(), SrcName
.c_str(), SrcVersion
.c_str());
3120 std::string
pkgAcqChangelog::URI(pkgCache::VerIterator
const &Ver
) /*{{{*/
3122 char const * const SrcName
= Ver
.SourcePkgName();
3123 char const * const SrcVersion
= Ver
.SourceVerStr();
3124 pkgCache::PkgFileIterator PkgFile
;
3125 // find the first source for this version which promises a changelog
3126 for (pkgCache::VerFileIterator VF
= Ver
.FileList(); VF
.end() == false; ++VF
)
3128 pkgCache::PkgFileIterator
const PF
= VF
.File();
3129 if (PF
.Flagged(pkgCache::Flag::NotSource
) || PF
->Release
== 0)
3132 pkgCache::RlsFileIterator
const RF
= PF
.ReleaseFile();
3133 std::string
const uri
= URI(RF
, PF
.Component(), SrcName
, SrcVersion
);
3140 std::string
pkgAcqChangelog::URITemplate(pkgCache::RlsFileIterator
const &Rls
)
3142 if (Rls
.end() == true || (Rls
->Label
== 0 && Rls
->Origin
== 0))
3144 std::string
const serverConfig
= "Acquire::Changelogs::URI";
3146 #define APT_EMPTY_SERVER \
3147 if (server.empty() == false) \
3149 if (server != "no") \
3153 #define APT_CHECK_SERVER(X, Y) \
3156 std::string const specialServerConfig = serverConfig + "::" + Y + #X + "::" + Rls.X(); \
3157 server = _config->Find(specialServerConfig); \
3160 // this way e.g. Debian-Security can fallback to Debian
3161 APT_CHECK_SERVER(Label
, "Override::")
3162 APT_CHECK_SERVER(Origin
, "Override::")
3164 if (RealFileExists(Rls
.FileName()))
3166 _error
->PushToStack();
3168 /* This can be costly. A caller wanting to get millions of URIs might
3169 want to do this on its own once and use Override settings.
3170 We don't do this here as Origin/Label are not as unique as they
3171 should be so this could produce request order-dependent anomalies */
3172 if (OpenMaybeClearSignedFile(Rls
.FileName(), rf
) == true)
3174 pkgTagFile
TagFile(&rf
, rf
.Size());
3175 pkgTagSection Section
;
3176 if (TagFile
.Step(Section
) == true)
3177 server
= Section
.FindS("Changelogs");
3179 _error
->RevertToStack();
3183 APT_CHECK_SERVER(Label
, "")
3184 APT_CHECK_SERVER(Origin
, "")
3185 #undef APT_CHECK_SERVER
3186 #undef APT_EMPTY_SERVER
3189 std::string
pkgAcqChangelog::URI(pkgCache::RlsFileIterator
const &Rls
,
3190 char const * const Component
, char const * const SrcName
,
3191 char const * const SrcVersion
)
3193 return URI(URITemplate(Rls
), Component
, SrcName
, SrcVersion
);
3195 std::string
pkgAcqChangelog::URI(std::string
const &Template
,
3196 char const * const Component
, char const * const SrcName
,
3197 char const * const SrcVersion
)
3199 if (Template
.find("@CHANGEPATH@") == std::string::npos
)
3202 // the path is: COMPONENT/SRC/SRCNAME/SRCNAME_SRCVER, e.g. main/a/apt/1.1 or contrib/liba/libapt/2.0
3203 std::string Src
= SrcName
;
3204 std::string path
= APT::String::Startswith(SrcName
, "lib") ? Src
.substr(0, 4) : Src
.substr(0,1);
3205 path
.append("/").append(Src
).append("/");
3206 path
.append(Src
).append("_").append(StripEpoch(SrcVersion
));
3207 // we omit component for releases without one (= flat-style repositories)
3208 if (Component
!= NULL
&& strlen(Component
) != 0)
3209 path
= std::string(Component
) + "/" + path
;
3211 return SubstVar(Template
, "@CHANGEPATH@", path
);
3214 // AcqChangelog::Failed - Failure handler /*{{{*/
3215 void pkgAcqChangelog::Failed(string
const &Message
, pkgAcquire::MethodConfig
const * const Cnf
)
3217 Item::Failed(Message
,Cnf
);
3219 std::string errText
;
3220 // TRANSLATOR: %s=%s is sourcename=sourceversion, e.g. apt=1.1
3221 strprintf(errText
, _("Changelog unavailable for %s=%s"), SrcName
.c_str(), SrcVersion
.c_str());
3223 // Error is probably something techy like 404 Not Found
3224 if (ErrorText
.empty())
3225 ErrorText
= errText
;
3227 ErrorText
= errText
+ " (" + ErrorText
+ ")";
3231 // AcqChangelog::Done - Item downloaded OK /*{{{*/
3232 void pkgAcqChangelog::Done(string
const &Message
,HashStringList
const &CalcHashes
,
3233 pkgAcquire::MethodConfig
const * const Cnf
)
3235 Item::Done(Message
,CalcHashes
,Cnf
);
3240 pkgAcqChangelog::~pkgAcqChangelog() /*{{{*/
3242 if (TemporaryDirectory
.empty() == false)
3244 RemoveFile("~pkgAcqChangelog", DestFile
);
3245 rmdir(TemporaryDirectory
.c_str());
3250 // AcqFile::pkgAcqFile - Constructor /*{{{*/
3251 pkgAcqFile::pkgAcqFile(pkgAcquire
* const Owner
,string
const &URI
, HashStringList
const &Hashes
,
3252 unsigned long long const Size
,string
const &Dsc
,string
const &ShortDesc
,
3253 const string
&DestDir
, const string
&DestFilename
,
3254 bool const IsIndexFile
) :
3255 Item(Owner
), d(NULL
), IsIndexFile(IsIndexFile
), ExpectedHashes(Hashes
)
3257 Retries
= _config
->FindI("Acquire::Retries",0);
3259 if(!DestFilename
.empty())
3260 DestFile
= DestFilename
;
3261 else if(!DestDir
.empty())
3262 DestFile
= DestDir
+ "/" + flNotDir(URI
);
3264 DestFile
= flNotDir(URI
);
3268 Desc
.Description
= Dsc
;
3271 // Set the short description to the archive component
3272 Desc
.ShortDesc
= ShortDesc
;
3274 // Get the transfer sizes
3277 if (stat(DestFile
.c_str(),&Buf
) == 0)
3279 // Hmm, the partial file is too big, erase it
3280 if ((Size
> 0) && (unsigned long long)Buf
.st_size
> Size
)
3281 RemoveFile("pkgAcqFile", DestFile
);
3283 PartialSize
= Buf
.st_size
;
3289 // AcqFile::Done - Item downloaded OK /*{{{*/
3290 void pkgAcqFile::Done(string
const &Message
,HashStringList
const &CalcHashes
,
3291 pkgAcquire::MethodConfig
const * const Cnf
)
3293 Item::Done(Message
,CalcHashes
,Cnf
);
3295 std::string
const FileName
= LookupTag(Message
,"Filename");
3298 // The files timestamp matches
3299 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
3302 // We have to copy it into place
3303 if (RealFileExists(DestFile
.c_str()) == false)
3306 if (_config
->FindB("Acquire::Source-Symlinks",true) == false ||
3307 Cnf
->Removable
== true)
3309 Desc
.URI
= "copy:" + FileName
;
3314 // Erase the file if it is a symlink so we can overwrite it
3316 if (lstat(DestFile
.c_str(),&St
) == 0)
3318 if (S_ISLNK(St
.st_mode
) != 0)
3319 RemoveFile("pkgAcqFile::Done", DestFile
);
3323 if (symlink(FileName
.c_str(),DestFile
.c_str()) != 0)
3325 _error
->PushToStack();
3326 _error
->Errno("pkgAcqFile::Done", "Symlinking file %s failed", DestFile
.c_str());
3327 std::stringstream msg
;
3328 _error
->DumpErrors(msg
, GlobalError::DEBUG
, false);
3329 _error
->RevertToStack();
3330 ErrorText
= msg
.str();
3337 // AcqFile::Failed - Failure handler /*{{{*/
3338 // ---------------------------------------------------------------------
3339 /* Here we try other sources */
3340 void pkgAcqFile::Failed(string
const &Message
, pkgAcquire::MethodConfig
const * const Cnf
)
3342 Item::Failed(Message
,Cnf
);
3344 // This is the retry counter
3346 Cnf
->LocalOnly
== false &&
3347 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
3357 string
pkgAcqFile::Custom600Headers() const /*{{{*/
3360 return "\nIndex-File: true";
3364 pkgAcqFile::~pkgAcqFile() {}