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 KeepCompressedAs
= Target
.Option(IndexTarget::KEEPCOMPRESSEDAS
);
89 if (KeepCompressedAs
.empty() == false)
91 std::string
const ext
= KeepCompressedAs
.substr(0, KeepCompressedAs
.find(' '));
92 if (ext
!= "uncompressed")
93 file
.append(".").append(ext
);
98 static std::string
GetMergeDiffsPatchFileName(std::string
const &Final
, std::string
const &Patch
)/*{{{*/
100 // rred expects the patch as $FinalFile.ed.$patchname.gz
101 return Final
+ ".ed." + Patch
+ ".gz";
104 static std::string
GetDiffsPatchFileName(std::string
const &Final
) /*{{{*/
106 // rred expects the patch as $FinalFile.ed
107 return Final
+ ".ed";
110 static std::string
GetExistingFilename(std::string
const &File
) /*{{{*/
112 if (RealFileExists(File
))
114 for (auto const &type
: APT::Configuration::getCompressorExtensions())
116 std::string
const Final
= File
+ type
;
117 if (RealFileExists(Final
))
124 static bool MessageInsecureRepository(bool const isError
, std::string
const &msg
)/*{{{*/
128 _error
->Error("%s", msg
.c_str());
129 _error
->Notice("%s", _("Updating from such a repository can't be done securely, and is therefore disabled by default."));
133 _error
->Warning("%s", msg
.c_str());
134 _error
->Notice("%s", _("Data from such a repository can't be authenticated and is therefore potentially dangerous to use."));
136 _error
->Notice("%s", _("See apt-secure(8) manpage for repository creation and user configuration details."));
139 static bool MessageInsecureRepository(bool const isError
, char const * const msg
, std::string
const &repo
)
142 strprintf(m
, msg
, repo
.c_str());
143 return MessageInsecureRepository(isError
, m
);
146 static bool AllowInsecureRepositories(char const * const msg
, std::string
const &repo
,/*{{{*/
147 metaIndex
const * const MetaIndexParser
, pkgAcqMetaClearSig
* const TransactionManager
, pkgAcquire::Item
* const I
)
149 if(MetaIndexParser
->GetTrusted() == metaIndex::TRI_YES
)
152 if (_config
->FindB("Acquire::AllowInsecureRepositories") == true)
154 MessageInsecureRepository(false, msg
, repo
);
158 MessageInsecureRepository(true, msg
, repo
);
159 TransactionManager
->AbortTransaction();
160 I
->Status
= pkgAcquire::Item::StatError
;
164 static HashStringList
GetExpectedHashesFromFor(metaIndex
* const Parser
, std::string
const &MetaKey
)/*{{{*/
167 return HashStringList();
168 metaIndex::checkSum
* const R
= Parser
->Lookup(MetaKey
);
170 return HashStringList();
175 // all ::HashesRequired and ::GetExpectedHashes implementations /*{{{*/
176 /* ::GetExpectedHashes is abstract and has to be implemented by all subclasses.
177 It is best to implement it as broadly as possible, while ::HashesRequired defaults
178 to true and should be as restrictive as possible for false cases. Note that if
179 a hash is returned by ::GetExpectedHashes it must match. Only if it doesn't
180 ::HashesRequired is called to evaluate if its okay to have no hashes. */
181 APT_CONST
bool pkgAcqTransactionItem::HashesRequired() const
183 /* signed repositories obviously have a parser and good hashes.
184 unsigned repositories, too, as even if we can't trust them for security,
185 we can at least trust them for integrity of the download itself.
186 Only repositories without a Release file can (obviously) not have
187 hashes – and they are very uncommon and strongly discouraged */
188 return TransactionManager
->MetaIndexParser
!= NULL
&&
189 TransactionManager
->MetaIndexParser
->GetLoadedSuccessfully() == metaIndex::TRI_YES
;
191 HashStringList
pkgAcqTransactionItem::GetExpectedHashes() const
193 return GetExpectedHashesFor(GetMetaKey());
196 APT_CONST
bool pkgAcqMetaBase::HashesRequired() const
198 // Release and co have no hashes 'by design'.
201 HashStringList
pkgAcqMetaBase::GetExpectedHashes() const
203 return HashStringList();
206 APT_CONST
bool pkgAcqIndexDiffs::HashesRequired() const
208 /* We don't always have the diff of the downloaded pdiff file.
209 What we have for sure is hashes for the uncompressed file,
210 but rred uncompresses them on the fly while parsing, so not handled here.
211 Hashes are (also) checked while searching for (next) patch to apply. */
212 if (State
== StateFetchDiff
)
213 return available_patches
[0].download_hashes
.empty() == false;
216 HashStringList
pkgAcqIndexDiffs::GetExpectedHashes() const
218 if (State
== StateFetchDiff
)
219 return available_patches
[0].download_hashes
;
220 return HashStringList();
223 APT_CONST
bool pkgAcqIndexMergeDiffs::HashesRequired() const
225 /* @see #pkgAcqIndexDiffs::HashesRequired, with the difference that
226 we can check the rred result after all patches are applied as
227 we know the expected result rather than potentially apply more patches */
228 if (State
== StateFetchDiff
)
229 return patch
.download_hashes
.empty() == false;
230 return State
== StateApplyDiff
;
232 HashStringList
pkgAcqIndexMergeDiffs::GetExpectedHashes() const
234 if (State
== StateFetchDiff
)
235 return patch
.download_hashes
;
236 else if (State
== StateApplyDiff
)
237 return GetExpectedHashesFor(Target
.MetaKey
);
238 return HashStringList();
241 APT_CONST
bool pkgAcqArchive::HashesRequired() const
243 return LocalSource
== false;
245 HashStringList
pkgAcqArchive::GetExpectedHashes() const
247 // figured out while parsing the records
248 return ExpectedHashes
;
251 APT_CONST
bool pkgAcqFile::HashesRequired() const
253 // supplied as parameter at creation time, so the caller decides
254 return ExpectedHashes
.usable();
256 HashStringList
pkgAcqFile::GetExpectedHashes() const
258 return ExpectedHashes
;
261 // Acquire::Item::QueueURI and specialisations from child classes /*{{{*/
262 bool pkgAcquire::Item::QueueURI(pkgAcquire::ItemDesc
&Item
)
264 Owner
->Enqueue(Item
);
267 /* The idea here is that an item isn't queued if it exists on disk and the
268 transition manager was a hit as this means that the files it contains
269 the checksums for can't be updated either (or they are and we are asking
270 for a hashsum mismatch to happen which helps nobody) */
271 bool pkgAcqTransactionItem::QueueURI(pkgAcquire::ItemDesc
&Item
)
273 std::string
const FinalFile
= GetFinalFilename();
274 if (TransactionManager
!= NULL
&& TransactionManager
->IMSHit
== true &&
275 FileExists(FinalFile
) == true)
277 PartialFile
= DestFile
= FinalFile
;
281 return pkgAcquire::Item::QueueURI(Item
);
283 /* The transition manager InRelease itself (or its older sisters-in-law
284 Release & Release.gpg) is always queued as this allows us to rerun gpgv
285 on it to verify that we aren't stalled with old files */
286 bool pkgAcqMetaBase::QueueURI(pkgAcquire::ItemDesc
&Item
)
288 return pkgAcquire::Item::QueueURI(Item
);
290 /* the Diff/Index needs to queue also the up-to-date complete index file
291 to ensure that the list cleaner isn't eating it */
292 bool pkgAcqDiffIndex::QueueURI(pkgAcquire::ItemDesc
&Item
)
294 if (pkgAcqTransactionItem::QueueURI(Item
) == true)
300 // Acquire::Item::GetFinalFilename and specialisations for child classes /*{{{*/
301 std::string
pkgAcquire::Item::GetFinalFilename() const
303 return GetFinalFileNameFromURI(Desc
.URI
);
305 std::string
pkgAcqDiffIndex::GetFinalFilename() const
307 // the logic we inherent from pkgAcqBaseIndex isn't what we need here
308 return pkgAcquire::Item::GetFinalFilename();
310 std::string
pkgAcqIndex::GetFinalFilename() const
312 std::string
const FinalFile
= GetFinalFileNameFromURI(Target
.URI
);
313 return GetKeepCompressedFileName(FinalFile
, Target
);
315 std::string
pkgAcqMetaSig::GetFinalFilename() const
317 return GetFinalFileNameFromURI(Target
.URI
);
319 std::string
pkgAcqBaseIndex::GetFinalFilename() const
321 return GetFinalFileNameFromURI(Target
.URI
);
323 std::string
pkgAcqMetaBase::GetFinalFilename() const
325 return GetFinalFileNameFromURI(Target
.URI
);
327 std::string
pkgAcqArchive::GetFinalFilename() const
329 return _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
332 // pkgAcqTransactionItem::GetMetaKey and specialisations for child classes /*{{{*/
333 std::string
pkgAcqTransactionItem::GetMetaKey() const
335 return Target
.MetaKey
;
337 std::string
pkgAcqIndex::GetMetaKey() const
339 if (Stage
== STAGE_DECOMPRESS_AND_VERIFY
|| CurrentCompressionExtension
== "uncompressed")
340 return Target
.MetaKey
;
341 return Target
.MetaKey
+ "." + CurrentCompressionExtension
;
343 std::string
pkgAcqDiffIndex::GetMetaKey() const
345 return Target
.MetaKey
+ ".diff/Index";
348 //pkgAcqTransactionItem::TransactionState and specialisations for child classes /*{{{*/
349 bool pkgAcqTransactionItem::TransactionState(TransactionStates
const state
)
351 bool const Debug
= _config
->FindB("Debug::Acquire::Transaction", false);
354 case TransactionAbort
:
356 std::clog
<< " Cancel: " << DestFile
<< std::endl
;
357 if (Status
== pkgAcquire::Item::StatIdle
)
359 Status
= pkgAcquire::Item::StatDone
;
363 case TransactionCommit
:
364 if(PartialFile
.empty() == false)
366 bool sameFile
= (PartialFile
== DestFile
);
367 // we use symlinks on IMS-Hit to avoid copies
368 if (RealFileExists(DestFile
))
371 if (lstat(PartialFile
.c_str(), &Buf
) != -1)
373 if (S_ISLNK(Buf
.st_mode
) && Buf
.st_size
> 0)
375 char partial
[Buf
.st_size
+ 1];
376 ssize_t
const sp
= readlink(PartialFile
.c_str(), partial
, Buf
.st_size
);
378 _error
->Errno("pkgAcqTransactionItem::TransactionState-sp", _("Failed to readlink %s"), PartialFile
.c_str());
382 sameFile
= (DestFile
== partial
);
387 _error
->Errno("pkgAcqTransactionItem::TransactionState-stat", _("Failed to stat %s"), PartialFile
.c_str());
389 if (sameFile
== false)
391 // ensure that even without lists-cleanup all compressions are nuked
392 std::string FinalFile
= GetFinalFileNameFromURI(Target
.URI
);
393 if (FileExists(FinalFile
))
396 std::clog
<< "rm " << FinalFile
<< " # " << DescURI() << std::endl
;
397 if (RemoveFile("TransactionStates-Cleanup", FinalFile
) == false)
400 for (auto const &ext
: APT::Configuration::getCompressorExtensions())
402 auto const Final
= FinalFile
+ ext
;
403 if (FileExists(Final
))
406 std::clog
<< "rm " << Final
<< " # " << DescURI() << std::endl
;
407 if (RemoveFile("TransactionStates-Cleanup", Final
) == false)
412 std::clog
<< "mv " << PartialFile
<< " -> "<< DestFile
<< " # " << DescURI() << std::endl
;
413 if (Rename(PartialFile
, DestFile
) == false)
416 else if(Debug
== true)
417 std::clog
<< "keep " << PartialFile
<< " # " << DescURI() << std::endl
;
421 std::clog
<< "rm " << DestFile
<< " # " << DescURI() << std::endl
;
422 if (RemoveFile("TransactionCommit", DestFile
) == false)
429 bool pkgAcqMetaBase::TransactionState(TransactionStates
const state
)
431 // Do not remove InRelease on IMSHit of Release.gpg [yes, this is very edgecasey]
432 if (TransactionManager
->IMSHit
== false)
433 return pkgAcqTransactionItem::TransactionState(state
);
436 bool pkgAcqIndex::TransactionState(TransactionStates
const state
)
438 if (pkgAcqTransactionItem::TransactionState(state
) == false)
443 case TransactionAbort
:
444 if (Stage
== STAGE_DECOMPRESS_AND_VERIFY
)
446 // keep the compressed file, but drop the decompressed
447 EraseFileName
.clear();
448 if (PartialFile
.empty() == false && flExtension(PartialFile
) != CurrentCompressionExtension
)
449 RemoveFile("TransactionAbort", PartialFile
);
452 case TransactionCommit
:
453 if (EraseFileName
.empty() == false)
454 RemoveFile("TransactionCommit", EraseFileName
);
459 bool pkgAcqDiffIndex::TransactionState(TransactionStates
const state
)
461 if (pkgAcqTransactionItem::TransactionState(state
) == false)
466 case TransactionCommit
:
468 case TransactionAbort
:
469 std::string
const Partial
= GetPartialFileNameFromURI(Target
.URI
);
470 RemoveFile("TransactionAbort", Partial
);
478 class APT_HIDDEN NoActionItem
: public pkgAcquire::Item
/*{{{*/
479 /* The sole purpose of this class is having an item which does nothing to
480 reach its done state to prevent cleanup deleting the mentioned file.
481 Handy in cases in which we know we have the file already, like IMS-Hits. */
483 IndexTarget
const Target
;
485 virtual std::string
DescURI() const APT_OVERRIDE
{return Target
.URI
;};
486 virtual HashStringList
GetExpectedHashes() const APT_OVERRIDE
{return HashStringList();};
488 NoActionItem(pkgAcquire
* const Owner
, IndexTarget
const &Target
) :
489 pkgAcquire::Item(Owner
), Target(Target
)
492 DestFile
= GetFinalFileNameFromURI(Target
.URI
);
494 NoActionItem(pkgAcquire
* const Owner
, IndexTarget
const &Target
, std::string
const &FinalFile
) :
495 pkgAcquire::Item(Owner
), Target(Target
)
498 DestFile
= FinalFile
;
503 // Acquire::Item::Item - Constructor /*{{{*/
504 APT_IGNORE_DEPRECATED_PUSH
505 pkgAcquire::Item::Item(pkgAcquire
* const owner
) :
506 FileSize(0), PartialSize(0), Mode(0), ID(0), Complete(false), Local(false),
507 QueueCounter(0), ExpectedAdditionalItems(0), Owner(owner
), d(NULL
)
512 APT_IGNORE_DEPRECATED_POP
514 // Acquire::Item::~Item - Destructor /*{{{*/
515 pkgAcquire::Item::~Item()
520 std::string
pkgAcquire::Item::Custom600Headers() const /*{{{*/
522 return std::string();
525 std::string
pkgAcquire::Item::ShortDesc() const /*{{{*/
530 APT_CONST
void pkgAcquire::Item::Finished() /*{{{*/
534 APT_PURE pkgAcquire
* pkgAcquire::Item::GetOwner() const /*{{{*/
539 APT_CONST
pkgAcquire::ItemDesc
&pkgAcquire::Item::GetItemDesc() /*{{{*/
544 APT_CONST
bool pkgAcquire::Item::IsTrusted() const /*{{{*/
549 // Acquire::Item::Failed - Item failed to download /*{{{*/
550 // ---------------------------------------------------------------------
551 /* We return to an idle state if there are still other queues that could
553 void pkgAcquire::Item::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)
555 if(ErrorText
.empty())
556 ErrorText
= LookupTag(Message
,"Message");
557 if (QueueCounter
<= 1)
559 /* This indicates that the file is not available right now but might
560 be sometime later. If we do a retry cycle then this should be
562 if (Cnf
!= NULL
&& Cnf
->LocalOnly
== true &&
563 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
579 case StatTransientNetworkError
:
586 string
const FailReason
= LookupTag(Message
, "FailReason");
587 if (FailReason
== "MaximumSizeExceeded")
588 RenameOnError(MaximumSizeExceeded
);
589 else if (Status
== StatAuthError
)
590 RenameOnError(HashSumMismatch
);
592 // report mirror failure back to LP if we actually use a mirror
593 if (FailReason
.empty() == false)
594 ReportMirrorFailure(FailReason
);
596 ReportMirrorFailure(ErrorText
);
598 if (QueueCounter
> 1)
602 // Acquire::Item::Start - Item has begun to download /*{{{*/
603 // ---------------------------------------------------------------------
604 /* Stash status and the file size. Note that setting Complete means
605 sub-phases of the acquire process such as decompresion are operating */
606 void pkgAcquire::Item::Start(string
const &/*Message*/, unsigned long long const Size
)
608 Status
= StatFetching
;
610 if (FileSize
== 0 && Complete
== false)
614 // Acquire::Item::VerifyDone - check if Item was downloaded OK /*{{{*/
615 /* Note that hash-verification is 'hardcoded' in acquire-worker and has
616 * already passed if this method is called. */
617 bool pkgAcquire::Item::VerifyDone(std::string
const &Message
,
618 pkgAcquire::MethodConfig
const * const /*Cnf*/)
620 std::string
const FileName
= LookupTag(Message
,"Filename");
621 if (FileName
.empty() == true)
624 ErrorText
= "Method gave a blank filename";
631 // Acquire::Item::Done - Item downloaded OK /*{{{*/
632 void pkgAcquire::Item::Done(string
const &/*Message*/, HashStringList
const &Hashes
,
633 pkgAcquire::MethodConfig
const * const /*Cnf*/)
635 // We just downloaded something..
638 unsigned long long const downloadedSize
= Hashes
.FileSize();
639 if (downloadedSize
!= 0)
641 FileSize
= downloadedSize
;
645 ErrorText
= string();
646 Owner
->Dequeue(this);
649 // Acquire::Item::Rename - Rename a file /*{{{*/
650 // ---------------------------------------------------------------------
651 /* This helper function is used by a lot of item methods as their final
653 bool pkgAcquire::Item::Rename(string
const &From
,string
const &To
)
655 if (From
== To
|| rename(From
.c_str(),To
.c_str()) == 0)
659 strprintf(S
, _("rename failed, %s (%s -> %s)."), strerror(errno
),
660 From
.c_str(),To
.c_str());
662 if (ErrorText
.empty())
665 ErrorText
= ErrorText
+ ": " + S
;
669 void pkgAcquire::Item::Dequeue() /*{{{*/
671 Owner
->Dequeue(this);
674 bool pkgAcquire::Item::RenameOnError(pkgAcquire::Item::RenameOnErrorState
const error
)/*{{{*/
676 if (RealFileExists(DestFile
))
677 Rename(DestFile
, DestFile
+ ".FAILED");
682 case HashSumMismatch
:
683 errtext
= _("Hash Sum mismatch");
684 Status
= StatAuthError
;
685 ReportMirrorFailure("HashChecksumFailure");
688 errtext
= _("Size mismatch");
689 Status
= StatAuthError
;
690 ReportMirrorFailure("SizeFailure");
693 errtext
= _("Invalid file format");
695 // do not report as usually its not the mirrors fault, but Portal/Proxy
698 errtext
= _("Signature error");
702 strprintf(errtext
, _("Clearsigned file isn't valid, got '%s' (does the network require authentication?)"), "NOSPLIT");
703 Status
= StatAuthError
;
705 case MaximumSizeExceeded
:
706 // the method is expected to report a good error for this
710 // no handling here, done by callers
713 if (ErrorText
.empty())
718 void pkgAcquire::Item::SetActiveSubprocess(const std::string
&subprocess
)/*{{{*/
720 ActiveSubprocess
= subprocess
;
721 APT_IGNORE_DEPRECATED(Mode
= ActiveSubprocess
.c_str();)
724 // Acquire::Item::ReportMirrorFailure /*{{{*/
725 void pkgAcquire::Item::ReportMirrorFailure(string
const &FailCode
)
727 // we only act if a mirror was used at all
728 if(UsedMirror
.empty())
731 std::cerr
<< "\nReportMirrorFailure: "
733 << " Uri: " << DescURI()
735 << FailCode
<< std::endl
;
737 string report
= _config
->Find("Methods::Mirror::ProblemReporting",
738 "/usr/lib/apt/apt-report-mirror-failure");
739 if(!FileExists(report
))
742 std::vector
<char const*> Args
;
743 Args
.push_back(report
.c_str());
744 Args
.push_back(UsedMirror
.c_str());
745 Args
.push_back(DescURI().c_str());
746 Args
.push_back(FailCode
.c_str());
747 Args
.push_back(NULL
);
749 pid_t pid
= ExecFork();
752 _error
->Error("ReportMirrorFailure Fork failed");
757 execvp(Args
[0], (char**)Args
.data());
758 std::cerr
<< "Could not exec " << Args
[0] << std::endl
;
761 if(!ExecWait(pid
, "report-mirror-failure"))
763 _error
->Warning("Couldn't report problem to '%s'",
764 _config
->Find("Methods::Mirror::ProblemReporting").c_str());
768 std::string
pkgAcquire::Item::HashSum() const /*{{{*/
770 HashStringList
const hashes
= GetExpectedHashes();
771 HashString
const * const hs
= hashes
.find(NULL
);
772 return hs
!= NULL
? hs
->toStr() : "";
776 pkgAcqTransactionItem::pkgAcqTransactionItem(pkgAcquire
* const Owner
, /*{{{*/
777 pkgAcqMetaClearSig
* const transactionManager
, IndexTarget
const &target
) :
778 pkgAcquire::Item(Owner
), d(NULL
), Target(target
), TransactionManager(transactionManager
)
780 if (TransactionManager
!= this)
781 TransactionManager
->Add(this);
784 pkgAcqTransactionItem::~pkgAcqTransactionItem() /*{{{*/
788 HashStringList
pkgAcqTransactionItem::GetExpectedHashesFor(std::string
const &MetaKey
) const /*{{{*/
790 return GetExpectedHashesFromFor(TransactionManager
->MetaIndexParser
, MetaKey
);
794 // AcqMetaBase - Constructor /*{{{*/
795 pkgAcqMetaBase::pkgAcqMetaBase(pkgAcquire
* const Owner
,
796 pkgAcqMetaClearSig
* const TransactionManager
,
797 std::vector
<IndexTarget
> const &IndexTargets
,
798 IndexTarget
const &DataTarget
)
799 : pkgAcqTransactionItem(Owner
, TransactionManager
, DataTarget
), d(NULL
),
800 IndexTargets(IndexTargets
),
801 AuthPass(false), IMSHit(false)
805 // AcqMetaBase::Add - Add a item to the current Transaction /*{{{*/
806 void pkgAcqMetaBase::Add(pkgAcqTransactionItem
* const I
)
808 Transaction
.push_back(I
);
811 // AcqMetaBase::AbortTransaction - Abort the current Transaction /*{{{*/
812 void pkgAcqMetaBase::AbortTransaction()
814 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
815 std::clog
<< "AbortTransaction: " << TransactionManager
<< std::endl
;
817 // ensure the toplevel is in error state too
818 for (std::vector
<pkgAcqTransactionItem
*>::iterator I
= Transaction
.begin();
819 I
!= Transaction
.end(); ++I
)
821 (*I
)->TransactionState(TransactionAbort
);
826 // AcqMetaBase::TransactionHasError - Check for errors in Transaction /*{{{*/
827 APT_PURE
bool pkgAcqMetaBase::TransactionHasError() const
829 for (std::vector
<pkgAcqTransactionItem
*>::const_iterator I
= Transaction
.begin();
830 I
!= Transaction
.end(); ++I
)
832 switch((*I
)->Status
) {
833 case StatDone
: break;
834 case StatIdle
: break;
835 case StatAuthError
: return true;
836 case StatError
: return true;
837 case StatTransientNetworkError
: return true;
838 case StatFetching
: break;
844 // AcqMetaBase::CommitTransaction - Commit a transaction /*{{{*/
845 void pkgAcqMetaBase::CommitTransaction()
847 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
848 std::clog
<< "CommitTransaction: " << this << std::endl
;
850 // move new files into place *and* remove files that are not
851 // part of the transaction but are still on disk
852 for (std::vector
<pkgAcqTransactionItem
*>::iterator I
= Transaction
.begin();
853 I
!= Transaction
.end(); ++I
)
855 (*I
)->TransactionState(TransactionCommit
);
860 // AcqMetaBase::TransactionStageCopy - Stage a file for copying /*{{{*/
861 void pkgAcqMetaBase::TransactionStageCopy(pkgAcqTransactionItem
* const I
,
862 const std::string
&From
,
863 const std::string
&To
)
865 I
->PartialFile
= From
;
869 // AcqMetaBase::TransactionStageRemoval - Stage a file for removal /*{{{*/
870 void pkgAcqMetaBase::TransactionStageRemoval(pkgAcqTransactionItem
* const I
,
871 const std::string
&FinalFile
)
874 I
->DestFile
= FinalFile
;
877 // AcqMetaBase::GenerateAuthWarning - Check gpg authentication error /*{{{*/
878 bool pkgAcqMetaBase::CheckStopAuthentication(pkgAcquire::Item
* const I
, const std::string
&Message
)
880 // FIXME: this entire function can do now that we disallow going to
881 // a unauthenticated state and can cleanly rollback
883 string
const Final
= I
->GetFinalFilename();
884 if(FileExists(Final
))
886 I
->Status
= StatTransientNetworkError
;
887 _error
->Warning(_("An error occurred during the signature "
888 "verification. The repository is not updated "
889 "and the previous index files will be used. "
890 "GPG error: %s: %s"),
891 Desc
.Description
.c_str(),
892 LookupTag(Message
,"Message").c_str());
893 RunScripts("APT::Update::Auth-Failure");
895 } else if (LookupTag(Message
,"Message").find("NODATA") != string::npos
) {
896 /* Invalid signature file, reject (LP: #346386) (Closes: #627642) */
897 _error
->Error(_("GPG error: %s: %s"),
898 Desc
.Description
.c_str(),
899 LookupTag(Message
,"Message").c_str());
900 I
->Status
= StatAuthError
;
903 _error
->Warning(_("GPG error: %s: %s"),
904 Desc
.Description
.c_str(),
905 LookupTag(Message
,"Message").c_str());
907 // gpgv method failed
908 ReportMirrorFailure("GPGFailure");
912 // AcqMetaBase::Custom600Headers - Get header for AcqMetaBase /*{{{*/
913 // ---------------------------------------------------------------------
914 string
pkgAcqMetaBase::Custom600Headers() const
916 std::string Header
= "\nIndex-File: true";
917 std::string MaximumSize
;
918 strprintf(MaximumSize
, "\nMaximum-Size: %i",
919 _config
->FindI("Acquire::MaxReleaseFileSize", 10*1000*1000));
920 Header
+= MaximumSize
;
922 string
const FinalFile
= GetFinalFilename();
924 if (stat(FinalFile
.c_str(),&Buf
) == 0)
925 Header
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
930 // AcqMetaBase::QueueForSignatureVerify /*{{{*/
931 void pkgAcqMetaBase::QueueForSignatureVerify(pkgAcqTransactionItem
* const I
, std::string
const &File
, std::string
const &Signature
)
934 I
->Desc
.URI
= "gpgv:" + Signature
;
937 I
->SetActiveSubprocess("gpgv");
940 // AcqMetaBase::CheckDownloadDone /*{{{*/
941 bool pkgAcqMetaBase::CheckDownloadDone(pkgAcqTransactionItem
* const I
, const std::string
&Message
, HashStringList
const &Hashes
) const
943 // We have just finished downloading a Release file (it is not
946 std::string
const FileName
= LookupTag(Message
,"Filename");
947 if (FileName
!= I
->DestFile
&& RealFileExists(I
->DestFile
) == false)
950 I
->Desc
.URI
= "copy:" + FileName
;
951 I
->QueueURI(I
->Desc
);
955 // make sure to verify against the right file on I-M-S hit
956 bool IMSHit
= StringToBool(LookupTag(Message
,"IMS-Hit"), false);
957 if (IMSHit
== false && Hashes
.usable())
959 // detect IMS-Hits servers haven't detected by Hash comparison
960 std::string
const FinalFile
= I
->GetFinalFilename();
961 if (RealFileExists(FinalFile
) && Hashes
.VerifyFile(FinalFile
) == true)
964 RemoveFile("CheckDownloadDone", I
->DestFile
);
970 // for simplicity, the transaction manager is always InRelease
971 // even if it doesn't exist.
972 if (TransactionManager
!= NULL
)
973 TransactionManager
->IMSHit
= true;
974 I
->PartialFile
= I
->DestFile
= I
->GetFinalFilename();
977 // set Item to complete as the remaining work is all local (verify etc)
983 bool pkgAcqMetaBase::CheckAuthDone(string
const &Message
) /*{{{*/
985 // At this point, the gpgv method has succeeded, so there is a
986 // valid signature from a key in the trusted keyring. We
987 // perform additional verification of its contents, and use them
988 // to verify the indexes we are about to download
990 if (TransactionManager
->IMSHit
== false)
992 // open the last (In)Release if we have it
993 std::string
const FinalFile
= GetFinalFilename();
994 std::string FinalRelease
;
995 std::string FinalInRelease
;
996 if (APT::String::Endswith(FinalFile
, "InRelease"))
998 FinalInRelease
= FinalFile
;
999 FinalRelease
= FinalFile
.substr(0, FinalFile
.length() - strlen("InRelease")) + "Release";
1003 FinalInRelease
= FinalFile
.substr(0, FinalFile
.length() - strlen("Release")) + "InRelease";
1004 FinalRelease
= FinalFile
;
1006 if (RealFileExists(FinalInRelease
) || RealFileExists(FinalRelease
))
1008 TransactionManager
->LastMetaIndexParser
= TransactionManager
->MetaIndexParser
->UnloadedClone();
1009 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1011 _error
->PushToStack();
1012 if (RealFileExists(FinalInRelease
))
1013 TransactionManager
->LastMetaIndexParser
->Load(FinalInRelease
, NULL
);
1015 TransactionManager
->LastMetaIndexParser
->Load(FinalRelease
, NULL
);
1016 // its unlikely to happen, but if what we have is bad ignore it
1017 if (_error
->PendingError())
1019 delete TransactionManager
->LastMetaIndexParser
;
1020 TransactionManager
->LastMetaIndexParser
= NULL
;
1022 _error
->RevertToStack();
1027 if (TransactionManager
->MetaIndexParser
->Load(DestFile
, &ErrorText
) == false)
1029 Status
= StatAuthError
;
1033 if (!VerifyVendor(Message
))
1035 Status
= StatAuthError
;
1039 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1040 std::cerr
<< "Signature verification succeeded: "
1041 << DestFile
<< std::endl
;
1043 // Download further indexes with verification
1049 void pkgAcqMetaBase::QueueIndexes(bool const verify
) /*{{{*/
1051 // at this point the real Items are loaded in the fetcher
1052 ExpectedAdditionalItems
= 0;
1054 bool metaBaseSupportsByHash
= false;
1055 if (TransactionManager
!= NULL
&& TransactionManager
->MetaIndexParser
!= NULL
)
1056 metaBaseSupportsByHash
= TransactionManager
->MetaIndexParser
->GetSupportsAcquireByHash();
1058 for (std::vector
<IndexTarget
>::iterator Target
= IndexTargets
.begin();
1059 Target
!= IndexTargets
.end();
1062 // all is an implementation detail. Users shouldn't use this as arch
1063 // We need this support trickery here as e.g. Debian has binary-all files already,
1064 // but arch:all packages are still in the arch:any files, so we would waste precious
1065 // download time, bandwidth and diskspace for nothing, BUT Debian doesn't feature all
1066 // in the set of supported architectures, so we can filter based on this property rather
1067 // than invent an entirely new flag we would need to carry for all of eternity.
1068 if (Target
->Option(IndexTarget::ARCHITECTURE
) == "all")
1070 if (TransactionManager
->MetaIndexParser
->IsArchitectureSupported("all") == false)
1072 if (TransactionManager
->MetaIndexParser
->IsArchitectureAllSupportedFor(*Target
) == false)
1076 bool trypdiff
= Target
->OptionBool(IndexTarget::PDIFFS
);
1079 if (TransactionManager
->MetaIndexParser
->Exists(Target
->MetaKey
) == false)
1081 // optional targets that we do not have in the Release file are skipped
1082 if (Target
->IsOptional
)
1085 std::string
const &arch
= Target
->Option(IndexTarget::ARCHITECTURE
);
1086 if (arch
.empty() == false)
1088 if (TransactionManager
->MetaIndexParser
->IsArchitectureSupported(arch
) == false)
1090 _error
->Notice(_("Skipping acquire of configured file '%s' as repository '%s' doesn't support architecture '%s'"),
1091 Target
->MetaKey
.c_str(), TransactionManager
->Target
.Description
.c_str(), arch
.c_str());
1094 // if the architecture is officially supported but currently no packages for it available,
1095 // ignore silently as this is pretty much the same as just shipping an empty file.
1096 // if we don't know which architectures are supported, we do NOT ignore it to notify user about this
1097 if (TransactionManager
->MetaIndexParser
->IsArchitectureSupported("*undefined*") == false)
1101 Status
= StatAuthError
;
1102 strprintf(ErrorText
, _("Unable to find expected entry '%s' in Release file (Wrong sources.list entry or malformed file)"), Target
->MetaKey
.c_str());
1107 auto const hashes
= GetExpectedHashesFor(Target
->MetaKey
);
1108 if (hashes
.usable() == false && hashes
.empty() == false)
1110 _error
->Warning(_("Skipping acquire of configured file '%s' as repository '%s' provides only weak security information for it"),
1111 Target
->MetaKey
.c_str(), TransactionManager
->Target
.Description
.c_str());
1116 // autoselect the compression method
1117 std::vector
<std::string
> types
= VectorizeString(Target
->Option(IndexTarget::COMPRESSIONTYPES
), ' ');
1118 types
.erase(std::remove_if(types
.begin(), types
.end(), [&](std::string
const &t
) {
1119 if (t
== "uncompressed")
1120 return TransactionManager
->MetaIndexParser
->Exists(Target
->MetaKey
) == false;
1121 std::string
const MetaKey
= Target
->MetaKey
+ "." + t
;
1122 return TransactionManager
->MetaIndexParser
->Exists(MetaKey
) == false;
1124 if (types
.empty() == false)
1126 std::ostringstream os
;
1127 // add the special compressiontype byhash first if supported
1128 std::string
const useByHashConf
= Target
->Option(IndexTarget::BY_HASH
);
1129 bool useByHash
= false;
1130 if(useByHashConf
== "force")
1133 useByHash
= StringToBool(useByHashConf
) == true && metaBaseSupportsByHash
;
1134 if (useByHash
== true)
1136 std::copy(types
.begin(), types
.end()-1, std::ostream_iterator
<std::string
>(os
, " "));
1137 os
<< *types
.rbegin();
1138 Target
->Options
["COMPRESSIONTYPES"] = os
.str();
1141 Target
->Options
["COMPRESSIONTYPES"].clear();
1143 std::string filename
= GetExistingFilename(GetFinalFileNameFromURI(Target
->URI
));
1144 if (filename
.empty() == false)
1146 // if the Release file is a hit and we have an index it must be the current one
1147 if (TransactionManager
->IMSHit
== true)
1149 else if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1151 // see if the file changed since the last Release file
1152 // we use the uncompressed files as we might compress differently compared to the server,
1153 // so the hashes might not match, even if they contain the same data.
1154 HashStringList
const newFile
= GetExpectedHashesFromFor(TransactionManager
->MetaIndexParser
, Target
->MetaKey
);
1155 HashStringList
const oldFile
= GetExpectedHashesFromFor(TransactionManager
->LastMetaIndexParser
, Target
->MetaKey
);
1156 if (newFile
!= oldFile
)
1163 trypdiff
= false; // no file to patch
1165 if (filename
.empty() == false)
1167 new NoActionItem(Owner
, *Target
, filename
);
1168 std::string
const idxfilename
= GetFinalFileNameFromURI(Target
->URI
+ ".diff/Index");
1169 if (FileExists(idxfilename
))
1170 new NoActionItem(Owner
, *Target
, idxfilename
);
1174 // check if we have patches available
1175 trypdiff
&= TransactionManager
->MetaIndexParser
->Exists(Target
->MetaKey
+ ".diff/Index");
1179 // if we have no file to patch, no point in trying
1180 trypdiff
&= (GetExistingFilename(GetFinalFileNameFromURI(Target
->URI
)).empty() == false);
1183 // no point in patching from local sources
1186 std::string
const proto
= Target
->URI
.substr(0, strlen("file:/"));
1187 if (proto
== "file:/" || proto
== "copy:/" || proto
== "cdrom:")
1191 // Queue the Index file (Packages, Sources, Translation-$foo, …)
1193 new pkgAcqDiffIndex(Owner
, TransactionManager
, *Target
);
1195 new pkgAcqIndex(Owner
, TransactionManager
, *Target
);
1199 bool pkgAcqMetaBase::VerifyVendor(string
const &Message
) /*{{{*/
1201 string::size_type pos
;
1203 // check for missing sigs (that where not fatal because otherwise we had
1206 string msg
= _("There is no public key available for the "
1207 "following key IDs:\n");
1208 pos
= Message
.find("NO_PUBKEY ");
1209 if (pos
!= std::string::npos
)
1211 string::size_type start
= pos
+strlen("NO_PUBKEY ");
1212 string Fingerprint
= Message
.substr(start
, Message
.find("\n")-start
);
1213 missingkeys
+= (Fingerprint
);
1215 if(!missingkeys
.empty())
1216 _error
->Warning("%s", (msg
+ missingkeys
).c_str());
1218 string Transformed
= TransactionManager
->MetaIndexParser
->GetExpectedDist();
1220 if (Transformed
== "../project/experimental")
1222 Transformed
= "experimental";
1225 pos
= Transformed
.rfind('/');
1226 if (pos
!= string::npos
)
1228 Transformed
= Transformed
.substr(0, pos
);
1231 if (Transformed
== ".")
1236 if (TransactionManager
->MetaIndexParser
->GetValidUntil() > 0)
1238 time_t const invalid_since
= time(NULL
) - TransactionManager
->MetaIndexParser
->GetValidUntil();
1239 if (invalid_since
> 0)
1243 // TRANSLATOR: The first %s is the URL of the bad Release file, the second is
1244 // the time since then the file is invalid - formatted in the same way as in
1245 // the download progress display (e.g. 7d 3h 42min 1s)
1246 _("Release file for %s is expired (invalid since %s). "
1247 "Updates for this repository will not be applied."),
1248 Target
.URI
.c_str(), TimeToStr(invalid_since
).c_str());
1249 if (ErrorText
.empty())
1251 return _error
->Error("%s", errmsg
.c_str());
1255 /* Did we get a file older than what we have? This is a last minute IMS hit and doubles
1256 as a prevention of downgrading us to older (still valid) files */
1257 if (TransactionManager
->IMSHit
== false && TransactionManager
->LastMetaIndexParser
!= NULL
&&
1258 TransactionManager
->LastMetaIndexParser
->GetDate() > TransactionManager
->MetaIndexParser
->GetDate())
1260 TransactionManager
->IMSHit
= true;
1261 RemoveFile("VerifyVendor", DestFile
);
1262 PartialFile
= DestFile
= GetFinalFilename();
1263 // load the 'old' file in the 'new' one instead of flipping pointers as
1264 // the new one isn't owned by us, while the old one is so cleanup would be confused.
1265 TransactionManager
->MetaIndexParser
->swapLoad(TransactionManager
->LastMetaIndexParser
);
1266 delete TransactionManager
->LastMetaIndexParser
;
1267 TransactionManager
->LastMetaIndexParser
= NULL
;
1270 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1272 std::cerr
<< "Got Codename: " << TransactionManager
->MetaIndexParser
->GetCodename() << std::endl
;
1273 std::cerr
<< "Expecting Dist: " << TransactionManager
->MetaIndexParser
->GetExpectedDist() << std::endl
;
1274 std::cerr
<< "Transformed Dist: " << Transformed
<< std::endl
;
1277 if (TransactionManager
->MetaIndexParser
->CheckDist(Transformed
) == false)
1279 // This might become fatal one day
1280 // Status = StatAuthError;
1281 // ErrorText = "Conflicting distribution; expected "
1282 // + MetaIndexParser->GetExpectedDist() + " but got "
1283 // + MetaIndexParser->GetCodename();
1285 if (!Transformed
.empty())
1287 _error
->Warning(_("Conflicting distribution: %s (expected %s but got %s)"),
1288 Desc
.Description
.c_str(),
1289 Transformed
.c_str(),
1290 TransactionManager
->MetaIndexParser
->GetCodename().c_str());
1297 pkgAcqMetaBase::~pkgAcqMetaBase()
1301 pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire
* const Owner
, /*{{{*/
1302 IndexTarget
const &ClearsignedTarget
,
1303 IndexTarget
const &DetachedDataTarget
, IndexTarget
const &DetachedSigTarget
,
1304 std::vector
<IndexTarget
> const &IndexTargets
,
1305 metaIndex
* const MetaIndexParser
) :
1306 pkgAcqMetaIndex(Owner
, this, ClearsignedTarget
, DetachedSigTarget
, IndexTargets
),
1307 d(NULL
), ClearsignedTarget(ClearsignedTarget
),
1308 DetachedDataTarget(DetachedDataTarget
),
1309 MetaIndexParser(MetaIndexParser
), LastMetaIndexParser(NULL
)
1311 // index targets + (worst case:) Release/Release.gpg
1312 ExpectedAdditionalItems
= IndexTargets
.size() + 2;
1313 TransactionManager
->Add(this);
1316 pkgAcqMetaClearSig::~pkgAcqMetaClearSig() /*{{{*/
1318 if (LastMetaIndexParser
!= NULL
)
1319 delete LastMetaIndexParser
;
1322 // pkgAcqMetaClearSig::Custom600Headers - Insert custom request headers /*{{{*/
1323 string
pkgAcqMetaClearSig::Custom600Headers() const
1325 string Header
= pkgAcqMetaBase::Custom600Headers();
1326 Header
+= "\nFail-Ignore: true";
1327 std::string
const key
= TransactionManager
->MetaIndexParser
->GetSignedBy();
1328 if (key
.empty() == false)
1329 Header
+= "\nSigned-By: " + key
;
1334 bool pkgAcqMetaClearSig::VerifyDone(std::string
const &Message
, /*{{{*/
1335 pkgAcquire::MethodConfig
const * const Cnf
)
1337 Item::VerifyDone(Message
, Cnf
);
1339 if (FileExists(DestFile
) && !StartsWithGPGClearTextSignature(DestFile
))
1340 return RenameOnError(NotClearsigned
);
1345 // pkgAcqMetaClearSig::Done - We got a file /*{{{*/
1346 void pkgAcqMetaClearSig::Done(std::string
const &Message
,
1347 HashStringList
const &Hashes
,
1348 pkgAcquire::MethodConfig
const * const Cnf
)
1350 Item::Done(Message
, Hashes
, Cnf
);
1352 if(AuthPass
== false)
1354 if(CheckDownloadDone(this, Message
, Hashes
) == true)
1355 QueueForSignatureVerify(this, DestFile
, DestFile
);
1358 else if(CheckAuthDone(Message
) == true)
1360 if (TransactionManager
->IMSHit
== false)
1361 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
1362 else if (RealFileExists(GetFinalFilename()) == false)
1364 // We got an InRelease file IMSHit, but we haven't one, which means
1365 // we had a valid Release/Release.gpg combo stepping in, which we have
1366 // to 'acquire' now to ensure list cleanup isn't removing them
1367 new NoActionItem(Owner
, DetachedDataTarget
);
1368 new NoActionItem(Owner
, DetachedSigTarget
);
1373 void pkgAcqMetaClearSig::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
) /*{{{*/
1375 Item::Failed(Message
, Cnf
);
1377 // we failed, we will not get additional items from this method
1378 ExpectedAdditionalItems
= 0;
1380 if (AuthPass
== false)
1382 if (Status
== StatAuthError
|| Status
== StatTransientNetworkError
)
1384 // if we expected a ClearTextSignature (InRelease) but got a network
1385 // error or got a file, but it wasn't valid, we end up here (see VerifyDone).
1386 // As these is usually called by web-portals we do not try Release/Release.gpg
1387 // as this is gonna fail anyway and instead abort our try (LP#346386)
1388 TransactionManager
->AbortTransaction();
1392 // Queue the 'old' InRelease file for removal if we try Release.gpg
1393 // as otherwise the file will stay around and gives a false-auth
1394 // impression (CVE-2012-0214)
1395 TransactionManager
->TransactionStageRemoval(this, GetFinalFilename());
1398 new pkgAcqMetaIndex(Owner
, TransactionManager
, DetachedDataTarget
, DetachedSigTarget
, IndexTargets
);
1402 if(CheckStopAuthentication(this, Message
))
1405 // No Release file was present, or verification failed, so fall
1406 // back to queueing Packages files without verification
1407 // only allow going further if the user explicitly wants it
1408 if(AllowInsecureRepositories(_("The repository '%s' is not signed."), ClearsignedTarget
.Description
, TransactionManager
->MetaIndexParser
, TransactionManager
, this) == true)
1412 /* InRelease files become Release files, otherwise
1413 * they would be considered as trusted later on */
1414 string
const FinalRelease
= GetFinalFileNameFromURI(DetachedDataTarget
.URI
);
1415 string
const PartialRelease
= GetPartialFileNameFromURI(DetachedDataTarget
.URI
);
1416 string
const FinalReleasegpg
= GetFinalFileNameFromURI(DetachedSigTarget
.URI
);
1417 string
const FinalInRelease
= GetFinalFilename();
1418 Rename(DestFile
, PartialRelease
);
1419 TransactionManager
->TransactionStageCopy(this, PartialRelease
, FinalRelease
);
1421 if (RealFileExists(FinalReleasegpg
) || RealFileExists(FinalInRelease
))
1423 // open the last Release if we have it
1424 if (TransactionManager
->IMSHit
== false)
1426 TransactionManager
->LastMetaIndexParser
= TransactionManager
->MetaIndexParser
->UnloadedClone();
1427 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1429 _error
->PushToStack();
1430 if (RealFileExists(FinalInRelease
))
1431 TransactionManager
->LastMetaIndexParser
->Load(FinalInRelease
, NULL
);
1433 TransactionManager
->LastMetaIndexParser
->Load(FinalRelease
, NULL
);
1434 // its unlikely to happen, but if what we have is bad ignore it
1435 if (_error
->PendingError())
1437 delete TransactionManager
->LastMetaIndexParser
;
1438 TransactionManager
->LastMetaIndexParser
= NULL
;
1440 _error
->RevertToStack();
1445 // we parse the indexes here because at this point the user wanted
1446 // a repository that may potentially harm him
1447 if (TransactionManager
->MetaIndexParser
->Load(PartialRelease
, &ErrorText
) == false || VerifyVendor(Message
) == false)
1448 /* expired Release files are still a problem you need extra force for */;
1456 pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire
* const Owner
, /*{{{*/
1457 pkgAcqMetaClearSig
* const TransactionManager
,
1458 IndexTarget
const &DataTarget
,
1459 IndexTarget
const &DetachedSigTarget
,
1460 vector
<IndexTarget
> const &IndexTargets
) :
1461 pkgAcqMetaBase(Owner
, TransactionManager
, IndexTargets
, DataTarget
), d(NULL
),
1462 DetachedSigTarget(DetachedSigTarget
)
1464 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1465 std::clog
<< "New pkgAcqMetaIndex with TransactionManager "
1466 << this->TransactionManager
<< std::endl
;
1468 DestFile
= GetPartialFileNameFromURI(DataTarget
.URI
);
1471 Desc
.Description
= DataTarget
.Description
;
1473 Desc
.ShortDesc
= DataTarget
.ShortDesc
;
1474 Desc
.URI
= DataTarget
.URI
;
1476 // we expect more item
1477 ExpectedAdditionalItems
= IndexTargets
.size();
1481 void pkgAcqMetaIndex::Done(string
const &Message
, /*{{{*/
1482 HashStringList
const &Hashes
,
1483 pkgAcquire::MethodConfig
const * const Cfg
)
1485 Item::Done(Message
,Hashes
,Cfg
);
1487 if(CheckDownloadDone(this, Message
, Hashes
))
1489 // we have a Release file, now download the Signature, all further
1490 // verify/queue for additional downloads will be done in the
1491 // pkgAcqMetaSig::Done() code
1492 new pkgAcqMetaSig(Owner
, TransactionManager
, DetachedSigTarget
, this);
1496 // pkgAcqMetaIndex::Failed - no Release file present /*{{{*/
1497 void pkgAcqMetaIndex::Failed(string
const &Message
,
1498 pkgAcquire::MethodConfig
const * const Cnf
)
1500 pkgAcquire::Item::Failed(Message
, Cnf
);
1503 // No Release file was present so fall
1504 // back to queueing Packages files without verification
1505 // only allow going further if the user explicitly wants it
1506 if(AllowInsecureRepositories(_("The repository '%s' does not have a Release file."), Target
.Description
, TransactionManager
->MetaIndexParser
, TransactionManager
, this) == true)
1508 // ensure old Release files are removed
1509 TransactionManager
->TransactionStageRemoval(this, GetFinalFilename());
1511 // queue without any kind of hashsum support
1512 QueueIndexes(false);
1516 void pkgAcqMetaIndex::Finished() /*{{{*/
1518 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1519 std::clog
<< "Finished: " << DestFile
<<std::endl
;
1520 if(TransactionManager
!= NULL
&&
1521 TransactionManager
->TransactionHasError() == false)
1522 TransactionManager
->CommitTransaction();
1525 std::string
pkgAcqMetaIndex::DescURI() const /*{{{*/
1530 pkgAcqMetaIndex::~pkgAcqMetaIndex() {}
1532 // AcqMetaSig::AcqMetaSig - Constructor /*{{{*/
1533 pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire
* const Owner
,
1534 pkgAcqMetaClearSig
* const TransactionManager
,
1535 IndexTarget
const &Target
,
1536 pkgAcqMetaIndex
* const MetaIndex
) :
1537 pkgAcqTransactionItem(Owner
, TransactionManager
, Target
), d(NULL
), MetaIndex(MetaIndex
)
1539 DestFile
= GetPartialFileNameFromURI(Target
.URI
);
1541 // remove any partial downloaded sig-file in partial/.
1542 // it may confuse proxies and is too small to warrant a
1543 // partial download anyway
1544 RemoveFile("pkgAcqMetaSig", DestFile
);
1546 // set the TransactionManager
1547 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1548 std::clog
<< "New pkgAcqMetaSig with TransactionManager "
1549 << TransactionManager
<< std::endl
;
1552 Desc
.Description
= Target
.Description
;
1554 Desc
.ShortDesc
= Target
.ShortDesc
;
1555 Desc
.URI
= Target
.URI
;
1557 // If we got a hit for Release, we will get one for Release.gpg too (or obscure errors),
1558 // so we skip the download step and go instantly to verification
1559 if (TransactionManager
->IMSHit
== true && RealFileExists(GetFinalFilename()))
1563 PartialFile
= DestFile
= GetFinalFilename();
1564 MetaIndexFileSignature
= DestFile
;
1565 MetaIndex
->QueueForSignatureVerify(this, MetaIndex
->DestFile
, DestFile
);
1571 pkgAcqMetaSig::~pkgAcqMetaSig() /*{{{*/
1575 // pkgAcqMetaSig::Custom600Headers - Insert custom request headers /*{{{*/
1576 std::string
pkgAcqMetaSig::Custom600Headers() const
1578 std::string Header
= pkgAcqTransactionItem::Custom600Headers();
1579 std::string
const key
= TransactionManager
->MetaIndexParser
->GetSignedBy();
1580 if (key
.empty() == false)
1581 Header
+= "\nSigned-By: " + key
;
1585 // AcqMetaSig::Done - The signature was downloaded/verified /*{{{*/
1586 void pkgAcqMetaSig::Done(string
const &Message
, HashStringList
const &Hashes
,
1587 pkgAcquire::MethodConfig
const * const Cfg
)
1589 if (MetaIndexFileSignature
.empty() == false)
1591 DestFile
= MetaIndexFileSignature
;
1592 MetaIndexFileSignature
.clear();
1594 Item::Done(Message
, Hashes
, Cfg
);
1596 if(MetaIndex
->AuthPass
== false)
1598 if(MetaIndex
->CheckDownloadDone(this, Message
, Hashes
) == true)
1600 // destfile will be modified to point to MetaIndexFile for the
1601 // gpgv method, so we need to save it here
1602 MetaIndexFileSignature
= DestFile
;
1603 MetaIndex
->QueueForSignatureVerify(this, MetaIndex
->DestFile
, DestFile
);
1607 else if(MetaIndex
->CheckAuthDone(Message
) == true)
1609 if (TransactionManager
->IMSHit
== false)
1611 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
1612 TransactionManager
->TransactionStageCopy(MetaIndex
, MetaIndex
->DestFile
, MetaIndex
->GetFinalFilename());
1617 void pkgAcqMetaSig::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
1619 Item::Failed(Message
,Cnf
);
1621 // check if we need to fail at this point
1622 if (MetaIndex
->AuthPass
== true && MetaIndex
->CheckStopAuthentication(this, Message
))
1625 string
const FinalRelease
= MetaIndex
->GetFinalFilename();
1626 string
const FinalReleasegpg
= GetFinalFilename();
1627 string
const FinalInRelease
= TransactionManager
->GetFinalFilename();
1629 if (RealFileExists(FinalReleasegpg
) || RealFileExists(FinalInRelease
))
1631 std::string downgrade_msg
;
1632 strprintf(downgrade_msg
, _("The repository '%s' is no longer signed."),
1633 MetaIndex
->Target
.Description
.c_str());
1634 if(_config
->FindB("Acquire::AllowDowngradeToInsecureRepositories"))
1636 // meh, the users wants to take risks (we still mark the packages
1637 // from this repository as unauthenticated)
1638 _error
->Warning("%s", downgrade_msg
.c_str());
1639 _error
->Warning(_("This is normally not allowed, but the option "
1640 "Acquire::AllowDowngradeToInsecureRepositories was "
1641 "given to override it."));
1644 MessageInsecureRepository(true, downgrade_msg
);
1645 if (TransactionManager
->IMSHit
== false)
1646 Rename(MetaIndex
->DestFile
, MetaIndex
->DestFile
+ ".FAILED");
1647 Item::Failed("Message: " + downgrade_msg
, Cnf
);
1648 TransactionManager
->AbortTransaction();
1653 // ensures that a Release.gpg file in the lists/ is removed by the transaction
1654 TransactionManager
->TransactionStageRemoval(this, DestFile
);
1656 // only allow going further if the user explicitly wants it
1657 if (AllowInsecureRepositories(_("The repository '%s' is not signed."), MetaIndex
->Target
.Description
, TransactionManager
->MetaIndexParser
, TransactionManager
, this) == true)
1659 if (RealFileExists(FinalReleasegpg
) || RealFileExists(FinalInRelease
))
1661 // open the last Release if we have it
1662 if (TransactionManager
->IMSHit
== false)
1664 TransactionManager
->LastMetaIndexParser
= TransactionManager
->MetaIndexParser
->UnloadedClone();
1665 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1667 _error
->PushToStack();
1668 if (RealFileExists(FinalInRelease
))
1669 TransactionManager
->LastMetaIndexParser
->Load(FinalInRelease
, NULL
);
1671 TransactionManager
->LastMetaIndexParser
->Load(FinalRelease
, NULL
);
1672 // its unlikely to happen, but if what we have is bad ignore it
1673 if (_error
->PendingError())
1675 delete TransactionManager
->LastMetaIndexParser
;
1676 TransactionManager
->LastMetaIndexParser
= NULL
;
1678 _error
->RevertToStack();
1683 // we parse the indexes here because at this point the user wanted
1684 // a repository that may potentially harm him
1685 bool const GoodLoad
= TransactionManager
->MetaIndexParser
->Load(MetaIndex
->DestFile
, &ErrorText
);
1686 if (MetaIndex
->VerifyVendor(Message
) == false)
1687 /* expired Release files are still a problem you need extra force for */;
1689 MetaIndex
->QueueIndexes(GoodLoad
);
1691 TransactionManager
->TransactionStageCopy(MetaIndex
, MetaIndex
->DestFile
, MetaIndex
->GetFinalFilename());
1694 // FIXME: this is used often (e.g. in pkgAcqIndexTrans) so refactor
1695 if (Cnf
->LocalOnly
== true ||
1696 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1705 // AcqBaseIndex - Constructor /*{{{*/
1706 pkgAcqBaseIndex::pkgAcqBaseIndex(pkgAcquire
* const Owner
,
1707 pkgAcqMetaClearSig
* const TransactionManager
,
1708 IndexTarget
const &Target
)
1709 : pkgAcqTransactionItem(Owner
, TransactionManager
, Target
), d(NULL
)
1713 pkgAcqBaseIndex::~pkgAcqBaseIndex() {}
1715 // AcqDiffIndex::AcqDiffIndex - Constructor /*{{{*/
1716 // ---------------------------------------------------------------------
1717 /* Get the DiffIndex file first and see if there are patches available
1718 * If so, create a pkgAcqIndexDiffs fetcher that will get and apply the
1719 * patches. If anything goes wrong in that process, it will fall back to
1720 * the original packages file
1722 pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire
* const Owner
,
1723 pkgAcqMetaClearSig
* const TransactionManager
,
1724 IndexTarget
const &Target
)
1725 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
), diffs(NULL
)
1727 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
1730 Desc
.Description
= Target
.Description
+ ".diff/Index";
1731 Desc
.ShortDesc
= Target
.ShortDesc
;
1732 Desc
.URI
= Target
.URI
+ ".diff/Index";
1734 DestFile
= GetPartialFileNameFromURI(Desc
.URI
);
1737 std::clog
<< "pkgAcqDiffIndex: " << Desc
.URI
<< std::endl
;
1742 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
1743 // ---------------------------------------------------------------------
1744 /* The only header we use is the last-modified header. */
1745 string
pkgAcqDiffIndex::Custom600Headers() const
1747 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1748 return "\nIndex-File: true";
1750 string
const Final
= GetFinalFilename();
1753 std::clog
<< "Custom600Header-IMS: " << Final
<< std::endl
;
1756 if (stat(Final
.c_str(),&Buf
) != 0)
1757 return "\nIndex-File: true";
1759 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1762 void pkgAcqDiffIndex::QueueOnIMSHit() const /*{{{*/
1764 // list cleanup needs to know that this file as well as the already
1765 // present index is ours, so we create an empty diff to save it for us
1766 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
);
1769 bool pkgAcqDiffIndex::ParseDiffIndex(string
const &IndexDiffFile
) /*{{{*/
1771 // failing here is fine: our caller will take care of trying to
1772 // get the complete file if patching fails
1774 std::clog
<< "pkgAcqDiffIndex::ParseIndexDiff() " << IndexDiffFile
1777 FileFd
Fd(IndexDiffFile
,FileFd::ReadOnly
);
1779 if (Fd
.IsOpen() == false || Fd
.Failed())
1783 if(unlikely(TF
.Step(Tags
) == false))
1786 HashStringList ServerHashes
;
1787 unsigned long long ServerSize
= 0;
1789 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
1791 std::string tagname
= *type
;
1792 tagname
.append("-Current");
1793 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1794 if (tmp
.empty() == true)
1798 unsigned long long size
;
1799 std::stringstream
ss(tmp
);
1801 if (unlikely(hash
.empty() == true))
1803 if (unlikely(ServerSize
!= 0 && ServerSize
!= size
))
1805 ServerHashes
.push_back(HashString(*type
, hash
));
1809 if (ServerHashes
.usable() == false)
1812 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": Did not find a good hashsum in the index" << std::endl
;
1816 std::string
const CurrentPackagesFile
= GetFinalFileNameFromURI(Target
.URI
);
1817 HashStringList
const TargetFileHashes
= GetExpectedHashesFor(Target
.MetaKey
);
1818 if (TargetFileHashes
.usable() == false || ServerHashes
!= TargetFileHashes
)
1822 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": Index has different hashes than parser, probably older, so fail pdiffing" << std::endl
;
1823 printHashSumComparision(CurrentPackagesFile
, ServerHashes
, TargetFileHashes
);
1828 HashStringList LocalHashes
;
1829 // try avoiding calculating the hash here as this is costly
1830 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1831 LocalHashes
= GetExpectedHashesFromFor(TransactionManager
->LastMetaIndexParser
, Target
.MetaKey
);
1832 if (LocalHashes
.usable() == false)
1834 FileFd
fd(CurrentPackagesFile
, FileFd::ReadOnly
, FileFd::Auto
);
1835 Hashes
LocalHashesCalc(ServerHashes
);
1836 LocalHashesCalc
.AddFD(fd
);
1837 LocalHashes
= LocalHashesCalc
.GetHashStringList();
1840 if (ServerHashes
== LocalHashes
)
1842 // we have the same sha1 as the server so we are done here
1844 std::clog
<< "pkgAcqDiffIndex: Package file " << CurrentPackagesFile
<< " is up-to-date" << std::endl
;
1850 std::clog
<< "Server-Current: " << ServerHashes
.find(NULL
)->toStr() << " and we start at "
1851 << CurrentPackagesFile
<< " " << LocalHashes
.FileSize() << " " << LocalHashes
.find(NULL
)->toStr() << std::endl
;
1853 // historically, older hashes have more info than newer ones, so start
1854 // collecting with older ones first to avoid implementing complicated
1855 // information merging techniques… a failure is after all always
1856 // recoverable with a complete file and hashes aren't changed that often.
1857 std::vector
<char const *> types
;
1858 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
1859 types
.push_back(*type
);
1861 // parse all of (provided) history
1862 vector
<DiffInfo
> available_patches
;
1863 bool firstAcceptedHashes
= true;
1864 for (auto type
= types
.crbegin(); type
!= types
.crend(); ++type
)
1866 if (LocalHashes
.find(*type
) == NULL
)
1869 std::string tagname
= *type
;
1870 tagname
.append("-History");
1871 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1872 if (tmp
.empty() == true)
1875 string hash
, filename
;
1876 unsigned long long size
;
1877 std::stringstream
ss(tmp
);
1879 while (ss
>> hash
>> size
>> filename
)
1881 if (unlikely(hash
.empty() == true || filename
.empty() == true))
1884 // see if we have a record for this file already
1885 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
1886 for (; cur
!= available_patches
.end(); ++cur
)
1888 if (cur
->file
!= filename
)
1890 cur
->result_hashes
.push_back(HashString(*type
, hash
));
1893 if (cur
!= available_patches
.end())
1895 if (firstAcceptedHashes
== true)
1898 next
.file
= filename
;
1899 next
.result_hashes
.push_back(HashString(*type
, hash
));
1900 next
.result_hashes
.FileSize(size
);
1901 available_patches
.push_back(next
);
1906 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
1907 << " wasn't in the list for the first parsed hash! (history)" << std::endl
;
1911 firstAcceptedHashes
= false;
1914 if (unlikely(available_patches
.empty() == true))
1917 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": "
1918 << "Couldn't find any patches for the patch series." << std::endl
;
1922 for (auto type
= types
.crbegin(); type
!= types
.crend(); ++type
)
1924 if (LocalHashes
.find(*type
) == NULL
)
1927 std::string tagname
= *type
;
1928 tagname
.append("-Patches");
1929 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1930 if (tmp
.empty() == true)
1933 string hash
, filename
;
1934 unsigned long long size
;
1935 std::stringstream
ss(tmp
);
1937 while (ss
>> hash
>> size
>> filename
)
1939 if (unlikely(hash
.empty() == true || filename
.empty() == true))
1942 // see if we have a record for this file already
1943 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
1944 for (; cur
!= available_patches
.end(); ++cur
)
1946 if (cur
->file
!= filename
)
1948 if (cur
->patch_hashes
.empty())
1949 cur
->patch_hashes
.FileSize(size
);
1950 cur
->patch_hashes
.push_back(HashString(*type
, hash
));
1953 if (cur
!= available_patches
.end())
1956 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
1957 << " wasn't in the list for the first parsed hash! (patches)" << std::endl
;
1962 for (auto type
= types
.crbegin(); type
!= types
.crend(); ++type
)
1964 std::string tagname
= *type
;
1965 tagname
.append("-Download");
1966 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1967 if (tmp
.empty() == true)
1970 string hash
, filename
;
1971 unsigned long long size
;
1972 std::stringstream
ss(tmp
);
1974 // FIXME: all of pdiff supports only .gz compressed patches
1975 while (ss
>> hash
>> size
>> filename
)
1977 if (unlikely(hash
.empty() == true || filename
.empty() == true))
1979 if (unlikely(APT::String::Endswith(filename
, ".gz") == false))
1981 filename
.erase(filename
.length() - 3);
1983 // see if we have a record for this file already
1984 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
1985 for (; cur
!= available_patches
.end(); ++cur
)
1987 if (cur
->file
!= filename
)
1989 if (cur
->download_hashes
.empty())
1990 cur
->download_hashes
.FileSize(size
);
1991 cur
->download_hashes
.push_back(HashString(*type
, hash
));
1994 if (cur
!= available_patches
.end())
1997 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
1998 << " wasn't in the list for the first parsed hash! (download)" << std::endl
;
2004 bool foundStart
= false;
2005 for (std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
2006 cur
!= available_patches
.end(); ++cur
)
2008 if (LocalHashes
!= cur
->result_hashes
)
2011 available_patches
.erase(available_patches
.begin(), cur
);
2016 if (foundStart
== false || unlikely(available_patches
.empty() == true))
2019 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": "
2020 << "Couldn't find the start of the patch series." << std::endl
;
2024 // patching with too many files is rather slow compared to a fast download
2025 unsigned long const fileLimit
= _config
->FindI("Acquire::PDiffs::FileLimit", 0);
2026 if (fileLimit
!= 0 && fileLimit
< available_patches
.size())
2029 std::clog
<< "Need " << available_patches
.size() << " diffs (Limit is " << fileLimit
2030 << ") so fallback to complete download" << std::endl
;
2034 // calculate the size of all patches we have to get
2035 unsigned short const sizeLimitPercent
= _config
->FindI("Acquire::PDiffs::SizeLimit", 100);
2036 if (sizeLimitPercent
> 0 && TransactionManager
->MetaIndexParser
!= nullptr)
2039 unsigned long long downloadSize
= std::accumulate(available_patches
.begin(),
2040 available_patches
.end(), 0llu, [](unsigned long long const T
, DiffInfo
const &I
) {
2041 return T
+ I
.download_hashes
.FileSize();
2043 if (downloadSize
!= 0)
2045 unsigned long long downloadSizeIdx
= 0;
2046 auto const types
= VectorizeString(Target
.Option(IndexTarget::COMPRESSIONTYPES
), ' ');
2047 for (auto const &t
: types
)
2049 std::string MetaKey
= Target
.MetaKey
;
2050 if (t
!= "uncompressed")
2052 HashStringList
const hsl
= GetExpectedHashesFor(MetaKey
);
2053 if (unlikely(hsl
.usable() == false))
2055 downloadSizeIdx
= hsl
.FileSize();
2058 unsigned long long const sizeLimit
= downloadSizeIdx
* sizeLimitPercent
;
2059 if ((sizeLimit
/100) < downloadSize
)
2062 std::clog
<< "Need " << downloadSize
<< " compressed bytes (Limit is " << (sizeLimit
/100) << ", "
2063 << "original is " << downloadSizeIdx
<< ") so fallback to complete download" << std::endl
;
2067 // uncompressed case
2068 downloadSize
= std::accumulate(available_patches
.begin(),
2069 available_patches
.end(), 0llu, [](unsigned long long const T
, DiffInfo
const &I
) {
2070 return T
+ I
.patch_hashes
.FileSize();
2072 if (downloadSize
!= 0)
2074 unsigned long long const downloadSizeIdx
= ServerSize
;
2075 unsigned long long const sizeLimit
= downloadSizeIdx
* sizeLimitPercent
;
2076 if ((sizeLimit
/100) < downloadSize
)
2079 std::clog
<< "Need " << downloadSize
<< " uncompressed bytes (Limit is " << (sizeLimit
/100) << ", "
2080 << "original is " << downloadSizeIdx
<< ") so fallback to complete download" << std::endl
;
2086 // we have something, queue the diffs
2087 string::size_type
const last_space
= Description
.rfind(" ");
2088 if(last_space
!= string::npos
)
2089 Description
.erase(last_space
, Description
.size()-last_space
);
2091 /* decide if we should download patches one by one or in one go:
2092 The first is good if the server merges patches, but many don't so client
2093 based merging can be attempt in which case the second is better.
2094 "bad things" will happen if patches are merged on the server,
2095 but client side merging is attempt as well */
2096 bool pdiff_merge
= _config
->FindB("Acquire::PDiffs::Merge", true);
2097 if (pdiff_merge
== true)
2099 // reprepro adds this flag if it has merged patches on the server
2100 std::string
const precedence
= Tags
.FindS("X-Patch-Precedence");
2101 pdiff_merge
= (precedence
!= "merged");
2106 std::string
const Final
= GetExistingFilename(CurrentPackagesFile
);
2107 if (unlikely(Final
.empty())) // because we wouldn't be called in such a case
2109 std::string
const PartialFile
= GetPartialFileNameFromURI(Target
.URI
);
2110 if (FileExists(PartialFile
) && RemoveFile("Bootstrap-linking", PartialFile
) == false)
2113 std::clog
<< "Bootstrap-linking for patching " << CurrentPackagesFile
2114 << " by removing stale " << PartialFile
<< " failed!" << std::endl
;
2117 for (auto const &ext
: APT::Configuration::getCompressorExtensions())
2119 std::string
const Partial
= PartialFile
+ ext
;
2120 if (FileExists(Partial
) && RemoveFile("Bootstrap-linking", Partial
) == false)
2123 std::clog
<< "Bootstrap-linking for patching " << CurrentPackagesFile
2124 << " by removing stale " << Partial
<< " failed!" << std::endl
;
2128 std::string
const Ext
= Final
.substr(CurrentPackagesFile
.length());
2129 std::string
const Partial
= PartialFile
+ Ext
;
2130 if (symlink(Final
.c_str(), Partial
.c_str()) != 0)
2133 std::clog
<< "Bootstrap-linking for patching " << CurrentPackagesFile
2134 << " by linking " << Final
<< " to " << Partial
<< " failed!" << std::endl
;
2139 if (pdiff_merge
== false)
2140 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
, available_patches
);
2143 diffs
= new std::vector
<pkgAcqIndexMergeDiffs
*>(available_patches
.size());
2144 for(size_t i
= 0; i
< available_patches
.size(); ++i
)
2145 (*diffs
)[i
] = new pkgAcqIndexMergeDiffs(Owner
, TransactionManager
,
2147 available_patches
[i
],
2157 void pkgAcqDiffIndex::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
2159 Item::Failed(Message
,Cnf
);
2163 std::clog
<< "pkgAcqDiffIndex failed: " << Desc
.URI
<< " with " << Message
<< std::endl
2164 << "Falling back to normal index file acquire" << std::endl
;
2166 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
2169 void pkgAcqDiffIndex::Done(string
const &Message
,HashStringList
const &Hashes
, /*{{{*/
2170 pkgAcquire::MethodConfig
const * const Cnf
)
2173 std::clog
<< "pkgAcqDiffIndex::Done(): " << Desc
.URI
<< std::endl
;
2175 Item::Done(Message
, Hashes
, Cnf
);
2177 string
const FinalFile
= GetFinalFilename();
2178 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false))
2179 DestFile
= FinalFile
;
2181 if(ParseDiffIndex(DestFile
) == false)
2183 Failed("Message: Couldn't parse pdiff index", Cnf
);
2184 // queue for final move - this should happen even if we fail
2185 // while parsing (e.g. on sizelimit) and download the complete file.
2186 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
2190 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
2199 pkgAcqDiffIndex::~pkgAcqDiffIndex()
2205 // AcqIndexDiffs::AcqIndexDiffs - Constructor /*{{{*/
2206 // ---------------------------------------------------------------------
2207 /* The package diff is added to the queue. one object is constructed
2208 * for each diff and the index
2210 pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire
* const Owner
,
2211 pkgAcqMetaClearSig
* const TransactionManager
,
2212 IndexTarget
const &Target
,
2213 vector
<DiffInfo
> const &diffs
)
2214 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
),
2215 available_patches(diffs
)
2217 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
2219 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
2222 Description
= Target
.Description
;
2223 Desc
.ShortDesc
= Target
.ShortDesc
;
2225 if(available_patches
.empty() == true)
2227 // we are done (yeah!), check hashes against the final file
2228 DestFile
= GetKeepCompressedFileName(GetFinalFileNameFromURI(Target
.URI
), Target
);
2233 State
= StateFetchDiff
;
2238 void pkgAcqIndexDiffs::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
2240 Item::Failed(Message
,Cnf
);
2243 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
2245 std::clog
<< "pkgAcqIndexDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
2246 << "Falling back to normal index file acquire " << std::endl
;
2247 RenameOnError(PDiffError
);
2248 std::string
const patchname
= GetDiffsPatchFileName(DestFile
);
2249 if (RealFileExists(patchname
))
2250 Rename(patchname
, patchname
+ ".FAILED");
2251 std::string
const UnpatchedFile
= GetExistingFilename(GetPartialFileNameFromURI(Target
.URI
));
2252 if (UnpatchedFile
.empty() == false && FileExists(UnpatchedFile
))
2253 Rename(UnpatchedFile
, UnpatchedFile
+ ".FAILED");
2254 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
2258 // Finish - helper that cleans the item out of the fetcher queue /*{{{*/
2259 void pkgAcqIndexDiffs::Finish(bool allDone
)
2262 std::clog
<< "pkgAcqIndexDiffs::Finish(): "
2264 << Desc
.URI
<< std::endl
;
2266 // we restore the original name, this is required, otherwise
2267 // the file will be cleaned
2270 std::string
const Final
= GetKeepCompressedFileName(GetFinalFilename(), Target
);
2271 TransactionManager
->TransactionStageCopy(this, DestFile
, Final
);
2273 // this is for the "real" finish
2278 std::clog
<< "\n\nallDone: " << DestFile
<< "\n" << std::endl
;
2285 std::clog
<< "Finishing: " << Desc
.URI
<< std::endl
;
2292 bool pkgAcqIndexDiffs::QueueNextDiff() /*{{{*/
2294 // calc sha1 of the just patched file
2295 std::string
const PartialFile
= GetExistingFilename(GetPartialFileNameFromURI(Target
.URI
));
2296 if(unlikely(PartialFile
.empty()))
2298 Failed("Message: The file " + GetPartialFileNameFromURI(Target
.URI
) + " isn't available", NULL
);
2302 FileFd
fd(PartialFile
, FileFd::ReadOnly
, FileFd::Extension
);
2303 Hashes LocalHashesCalc
;
2304 LocalHashesCalc
.AddFD(fd
);
2305 HashStringList
const LocalHashes
= LocalHashesCalc
.GetHashStringList();
2308 std::clog
<< "QueueNextDiff: " << PartialFile
<< " (" << LocalHashes
.find(NULL
)->toStr() << ")" << std::endl
;
2310 HashStringList
const TargetFileHashes
= GetExpectedHashesFor(Target
.MetaKey
);
2311 if (unlikely(LocalHashes
.usable() == false || TargetFileHashes
.usable() == false))
2313 Failed("Local/Expected hashes are not usable for " + PartialFile
, NULL
);
2317 // final file reached before all patches are applied
2318 if(LocalHashes
== TargetFileHashes
)
2324 // remove all patches until the next matching patch is found
2325 // this requires the Index file to be ordered
2326 available_patches
.erase(available_patches
.begin(),
2327 std::find_if(available_patches
.begin(), available_patches
.end(), [&](DiffInfo
const &I
) {
2328 return I
.result_hashes
== LocalHashes
;
2331 // error checking and falling back if no patch was found
2332 if(available_patches
.empty() == true)
2334 Failed("No patches left to reach target for " + PartialFile
, NULL
);
2338 // queue the right diff
2339 Desc
.URI
= Target
.URI
+ ".diff/" + available_patches
[0].file
+ ".gz";
2340 Desc
.Description
= Description
+ " " + available_patches
[0].file
+ string(".pdiff");
2341 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
+ ".diff/" + available_patches
[0].file
), Target
);
2344 std::clog
<< "pkgAcqIndexDiffs::QueueNextDiff(): " << Desc
.URI
<< std::endl
;
2351 void pkgAcqIndexDiffs::Done(string
const &Message
, HashStringList
const &Hashes
, /*{{{*/
2352 pkgAcquire::MethodConfig
const * const Cnf
)
2355 std::clog
<< "pkgAcqIndexDiffs::Done(): " << Desc
.URI
<< std::endl
;
2357 Item::Done(Message
, Hashes
, Cnf
);
2359 std::string
const UncompressedUnpatchedFile
= GetPartialFileNameFromURI(Target
.URI
);
2360 std::string
const UnpatchedFile
= GetExistingFilename(UncompressedUnpatchedFile
);
2361 std::string
const PatchFile
= GetDiffsPatchFileName(UnpatchedFile
);
2362 std::string
const PatchedFile
= GetKeepCompressedFileName(UncompressedUnpatchedFile
, Target
);
2366 // success in downloading a diff, enter ApplyDiff state
2367 case StateFetchDiff
:
2368 Rename(DestFile
, PatchFile
);
2369 DestFile
= GetKeepCompressedFileName(UncompressedUnpatchedFile
+ "-patched", Target
);
2371 std::clog
<< "Sending to rred method: " << UnpatchedFile
<< std::endl
;
2372 State
= StateApplyDiff
;
2374 Desc
.URI
= "rred:" + UnpatchedFile
;
2376 SetActiveSubprocess("rred");
2378 // success in download/apply a diff, queue next (if needed)
2379 case StateApplyDiff
:
2380 // remove the just applied patch and base file
2381 available_patches
.erase(available_patches
.begin());
2382 RemoveFile("pkgAcqIndexDiffs::Done", PatchFile
);
2383 RemoveFile("pkgAcqIndexDiffs::Done", UnpatchedFile
);
2385 std::clog
<< "Moving patched file in place: " << std::endl
2386 << DestFile
<< " -> " << PatchedFile
<< std::endl
;
2387 Rename(DestFile
, PatchedFile
);
2389 // see if there is more to download
2390 if(available_patches
.empty() == false)
2392 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
, available_patches
);
2395 DestFile
= PatchedFile
;
2402 std::string
pkgAcqIndexDiffs::Custom600Headers() const /*{{{*/
2404 if(State
!= StateApplyDiff
)
2405 return pkgAcqBaseIndex::Custom600Headers();
2406 std::ostringstream patchhashes
;
2407 HashStringList
const ExpectedHashes
= available_patches
[0].patch_hashes
;
2408 for (HashStringList::const_iterator hs
= ExpectedHashes
.begin(); hs
!= ExpectedHashes
.end(); ++hs
)
2409 patchhashes
<< "\nPatch-0-" << hs
->HashType() << "-Hash: " << hs
->HashValue();
2410 patchhashes
<< pkgAcqBaseIndex::Custom600Headers();
2411 return patchhashes
.str();
2414 pkgAcqIndexDiffs::~pkgAcqIndexDiffs() {}
2416 // AcqIndexMergeDiffs::AcqIndexMergeDiffs - Constructor /*{{{*/
2417 pkgAcqIndexMergeDiffs::pkgAcqIndexMergeDiffs(pkgAcquire
* const Owner
,
2418 pkgAcqMetaClearSig
* const TransactionManager
,
2419 IndexTarget
const &Target
,
2420 DiffInfo
const &patch
,
2421 std::vector
<pkgAcqIndexMergeDiffs
*> const * const allPatches
)
2422 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
),
2423 patch(patch
), allPatches(allPatches
), State(StateFetchDiff
)
2425 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
2428 Description
= Target
.Description
;
2429 Desc
.ShortDesc
= Target
.ShortDesc
;
2430 Desc
.URI
= Target
.URI
+ ".diff/" + patch
.file
+ ".gz";
2431 Desc
.Description
= Description
+ " " + patch
.file
+ ".pdiff";
2432 DestFile
= GetPartialFileNameFromURI(Desc
.URI
);
2435 std::clog
<< "pkgAcqIndexMergeDiffs: " << Desc
.URI
<< std::endl
;
2440 void pkgAcqIndexMergeDiffs::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
2443 std::clog
<< "pkgAcqIndexMergeDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
;
2445 Item::Failed(Message
,Cnf
);
2448 // check if we are the first to fail, otherwise we are done here
2449 State
= StateDoneDiff
;
2450 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2451 I
!= allPatches
->end(); ++I
)
2452 if ((*I
)->State
== StateErrorDiff
)
2455 // first failure means we should fallback
2456 State
= StateErrorDiff
;
2458 std::clog
<< "Falling back to normal index file acquire" << std::endl
;
2459 RenameOnError(PDiffError
);
2460 std::string
const patchname
= GetPartialFileNameFromURI(Desc
.URI
);
2461 if (RealFileExists(patchname
))
2462 Rename(patchname
, patchname
+ ".FAILED");
2463 std::string
const UnpatchedFile
= GetExistingFilename(GetPartialFileNameFromURI(Target
.URI
));
2464 if (UnpatchedFile
.empty() == false && FileExists(UnpatchedFile
))
2465 Rename(UnpatchedFile
, UnpatchedFile
+ ".FAILED");
2467 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
2470 void pkgAcqIndexMergeDiffs::Done(string
const &Message
, HashStringList
const &Hashes
, /*{{{*/
2471 pkgAcquire::MethodConfig
const * const Cnf
)
2474 std::clog
<< "pkgAcqIndexMergeDiffs::Done(): " << Desc
.URI
<< std::endl
;
2476 Item::Done(Message
, Hashes
, Cnf
);
2478 std::string
const UncompressedUnpatchedFile
= GetPartialFileNameFromURI(Target
.URI
);
2479 std::string
const UnpatchedFile
= GetExistingFilename(UncompressedUnpatchedFile
);
2480 std::string
const PatchFile
= GetMergeDiffsPatchFileName(UnpatchedFile
, patch
.file
);
2481 std::string
const PatchedFile
= GetKeepCompressedFileName(UncompressedUnpatchedFile
, Target
);
2485 case StateFetchDiff
:
2486 Rename(DestFile
, PatchFile
);
2488 // check if this is the last completed diff
2489 State
= StateDoneDiff
;
2490 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2491 I
!= allPatches
->end(); ++I
)
2492 if ((*I
)->State
!= StateDoneDiff
)
2495 std::clog
<< "Not the last done diff in the batch: " << Desc
.URI
<< std::endl
;
2498 // this is the last completed diff, so we are ready to apply now
2499 DestFile
= GetKeepCompressedFileName(UncompressedUnpatchedFile
+ "-patched", Target
);
2501 std::clog
<< "Sending to rred method: " << UnpatchedFile
<< std::endl
;
2502 State
= StateApplyDiff
;
2504 Desc
.URI
= "rred:" + UnpatchedFile
;
2506 SetActiveSubprocess("rred");
2508 case StateApplyDiff
:
2509 // success in download & apply all diffs, finialize and clean up
2511 std::clog
<< "Queue patched file in place: " << std::endl
2512 << DestFile
<< " -> " << PatchedFile
<< std::endl
;
2514 // queue for copy by the transaction manager
2515 TransactionManager
->TransactionStageCopy(this, DestFile
, GetKeepCompressedFileName(GetFinalFilename(), Target
));
2517 // ensure the ed's are gone regardless of list-cleanup
2518 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2519 I
!= allPatches
->end(); ++I
)
2520 RemoveFile("pkgAcqIndexMergeDiffs::Done", GetMergeDiffsPatchFileName(UnpatchedFile
, (*I
)->patch
.file
));
2521 RemoveFile("pkgAcqIndexMergeDiffs::Done", UnpatchedFile
);
2526 std::clog
<< "allDone: " << DestFile
<< "\n" << std::endl
;
2528 case StateDoneDiff
: _error
->Fatal("Done called for %s which is in an invalid Done state", PatchFile
.c_str()); break;
2529 case StateErrorDiff
: _error
->Fatal("Done called for %s which is in an invalid Error state", PatchFile
.c_str()); break;
2533 std::string
pkgAcqIndexMergeDiffs::Custom600Headers() const /*{{{*/
2535 if(State
!= StateApplyDiff
)
2536 return pkgAcqBaseIndex::Custom600Headers();
2537 std::ostringstream patchhashes
;
2538 unsigned int seen_patches
= 0;
2539 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2540 I
!= allPatches
->end(); ++I
)
2542 HashStringList
const ExpectedHashes
= (*I
)->patch
.patch_hashes
;
2543 for (HashStringList::const_iterator hs
= ExpectedHashes
.begin(); hs
!= ExpectedHashes
.end(); ++hs
)
2544 patchhashes
<< "\nPatch-" << seen_patches
<< "-" << hs
->HashType() << "-Hash: " << hs
->HashValue();
2547 patchhashes
<< pkgAcqBaseIndex::Custom600Headers();
2548 return patchhashes
.str();
2551 pkgAcqIndexMergeDiffs::~pkgAcqIndexMergeDiffs() {}
2553 // AcqIndex::AcqIndex - Constructor /*{{{*/
2554 pkgAcqIndex::pkgAcqIndex(pkgAcquire
* const Owner
,
2555 pkgAcqMetaClearSig
* const TransactionManager
,
2556 IndexTarget
const &Target
)
2557 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
), Stage(STAGE_DOWNLOAD
),
2558 CompressionExtensions(Target
.Option(IndexTarget::COMPRESSIONTYPES
))
2560 Init(Target
.URI
, Target
.Description
, Target
.ShortDesc
);
2562 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
2563 std::clog
<< "New pkgIndex with TransactionManager "
2564 << TransactionManager
<< std::endl
;
2567 // AcqIndex::Init - defered Constructor /*{{{*/
2568 static void NextCompressionExtension(std::string
&CurrentCompressionExtension
, std::string
&CompressionExtensions
, bool const preview
)
2570 size_t const nextExt
= CompressionExtensions
.find(' ');
2571 if (nextExt
== std::string::npos
)
2573 CurrentCompressionExtension
= CompressionExtensions
;
2574 if (preview
== false)
2575 CompressionExtensions
.clear();
2579 CurrentCompressionExtension
= CompressionExtensions
.substr(0, nextExt
);
2580 if (preview
== false)
2581 CompressionExtensions
= CompressionExtensions
.substr(nextExt
+1);
2584 void pkgAcqIndex::Init(string
const &URI
, string
const &URIDesc
,
2585 string
const &ShortDesc
)
2587 Stage
= STAGE_DOWNLOAD
;
2589 DestFile
= GetPartialFileNameFromURI(URI
);
2590 NextCompressionExtension(CurrentCompressionExtension
, CompressionExtensions
, false);
2592 if (CurrentCompressionExtension
== "uncompressed")
2596 else if (CurrentCompressionExtension
== "by-hash")
2598 NextCompressionExtension(CurrentCompressionExtension
, CompressionExtensions
, true);
2599 if(unlikely(TransactionManager
->MetaIndexParser
== NULL
|| CurrentCompressionExtension
.empty()))
2601 if (CurrentCompressionExtension
!= "uncompressed")
2603 Desc
.URI
= URI
+ '.' + CurrentCompressionExtension
;
2604 DestFile
= DestFile
+ '.' + CurrentCompressionExtension
;
2607 HashStringList
const Hashes
= GetExpectedHashes();
2608 HashString
const * const TargetHash
= Hashes
.find(NULL
);
2609 if (unlikely(TargetHash
== nullptr))
2611 std::string
const ByHash
= "/by-hash/" + TargetHash
->HashType() + "/" + TargetHash
->HashValue();
2612 size_t const trailing_slash
= Desc
.URI
.find_last_of("/");
2613 if (unlikely(trailing_slash
== std::string::npos
))
2615 Desc
.URI
= Desc
.URI
.replace(
2617 Desc
.URI
.substr(trailing_slash
+1).size()+1,
2620 else if (unlikely(CurrentCompressionExtension
.empty()))
2624 Desc
.URI
= URI
+ '.' + CurrentCompressionExtension
;
2625 DestFile
= DestFile
+ '.' + CurrentCompressionExtension
;
2629 Desc
.Description
= URIDesc
;
2631 Desc
.ShortDesc
= ShortDesc
;
2636 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
2637 // ---------------------------------------------------------------------
2638 /* The only header we use is the last-modified header. */
2639 string
pkgAcqIndex::Custom600Headers() const
2642 string msg
= "\nIndex-File: true";
2644 if (TransactionManager
->LastMetaIndexParser
== NULL
)
2646 std::string
const Final
= GetFinalFilename();
2649 if (stat(Final
.c_str(),&Buf
) == 0)
2650 msg
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
2653 if(Target
.IsOptional
)
2654 msg
+= "\nFail-Ignore: true";
2659 // AcqIndex::Failed - getting the indexfile failed /*{{{*/
2660 void pkgAcqIndex::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)
2662 Item::Failed(Message
,Cnf
);
2664 // authorisation matches will not be fixed by other compression types
2665 if (Status
!= StatAuthError
)
2667 if (CompressionExtensions
.empty() == false)
2669 Init(Target
.URI
, Desc
.Description
, Desc
.ShortDesc
);
2675 if(Target
.IsOptional
&& GetExpectedHashes().empty() && Stage
== STAGE_DOWNLOAD
)
2678 TransactionManager
->AbortTransaction();
2681 // AcqIndex::Done - Finished a fetch /*{{{*/
2682 // ---------------------------------------------------------------------
2683 /* This goes through a number of states.. On the initial fetch the
2684 method could possibly return an alternate filename which points
2685 to the uncompressed version of the file. If this is so the file
2686 is copied into the partial directory. In all other cases the file
2687 is decompressed with a compressed uri. */
2688 void pkgAcqIndex::Done(string
const &Message
,
2689 HashStringList
const &Hashes
,
2690 pkgAcquire::MethodConfig
const * const Cfg
)
2692 Item::Done(Message
,Hashes
,Cfg
);
2696 case STAGE_DOWNLOAD
:
2697 StageDownloadDone(Message
);
2699 case STAGE_DECOMPRESS_AND_VERIFY
:
2700 StageDecompressDone();
2705 // AcqIndex::StageDownloadDone - Queue for decompress and verify /*{{{*/
2706 void pkgAcqIndex::StageDownloadDone(string
const &Message
)
2711 std::string
const AltFilename
= LookupTag(Message
,"Alt-Filename");
2712 std::string Filename
= LookupTag(Message
,"Filename");
2714 // we need to verify the file against the current Release file again
2715 // on if-modfied-since hit to avoid a stale attack against us
2716 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
2718 // copy FinalFile into partial/ so that we check the hash again
2719 string
const FinalFile
= GetExistingFilename(GetFinalFileNameFromURI(Target
.URI
));
2720 if (symlink(FinalFile
.c_str(), DestFile
.c_str()) != 0)
2721 _error
->WarningE("pkgAcqIndex::StageDownloadDone", "Symlinking final file %s back to %s failed", FinalFile
.c_str(), DestFile
.c_str());
2724 EraseFileName
= DestFile
;
2725 Filename
= DestFile
;
2727 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
2728 Desc
.URI
= "store:" + Filename
;
2730 SetActiveSubprocess(::URI(Desc
.URI
).Access
);
2733 // methods like file:// give us an alternative (uncompressed) file
2734 else if (Target
.KeepCompressed
== false && AltFilename
.empty() == false)
2736 if (CurrentCompressionExtension
!= "uncompressed")
2737 DestFile
.erase(DestFile
.length() - (CurrentCompressionExtension
.length() + 1));
2738 Filename
= AltFilename
;
2740 // Methods like e.g. "file:" will give us a (compressed) FileName that is
2741 // not the "DestFile" we set, in this case we uncompress from the local file
2742 else if (Filename
!= DestFile
&& RealFileExists(DestFile
) == false)
2744 // symlinking ensures that the filename can be used for compression detection
2745 // that is e.g. needed for by-hash which has no extension over file
2746 if (symlink(Filename
.c_str(),DestFile
.c_str()) != 0)
2747 _error
->WarningE("pkgAcqIndex::StageDownloadDone", "Symlinking file %s to %s failed", Filename
.c_str(), DestFile
.c_str());
2750 EraseFileName
= DestFile
;
2751 Filename
= DestFile
;
2755 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
2756 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
2757 if (Filename
!= DestFile
&& flExtension(Filename
) == flExtension(DestFile
))
2758 Desc
.URI
= "copy:" + Filename
;
2760 Desc
.URI
= "store:" + Filename
;
2761 if (DestFile
== Filename
)
2763 if (CurrentCompressionExtension
== "uncompressed")
2764 return StageDecompressDone();
2765 DestFile
= "/dev/null";
2768 if (EraseFileName
.empty())
2769 EraseFileName
= Filename
;
2771 // queue uri for the next stage
2773 SetActiveSubprocess(::URI(Desc
.URI
).Access
);
2776 // AcqIndex::StageDecompressDone - Final verification /*{{{*/
2777 void pkgAcqIndex::StageDecompressDone()
2779 if (DestFile
== "/dev/null")
2780 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
2782 // Done, queue for rename on transaction finished
2783 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
2786 pkgAcqIndex::~pkgAcqIndex() {}
2789 // AcqArchive::AcqArchive - Constructor /*{{{*/
2790 // ---------------------------------------------------------------------
2791 /* This just sets up the initial fetch environment and queues the first
2793 pkgAcqArchive::pkgAcqArchive(pkgAcquire
* const Owner
,pkgSourceList
* const Sources
,
2794 pkgRecords
* const Recs
,pkgCache::VerIterator
const &Version
,
2795 string
&StoreFilename
) :
2796 Item(Owner
), d(NULL
), LocalSource(false), Version(Version
), Sources(Sources
), Recs(Recs
),
2797 StoreFilename(StoreFilename
), Vf(Version
.FileList()),
2800 Retries
= _config
->FindI("Acquire::Retries",0);
2802 if (Version
.Arch() == 0)
2804 _error
->Error(_("I wasn't able to locate a file for the %s package. "
2805 "This might mean you need to manually fix this package. "
2806 "(due to missing arch)"),
2807 Version
.ParentPkg().FullName().c_str());
2811 /* We need to find a filename to determine the extension. We make the
2812 assumption here that all the available sources for this version share
2813 the same extension.. */
2814 // Skip not source sources, they do not have file fields.
2815 for (; Vf
.end() == false; ++Vf
)
2817 if (Vf
.File().Flagged(pkgCache::Flag::NotSource
))
2822 // Does not really matter here.. we are going to fail out below
2823 if (Vf
.end() != true)
2825 // If this fails to get a file name we will bomb out below.
2826 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2827 if (_error
->PendingError() == true)
2830 // Generate the final file name as: package_version_arch.foo
2831 StoreFilename
= QuoteString(Version
.ParentPkg().Name(),"_:") + '_' +
2832 QuoteString(Version
.VerStr(),"_:") + '_' +
2833 QuoteString(Version
.Arch(),"_:.") +
2834 "." + flExtension(Parse
.FileName());
2837 // check if we have one trusted source for the package. if so, switch
2838 // to "TrustedOnly" mode - but only if not in AllowUnauthenticated mode
2839 bool const allowUnauth
= _config
->FindB("APT::Get::AllowUnauthenticated", false);
2840 bool const debugAuth
= _config
->FindB("Debug::pkgAcquire::Auth", false);
2841 bool seenUntrusted
= false;
2842 for (pkgCache::VerFileIterator i
= Version
.FileList(); i
.end() == false; ++i
)
2844 pkgIndexFile
*Index
;
2845 if (Sources
->FindIndex(i
.File(),Index
) == false)
2848 if (debugAuth
== true)
2849 std::cerr
<< "Checking index: " << Index
->Describe()
2850 << "(Trusted=" << Index
->IsTrusted() << ")" << std::endl
;
2852 if (Index
->IsTrusted() == true)
2855 if (allowUnauth
== false)
2859 seenUntrusted
= true;
2862 // "allow-unauthenticated" restores apts old fetching behaviour
2863 // that means that e.g. unauthenticated file:// uris are higher
2864 // priority than authenticated http:// uris
2865 if (allowUnauth
== true && seenUntrusted
== true)
2869 if (QueueNext() == false && _error
->PendingError() == false)
2870 _error
->Error(_("Can't find a source to download version '%s' of '%s'"),
2871 Version
.VerStr(), Version
.ParentPkg().FullName(false).c_str());
2874 // AcqArchive::QueueNext - Queue the next file source /*{{{*/
2875 // ---------------------------------------------------------------------
2876 /* This queues the next available file version for download. It checks if
2877 the archive is already available in the cache and stashs the MD5 for
2879 bool pkgAcqArchive::QueueNext()
2881 for (; Vf
.end() == false; ++Vf
)
2883 pkgCache::PkgFileIterator
const PkgF
= Vf
.File();
2884 // Ignore not source sources
2885 if (PkgF
.Flagged(pkgCache::Flag::NotSource
))
2888 // Try to cross match against the source list
2889 pkgIndexFile
*Index
;
2890 if (Sources
->FindIndex(PkgF
, Index
) == false)
2892 LocalSource
= PkgF
.Flagged(pkgCache::Flag::LocalSource
);
2894 // only try to get a trusted package from another source if that source
2896 if(Trusted
&& !Index
->IsTrusted())
2899 // Grab the text package record
2900 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2901 if (_error
->PendingError() == true)
2904 string PkgFile
= Parse
.FileName();
2905 ExpectedHashes
= Parse
.Hashes();
2907 if (PkgFile
.empty() == true)
2908 return _error
->Error(_("The package index files are corrupted. No Filename: "
2909 "field for package %s."),
2910 Version
.ParentPkg().Name());
2912 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
2913 Desc
.Description
= Index
->ArchiveInfo(Version
);
2915 Desc
.ShortDesc
= Version
.ParentPkg().FullName(true);
2917 // See if we already have the file. (Legacy filenames)
2918 FileSize
= Version
->Size
;
2919 string FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile
);
2921 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2923 // Make sure the size matches
2924 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2929 StoreFilename
= DestFile
= FinalFile
;
2933 /* Hmm, we have a file and its size does not match, this means it is
2934 an old style mismatched arch */
2935 RemoveFile("pkgAcqArchive::QueueNext", FinalFile
);
2938 // Check it again using the new style output filenames
2939 FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
2940 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2942 // Make sure the size matches
2943 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2948 StoreFilename
= DestFile
= FinalFile
;
2952 /* Hmm, we have a file and its size does not match, this shouldn't
2954 RemoveFile("pkgAcqArchive::QueueNext", FinalFile
);
2957 DestFile
= _config
->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename
);
2959 // Check the destination file
2960 if (stat(DestFile
.c_str(),&Buf
) == 0)
2962 // Hmm, the partial file is too big, erase it
2963 if ((unsigned long long)Buf
.st_size
> Version
->Size
)
2964 RemoveFile("pkgAcqArchive::QueueNext", DestFile
);
2966 PartialSize
= Buf
.st_size
;
2969 // Disables download of archives - useful if no real installation follows,
2970 // e.g. if we are just interested in proposed installation order
2971 if (_config
->FindB("Debug::pkgAcqArchive::NoQueue", false) == true)
2976 StoreFilename
= DestFile
= FinalFile
;
2990 // AcqArchive::Done - Finished fetching /*{{{*/
2991 // ---------------------------------------------------------------------
2993 void pkgAcqArchive::Done(string
const &Message
, HashStringList
const &Hashes
,
2994 pkgAcquire::MethodConfig
const * const Cfg
)
2996 Item::Done(Message
, Hashes
, Cfg
);
2998 // Grab the output filename
2999 std::string
const FileName
= LookupTag(Message
,"Filename");
3000 if (DestFile
!= FileName
&& RealFileExists(DestFile
) == false)
3002 StoreFilename
= DestFile
= FileName
;
3008 // Done, move it into position
3009 string
const FinalFile
= GetFinalFilename();
3010 Rename(DestFile
,FinalFile
);
3011 StoreFilename
= DestFile
= FinalFile
;
3015 // AcqArchive::Failed - Failure handler /*{{{*/
3016 // ---------------------------------------------------------------------
3017 /* Here we try other sources */
3018 void pkgAcqArchive::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)
3020 Item::Failed(Message
,Cnf
);
3022 /* We don't really want to retry on failed media swaps, this prevents
3023 that. An interesting observation is that permanent failures are not
3025 if (Cnf
->Removable
== true &&
3026 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
3028 // Vf = Version.FileList();
3029 while (Vf
.end() == false) ++Vf
;
3030 StoreFilename
= string();
3035 if (QueueNext() == false)
3037 // This is the retry counter
3039 Cnf
->LocalOnly
== false &&
3040 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
3043 Vf
= Version
.FileList();
3044 if (QueueNext() == true)
3048 StoreFilename
= string();
3053 APT_PURE
bool pkgAcqArchive::IsTrusted() const /*{{{*/
3058 void pkgAcqArchive::Finished() /*{{{*/
3060 if (Status
== pkgAcquire::Item::StatDone
&&
3063 StoreFilename
= string();
3066 std::string
pkgAcqArchive::DescURI() const /*{{{*/
3071 std::string
pkgAcqArchive::ShortDesc() const /*{{{*/
3073 return Desc
.ShortDesc
;
3076 pkgAcqArchive::~pkgAcqArchive() {}
3078 // AcqChangelog::pkgAcqChangelog - Constructors /*{{{*/
3079 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire
* const Owner
, pkgCache::VerIterator
const &Ver
,
3080 std::string
const &DestDir
, std::string
const &DestFilename
) :
3081 pkgAcquire::Item(Owner
), d(NULL
), SrcName(Ver
.SourcePkgName()), SrcVersion(Ver
.SourceVerStr())
3083 Desc
.URI
= URI(Ver
);
3084 Init(DestDir
, DestFilename
);
3086 // some parameters are char* here as they come likely from char* interfaces – which can also return NULL
3087 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire
* const Owner
, pkgCache::RlsFileIterator
const &RlsFile
,
3088 char const * const Component
, char const * const SrcName
, char const * const SrcVersion
,
3089 const string
&DestDir
, const string
&DestFilename
) :
3090 pkgAcquire::Item(Owner
), d(NULL
), SrcName(SrcName
), SrcVersion(SrcVersion
)
3092 Desc
.URI
= URI(RlsFile
, Component
, SrcName
, SrcVersion
);
3093 Init(DestDir
, DestFilename
);
3095 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire
* const Owner
,
3096 std::string
const &URI
, char const * const SrcName
, char const * const SrcVersion
,
3097 const string
&DestDir
, const string
&DestFilename
) :
3098 pkgAcquire::Item(Owner
), d(NULL
), SrcName(SrcName
), SrcVersion(SrcVersion
)
3101 Init(DestDir
, DestFilename
);
3103 void pkgAcqChangelog::Init(std::string
const &DestDir
, std::string
const &DestFilename
)
3105 if (Desc
.URI
.empty())
3108 // TRANSLATOR: %s=%s is sourcename=sourceversion, e.g. apt=1.1
3109 strprintf(ErrorText
, _("Changelog unavailable for %s=%s"), SrcName
.c_str(), SrcVersion
.c_str());
3110 // Let the error message print something sensible rather than "Failed to fetch /"
3111 if (DestFilename
.empty())
3112 DestFile
= SrcName
+ ".changelog";
3114 DestFile
= DestFilename
;
3115 Desc
.URI
= "changelog:/" + DestFile
;
3119 if (DestDir
.empty())
3121 std::string
const SandboxUser
= _config
->Find("APT::Sandbox::User");
3122 std::string
const systemTemp
= GetTempDir(SandboxUser
);
3124 snprintf(tmpname
, sizeof(tmpname
), "%s/apt-changelog-XXXXXX", systemTemp
.c_str());
3125 if (NULL
== mkdtemp(tmpname
))
3127 _error
->Errno("mkdtemp", "mkdtemp failed in changelog acquire of %s %s", SrcName
.c_str(), SrcVersion
.c_str());
3131 DestFile
= TemporaryDirectory
= tmpname
;
3133 ChangeOwnerAndPermissionOfFile("Item::QueueURI", DestFile
.c_str(),
3134 SandboxUser
.c_str(), "root", 0700);
3139 if (DestFilename
.empty())
3140 DestFile
= flCombine(DestFile
, SrcName
+ ".changelog");
3142 DestFile
= flCombine(DestFile
, DestFilename
);
3144 Desc
.ShortDesc
= "Changelog";
3145 strprintf(Desc
.Description
, "%s %s %s Changelog", URI::SiteOnly(Desc
.URI
).c_str(), SrcName
.c_str(), SrcVersion
.c_str());
3150 std::string
pkgAcqChangelog::URI(pkgCache::VerIterator
const &Ver
) /*{{{*/
3152 std::string
const confOnline
= "Acquire::Changelogs::AlwaysOnline";
3153 bool AlwaysOnline
= _config
->FindB(confOnline
, false);
3154 if (AlwaysOnline
== false)
3155 for (pkgCache::VerFileIterator VF
= Ver
.FileList(); VF
.end() == false; ++VF
)
3157 pkgCache::PkgFileIterator
const PF
= VF
.File();
3158 if (PF
.Flagged(pkgCache::Flag::NotSource
) || PF
->Release
== 0)
3160 pkgCache::RlsFileIterator
const RF
= PF
.ReleaseFile();
3161 if (RF
->Origin
!= 0 && _config
->FindB(confOnline
+ "::Origin::" + RF
.Origin(), false))
3163 AlwaysOnline
= true;
3167 if (AlwaysOnline
== false)
3169 pkgCache::PkgIterator
const Pkg
= Ver
.ParentPkg();
3170 if (Pkg
->CurrentVer
!= 0 && Pkg
.CurrentVer() == Ver
)
3172 std::string
const basename
= std::string("/usr/share/doc/") + Pkg
.Name() + "/changelog";
3173 std::string
const debianname
= basename
+ ".Debian";
3174 if (FileExists(debianname
))
3175 return "copy://" + debianname
;
3176 else if (FileExists(debianname
+ ".gz"))
3177 return "gzip://" + debianname
+ ".gz";
3178 else if (FileExists(basename
))
3179 return "copy://" + basename
;
3180 else if (FileExists(basename
+ ".gz"))
3181 return "gzip://" + basename
+ ".gz";
3185 char const * const SrcName
= Ver
.SourcePkgName();
3186 char const * const SrcVersion
= Ver
.SourceVerStr();
3187 // find the first source for this version which promises a changelog
3188 for (pkgCache::VerFileIterator VF
= Ver
.FileList(); VF
.end() == false; ++VF
)
3190 pkgCache::PkgFileIterator
const PF
= VF
.File();
3191 if (PF
.Flagged(pkgCache::Flag::NotSource
) || PF
->Release
== 0)
3193 pkgCache::RlsFileIterator
const RF
= PF
.ReleaseFile();
3194 std::string
const uri
= URI(RF
, PF
.Component(), SrcName
, SrcVersion
);
3201 std::string
pkgAcqChangelog::URITemplate(pkgCache::RlsFileIterator
const &Rls
)
3203 if (Rls
.end() == true || (Rls
->Label
== 0 && Rls
->Origin
== 0))
3205 std::string
const serverConfig
= "Acquire::Changelogs::URI";
3207 #define APT_EMPTY_SERVER \
3208 if (server.empty() == false) \
3210 if (server != "no") \
3214 #define APT_CHECK_SERVER(X, Y) \
3217 std::string const specialServerConfig = serverConfig + "::" + Y + #X + "::" + Rls.X(); \
3218 server = _config->Find(specialServerConfig); \
3221 // this way e.g. Debian-Security can fallback to Debian
3222 APT_CHECK_SERVER(Label
, "Override::")
3223 APT_CHECK_SERVER(Origin
, "Override::")
3225 if (RealFileExists(Rls
.FileName()))
3227 _error
->PushToStack();
3229 /* This can be costly. A caller wanting to get millions of URIs might
3230 want to do this on its own once and use Override settings.
3231 We don't do this here as Origin/Label are not as unique as they
3232 should be so this could produce request order-dependent anomalies */
3233 if (OpenMaybeClearSignedFile(Rls
.FileName(), rf
) == true)
3235 pkgTagFile
TagFile(&rf
, rf
.Size());
3236 pkgTagSection Section
;
3237 if (TagFile
.Step(Section
) == true)
3238 server
= Section
.FindS("Changelogs");
3240 _error
->RevertToStack();
3244 APT_CHECK_SERVER(Label
, "")
3245 APT_CHECK_SERVER(Origin
, "")
3246 #undef APT_CHECK_SERVER
3247 #undef APT_EMPTY_SERVER
3250 std::string
pkgAcqChangelog::URI(pkgCache::RlsFileIterator
const &Rls
,
3251 char const * const Component
, char const * const SrcName
,
3252 char const * const SrcVersion
)
3254 return URI(URITemplate(Rls
), Component
, SrcName
, SrcVersion
);
3256 std::string
pkgAcqChangelog::URI(std::string
const &Template
,
3257 char const * const Component
, char const * const SrcName
,
3258 char const * const SrcVersion
)
3260 if (Template
.find("@CHANGEPATH@") == std::string::npos
)
3263 // the path is: COMPONENT/SRC/SRCNAME/SRCNAME_SRCVER, e.g. main/a/apt/1.1 or contrib/liba/libapt/2.0
3264 std::string Src
= SrcName
;
3265 std::string path
= APT::String::Startswith(SrcName
, "lib") ? Src
.substr(0, 4) : Src
.substr(0,1);
3266 path
.append("/").append(Src
).append("/");
3267 path
.append(Src
).append("_").append(StripEpoch(SrcVersion
));
3268 // we omit component for releases without one (= flat-style repositories)
3269 if (Component
!= NULL
&& strlen(Component
) != 0)
3270 path
= std::string(Component
) + "/" + path
;
3272 return SubstVar(Template
, "@CHANGEPATH@", path
);
3275 // AcqChangelog::Failed - Failure handler /*{{{*/
3276 void pkgAcqChangelog::Failed(string
const &Message
, pkgAcquire::MethodConfig
const * const Cnf
)
3278 Item::Failed(Message
,Cnf
);
3280 std::string errText
;
3281 // TRANSLATOR: %s=%s is sourcename=sourceversion, e.g. apt=1.1
3282 strprintf(errText
, _("Changelog unavailable for %s=%s"), SrcName
.c_str(), SrcVersion
.c_str());
3284 // Error is probably something techy like 404 Not Found
3285 if (ErrorText
.empty())
3286 ErrorText
= errText
;
3288 ErrorText
= errText
+ " (" + ErrorText
+ ")";
3292 // AcqChangelog::Done - Item downloaded OK /*{{{*/
3293 void pkgAcqChangelog::Done(string
const &Message
,HashStringList
const &CalcHashes
,
3294 pkgAcquire::MethodConfig
const * const Cnf
)
3296 Item::Done(Message
,CalcHashes
,Cnf
);
3301 pkgAcqChangelog::~pkgAcqChangelog() /*{{{*/
3303 if (TemporaryDirectory
.empty() == false)
3305 RemoveFile("~pkgAcqChangelog", DestFile
);
3306 rmdir(TemporaryDirectory
.c_str());
3311 // AcqFile::pkgAcqFile - Constructor /*{{{*/
3312 pkgAcqFile::pkgAcqFile(pkgAcquire
* const Owner
,string
const &URI
, HashStringList
const &Hashes
,
3313 unsigned long long const Size
,string
const &Dsc
,string
const &ShortDesc
,
3314 const string
&DestDir
, const string
&DestFilename
,
3315 bool const IsIndexFile
) :
3316 Item(Owner
), d(NULL
), IsIndexFile(IsIndexFile
), ExpectedHashes(Hashes
)
3318 Retries
= _config
->FindI("Acquire::Retries",0);
3320 if(!DestFilename
.empty())
3321 DestFile
= DestFilename
;
3322 else if(!DestDir
.empty())
3323 DestFile
= DestDir
+ "/" + flNotDir(URI
);
3325 DestFile
= flNotDir(URI
);
3329 Desc
.Description
= Dsc
;
3332 // Set the short description to the archive component
3333 Desc
.ShortDesc
= ShortDesc
;
3335 // Get the transfer sizes
3338 if (stat(DestFile
.c_str(),&Buf
) == 0)
3340 // Hmm, the partial file is too big, erase it
3341 if ((Size
> 0) && (unsigned long long)Buf
.st_size
> Size
)
3342 RemoveFile("pkgAcqFile", DestFile
);
3344 PartialSize
= Buf
.st_size
;
3350 // AcqFile::Done - Item downloaded OK /*{{{*/
3351 void pkgAcqFile::Done(string
const &Message
,HashStringList
const &CalcHashes
,
3352 pkgAcquire::MethodConfig
const * const Cnf
)
3354 Item::Done(Message
,CalcHashes
,Cnf
);
3356 std::string
const FileName
= LookupTag(Message
,"Filename");
3359 // The files timestamp matches
3360 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
3363 // We have to copy it into place
3364 if (RealFileExists(DestFile
.c_str()) == false)
3367 if (_config
->FindB("Acquire::Source-Symlinks",true) == false ||
3368 Cnf
->Removable
== true)
3370 Desc
.URI
= "copy:" + FileName
;
3375 // Erase the file if it is a symlink so we can overwrite it
3377 if (lstat(DestFile
.c_str(),&St
) == 0)
3379 if (S_ISLNK(St
.st_mode
) != 0)
3380 RemoveFile("pkgAcqFile::Done", DestFile
);
3384 if (symlink(FileName
.c_str(),DestFile
.c_str()) != 0)
3386 _error
->PushToStack();
3387 _error
->Errno("pkgAcqFile::Done", "Symlinking file %s failed", DestFile
.c_str());
3388 std::stringstream msg
;
3389 _error
->DumpErrors(msg
, GlobalError::DEBUG
, false);
3390 _error
->RevertToStack();
3391 ErrorText
= msg
.str();
3398 // AcqFile::Failed - Failure handler /*{{{*/
3399 // ---------------------------------------------------------------------
3400 /* Here we try other sources */
3401 void pkgAcqFile::Failed(string
const &Message
, pkgAcquire::MethodConfig
const * const Cnf
)
3403 Item::Failed(Message
,Cnf
);
3405 // This is the retry counter
3407 Cnf
->LocalOnly
== false &&
3408 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
3418 string
pkgAcqFile::Custom600Headers() const /*{{{*/
3421 return "\nIndex-File: true";
3425 pkgAcqFile::~pkgAcqFile() {}