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>
55 static void printHashSumComparison(std::string
const &URI
, HashStringList
const &Expected
, HashStringList
const &Actual
) /*{{{*/
57 if (_config
->FindB("Debug::Acquire::HashSumMismatch", false) == false)
59 std::cerr
<< std::endl
<< URI
<< ":" << std::endl
<< " Expected Hash: " << std::endl
;
60 for (HashStringList::const_iterator hs
= Expected
.begin(); hs
!= Expected
.end(); ++hs
)
61 std::cerr
<< "\t- " << hs
->toStr() << std::endl
;
62 std::cerr
<< " Actual Hash: " << std::endl
;
63 for (HashStringList::const_iterator hs
= Actual
.begin(); hs
!= Actual
.end(); ++hs
)
64 std::cerr
<< "\t- " << hs
->toStr() << std::endl
;
67 static std::string
GetPartialFileName(std::string
const &file
) /*{{{*/
69 std::string DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
74 static std::string
GetPartialFileNameFromURI(std::string
const &uri
) /*{{{*/
76 return GetPartialFileName(URItoFileName(uri
));
79 static std::string
GetFinalFileNameFromURI(std::string
const &uri
) /*{{{*/
81 return _config
->FindDir("Dir::State::lists") + URItoFileName(uri
);
84 static std::string
GetKeepCompressedFileName(std::string file
, IndexTarget
const &Target
)/*{{{*/
86 if (Target
.KeepCompressed
== false)
89 std::string
const KeepCompressedAs
= Target
.Option(IndexTarget::KEEPCOMPRESSEDAS
);
90 if (KeepCompressedAs
.empty() == false)
92 std::string
const ext
= KeepCompressedAs
.substr(0, KeepCompressedAs
.find(' '));
93 if (ext
!= "uncompressed")
94 file
.append(".").append(ext
);
99 static std::string
GetMergeDiffsPatchFileName(std::string
const &Final
, std::string
const &Patch
)/*{{{*/
101 // rred expects the patch as $FinalFile.ed.$patchname.gz
102 return Final
+ ".ed." + Patch
+ ".gz";
105 static std::string
GetDiffsPatchFileName(std::string
const &Final
) /*{{{*/
107 // rred expects the patch as $FinalFile.ed
108 return Final
+ ".ed";
111 static std::string
GetExistingFilename(std::string
const &File
) /*{{{*/
113 if (RealFileExists(File
))
115 for (auto const &type
: APT::Configuration::getCompressorExtensions())
117 std::string
const Final
= File
+ type
;
118 if (RealFileExists(Final
))
124 static std::string
GetDiffIndexFileName(std::string
const &Name
) /*{{{*/
126 return Name
+ ".diff/Index";
129 static std::string
GetDiffIndexURI(IndexTarget
const &Target
) /*{{{*/
131 return Target
.URI
+ ".diff/Index";
135 static bool MessageInsecureRepository(bool const isError
, std::string
const &msg
)/*{{{*/
139 _error
->Error("%s", msg
.c_str());
140 _error
->Notice("%s", _("Updating from such a repository can't be done securely, and is therefore disabled by default."));
144 _error
->Warning("%s", msg
.c_str());
145 _error
->Notice("%s", _("Data from such a repository can't be authenticated and is therefore potentially dangerous to use."));
147 _error
->Notice("%s", _("See apt-secure(8) manpage for repository creation and user configuration details."));
150 static bool MessageInsecureRepository(bool const isError
, char const * const msg
, std::string
const &repo
)
153 strprintf(m
, msg
, repo
.c_str());
154 return MessageInsecureRepository(isError
, m
);
157 static bool AllowInsecureRepositories(char const * const msg
, std::string
const &repo
,/*{{{*/
158 metaIndex
const * const MetaIndexParser
, pkgAcqMetaClearSig
* const TransactionManager
, pkgAcquire::Item
* const I
)
160 if(MetaIndexParser
->GetTrusted() == metaIndex::TRI_YES
)
163 if (_config
->FindB("Acquire::AllowInsecureRepositories") == true)
165 MessageInsecureRepository(false, msg
, repo
);
169 MessageInsecureRepository(true, msg
, repo
);
170 TransactionManager
->AbortTransaction();
171 I
->Status
= pkgAcquire::Item::StatError
;
175 static HashStringList
GetExpectedHashesFromFor(metaIndex
* const Parser
, std::string
const &MetaKey
)/*{{{*/
178 return HashStringList();
179 metaIndex::checkSum
* const R
= Parser
->Lookup(MetaKey
);
181 return HashStringList();
186 // all ::HashesRequired and ::GetExpectedHashes implementations /*{{{*/
187 /* ::GetExpectedHashes is abstract and has to be implemented by all subclasses.
188 It is best to implement it as broadly as possible, while ::HashesRequired defaults
189 to true and should be as restrictive as possible for false cases. Note that if
190 a hash is returned by ::GetExpectedHashes it must match. Only if it doesn't
191 ::HashesRequired is called to evaluate if its okay to have no hashes. */
192 APT_CONST
bool pkgAcqTransactionItem::HashesRequired() const
194 /* signed repositories obviously have a parser and good hashes.
195 unsigned repositories, too, as even if we can't trust them for security,
196 we can at least trust them for integrity of the download itself.
197 Only repositories without a Release file can (obviously) not have
198 hashes – and they are very uncommon and strongly discouraged */
199 return TransactionManager
->MetaIndexParser
!= NULL
&&
200 TransactionManager
->MetaIndexParser
->GetLoadedSuccessfully() == metaIndex::TRI_YES
;
202 HashStringList
pkgAcqTransactionItem::GetExpectedHashes() const
204 return GetExpectedHashesFor(GetMetaKey());
207 APT_CONST
bool pkgAcqMetaBase::HashesRequired() const
209 // Release and co have no hashes 'by design'.
212 HashStringList
pkgAcqMetaBase::GetExpectedHashes() const
214 return HashStringList();
217 APT_CONST
bool pkgAcqIndexDiffs::HashesRequired() const
219 /* We can't check hashes of rred result as we don't know what the
220 hash of the file will be. We just know the hash of the patch(es),
221 the hash of the file they will apply on and the hash of the resulting
223 if (State
== StateFetchDiff
)
227 HashStringList
pkgAcqIndexDiffs::GetExpectedHashes() const
229 if (State
== StateFetchDiff
)
230 return available_patches
[0].download_hashes
;
231 return HashStringList();
234 APT_CONST
bool pkgAcqIndexMergeDiffs::HashesRequired() const
236 /* @see #pkgAcqIndexDiffs::HashesRequired, with the difference that
237 we can check the rred result after all patches are applied as
238 we know the expected result rather than potentially apply more patches */
239 if (State
== StateFetchDiff
)
241 return State
== StateApplyDiff
;
243 HashStringList
pkgAcqIndexMergeDiffs::GetExpectedHashes() const
245 if (State
== StateFetchDiff
)
246 return patch
.download_hashes
;
247 else if (State
== StateApplyDiff
)
248 return GetExpectedHashesFor(Target
.MetaKey
);
249 return HashStringList();
252 APT_CONST
bool pkgAcqArchive::HashesRequired() const
254 return LocalSource
== false;
256 HashStringList
pkgAcqArchive::GetExpectedHashes() const
258 // figured out while parsing the records
259 return ExpectedHashes
;
262 APT_CONST
bool pkgAcqFile::HashesRequired() const
264 // supplied as parameter at creation time, so the caller decides
265 return ExpectedHashes
.usable();
267 HashStringList
pkgAcqFile::GetExpectedHashes() const
269 return ExpectedHashes
;
272 // Acquire::Item::QueueURI and specialisations from child classes /*{{{*/
273 bool pkgAcquire::Item::QueueURI(pkgAcquire::ItemDesc
&Item
)
275 Owner
->Enqueue(Item
);
278 /* The idea here is that an item isn't queued if it exists on disk and the
279 transition manager was a hit as this means that the files it contains
280 the checksums for can't be updated either (or they are and we are asking
281 for a hashsum mismatch to happen which helps nobody) */
282 bool pkgAcqTransactionItem::QueueURI(pkgAcquire::ItemDesc
&Item
)
284 std::string
const FinalFile
= GetFinalFilename();
285 if (TransactionManager
!= NULL
&& TransactionManager
->IMSHit
== true &&
286 FileExists(FinalFile
) == true)
288 PartialFile
= DestFile
= FinalFile
;
292 return pkgAcquire::Item::QueueURI(Item
);
294 /* The transition manager InRelease itself (or its older sisters-in-law
295 Release & Release.gpg) is always queued as this allows us to rerun gpgv
296 on it to verify that we aren't stalled with old files */
297 bool pkgAcqMetaBase::QueueURI(pkgAcquire::ItemDesc
&Item
)
299 return pkgAcquire::Item::QueueURI(Item
);
301 /* the Diff/Index needs to queue also the up-to-date complete index file
302 to ensure that the list cleaner isn't eating it */
303 bool pkgAcqDiffIndex::QueueURI(pkgAcquire::ItemDesc
&Item
)
305 if (pkgAcqTransactionItem::QueueURI(Item
) == true)
311 // Acquire::Item::GetFinalFilename and specialisations for child classes /*{{{*/
312 std::string
pkgAcquire::Item::GetFinalFilename() const
314 // Beware: Desc.URI is modified by redirections
315 return GetFinalFileNameFromURI(Desc
.URI
);
317 std::string
pkgAcqDiffIndex::GetFinalFilename() const
319 return GetFinalFileNameFromURI(GetDiffIndexURI(Target
));
321 std::string
pkgAcqIndex::GetFinalFilename() const
323 std::string
const FinalFile
= GetFinalFileNameFromURI(Target
.URI
);
324 return GetKeepCompressedFileName(FinalFile
, Target
);
326 std::string
pkgAcqMetaSig::GetFinalFilename() const
328 return GetFinalFileNameFromURI(Target
.URI
);
330 std::string
pkgAcqBaseIndex::GetFinalFilename() const
332 return GetFinalFileNameFromURI(Target
.URI
);
334 std::string
pkgAcqMetaBase::GetFinalFilename() const
336 return GetFinalFileNameFromURI(Target
.URI
);
338 std::string
pkgAcqArchive::GetFinalFilename() const
340 return _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
343 // pkgAcqTransactionItem::GetMetaKey and specialisations for child classes /*{{{*/
344 std::string
pkgAcqTransactionItem::GetMetaKey() const
346 return Target
.MetaKey
;
348 std::string
pkgAcqIndex::GetMetaKey() const
350 if (Stage
== STAGE_DECOMPRESS_AND_VERIFY
|| CurrentCompressionExtension
== "uncompressed")
351 return Target
.MetaKey
;
352 return Target
.MetaKey
+ "." + CurrentCompressionExtension
;
354 std::string
pkgAcqDiffIndex::GetMetaKey() const
356 return GetDiffIndexFileName(Target
.MetaKey
);
359 //pkgAcqTransactionItem::TransactionState and specialisations for child classes /*{{{*/
360 bool pkgAcqTransactionItem::TransactionState(TransactionStates
const state
)
362 bool const Debug
= _config
->FindB("Debug::Acquire::Transaction", false);
365 case TransactionAbort
:
367 std::clog
<< " Cancel: " << DestFile
<< std::endl
;
368 if (Status
== pkgAcquire::Item::StatIdle
)
370 Status
= pkgAcquire::Item::StatDone
;
374 case TransactionCommit
:
375 if(PartialFile
.empty() == false)
377 bool sameFile
= (PartialFile
== DestFile
);
378 // we use symlinks on IMS-Hit to avoid copies
379 if (RealFileExists(DestFile
))
382 if (lstat(PartialFile
.c_str(), &Buf
) != -1)
384 if (S_ISLNK(Buf
.st_mode
) && Buf
.st_size
> 0)
386 char partial
[Buf
.st_size
+ 1];
387 ssize_t
const sp
= readlink(PartialFile
.c_str(), partial
, Buf
.st_size
);
389 _error
->Errno("pkgAcqTransactionItem::TransactionState-sp", _("Failed to readlink %s"), PartialFile
.c_str());
393 sameFile
= (DestFile
== partial
);
398 _error
->Errno("pkgAcqTransactionItem::TransactionState-stat", _("Failed to stat %s"), PartialFile
.c_str());
400 if (sameFile
== false)
402 // ensure that even without lists-cleanup all compressions are nuked
403 std::string FinalFile
= GetFinalFileNameFromURI(Target
.URI
);
404 if (FileExists(FinalFile
))
407 std::clog
<< "rm " << FinalFile
<< " # " << DescURI() << std::endl
;
408 if (RemoveFile("TransactionStates-Cleanup", FinalFile
) == false)
411 for (auto const &ext
: APT::Configuration::getCompressorExtensions())
413 auto const Final
= FinalFile
+ ext
;
414 if (FileExists(Final
))
417 std::clog
<< "rm " << Final
<< " # " << DescURI() << std::endl
;
418 if (RemoveFile("TransactionStates-Cleanup", Final
) == false)
423 std::clog
<< "mv " << PartialFile
<< " -> "<< DestFile
<< " # " << DescURI() << std::endl
;
424 if (Rename(PartialFile
, DestFile
) == false)
427 else if(Debug
== true)
428 std::clog
<< "keep " << PartialFile
<< " # " << DescURI() << std::endl
;
432 std::clog
<< "rm " << DestFile
<< " # " << DescURI() << std::endl
;
433 if (RemoveFile("TransactionCommit", DestFile
) == false)
440 bool pkgAcqMetaBase::TransactionState(TransactionStates
const state
)
442 // Do not remove InRelease on IMSHit of Release.gpg [yes, this is very edgecasey]
443 if (TransactionManager
->IMSHit
== false)
444 return pkgAcqTransactionItem::TransactionState(state
);
447 bool pkgAcqIndex::TransactionState(TransactionStates
const state
)
449 if (pkgAcqTransactionItem::TransactionState(state
) == false)
454 case TransactionAbort
:
455 if (Stage
== STAGE_DECOMPRESS_AND_VERIFY
)
457 // keep the compressed file, but drop the decompressed
458 EraseFileName
.clear();
459 if (PartialFile
.empty() == false && flExtension(PartialFile
) != CurrentCompressionExtension
)
460 RemoveFile("TransactionAbort", PartialFile
);
463 case TransactionCommit
:
464 if (EraseFileName
.empty() == false)
465 RemoveFile("TransactionCommit", EraseFileName
);
470 bool pkgAcqDiffIndex::TransactionState(TransactionStates
const state
)
472 if (pkgAcqTransactionItem::TransactionState(state
) == false)
477 case TransactionCommit
:
479 case TransactionAbort
:
480 std::string
const Partial
= GetPartialFileNameFromURI(Target
.URI
);
481 RemoveFile("TransactionAbort", Partial
);
489 class APT_HIDDEN NoActionItem
: public pkgAcquire::Item
/*{{{*/
490 /* The sole purpose of this class is having an item which does nothing to
491 reach its done state to prevent cleanup deleting the mentioned file.
492 Handy in cases in which we know we have the file already, like IMS-Hits. */
494 IndexTarget
const Target
;
496 virtual std::string
DescURI() const APT_OVERRIDE
{return Target
.URI
;};
497 virtual HashStringList
GetExpectedHashes() const APT_OVERRIDE
{return HashStringList();};
499 NoActionItem(pkgAcquire
* const Owner
, IndexTarget
const &Target
) :
500 pkgAcquire::Item(Owner
), Target(Target
)
503 DestFile
= GetFinalFileNameFromURI(Target
.URI
);
505 NoActionItem(pkgAcquire
* const Owner
, IndexTarget
const &Target
, std::string
const &FinalFile
) :
506 pkgAcquire::Item(Owner
), Target(Target
)
509 DestFile
= FinalFile
;
514 // Acquire::Item::Item - Constructor /*{{{*/
515 APT_IGNORE_DEPRECATED_PUSH
516 pkgAcquire::Item::Item(pkgAcquire
* const owner
) :
517 FileSize(0), PartialSize(0), Mode(0), ID(0), Complete(false), Local(false),
518 QueueCounter(0), ExpectedAdditionalItems(0), Owner(owner
), d(NULL
)
523 APT_IGNORE_DEPRECATED_POP
525 // Acquire::Item::~Item - Destructor /*{{{*/
526 pkgAcquire::Item::~Item()
531 std::string
pkgAcquire::Item::Custom600Headers() const /*{{{*/
533 return std::string();
536 std::string
pkgAcquire::Item::ShortDesc() const /*{{{*/
541 APT_CONST
void pkgAcquire::Item::Finished() /*{{{*/
545 APT_PURE pkgAcquire
* pkgAcquire::Item::GetOwner() const /*{{{*/
550 APT_CONST
pkgAcquire::ItemDesc
&pkgAcquire::Item::GetItemDesc() /*{{{*/
555 APT_CONST
bool pkgAcquire::Item::IsTrusted() const /*{{{*/
560 // Acquire::Item::Failed - Item failed to download /*{{{*/
561 // ---------------------------------------------------------------------
562 /* We return to an idle state if there are still other queues that could
564 void pkgAcquire::Item::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)
566 if(ErrorText
.empty())
567 ErrorText
= LookupTag(Message
,"Message");
568 if (QueueCounter
<= 1)
570 /* This indicates that the file is not available right now but might
571 be sometime later. If we do a retry cycle then this should be
573 if (Cnf
!= NULL
&& Cnf
->LocalOnly
== true &&
574 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
590 case StatTransientNetworkError
:
597 string
const FailReason
= LookupTag(Message
, "FailReason");
598 if (FailReason
== "MaximumSizeExceeded")
599 RenameOnError(MaximumSizeExceeded
);
600 else if (Status
== StatAuthError
)
601 RenameOnError(HashSumMismatch
);
603 // report mirror failure back to LP if we actually use a mirror
604 if (FailReason
.empty() == false)
605 ReportMirrorFailure(FailReason
);
607 ReportMirrorFailure(ErrorText
);
609 if (QueueCounter
> 1)
613 // Acquire::Item::Start - Item has begun to download /*{{{*/
614 // ---------------------------------------------------------------------
615 /* Stash status and the file size. Note that setting Complete means
616 sub-phases of the acquire process such as decompresion are operating */
617 void pkgAcquire::Item::Start(string
const &/*Message*/, unsigned long long const Size
)
619 Status
= StatFetching
;
621 if (FileSize
== 0 && Complete
== false)
625 // Acquire::Item::VerifyDone - check if Item was downloaded OK /*{{{*/
626 /* Note that hash-verification is 'hardcoded' in acquire-worker and has
627 * already passed if this method is called. */
628 bool pkgAcquire::Item::VerifyDone(std::string
const &Message
,
629 pkgAcquire::MethodConfig
const * const /*Cnf*/)
631 std::string
const FileName
= LookupTag(Message
,"Filename");
632 if (FileName
.empty() == true)
635 ErrorText
= "Method gave a blank filename";
642 // Acquire::Item::Done - Item downloaded OK /*{{{*/
643 void pkgAcquire::Item::Done(string
const &/*Message*/, HashStringList
const &Hashes
,
644 pkgAcquire::MethodConfig
const * const /*Cnf*/)
646 // We just downloaded something..
649 unsigned long long const downloadedSize
= Hashes
.FileSize();
650 if (downloadedSize
!= 0)
652 FileSize
= downloadedSize
;
656 ErrorText
= string();
657 Owner
->Dequeue(this);
660 // Acquire::Item::Rename - Rename a file /*{{{*/
661 // ---------------------------------------------------------------------
662 /* This helper function is used by a lot of item methods as their final
664 bool pkgAcquire::Item::Rename(string
const &From
,string
const &To
)
666 if (From
== To
|| rename(From
.c_str(),To
.c_str()) == 0)
670 strprintf(S
, _("rename failed, %s (%s -> %s)."), strerror(errno
),
671 From
.c_str(),To
.c_str());
673 if (ErrorText
.empty())
676 ErrorText
= ErrorText
+ ": " + S
;
680 void pkgAcquire::Item::Dequeue() /*{{{*/
682 Owner
->Dequeue(this);
685 bool pkgAcquire::Item::RenameOnError(pkgAcquire::Item::RenameOnErrorState
const error
)/*{{{*/
687 if (RealFileExists(DestFile
))
688 Rename(DestFile
, DestFile
+ ".FAILED");
693 case HashSumMismatch
:
694 errtext
= _("Hash Sum mismatch");
695 Status
= StatAuthError
;
696 ReportMirrorFailure("HashChecksumFailure");
699 errtext
= _("Size mismatch");
700 Status
= StatAuthError
;
701 ReportMirrorFailure("SizeFailure");
704 errtext
= _("Invalid file format");
706 // do not report as usually its not the mirrors fault, but Portal/Proxy
709 errtext
= _("Signature error");
713 strprintf(errtext
, _("Clearsigned file isn't valid, got '%s' (does the network require authentication?)"), "NOSPLIT");
714 Status
= StatAuthError
;
716 case MaximumSizeExceeded
:
717 // the method is expected to report a good error for this
721 // no handling here, done by callers
724 if (ErrorText
.empty())
729 void pkgAcquire::Item::SetActiveSubprocess(const std::string
&subprocess
)/*{{{*/
731 ActiveSubprocess
= subprocess
;
732 APT_IGNORE_DEPRECATED(Mode
= ActiveSubprocess
.c_str();)
735 // Acquire::Item::ReportMirrorFailure /*{{{*/
736 void pkgAcquire::Item::ReportMirrorFailure(string
const &FailCode
)
738 // we only act if a mirror was used at all
739 if(UsedMirror
.empty())
742 std::cerr
<< "\nReportMirrorFailure: "
744 << " Uri: " << DescURI()
746 << FailCode
<< std::endl
;
748 string report
= _config
->Find("Methods::Mirror::ProblemReporting",
749 "/usr/lib/apt/apt-report-mirror-failure");
750 if(!FileExists(report
))
753 std::vector
<char const*> Args
;
754 Args
.push_back(report
.c_str());
755 Args
.push_back(UsedMirror
.c_str());
756 Args
.push_back(DescURI().c_str());
757 Args
.push_back(FailCode
.c_str());
758 Args
.push_back(NULL
);
760 pid_t pid
= ExecFork();
763 _error
->Error("ReportMirrorFailure Fork failed");
768 execvp(Args
[0], (char**)Args
.data());
769 std::cerr
<< "Could not exec " << Args
[0] << std::endl
;
772 if(!ExecWait(pid
, "report-mirror-failure"))
774 _error
->Warning("Couldn't report problem to '%s'",
775 _config
->Find("Methods::Mirror::ProblemReporting").c_str());
779 std::string
pkgAcquire::Item::HashSum() const /*{{{*/
781 HashStringList
const hashes
= GetExpectedHashes();
782 HashString
const * const hs
= hashes
.find(NULL
);
783 return hs
!= NULL
? hs
->toStr() : "";
787 pkgAcqTransactionItem::pkgAcqTransactionItem(pkgAcquire
* const Owner
, /*{{{*/
788 pkgAcqMetaClearSig
* const transactionManager
, IndexTarget
const &target
) :
789 pkgAcquire::Item(Owner
), d(NULL
), Target(target
), TransactionManager(transactionManager
)
791 if (TransactionManager
!= this)
792 TransactionManager
->Add(this);
795 pkgAcqTransactionItem::~pkgAcqTransactionItem() /*{{{*/
799 HashStringList
pkgAcqTransactionItem::GetExpectedHashesFor(std::string
const &MetaKey
) const /*{{{*/
801 return GetExpectedHashesFromFor(TransactionManager
->MetaIndexParser
, MetaKey
);
805 // AcqMetaBase - Constructor /*{{{*/
806 pkgAcqMetaBase::pkgAcqMetaBase(pkgAcquire
* const Owner
,
807 pkgAcqMetaClearSig
* const TransactionManager
,
808 std::vector
<IndexTarget
> const &IndexTargets
,
809 IndexTarget
const &DataTarget
)
810 : pkgAcqTransactionItem(Owner
, TransactionManager
, DataTarget
), d(NULL
),
811 IndexTargets(IndexTargets
),
812 AuthPass(false), IMSHit(false)
816 // AcqMetaBase::Add - Add a item to the current Transaction /*{{{*/
817 void pkgAcqMetaBase::Add(pkgAcqTransactionItem
* const I
)
819 Transaction
.push_back(I
);
822 // AcqMetaBase::AbortTransaction - Abort the current Transaction /*{{{*/
823 void pkgAcqMetaBase::AbortTransaction()
825 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
826 std::clog
<< "AbortTransaction: " << TransactionManager
<< std::endl
;
828 // ensure the toplevel is in error state too
829 for (std::vector
<pkgAcqTransactionItem
*>::iterator I
= Transaction
.begin();
830 I
!= Transaction
.end(); ++I
)
832 (*I
)->TransactionState(TransactionAbort
);
837 // AcqMetaBase::TransactionHasError - Check for errors in Transaction /*{{{*/
838 APT_PURE
bool pkgAcqMetaBase::TransactionHasError() const
840 for (std::vector
<pkgAcqTransactionItem
*>::const_iterator I
= Transaction
.begin();
841 I
!= Transaction
.end(); ++I
)
843 switch((*I
)->Status
) {
844 case StatDone
: break;
845 case StatIdle
: break;
846 case StatAuthError
: return true;
847 case StatError
: return true;
848 case StatTransientNetworkError
: return true;
849 case StatFetching
: break;
855 // AcqMetaBase::CommitTransaction - Commit a transaction /*{{{*/
856 void pkgAcqMetaBase::CommitTransaction()
858 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
859 std::clog
<< "CommitTransaction: " << this << std::endl
;
861 // move new files into place *and* remove files that are not
862 // part of the transaction but are still on disk
863 for (std::vector
<pkgAcqTransactionItem
*>::iterator I
= Transaction
.begin();
864 I
!= Transaction
.end(); ++I
)
866 (*I
)->TransactionState(TransactionCommit
);
871 // AcqMetaBase::TransactionStageCopy - Stage a file for copying /*{{{*/
872 void pkgAcqMetaBase::TransactionStageCopy(pkgAcqTransactionItem
* const I
,
873 const std::string
&From
,
874 const std::string
&To
)
876 I
->PartialFile
= From
;
880 // AcqMetaBase::TransactionStageRemoval - Stage a file for removal /*{{{*/
881 void pkgAcqMetaBase::TransactionStageRemoval(pkgAcqTransactionItem
* const I
,
882 const std::string
&FinalFile
)
885 I
->DestFile
= FinalFile
;
888 // AcqMetaBase::GenerateAuthWarning - Check gpg authentication error /*{{{*/
889 bool pkgAcqMetaBase::CheckStopAuthentication(pkgAcquire::Item
* const I
, const std::string
&Message
)
891 // FIXME: this entire function can do now that we disallow going to
892 // a unauthenticated state and can cleanly rollback
894 string
const Final
= I
->GetFinalFilename();
895 if(FileExists(Final
))
897 I
->Status
= StatTransientNetworkError
;
898 _error
->Warning(_("An error occurred during the signature "
899 "verification. The repository is not updated "
900 "and the previous index files will be used. "
901 "GPG error: %s: %s"),
902 Desc
.Description
.c_str(),
903 LookupTag(Message
,"Message").c_str());
904 RunScripts("APT::Update::Auth-Failure");
906 } else if (LookupTag(Message
,"Message").find("NODATA") != string::npos
) {
907 /* Invalid signature file, reject (LP: #346386) (Closes: #627642) */
908 _error
->Error(_("GPG error: %s: %s"),
909 Desc
.Description
.c_str(),
910 LookupTag(Message
,"Message").c_str());
911 I
->Status
= StatAuthError
;
914 _error
->Warning(_("GPG error: %s: %s"),
915 Desc
.Description
.c_str(),
916 LookupTag(Message
,"Message").c_str());
918 // gpgv method failed
919 ReportMirrorFailure("GPGFailure");
923 // AcqMetaBase::Custom600Headers - Get header for AcqMetaBase /*{{{*/
924 // ---------------------------------------------------------------------
925 string
pkgAcqMetaBase::Custom600Headers() const
927 std::string Header
= "\nIndex-File: true";
928 std::string MaximumSize
;
929 strprintf(MaximumSize
, "\nMaximum-Size: %i",
930 _config
->FindI("Acquire::MaxReleaseFileSize", 10*1000*1000));
931 Header
+= MaximumSize
;
933 string
const FinalFile
= GetFinalFilename();
935 if (stat(FinalFile
.c_str(),&Buf
) == 0)
936 Header
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
941 // AcqMetaBase::QueueForSignatureVerify /*{{{*/
942 void pkgAcqMetaBase::QueueForSignatureVerify(pkgAcqTransactionItem
* const I
, std::string
const &File
, std::string
const &Signature
)
945 I
->Desc
.URI
= "gpgv:" + Signature
;
948 I
->SetActiveSubprocess("gpgv");
951 // AcqMetaBase::CheckDownloadDone /*{{{*/
952 bool pkgAcqMetaBase::CheckDownloadDone(pkgAcqTransactionItem
* const I
, const std::string
&Message
, HashStringList
const &Hashes
) const
954 // We have just finished downloading a Release file (it is not
957 std::string
const FileName
= LookupTag(Message
,"Filename");
958 if (FileName
!= I
->DestFile
&& RealFileExists(I
->DestFile
) == false)
961 I
->Desc
.URI
= "copy:" + FileName
;
962 I
->QueueURI(I
->Desc
);
966 // make sure to verify against the right file on I-M-S hit
967 bool IMSHit
= StringToBool(LookupTag(Message
,"IMS-Hit"), false);
968 if (IMSHit
== false && Hashes
.usable())
970 // detect IMS-Hits servers haven't detected by Hash comparison
971 std::string
const FinalFile
= I
->GetFinalFilename();
972 if (RealFileExists(FinalFile
) && Hashes
.VerifyFile(FinalFile
) == true)
975 RemoveFile("CheckDownloadDone", I
->DestFile
);
981 // for simplicity, the transaction manager is always InRelease
982 // even if it doesn't exist.
983 if (TransactionManager
!= NULL
)
984 TransactionManager
->IMSHit
= true;
985 I
->PartialFile
= I
->DestFile
= I
->GetFinalFilename();
988 // set Item to complete as the remaining work is all local (verify etc)
994 bool pkgAcqMetaBase::CheckAuthDone(string
const &Message
) /*{{{*/
996 // At this point, the gpgv method has succeeded, so there is a
997 // valid signature from a key in the trusted keyring. We
998 // perform additional verification of its contents, and use them
999 // to verify the indexes we are about to download
1001 if (TransactionManager
->IMSHit
== false)
1003 // open the last (In)Release if we have it
1004 std::string
const FinalFile
= GetFinalFilename();
1005 std::string FinalRelease
;
1006 std::string FinalInRelease
;
1007 if (APT::String::Endswith(FinalFile
, "InRelease"))
1009 FinalInRelease
= FinalFile
;
1010 FinalRelease
= FinalFile
.substr(0, FinalFile
.length() - strlen("InRelease")) + "Release";
1014 FinalInRelease
= FinalFile
.substr(0, FinalFile
.length() - strlen("Release")) + "InRelease";
1015 FinalRelease
= FinalFile
;
1017 if (RealFileExists(FinalInRelease
) || RealFileExists(FinalRelease
))
1019 TransactionManager
->LastMetaIndexParser
= TransactionManager
->MetaIndexParser
->UnloadedClone();
1020 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1022 _error
->PushToStack();
1023 if (RealFileExists(FinalInRelease
))
1024 TransactionManager
->LastMetaIndexParser
->Load(FinalInRelease
, NULL
);
1026 TransactionManager
->LastMetaIndexParser
->Load(FinalRelease
, NULL
);
1027 // its unlikely to happen, but if what we have is bad ignore it
1028 if (_error
->PendingError())
1030 delete TransactionManager
->LastMetaIndexParser
;
1031 TransactionManager
->LastMetaIndexParser
= NULL
;
1033 _error
->RevertToStack();
1038 if (TransactionManager
->MetaIndexParser
->Load(DestFile
, &ErrorText
) == false)
1040 Status
= StatAuthError
;
1044 if (!VerifyVendor(Message
))
1046 Status
= StatAuthError
;
1050 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1051 std::cerr
<< "Signature verification succeeded: "
1052 << DestFile
<< std::endl
;
1054 // Download further indexes with verification
1060 void pkgAcqMetaBase::QueueIndexes(bool const verify
) /*{{{*/
1062 // at this point the real Items are loaded in the fetcher
1063 ExpectedAdditionalItems
= 0;
1065 bool metaBaseSupportsByHash
= false;
1066 if (TransactionManager
!= NULL
&& TransactionManager
->MetaIndexParser
!= NULL
)
1067 metaBaseSupportsByHash
= TransactionManager
->MetaIndexParser
->GetSupportsAcquireByHash();
1069 for (std::vector
<IndexTarget
>::iterator Target
= IndexTargets
.begin();
1070 Target
!= IndexTargets
.end();
1073 // all is an implementation detail. Users shouldn't use this as arch
1074 // We need this support trickery here as e.g. Debian has binary-all files already,
1075 // but arch:all packages are still in the arch:any files, so we would waste precious
1076 // download time, bandwidth and diskspace for nothing, BUT Debian doesn't feature all
1077 // in the set of supported architectures, so we can filter based on this property rather
1078 // than invent an entirely new flag we would need to carry for all of eternity.
1079 if (Target
->Option(IndexTarget::ARCHITECTURE
) == "all")
1081 if (TransactionManager
->MetaIndexParser
->IsArchitectureSupported("all") == false)
1083 if (TransactionManager
->MetaIndexParser
->IsArchitectureAllSupportedFor(*Target
) == false)
1087 bool trypdiff
= Target
->OptionBool(IndexTarget::PDIFFS
);
1090 if (TransactionManager
->MetaIndexParser
->Exists(Target
->MetaKey
) == false)
1092 // optional targets that we do not have in the Release file are skipped
1093 if (Target
->IsOptional
)
1096 std::string
const &arch
= Target
->Option(IndexTarget::ARCHITECTURE
);
1097 if (arch
.empty() == false)
1099 if (TransactionManager
->MetaIndexParser
->IsArchitectureSupported(arch
) == false)
1101 _error
->Notice(_("Skipping acquire of configured file '%s' as repository '%s' doesn't support architecture '%s'"),
1102 Target
->MetaKey
.c_str(), TransactionManager
->Target
.Description
.c_str(), arch
.c_str());
1105 // if the architecture is officially supported but currently no packages for it available,
1106 // ignore silently as this is pretty much the same as just shipping an empty file.
1107 // if we don't know which architectures are supported, we do NOT ignore it to notify user about this
1108 if (TransactionManager
->MetaIndexParser
->IsArchitectureSupported("*undefined*") == false)
1112 Status
= StatAuthError
;
1113 strprintf(ErrorText
, _("Unable to find expected entry '%s' in Release file (Wrong sources.list entry or malformed file)"), Target
->MetaKey
.c_str());
1118 auto const hashes
= GetExpectedHashesFor(Target
->MetaKey
);
1119 if (hashes
.usable() == false && hashes
.empty() == false)
1121 _error
->Warning(_("Skipping acquire of configured file '%s' as repository '%s' provides only weak security information for it"),
1122 Target
->MetaKey
.c_str(), TransactionManager
->Target
.Description
.c_str());
1127 // autoselect the compression method
1128 std::vector
<std::string
> types
= VectorizeString(Target
->Option(IndexTarget::COMPRESSIONTYPES
), ' ');
1129 types
.erase(std::remove_if(types
.begin(), types
.end(), [&](std::string
const &t
) {
1130 if (t
== "uncompressed")
1131 return TransactionManager
->MetaIndexParser
->Exists(Target
->MetaKey
) == false;
1132 std::string
const MetaKey
= Target
->MetaKey
+ "." + t
;
1133 return TransactionManager
->MetaIndexParser
->Exists(MetaKey
) == false;
1135 if (types
.empty() == false)
1137 std::ostringstream os
;
1138 // add the special compressiontype byhash first if supported
1139 std::string
const useByHashConf
= Target
->Option(IndexTarget::BY_HASH
);
1140 bool useByHash
= false;
1141 if(useByHashConf
== "force")
1144 useByHash
= StringToBool(useByHashConf
) == true && metaBaseSupportsByHash
;
1145 if (useByHash
== true)
1147 std::copy(types
.begin(), types
.end()-1, std::ostream_iterator
<std::string
>(os
, " "));
1148 os
<< *types
.rbegin();
1149 Target
->Options
["COMPRESSIONTYPES"] = os
.str();
1152 Target
->Options
["COMPRESSIONTYPES"].clear();
1154 std::string filename
= GetExistingFilename(GetFinalFileNameFromURI(Target
->URI
));
1155 if (filename
.empty() == false)
1157 // if the Release file is a hit and we have an index it must be the current one
1158 if (TransactionManager
->IMSHit
== true)
1160 else if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1162 // see if the file changed since the last Release file
1163 // we use the uncompressed files as we might compress differently compared to the server,
1164 // so the hashes might not match, even if they contain the same data.
1165 HashStringList
const newFile
= GetExpectedHashesFromFor(TransactionManager
->MetaIndexParser
, Target
->MetaKey
);
1166 HashStringList
const oldFile
= GetExpectedHashesFromFor(TransactionManager
->LastMetaIndexParser
, Target
->MetaKey
);
1167 if (newFile
!= oldFile
)
1174 trypdiff
= false; // no file to patch
1176 if (filename
.empty() == false)
1178 new NoActionItem(Owner
, *Target
, filename
);
1179 std::string
const idxfilename
= GetFinalFileNameFromURI(GetDiffIndexURI(*Target
));
1180 if (FileExists(idxfilename
))
1181 new NoActionItem(Owner
, *Target
, idxfilename
);
1185 // check if we have patches available
1186 trypdiff
&= TransactionManager
->MetaIndexParser
->Exists(GetDiffIndexFileName(Target
->MetaKey
));
1190 // if we have no file to patch, no point in trying
1191 trypdiff
&= (GetExistingFilename(GetFinalFileNameFromURI(Target
->URI
)).empty() == false);
1194 // no point in patching from local sources
1197 std::string
const proto
= Target
->URI
.substr(0, strlen("file:/"));
1198 if (proto
== "file:/" || proto
== "copy:/" || proto
== "cdrom:")
1202 // Queue the Index file (Packages, Sources, Translation-$foo, …)
1204 new pkgAcqDiffIndex(Owner
, TransactionManager
, *Target
);
1206 new pkgAcqIndex(Owner
, TransactionManager
, *Target
);
1210 bool pkgAcqMetaBase::VerifyVendor(string
const &Message
) /*{{{*/
1212 string::size_type pos
;
1214 // check for missing sigs (that where not fatal because otherwise we had
1217 string msg
= _("There is no public key available for the "
1218 "following key IDs:\n");
1219 pos
= Message
.find("NO_PUBKEY ");
1220 if (pos
!= std::string::npos
)
1222 string::size_type start
= pos
+strlen("NO_PUBKEY ");
1223 string Fingerprint
= Message
.substr(start
, Message
.find("\n")-start
);
1224 missingkeys
+= (Fingerprint
);
1226 if(!missingkeys
.empty())
1227 _error
->Warning("%s", (msg
+ missingkeys
).c_str());
1229 string Transformed
= TransactionManager
->MetaIndexParser
->GetExpectedDist();
1231 if (Transformed
== "../project/experimental")
1233 Transformed
= "experimental";
1236 pos
= Transformed
.rfind('/');
1237 if (pos
!= string::npos
)
1239 Transformed
= Transformed
.substr(0, pos
);
1242 if (Transformed
== ".")
1247 if (TransactionManager
->MetaIndexParser
->GetValidUntil() > 0)
1249 time_t const invalid_since
= time(NULL
) - TransactionManager
->MetaIndexParser
->GetValidUntil();
1250 if (invalid_since
> 0)
1254 // TRANSLATOR: The first %s is the URL of the bad Release file, the second is
1255 // the time since then the file is invalid - formatted in the same way as in
1256 // the download progress display (e.g. 7d 3h 42min 1s)
1257 _("Release file for %s is expired (invalid since %s). "
1258 "Updates for this repository will not be applied."),
1259 Target
.URI
.c_str(), TimeToStr(invalid_since
).c_str());
1260 if (ErrorText
.empty())
1262 return _error
->Error("%s", errmsg
.c_str());
1266 /* Did we get a file older than what we have? This is a last minute IMS hit and doubles
1267 as a prevention of downgrading us to older (still valid) files */
1268 if (TransactionManager
->IMSHit
== false && TransactionManager
->LastMetaIndexParser
!= NULL
&&
1269 TransactionManager
->LastMetaIndexParser
->GetDate() > TransactionManager
->MetaIndexParser
->GetDate())
1271 TransactionManager
->IMSHit
= true;
1272 RemoveFile("VerifyVendor", DestFile
);
1273 PartialFile
= DestFile
= GetFinalFilename();
1274 // load the 'old' file in the 'new' one instead of flipping pointers as
1275 // the new one isn't owned by us, while the old one is so cleanup would be confused.
1276 TransactionManager
->MetaIndexParser
->swapLoad(TransactionManager
->LastMetaIndexParser
);
1277 delete TransactionManager
->LastMetaIndexParser
;
1278 TransactionManager
->LastMetaIndexParser
= NULL
;
1281 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1283 std::cerr
<< "Got Codename: " << TransactionManager
->MetaIndexParser
->GetCodename() << std::endl
;
1284 std::cerr
<< "Expecting Dist: " << TransactionManager
->MetaIndexParser
->GetExpectedDist() << std::endl
;
1285 std::cerr
<< "Transformed Dist: " << Transformed
<< std::endl
;
1288 if (TransactionManager
->MetaIndexParser
->CheckDist(Transformed
) == false)
1290 // This might become fatal one day
1291 // Status = StatAuthError;
1292 // ErrorText = "Conflicting distribution; expected "
1293 // + MetaIndexParser->GetExpectedDist() + " but got "
1294 // + MetaIndexParser->GetCodename();
1296 if (!Transformed
.empty())
1298 _error
->Warning(_("Conflicting distribution: %s (expected %s but got %s)"),
1299 Desc
.Description
.c_str(),
1300 Transformed
.c_str(),
1301 TransactionManager
->MetaIndexParser
->GetCodename().c_str());
1308 pkgAcqMetaBase::~pkgAcqMetaBase()
1312 pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire
* const Owner
, /*{{{*/
1313 IndexTarget
const &ClearsignedTarget
,
1314 IndexTarget
const &DetachedDataTarget
, IndexTarget
const &DetachedSigTarget
,
1315 std::vector
<IndexTarget
> const &IndexTargets
,
1316 metaIndex
* const MetaIndexParser
) :
1317 pkgAcqMetaIndex(Owner
, this, ClearsignedTarget
, DetachedSigTarget
, IndexTargets
),
1318 d(NULL
), ClearsignedTarget(ClearsignedTarget
),
1319 DetachedDataTarget(DetachedDataTarget
),
1320 MetaIndexParser(MetaIndexParser
), LastMetaIndexParser(NULL
)
1322 // index targets + (worst case:) Release/Release.gpg
1323 ExpectedAdditionalItems
= IndexTargets
.size() + 2;
1324 TransactionManager
->Add(this);
1327 pkgAcqMetaClearSig::~pkgAcqMetaClearSig() /*{{{*/
1329 if (LastMetaIndexParser
!= NULL
)
1330 delete LastMetaIndexParser
;
1333 // pkgAcqMetaClearSig::Custom600Headers - Insert custom request headers /*{{{*/
1334 string
pkgAcqMetaClearSig::Custom600Headers() const
1336 string Header
= pkgAcqMetaBase::Custom600Headers();
1337 Header
+= "\nFail-Ignore: true";
1338 std::string
const key
= TransactionManager
->MetaIndexParser
->GetSignedBy();
1339 if (key
.empty() == false)
1340 Header
+= "\nSigned-By: " + key
;
1345 bool pkgAcqMetaClearSig::VerifyDone(std::string
const &Message
, /*{{{*/
1346 pkgAcquire::MethodConfig
const * const Cnf
)
1348 Item::VerifyDone(Message
, Cnf
);
1350 if (FileExists(DestFile
) && !StartsWithGPGClearTextSignature(DestFile
))
1351 return RenameOnError(NotClearsigned
);
1356 // pkgAcqMetaClearSig::Done - We got a file /*{{{*/
1357 void pkgAcqMetaClearSig::Done(std::string
const &Message
,
1358 HashStringList
const &Hashes
,
1359 pkgAcquire::MethodConfig
const * const Cnf
)
1361 Item::Done(Message
, Hashes
, Cnf
);
1363 if(AuthPass
== false)
1365 if(CheckDownloadDone(this, Message
, Hashes
) == true)
1366 QueueForSignatureVerify(this, DestFile
, DestFile
);
1369 else if(CheckAuthDone(Message
) == true)
1371 if (TransactionManager
->IMSHit
== false)
1372 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
1373 else if (RealFileExists(GetFinalFilename()) == false)
1375 // We got an InRelease file IMSHit, but we haven't one, which means
1376 // we had a valid Release/Release.gpg combo stepping in, which we have
1377 // to 'acquire' now to ensure list cleanup isn't removing them
1378 new NoActionItem(Owner
, DetachedDataTarget
);
1379 new NoActionItem(Owner
, DetachedSigTarget
);
1384 void pkgAcqMetaClearSig::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
) /*{{{*/
1386 Item::Failed(Message
, Cnf
);
1388 // we failed, we will not get additional items from this method
1389 ExpectedAdditionalItems
= 0;
1391 if (AuthPass
== false)
1393 if (Status
== StatAuthError
|| Status
== StatTransientNetworkError
)
1395 // if we expected a ClearTextSignature (InRelease) but got a network
1396 // error or got a file, but it wasn't valid, we end up here (see VerifyDone).
1397 // As these is usually called by web-portals we do not try Release/Release.gpg
1398 // as this is gonna fail anyway and instead abort our try (LP#346386)
1399 TransactionManager
->AbortTransaction();
1403 // Queue the 'old' InRelease file for removal if we try Release.gpg
1404 // as otherwise the file will stay around and gives a false-auth
1405 // impression (CVE-2012-0214)
1406 TransactionManager
->TransactionStageRemoval(this, GetFinalFilename());
1409 new pkgAcqMetaIndex(Owner
, TransactionManager
, DetachedDataTarget
, DetachedSigTarget
, IndexTargets
);
1413 if(CheckStopAuthentication(this, Message
))
1416 // No Release file was present, or verification failed, so fall
1417 // back to queueing Packages files without verification
1418 // only allow going further if the user explicitly wants it
1419 if(AllowInsecureRepositories(_("The repository '%s' is not signed."), ClearsignedTarget
.Description
, TransactionManager
->MetaIndexParser
, TransactionManager
, this) == true)
1423 /* InRelease files become Release files, otherwise
1424 * they would be considered as trusted later on */
1425 string
const FinalRelease
= GetFinalFileNameFromURI(DetachedDataTarget
.URI
);
1426 string
const PartialRelease
= GetPartialFileNameFromURI(DetachedDataTarget
.URI
);
1427 string
const FinalReleasegpg
= GetFinalFileNameFromURI(DetachedSigTarget
.URI
);
1428 string
const FinalInRelease
= GetFinalFilename();
1429 Rename(DestFile
, PartialRelease
);
1430 TransactionManager
->TransactionStageCopy(this, PartialRelease
, FinalRelease
);
1432 if (RealFileExists(FinalReleasegpg
) || RealFileExists(FinalInRelease
))
1434 // open the last Release if we have it
1435 if (TransactionManager
->IMSHit
== false)
1437 TransactionManager
->LastMetaIndexParser
= TransactionManager
->MetaIndexParser
->UnloadedClone();
1438 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1440 _error
->PushToStack();
1441 if (RealFileExists(FinalInRelease
))
1442 TransactionManager
->LastMetaIndexParser
->Load(FinalInRelease
, NULL
);
1444 TransactionManager
->LastMetaIndexParser
->Load(FinalRelease
, NULL
);
1445 // its unlikely to happen, but if what we have is bad ignore it
1446 if (_error
->PendingError())
1448 delete TransactionManager
->LastMetaIndexParser
;
1449 TransactionManager
->LastMetaIndexParser
= NULL
;
1451 _error
->RevertToStack();
1456 // we parse the indexes here because at this point the user wanted
1457 // a repository that may potentially harm him
1458 if (TransactionManager
->MetaIndexParser
->Load(PartialRelease
, &ErrorText
) == false || VerifyVendor(Message
) == false)
1459 /* expired Release files are still a problem you need extra force for */;
1467 pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire
* const Owner
, /*{{{*/
1468 pkgAcqMetaClearSig
* const TransactionManager
,
1469 IndexTarget
const &DataTarget
,
1470 IndexTarget
const &DetachedSigTarget
,
1471 vector
<IndexTarget
> const &IndexTargets
) :
1472 pkgAcqMetaBase(Owner
, TransactionManager
, IndexTargets
, DataTarget
), d(NULL
),
1473 DetachedSigTarget(DetachedSigTarget
)
1475 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1476 std::clog
<< "New pkgAcqMetaIndex with TransactionManager "
1477 << this->TransactionManager
<< std::endl
;
1479 DestFile
= GetPartialFileNameFromURI(DataTarget
.URI
);
1482 Desc
.Description
= DataTarget
.Description
;
1484 Desc
.ShortDesc
= DataTarget
.ShortDesc
;
1485 Desc
.URI
= DataTarget
.URI
;
1487 // we expect more item
1488 ExpectedAdditionalItems
= IndexTargets
.size();
1492 void pkgAcqMetaIndex::Done(string
const &Message
, /*{{{*/
1493 HashStringList
const &Hashes
,
1494 pkgAcquire::MethodConfig
const * const Cfg
)
1496 Item::Done(Message
,Hashes
,Cfg
);
1498 if(CheckDownloadDone(this, Message
, Hashes
))
1500 // we have a Release file, now download the Signature, all further
1501 // verify/queue for additional downloads will be done in the
1502 // pkgAcqMetaSig::Done() code
1503 new pkgAcqMetaSig(Owner
, TransactionManager
, DetachedSigTarget
, this);
1507 // pkgAcqMetaIndex::Failed - no Release file present /*{{{*/
1508 void pkgAcqMetaIndex::Failed(string
const &Message
,
1509 pkgAcquire::MethodConfig
const * const Cnf
)
1511 pkgAcquire::Item::Failed(Message
, Cnf
);
1514 // No Release file was present so fall
1515 // back to queueing Packages files without verification
1516 // only allow going further if the user explicitly wants it
1517 if(AllowInsecureRepositories(_("The repository '%s' does not have a Release file."), Target
.Description
, TransactionManager
->MetaIndexParser
, TransactionManager
, this) == true)
1519 // ensure old Release files are removed
1520 TransactionManager
->TransactionStageRemoval(this, GetFinalFilename());
1522 // queue without any kind of hashsum support
1523 QueueIndexes(false);
1527 void pkgAcqMetaIndex::Finished() /*{{{*/
1529 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1530 std::clog
<< "Finished: " << DestFile
<<std::endl
;
1531 if(TransactionManager
!= NULL
&&
1532 TransactionManager
->TransactionHasError() == false)
1533 TransactionManager
->CommitTransaction();
1536 std::string
pkgAcqMetaIndex::DescURI() const /*{{{*/
1541 pkgAcqMetaIndex::~pkgAcqMetaIndex() {}
1543 // AcqMetaSig::AcqMetaSig - Constructor /*{{{*/
1544 pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire
* const Owner
,
1545 pkgAcqMetaClearSig
* const TransactionManager
,
1546 IndexTarget
const &Target
,
1547 pkgAcqMetaIndex
* const MetaIndex
) :
1548 pkgAcqTransactionItem(Owner
, TransactionManager
, Target
), d(NULL
), MetaIndex(MetaIndex
)
1550 DestFile
= GetPartialFileNameFromURI(Target
.URI
);
1552 // remove any partial downloaded sig-file in partial/.
1553 // it may confuse proxies and is too small to warrant a
1554 // partial download anyway
1555 RemoveFile("pkgAcqMetaSig", DestFile
);
1557 // set the TransactionManager
1558 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1559 std::clog
<< "New pkgAcqMetaSig with TransactionManager "
1560 << TransactionManager
<< std::endl
;
1563 Desc
.Description
= Target
.Description
;
1565 Desc
.ShortDesc
= Target
.ShortDesc
;
1566 Desc
.URI
= Target
.URI
;
1568 // If we got a hit for Release, we will get one for Release.gpg too (or obscure errors),
1569 // so we skip the download step and go instantly to verification
1570 if (TransactionManager
->IMSHit
== true && RealFileExists(GetFinalFilename()))
1574 PartialFile
= DestFile
= GetFinalFilename();
1575 MetaIndexFileSignature
= DestFile
;
1576 MetaIndex
->QueueForSignatureVerify(this, MetaIndex
->DestFile
, DestFile
);
1582 pkgAcqMetaSig::~pkgAcqMetaSig() /*{{{*/
1586 // pkgAcqMetaSig::Custom600Headers - Insert custom request headers /*{{{*/
1587 std::string
pkgAcqMetaSig::Custom600Headers() const
1589 std::string Header
= pkgAcqTransactionItem::Custom600Headers();
1590 std::string
const key
= TransactionManager
->MetaIndexParser
->GetSignedBy();
1591 if (key
.empty() == false)
1592 Header
+= "\nSigned-By: " + key
;
1596 // AcqMetaSig::Done - The signature was downloaded/verified /*{{{*/
1597 void pkgAcqMetaSig::Done(string
const &Message
, HashStringList
const &Hashes
,
1598 pkgAcquire::MethodConfig
const * const Cfg
)
1600 if (MetaIndexFileSignature
.empty() == false)
1602 DestFile
= MetaIndexFileSignature
;
1603 MetaIndexFileSignature
.clear();
1605 Item::Done(Message
, Hashes
, Cfg
);
1607 if(MetaIndex
->AuthPass
== false)
1609 if(MetaIndex
->CheckDownloadDone(this, Message
, Hashes
) == true)
1611 // destfile will be modified to point to MetaIndexFile for the
1612 // gpgv method, so we need to save it here
1613 MetaIndexFileSignature
= DestFile
;
1614 MetaIndex
->QueueForSignatureVerify(this, MetaIndex
->DestFile
, DestFile
);
1618 else if(MetaIndex
->CheckAuthDone(Message
) == true)
1620 if (TransactionManager
->IMSHit
== false)
1622 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
1623 TransactionManager
->TransactionStageCopy(MetaIndex
, MetaIndex
->DestFile
, MetaIndex
->GetFinalFilename());
1628 void pkgAcqMetaSig::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
1630 Item::Failed(Message
,Cnf
);
1632 // check if we need to fail at this point
1633 if (MetaIndex
->AuthPass
== true && MetaIndex
->CheckStopAuthentication(this, Message
))
1636 string
const FinalRelease
= MetaIndex
->GetFinalFilename();
1637 string
const FinalReleasegpg
= GetFinalFilename();
1638 string
const FinalInRelease
= TransactionManager
->GetFinalFilename();
1640 if (RealFileExists(FinalReleasegpg
) || RealFileExists(FinalInRelease
))
1642 std::string downgrade_msg
;
1643 strprintf(downgrade_msg
, _("The repository '%s' is no longer signed."),
1644 MetaIndex
->Target
.Description
.c_str());
1645 if(_config
->FindB("Acquire::AllowDowngradeToInsecureRepositories"))
1647 // meh, the users wants to take risks (we still mark the packages
1648 // from this repository as unauthenticated)
1649 _error
->Warning("%s", downgrade_msg
.c_str());
1650 _error
->Warning(_("This is normally not allowed, but the option "
1651 "Acquire::AllowDowngradeToInsecureRepositories was "
1652 "given to override it."));
1655 MessageInsecureRepository(true, downgrade_msg
);
1656 if (TransactionManager
->IMSHit
== false)
1657 Rename(MetaIndex
->DestFile
, MetaIndex
->DestFile
+ ".FAILED");
1658 Item::Failed("Message: " + downgrade_msg
, Cnf
);
1659 TransactionManager
->AbortTransaction();
1664 // ensures that a Release.gpg file in the lists/ is removed by the transaction
1665 TransactionManager
->TransactionStageRemoval(this, DestFile
);
1667 // only allow going further if the user explicitly wants it
1668 if (AllowInsecureRepositories(_("The repository '%s' is not signed."), MetaIndex
->Target
.Description
, TransactionManager
->MetaIndexParser
, TransactionManager
, this) == true)
1670 if (RealFileExists(FinalReleasegpg
) || RealFileExists(FinalInRelease
))
1672 // open the last Release if we have it
1673 if (TransactionManager
->IMSHit
== false)
1675 TransactionManager
->LastMetaIndexParser
= TransactionManager
->MetaIndexParser
->UnloadedClone();
1676 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1678 _error
->PushToStack();
1679 if (RealFileExists(FinalInRelease
))
1680 TransactionManager
->LastMetaIndexParser
->Load(FinalInRelease
, NULL
);
1682 TransactionManager
->LastMetaIndexParser
->Load(FinalRelease
, NULL
);
1683 // its unlikely to happen, but if what we have is bad ignore it
1684 if (_error
->PendingError())
1686 delete TransactionManager
->LastMetaIndexParser
;
1687 TransactionManager
->LastMetaIndexParser
= NULL
;
1689 _error
->RevertToStack();
1694 // we parse the indexes here because at this point the user wanted
1695 // a repository that may potentially harm him
1696 bool const GoodLoad
= TransactionManager
->MetaIndexParser
->Load(MetaIndex
->DestFile
, &ErrorText
);
1697 if (MetaIndex
->VerifyVendor(Message
) == false)
1698 /* expired Release files are still a problem you need extra force for */;
1700 MetaIndex
->QueueIndexes(GoodLoad
);
1702 TransactionManager
->TransactionStageCopy(MetaIndex
, MetaIndex
->DestFile
, MetaIndex
->GetFinalFilename());
1705 // FIXME: this is used often (e.g. in pkgAcqIndexTrans) so refactor
1706 if (Cnf
->LocalOnly
== true ||
1707 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1716 // AcqBaseIndex - Constructor /*{{{*/
1717 pkgAcqBaseIndex::pkgAcqBaseIndex(pkgAcquire
* const Owner
,
1718 pkgAcqMetaClearSig
* const TransactionManager
,
1719 IndexTarget
const &Target
)
1720 : pkgAcqTransactionItem(Owner
, TransactionManager
, Target
), d(NULL
)
1724 pkgAcqBaseIndex::~pkgAcqBaseIndex() {}
1726 // AcqDiffIndex::AcqDiffIndex - Constructor /*{{{*/
1727 // ---------------------------------------------------------------------
1728 /* Get the DiffIndex file first and see if there are patches available
1729 * If so, create a pkgAcqIndexDiffs fetcher that will get and apply the
1730 * patches. If anything goes wrong in that process, it will fall back to
1731 * the original packages file
1733 pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire
* const Owner
,
1734 pkgAcqMetaClearSig
* const TransactionManager
,
1735 IndexTarget
const &Target
)
1736 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
), diffs(NULL
)
1738 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
1741 Desc
.Description
= GetDiffIndexFileName(Target
.Description
);
1742 Desc
.ShortDesc
= Target
.ShortDesc
;
1743 Desc
.URI
= GetDiffIndexURI(Target
);
1745 DestFile
= GetPartialFileNameFromURI(Desc
.URI
);
1748 std::clog
<< "pkgAcqDiffIndex: " << Desc
.URI
<< std::endl
;
1753 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
1754 // ---------------------------------------------------------------------
1755 /* The only header we use is the last-modified header. */
1756 string
pkgAcqDiffIndex::Custom600Headers() const
1758 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1759 return "\nIndex-File: true";
1761 string
const Final
= GetFinalFilename();
1764 std::clog
<< "Custom600Header-IMS: " << Final
<< std::endl
;
1767 if (stat(Final
.c_str(),&Buf
) != 0)
1768 return "\nIndex-File: true";
1770 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1773 void pkgAcqDiffIndex::QueueOnIMSHit() const /*{{{*/
1775 // list cleanup needs to know that this file as well as the already
1776 // present index is ours, so we create an empty diff to save it for us
1777 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
);
1780 bool pkgAcqDiffIndex::ParseDiffIndex(string
const &IndexDiffFile
) /*{{{*/
1782 // failing here is fine: our caller will take care of trying to
1783 // get the complete file if patching fails
1785 std::clog
<< "pkgAcqDiffIndex::ParseIndexDiff() " << IndexDiffFile
1788 FileFd
Fd(IndexDiffFile
,FileFd::ReadOnly
);
1790 if (Fd
.IsOpen() == false || Fd
.Failed())
1794 if(unlikely(TF
.Step(Tags
) == false))
1797 HashStringList ServerHashes
;
1798 unsigned long long ServerSize
= 0;
1800 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
1802 std::string tagname
= *type
;
1803 tagname
.append("-Current");
1804 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1805 if (tmp
.empty() == true)
1809 unsigned long long size
;
1810 std::stringstream
ss(tmp
);
1812 if (unlikely(hash
.empty() == true))
1814 if (unlikely(ServerSize
!= 0 && ServerSize
!= size
))
1816 ServerHashes
.push_back(HashString(*type
, hash
));
1820 if (ServerHashes
.usable() == false)
1823 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": Did not find a good hashsum in the index" << std::endl
;
1827 std::string
const CurrentPackagesFile
= GetFinalFileNameFromURI(Target
.URI
);
1828 HashStringList
const TargetFileHashes
= GetExpectedHashesFor(Target
.MetaKey
);
1829 if (TargetFileHashes
.usable() == false || ServerHashes
!= TargetFileHashes
)
1833 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": Index has different hashes than parser, probably older, so fail pdiffing" << std::endl
;
1834 printHashSumComparison(CurrentPackagesFile
, ServerHashes
, TargetFileHashes
);
1839 HashStringList LocalHashes
;
1840 // try avoiding calculating the hash here as this is costly
1841 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1842 LocalHashes
= GetExpectedHashesFromFor(TransactionManager
->LastMetaIndexParser
, Target
.MetaKey
);
1843 if (LocalHashes
.usable() == false)
1845 FileFd
fd(CurrentPackagesFile
, FileFd::ReadOnly
, FileFd::Auto
);
1846 Hashes
LocalHashesCalc(ServerHashes
);
1847 LocalHashesCalc
.AddFD(fd
);
1848 LocalHashes
= LocalHashesCalc
.GetHashStringList();
1851 if (ServerHashes
== LocalHashes
)
1853 // we have the same sha1 as the server so we are done here
1855 std::clog
<< "pkgAcqDiffIndex: Package file " << CurrentPackagesFile
<< " is up-to-date" << std::endl
;
1861 std::clog
<< "Server-Current: " << ServerHashes
.find(NULL
)->toStr() << " and we start at "
1862 << CurrentPackagesFile
<< " " << LocalHashes
.FileSize() << " " << LocalHashes
.find(NULL
)->toStr() << std::endl
;
1864 // historically, older hashes have more info than newer ones, so start
1865 // collecting with older ones first to avoid implementing complicated
1866 // information merging techniques… a failure is after all always
1867 // recoverable with a complete file and hashes aren't changed that often.
1868 std::vector
<char const *> types
;
1869 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
1870 types
.push_back(*type
);
1872 // parse all of (provided) history
1873 vector
<DiffInfo
> available_patches
;
1874 bool firstAcceptedHashes
= true;
1875 for (auto type
= types
.crbegin(); type
!= types
.crend(); ++type
)
1877 if (LocalHashes
.find(*type
) == NULL
)
1880 std::string tagname
= *type
;
1881 tagname
.append("-History");
1882 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1883 if (tmp
.empty() == true)
1886 string hash
, filename
;
1887 unsigned long long size
;
1888 std::stringstream
ss(tmp
);
1890 while (ss
>> hash
>> size
>> filename
)
1892 if (unlikely(hash
.empty() == true || filename
.empty() == true))
1895 // see if we have a record for this file already
1896 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
1897 for (; cur
!= available_patches
.end(); ++cur
)
1899 if (cur
->file
!= filename
)
1901 cur
->result_hashes
.push_back(HashString(*type
, hash
));
1904 if (cur
!= available_patches
.end())
1906 if (firstAcceptedHashes
== true)
1909 next
.file
= filename
;
1910 next
.result_hashes
.push_back(HashString(*type
, hash
));
1911 next
.result_hashes
.FileSize(size
);
1912 available_patches
.push_back(next
);
1917 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
1918 << " wasn't in the list for the first parsed hash! (history)" << std::endl
;
1922 firstAcceptedHashes
= false;
1925 if (unlikely(available_patches
.empty() == true))
1928 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": "
1929 << "Couldn't find any patches for the patch series." << std::endl
;
1933 for (auto type
= types
.crbegin(); type
!= types
.crend(); ++type
)
1935 if (LocalHashes
.find(*type
) == NULL
)
1938 std::string tagname
= *type
;
1939 tagname
.append("-Patches");
1940 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1941 if (tmp
.empty() == true)
1944 string hash
, filename
;
1945 unsigned long long size
;
1946 std::stringstream
ss(tmp
);
1948 while (ss
>> hash
>> size
>> filename
)
1950 if (unlikely(hash
.empty() == true || filename
.empty() == true))
1953 // see if we have a record for this file already
1954 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
1955 for (; cur
!= available_patches
.end(); ++cur
)
1957 if (cur
->file
!= filename
)
1959 if (cur
->patch_hashes
.empty())
1960 cur
->patch_hashes
.FileSize(size
);
1961 cur
->patch_hashes
.push_back(HashString(*type
, hash
));
1964 if (cur
!= available_patches
.end())
1967 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
1968 << " wasn't in the list for the first parsed hash! (patches)" << std::endl
;
1973 for (auto type
= types
.crbegin(); type
!= types
.crend(); ++type
)
1975 std::string tagname
= *type
;
1976 tagname
.append("-Download");
1977 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1978 if (tmp
.empty() == true)
1981 string hash
, filename
;
1982 unsigned long long size
;
1983 std::stringstream
ss(tmp
);
1985 // FIXME: all of pdiff supports only .gz compressed patches
1986 while (ss
>> hash
>> size
>> filename
)
1988 if (unlikely(hash
.empty() == true || filename
.empty() == true))
1990 if (unlikely(APT::String::Endswith(filename
, ".gz") == false))
1992 filename
.erase(filename
.length() - 3);
1994 // see if we have a record for this file already
1995 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
1996 for (; cur
!= available_patches
.end(); ++cur
)
1998 if (cur
->file
!= filename
)
2000 if (cur
->download_hashes
.empty())
2001 cur
->download_hashes
.FileSize(size
);
2002 cur
->download_hashes
.push_back(HashString(*type
, hash
));
2005 if (cur
!= available_patches
.end())
2008 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
2009 << " wasn't in the list for the first parsed hash! (download)" << std::endl
;
2015 bool foundStart
= false;
2016 for (std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
2017 cur
!= available_patches
.end(); ++cur
)
2019 if (LocalHashes
!= cur
->result_hashes
)
2022 available_patches
.erase(available_patches
.begin(), cur
);
2027 if (foundStart
== false || unlikely(available_patches
.empty() == true))
2030 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": "
2031 << "Couldn't find the start of the patch series." << std::endl
;
2035 for (auto const &patch
: available_patches
)
2036 if (patch
.result_hashes
.usable() == false ||
2037 patch
.patch_hashes
.usable() == false ||
2038 patch
.download_hashes
.usable() == false)
2041 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": provides no usable hashes for " << patch
.file
2042 << " so fallback to complete download" << std::endl
;
2046 // patching with too many files is rather slow compared to a fast download
2047 unsigned long const fileLimit
= _config
->FindI("Acquire::PDiffs::FileLimit", 0);
2048 if (fileLimit
!= 0 && fileLimit
< available_patches
.size())
2051 std::clog
<< "Need " << available_patches
.size() << " diffs (Limit is " << fileLimit
2052 << ") so fallback to complete download" << std::endl
;
2056 // calculate the size of all patches we have to get
2057 unsigned short const sizeLimitPercent
= _config
->FindI("Acquire::PDiffs::SizeLimit", 100);
2058 if (sizeLimitPercent
> 0 && TransactionManager
->MetaIndexParser
!= nullptr)
2060 unsigned long long downloadSize
= std::accumulate(available_patches
.begin(),
2061 available_patches
.end(), 0llu, [](unsigned long long const T
, DiffInfo
const &I
) {
2062 return T
+ I
.download_hashes
.FileSize();
2064 if (downloadSize
!= 0)
2066 unsigned long long downloadSizeIdx
= 0;
2067 auto const types
= VectorizeString(Target
.Option(IndexTarget::COMPRESSIONTYPES
), ' ');
2068 for (auto const &t
: types
)
2070 std::string MetaKey
= Target
.MetaKey
;
2071 if (t
!= "uncompressed")
2073 HashStringList
const hsl
= GetExpectedHashesFor(MetaKey
);
2074 if (unlikely(hsl
.usable() == false))
2076 downloadSizeIdx
= hsl
.FileSize();
2079 unsigned long long const sizeLimit
= downloadSizeIdx
* sizeLimitPercent
;
2080 if ((sizeLimit
/100) < downloadSize
)
2083 std::clog
<< "Need " << downloadSize
<< " compressed bytes (Limit is " << (sizeLimit
/100) << ", "
2084 << "original is " << downloadSizeIdx
<< ") so fallback to complete download" << std::endl
;
2090 // we have something, queue the diffs
2091 string::size_type
const last_space
= Description
.rfind(" ");
2092 if(last_space
!= string::npos
)
2093 Description
.erase(last_space
, Description
.size()-last_space
);
2095 /* decide if we should download patches one by one or in one go:
2096 The first is good if the server merges patches, but many don't so client
2097 based merging can be attempt in which case the second is better.
2098 "bad things" will happen if patches are merged on the server,
2099 but client side merging is attempt as well */
2100 bool pdiff_merge
= _config
->FindB("Acquire::PDiffs::Merge", true);
2101 if (pdiff_merge
== true)
2103 // reprepro adds this flag if it has merged patches on the server
2104 std::string
const precedence
= Tags
.FindS("X-Patch-Precedence");
2105 pdiff_merge
= (precedence
!= "merged");
2110 std::string
const Final
= GetExistingFilename(CurrentPackagesFile
);
2111 if (unlikely(Final
.empty())) // because we wouldn't be called in such a case
2113 std::string
const PartialFile
= GetPartialFileNameFromURI(Target
.URI
);
2114 if (FileExists(PartialFile
) && RemoveFile("Bootstrap-linking", PartialFile
) == false)
2117 std::clog
<< "Bootstrap-linking for patching " << CurrentPackagesFile
2118 << " by removing stale " << PartialFile
<< " failed!" << std::endl
;
2121 for (auto const &ext
: APT::Configuration::getCompressorExtensions())
2123 std::string
const Partial
= PartialFile
+ ext
;
2124 if (FileExists(Partial
) && RemoveFile("Bootstrap-linking", Partial
) == false)
2127 std::clog
<< "Bootstrap-linking for patching " << CurrentPackagesFile
2128 << " by removing stale " << Partial
<< " failed!" << std::endl
;
2132 std::string
const Ext
= Final
.substr(CurrentPackagesFile
.length());
2133 std::string
const Partial
= PartialFile
+ Ext
;
2134 if (symlink(Final
.c_str(), Partial
.c_str()) != 0)
2137 std::clog
<< "Bootstrap-linking for patching " << CurrentPackagesFile
2138 << " by linking " << Final
<< " to " << Partial
<< " failed!" << std::endl
;
2143 if (pdiff_merge
== false)
2144 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
, available_patches
);
2147 diffs
= new std::vector
<pkgAcqIndexMergeDiffs
*>(available_patches
.size());
2148 for(size_t i
= 0; i
< available_patches
.size(); ++i
)
2149 (*diffs
)[i
] = new pkgAcqIndexMergeDiffs(Owner
, TransactionManager
,
2151 available_patches
[i
],
2161 void pkgAcqDiffIndex::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
2163 Item::Failed(Message
,Cnf
);
2167 std::clog
<< "pkgAcqDiffIndex failed: " << Desc
.URI
<< " with " << Message
<< std::endl
2168 << "Falling back to normal index file acquire" << std::endl
;
2170 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
2173 void pkgAcqDiffIndex::Done(string
const &Message
,HashStringList
const &Hashes
, /*{{{*/
2174 pkgAcquire::MethodConfig
const * const Cnf
)
2177 std::clog
<< "pkgAcqDiffIndex::Done(): " << Desc
.URI
<< std::endl
;
2179 Item::Done(Message
, Hashes
, Cnf
);
2181 string
const FinalFile
= GetFinalFilename();
2182 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false))
2183 DestFile
= FinalFile
;
2185 if(ParseDiffIndex(DestFile
) == false)
2187 Failed("Message: Couldn't parse pdiff index", Cnf
);
2188 // queue for final move - this should happen even if we fail
2189 // while parsing (e.g. on sizelimit) and download the complete file.
2190 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
2194 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
2203 pkgAcqDiffIndex::~pkgAcqDiffIndex()
2209 // AcqIndexDiffs::AcqIndexDiffs - Constructor /*{{{*/
2210 // ---------------------------------------------------------------------
2211 /* The package diff is added to the queue. one object is constructed
2212 * for each diff and the index
2214 pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire
* const Owner
,
2215 pkgAcqMetaClearSig
* const TransactionManager
,
2216 IndexTarget
const &Target
,
2217 vector
<DiffInfo
> const &diffs
)
2218 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
),
2219 available_patches(diffs
)
2221 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
2223 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
2226 Description
= Target
.Description
;
2227 Desc
.ShortDesc
= Target
.ShortDesc
;
2229 if(available_patches
.empty() == true)
2231 // we are done (yeah!), check hashes against the final file
2232 DestFile
= GetKeepCompressedFileName(GetFinalFileNameFromURI(Target
.URI
), Target
);
2237 State
= StateFetchDiff
;
2242 void pkgAcqIndexDiffs::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
2244 Item::Failed(Message
,Cnf
);
2247 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
2249 std::clog
<< "pkgAcqIndexDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
2250 << "Falling back to normal index file acquire " << std::endl
;
2251 RenameOnError(PDiffError
);
2252 std::string
const patchname
= GetDiffsPatchFileName(DestFile
);
2253 if (RealFileExists(patchname
))
2254 Rename(patchname
, patchname
+ ".FAILED");
2255 std::string
const UnpatchedFile
= GetExistingFilename(GetPartialFileNameFromURI(Target
.URI
));
2256 if (UnpatchedFile
.empty() == false && FileExists(UnpatchedFile
))
2257 Rename(UnpatchedFile
, UnpatchedFile
+ ".FAILED");
2258 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
2262 // Finish - helper that cleans the item out of the fetcher queue /*{{{*/
2263 void pkgAcqIndexDiffs::Finish(bool allDone
)
2266 std::clog
<< "pkgAcqIndexDiffs::Finish(): "
2268 << Desc
.URI
<< std::endl
;
2270 // we restore the original name, this is required, otherwise
2271 // the file will be cleaned
2274 std::string
const Final
= GetKeepCompressedFileName(GetFinalFilename(), Target
);
2275 TransactionManager
->TransactionStageCopy(this, DestFile
, Final
);
2277 // this is for the "real" finish
2282 std::clog
<< "\n\nallDone: " << DestFile
<< "\n" << std::endl
;
2289 std::clog
<< "Finishing: " << Desc
.URI
<< std::endl
;
2296 bool pkgAcqIndexDiffs::QueueNextDiff() /*{{{*/
2298 // calc sha1 of the just patched file
2299 std::string
const PartialFile
= GetExistingFilename(GetPartialFileNameFromURI(Target
.URI
));
2300 if(unlikely(PartialFile
.empty()))
2302 Failed("Message: The file " + GetPartialFileNameFromURI(Target
.URI
) + " isn't available", NULL
);
2306 FileFd
fd(PartialFile
, FileFd::ReadOnly
, FileFd::Extension
);
2307 Hashes LocalHashesCalc
;
2308 LocalHashesCalc
.AddFD(fd
);
2309 HashStringList
const LocalHashes
= LocalHashesCalc
.GetHashStringList();
2312 std::clog
<< "QueueNextDiff: " << PartialFile
<< " (" << LocalHashes
.find(NULL
)->toStr() << ")" << std::endl
;
2314 HashStringList
const TargetFileHashes
= GetExpectedHashesFor(Target
.MetaKey
);
2315 if (unlikely(LocalHashes
.usable() == false || TargetFileHashes
.usable() == false))
2317 Failed("Local/Expected hashes are not usable for " + PartialFile
, NULL
);
2321 // final file reached before all patches are applied
2322 if(LocalHashes
== TargetFileHashes
)
2328 // remove all patches until the next matching patch is found
2329 // this requires the Index file to be ordered
2330 available_patches
.erase(available_patches
.begin(),
2331 std::find_if(available_patches
.begin(), available_patches
.end(), [&](DiffInfo
const &I
) {
2332 return I
.result_hashes
== LocalHashes
;
2335 // error checking and falling back if no patch was found
2336 if(available_patches
.empty() == true)
2338 Failed("No patches left to reach target for " + PartialFile
, NULL
);
2342 // queue the right diff
2343 Desc
.URI
= Target
.URI
+ ".diff/" + available_patches
[0].file
+ ".gz";
2344 Desc
.Description
= Description
+ " " + available_patches
[0].file
+ string(".pdiff");
2345 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
+ ".diff/" + available_patches
[0].file
), Target
);
2348 std::clog
<< "pkgAcqIndexDiffs::QueueNextDiff(): " << Desc
.URI
<< std::endl
;
2355 void pkgAcqIndexDiffs::Done(string
const &Message
, HashStringList
const &Hashes
, /*{{{*/
2356 pkgAcquire::MethodConfig
const * const Cnf
)
2359 std::clog
<< "pkgAcqIndexDiffs::Done(): " << Desc
.URI
<< std::endl
;
2361 Item::Done(Message
, Hashes
, Cnf
);
2363 std::string
const UncompressedUnpatchedFile
= GetPartialFileNameFromURI(Target
.URI
);
2364 std::string
const UnpatchedFile
= GetExistingFilename(UncompressedUnpatchedFile
);
2365 std::string
const PatchFile
= GetDiffsPatchFileName(UnpatchedFile
);
2366 std::string
const PatchedFile
= GetKeepCompressedFileName(UncompressedUnpatchedFile
, Target
);
2370 // success in downloading a diff, enter ApplyDiff state
2371 case StateFetchDiff
:
2372 Rename(DestFile
, PatchFile
);
2373 DestFile
= GetKeepCompressedFileName(UncompressedUnpatchedFile
+ "-patched", Target
);
2375 std::clog
<< "Sending to rred method: " << UnpatchedFile
<< std::endl
;
2376 State
= StateApplyDiff
;
2378 Desc
.URI
= "rred:" + UnpatchedFile
;
2380 SetActiveSubprocess("rred");
2382 // success in download/apply a diff, queue next (if needed)
2383 case StateApplyDiff
:
2384 // remove the just applied patch and base file
2385 available_patches
.erase(available_patches
.begin());
2386 RemoveFile("pkgAcqIndexDiffs::Done", PatchFile
);
2387 RemoveFile("pkgAcqIndexDiffs::Done", UnpatchedFile
);
2389 std::clog
<< "Moving patched file in place: " << std::endl
2390 << DestFile
<< " -> " << PatchedFile
<< std::endl
;
2391 Rename(DestFile
, PatchedFile
);
2393 // see if there is more to download
2394 if(available_patches
.empty() == false)
2396 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
, available_patches
);
2399 DestFile
= PatchedFile
;
2406 std::string
pkgAcqIndexDiffs::Custom600Headers() const /*{{{*/
2408 if(State
!= StateApplyDiff
)
2409 return pkgAcqBaseIndex::Custom600Headers();
2410 std::ostringstream patchhashes
;
2411 HashStringList
const ExpectedHashes
= available_patches
[0].patch_hashes
;
2412 for (HashStringList::const_iterator hs
= ExpectedHashes
.begin(); hs
!= ExpectedHashes
.end(); ++hs
)
2413 patchhashes
<< "\nPatch-0-" << hs
->HashType() << "-Hash: " << hs
->HashValue();
2414 patchhashes
<< pkgAcqBaseIndex::Custom600Headers();
2415 return patchhashes
.str();
2418 pkgAcqIndexDiffs::~pkgAcqIndexDiffs() {}
2420 // AcqIndexMergeDiffs::AcqIndexMergeDiffs - Constructor /*{{{*/
2421 pkgAcqIndexMergeDiffs::pkgAcqIndexMergeDiffs(pkgAcquire
* const Owner
,
2422 pkgAcqMetaClearSig
* const TransactionManager
,
2423 IndexTarget
const &Target
,
2424 DiffInfo
const &patch
,
2425 std::vector
<pkgAcqIndexMergeDiffs
*> const * const allPatches
)
2426 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
),
2427 patch(patch
), allPatches(allPatches
), State(StateFetchDiff
)
2429 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
2432 Description
= Target
.Description
;
2433 Desc
.ShortDesc
= Target
.ShortDesc
;
2434 Desc
.URI
= Target
.URI
+ ".diff/" + patch
.file
+ ".gz";
2435 Desc
.Description
= Description
+ " " + patch
.file
+ ".pdiff";
2436 DestFile
= GetPartialFileNameFromURI(Desc
.URI
);
2439 std::clog
<< "pkgAcqIndexMergeDiffs: " << Desc
.URI
<< std::endl
;
2444 void pkgAcqIndexMergeDiffs::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
2447 std::clog
<< "pkgAcqIndexMergeDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
;
2449 Item::Failed(Message
,Cnf
);
2452 // check if we are the first to fail, otherwise we are done here
2453 State
= StateDoneDiff
;
2454 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2455 I
!= allPatches
->end(); ++I
)
2456 if ((*I
)->State
== StateErrorDiff
)
2458 State
= StateErrorDiff
;
2462 // first failure means we should fallback
2463 State
= StateErrorDiff
;
2465 std::clog
<< "Falling back to normal index file acquire" << std::endl
;
2466 RenameOnError(PDiffError
);
2467 if (RealFileExists(DestFile
))
2468 Rename(DestFile
, DestFile
+ ".FAILED");
2469 std::string
const UnpatchedFile
= GetExistingFilename(GetPartialFileNameFromURI(Target
.URI
));
2470 if (UnpatchedFile
.empty() == false && FileExists(UnpatchedFile
))
2471 Rename(UnpatchedFile
, UnpatchedFile
+ ".FAILED");
2473 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
2476 void pkgAcqIndexMergeDiffs::Done(string
const &Message
, HashStringList
const &Hashes
, /*{{{*/
2477 pkgAcquire::MethodConfig
const * const Cnf
)
2480 std::clog
<< "pkgAcqIndexMergeDiffs::Done(): " << Desc
.URI
<< std::endl
;
2482 Item::Done(Message
, Hashes
, Cnf
);
2484 if (std::any_of(allPatches
->begin(), allPatches
->end(),
2485 [](pkgAcqIndexMergeDiffs
const * const P
) { return P
->State
== StateErrorDiff
; }))
2488 std::clog
<< "Another patch failed already, no point in processing this one." << std::endl
;
2489 State
= StateErrorDiff
;
2493 std::string
const UncompressedUnpatchedFile
= GetPartialFileNameFromURI(Target
.URI
);
2494 std::string
const UnpatchedFile
= GetExistingFilename(UncompressedUnpatchedFile
);
2495 if (UnpatchedFile
.empty())
2497 _error
->Fatal("Unpatched file %s doesn't exist (anymore)!", UncompressedUnpatchedFile
.c_str());
2498 State
= StateErrorDiff
;
2501 std::string
const PatchFile
= GetMergeDiffsPatchFileName(UnpatchedFile
, patch
.file
);
2502 std::string
const PatchedFile
= GetKeepCompressedFileName(UncompressedUnpatchedFile
, Target
);
2506 case StateFetchDiff
:
2507 Rename(DestFile
, PatchFile
);
2509 // check if this is the last completed diff
2510 State
= StateDoneDiff
;
2511 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2512 I
!= allPatches
->end(); ++I
)
2513 if ((*I
)->State
!= StateDoneDiff
)
2516 std::clog
<< "Not the last done diff in the batch: " << Desc
.URI
<< std::endl
;
2519 // this is the last completed diff, so we are ready to apply now
2520 DestFile
= GetKeepCompressedFileName(UncompressedUnpatchedFile
+ "-patched", Target
);
2522 std::clog
<< "Sending to rred method: " << UnpatchedFile
<< std::endl
;
2523 State
= StateApplyDiff
;
2525 Desc
.URI
= "rred:" + UnpatchedFile
;
2527 SetActiveSubprocess("rred");
2529 case StateApplyDiff
:
2530 // success in download & apply all diffs, finialize and clean up
2532 std::clog
<< "Queue patched file in place: " << std::endl
2533 << DestFile
<< " -> " << PatchedFile
<< std::endl
;
2535 // queue for copy by the transaction manager
2536 TransactionManager
->TransactionStageCopy(this, DestFile
, GetKeepCompressedFileName(GetFinalFilename(), Target
));
2538 // ensure the ed's are gone regardless of list-cleanup
2539 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2540 I
!= allPatches
->end(); ++I
)
2541 RemoveFile("pkgAcqIndexMergeDiffs::Done", GetMergeDiffsPatchFileName(UnpatchedFile
, (*I
)->patch
.file
));
2542 RemoveFile("pkgAcqIndexMergeDiffs::Done", UnpatchedFile
);
2547 std::clog
<< "allDone: " << DestFile
<< "\n" << std::endl
;
2549 case StateDoneDiff
: _error
->Fatal("Done called for %s which is in an invalid Done state", PatchFile
.c_str()); break;
2550 case StateErrorDiff
: _error
->Fatal("Done called for %s which is in an invalid Error state", PatchFile
.c_str()); break;
2554 std::string
pkgAcqIndexMergeDiffs::Custom600Headers() const /*{{{*/
2556 if(State
!= StateApplyDiff
)
2557 return pkgAcqBaseIndex::Custom600Headers();
2558 std::ostringstream patchhashes
;
2559 unsigned int seen_patches
= 0;
2560 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2561 I
!= allPatches
->end(); ++I
)
2563 HashStringList
const ExpectedHashes
= (*I
)->patch
.patch_hashes
;
2564 for (HashStringList::const_iterator hs
= ExpectedHashes
.begin(); hs
!= ExpectedHashes
.end(); ++hs
)
2565 patchhashes
<< "\nPatch-" << seen_patches
<< "-" << hs
->HashType() << "-Hash: " << hs
->HashValue();
2568 patchhashes
<< pkgAcqBaseIndex::Custom600Headers();
2569 return patchhashes
.str();
2572 pkgAcqIndexMergeDiffs::~pkgAcqIndexMergeDiffs() {}
2574 // AcqIndex::AcqIndex - Constructor /*{{{*/
2575 pkgAcqIndex::pkgAcqIndex(pkgAcquire
* const Owner
,
2576 pkgAcqMetaClearSig
* const TransactionManager
,
2577 IndexTarget
const &Target
)
2578 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
), Stage(STAGE_DOWNLOAD
),
2579 CompressionExtensions(Target
.Option(IndexTarget::COMPRESSIONTYPES
))
2581 Init(Target
.URI
, Target
.Description
, Target
.ShortDesc
);
2583 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
2584 std::clog
<< "New pkgIndex with TransactionManager "
2585 << TransactionManager
<< std::endl
;
2588 // AcqIndex::Init - defered Constructor /*{{{*/
2589 static void NextCompressionExtension(std::string
&CurrentCompressionExtension
, std::string
&CompressionExtensions
, bool const preview
)
2591 size_t const nextExt
= CompressionExtensions
.find(' ');
2592 if (nextExt
== std::string::npos
)
2594 CurrentCompressionExtension
= CompressionExtensions
;
2595 if (preview
== false)
2596 CompressionExtensions
.clear();
2600 CurrentCompressionExtension
= CompressionExtensions
.substr(0, nextExt
);
2601 if (preview
== false)
2602 CompressionExtensions
= CompressionExtensions
.substr(nextExt
+1);
2605 void pkgAcqIndex::Init(string
const &URI
, string
const &URIDesc
,
2606 string
const &ShortDesc
)
2608 Stage
= STAGE_DOWNLOAD
;
2610 DestFile
= GetPartialFileNameFromURI(URI
);
2611 NextCompressionExtension(CurrentCompressionExtension
, CompressionExtensions
, false);
2613 // store file size of the download to ensure the fetcher gives
2614 // accurate progress reporting
2615 FileSize
= GetExpectedHashes().FileSize();
2617 if (CurrentCompressionExtension
== "uncompressed")
2621 else if (CurrentCompressionExtension
== "by-hash")
2623 NextCompressionExtension(CurrentCompressionExtension
, CompressionExtensions
, true);
2624 if(unlikely(TransactionManager
->MetaIndexParser
== NULL
|| CurrentCompressionExtension
.empty()))
2626 if (CurrentCompressionExtension
!= "uncompressed")
2628 Desc
.URI
= URI
+ '.' + CurrentCompressionExtension
;
2629 DestFile
= DestFile
+ '.' + CurrentCompressionExtension
;
2632 HashStringList
const Hashes
= GetExpectedHashes();
2633 HashString
const * const TargetHash
= Hashes
.find(NULL
);
2634 if (unlikely(TargetHash
== nullptr))
2636 std::string
const ByHash
= "/by-hash/" + TargetHash
->HashType() + "/" + TargetHash
->HashValue();
2637 size_t const trailing_slash
= Desc
.URI
.find_last_of("/");
2638 if (unlikely(trailing_slash
== std::string::npos
))
2640 Desc
.URI
= Desc
.URI
.replace(
2642 Desc
.URI
.substr(trailing_slash
+1).size()+1,
2645 else if (unlikely(CurrentCompressionExtension
.empty()))
2649 Desc
.URI
= URI
+ '.' + CurrentCompressionExtension
;
2650 DestFile
= DestFile
+ '.' + CurrentCompressionExtension
;
2654 Desc
.Description
= URIDesc
;
2656 Desc
.ShortDesc
= ShortDesc
;
2661 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
2662 // ---------------------------------------------------------------------
2663 /* The only header we use is the last-modified header. */
2664 string
pkgAcqIndex::Custom600Headers() const
2667 string msg
= "\nIndex-File: true";
2669 if (TransactionManager
->LastMetaIndexParser
== NULL
)
2671 std::string
const Final
= GetFinalFilename();
2674 if (stat(Final
.c_str(),&Buf
) == 0)
2675 msg
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
2678 if(Target
.IsOptional
)
2679 msg
+= "\nFail-Ignore: true";
2684 // AcqIndex::Failed - getting the indexfile failed /*{{{*/
2685 void pkgAcqIndex::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)
2687 Item::Failed(Message
,Cnf
);
2689 // authorisation matches will not be fixed by other compression types
2690 if (Status
!= StatAuthError
)
2692 if (CompressionExtensions
.empty() == false)
2694 Init(Target
.URI
, Desc
.Description
, Desc
.ShortDesc
);
2700 if(Target
.IsOptional
&& GetExpectedHashes().empty() && Stage
== STAGE_DOWNLOAD
)
2703 TransactionManager
->AbortTransaction();
2706 // AcqIndex::Done - Finished a fetch /*{{{*/
2707 // ---------------------------------------------------------------------
2708 /* This goes through a number of states.. On the initial fetch the
2709 method could possibly return an alternate filename which points
2710 to the uncompressed version of the file. If this is so the file
2711 is copied into the partial directory. In all other cases the file
2712 is decompressed with a compressed uri. */
2713 void pkgAcqIndex::Done(string
const &Message
,
2714 HashStringList
const &Hashes
,
2715 pkgAcquire::MethodConfig
const * const Cfg
)
2717 Item::Done(Message
,Hashes
,Cfg
);
2721 case STAGE_DOWNLOAD
:
2722 StageDownloadDone(Message
);
2724 case STAGE_DECOMPRESS_AND_VERIFY
:
2725 StageDecompressDone();
2730 // AcqIndex::StageDownloadDone - Queue for decompress and verify /*{{{*/
2731 void pkgAcqIndex::StageDownloadDone(string
const &Message
)
2736 std::string
const AltFilename
= LookupTag(Message
,"Alt-Filename");
2737 std::string Filename
= LookupTag(Message
,"Filename");
2739 // we need to verify the file against the current Release file again
2740 // on if-modfied-since hit to avoid a stale attack against us
2741 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
2743 // copy FinalFile into partial/ so that we check the hash again
2744 string
const FinalFile
= GetExistingFilename(GetFinalFileNameFromURI(Target
.URI
));
2745 if (symlink(FinalFile
.c_str(), DestFile
.c_str()) != 0)
2746 _error
->WarningE("pkgAcqIndex::StageDownloadDone", "Symlinking final file %s back to %s failed", FinalFile
.c_str(), DestFile
.c_str());
2749 EraseFileName
= DestFile
;
2750 Filename
= DestFile
;
2752 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
2753 Desc
.URI
= "store:" + Filename
;
2755 SetActiveSubprocess(::URI(Desc
.URI
).Access
);
2758 // methods like file:// give us an alternative (uncompressed) file
2759 else if (Target
.KeepCompressed
== false && AltFilename
.empty() == false)
2761 if (CurrentCompressionExtension
!= "uncompressed")
2762 DestFile
.erase(DestFile
.length() - (CurrentCompressionExtension
.length() + 1));
2763 Filename
= AltFilename
;
2765 // Methods like e.g. "file:" will give us a (compressed) FileName that is
2766 // not the "DestFile" we set, in this case we uncompress from the local file
2767 else if (Filename
!= DestFile
&& RealFileExists(DestFile
) == false)
2769 // symlinking ensures that the filename can be used for compression detection
2770 // that is e.g. needed for by-hash which has no extension over file
2771 if (symlink(Filename
.c_str(),DestFile
.c_str()) != 0)
2772 _error
->WarningE("pkgAcqIndex::StageDownloadDone", "Symlinking file %s to %s failed", Filename
.c_str(), DestFile
.c_str());
2775 EraseFileName
= DestFile
;
2776 Filename
= DestFile
;
2780 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
2781 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
2782 if (Filename
!= DestFile
&& flExtension(Filename
) == flExtension(DestFile
))
2783 Desc
.URI
= "copy:" + Filename
;
2785 Desc
.URI
= "store:" + Filename
;
2786 if (DestFile
== Filename
)
2788 if (CurrentCompressionExtension
== "uncompressed")
2789 return StageDecompressDone();
2790 DestFile
= "/dev/null";
2793 if (EraseFileName
.empty())
2794 EraseFileName
= Filename
;
2796 // queue uri for the next stage
2798 SetActiveSubprocess(::URI(Desc
.URI
).Access
);
2801 // AcqIndex::StageDecompressDone - Final verification /*{{{*/
2802 void pkgAcqIndex::StageDecompressDone()
2804 if (DestFile
== "/dev/null")
2805 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
2807 // Done, queue for rename on transaction finished
2808 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
2811 pkgAcqIndex::~pkgAcqIndex() {}
2814 // AcqArchive::AcqArchive - Constructor /*{{{*/
2815 // ---------------------------------------------------------------------
2816 /* This just sets up the initial fetch environment and queues the first
2818 pkgAcqArchive::pkgAcqArchive(pkgAcquire
* const Owner
,pkgSourceList
* const Sources
,
2819 pkgRecords
* const Recs
,pkgCache::VerIterator
const &Version
,
2820 string
&StoreFilename
) :
2821 Item(Owner
), d(NULL
), LocalSource(false), Version(Version
), Sources(Sources
), Recs(Recs
),
2822 StoreFilename(StoreFilename
), Vf(Version
.FileList()),
2825 Retries
= _config
->FindI("Acquire::Retries",0);
2827 if (Version
.Arch() == 0)
2829 _error
->Error(_("I wasn't able to locate a file for the %s package. "
2830 "This might mean you need to manually fix this package. "
2831 "(due to missing arch)"),
2832 Version
.ParentPkg().FullName().c_str());
2836 /* We need to find a filename to determine the extension. We make the
2837 assumption here that all the available sources for this version share
2838 the same extension.. */
2839 // Skip not source sources, they do not have file fields.
2840 for (; Vf
.end() == false; ++Vf
)
2842 if (Vf
.File().Flagged(pkgCache::Flag::NotSource
))
2847 // Does not really matter here.. we are going to fail out below
2848 if (Vf
.end() != true)
2850 // If this fails to get a file name we will bomb out below.
2851 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2852 if (_error
->PendingError() == true)
2855 // Generate the final file name as: package_version_arch.foo
2856 StoreFilename
= QuoteString(Version
.ParentPkg().Name(),"_:") + '_' +
2857 QuoteString(Version
.VerStr(),"_:") + '_' +
2858 QuoteString(Version
.Arch(),"_:.") +
2859 "." + flExtension(Parse
.FileName());
2862 // check if we have one trusted source for the package. if so, switch
2863 // to "TrustedOnly" mode - but only if not in AllowUnauthenticated mode
2864 bool const allowUnauth
= _config
->FindB("APT::Get::AllowUnauthenticated", false);
2865 bool const debugAuth
= _config
->FindB("Debug::pkgAcquire::Auth", false);
2866 bool seenUntrusted
= false;
2867 for (pkgCache::VerFileIterator i
= Version
.FileList(); i
.end() == false; ++i
)
2869 pkgIndexFile
*Index
;
2870 if (Sources
->FindIndex(i
.File(),Index
) == false)
2873 if (debugAuth
== true)
2874 std::cerr
<< "Checking index: " << Index
->Describe()
2875 << "(Trusted=" << Index
->IsTrusted() << ")" << std::endl
;
2877 if (Index
->IsTrusted() == true)
2880 if (allowUnauth
== false)
2884 seenUntrusted
= true;
2887 // "allow-unauthenticated" restores apts old fetching behaviour
2888 // that means that e.g. unauthenticated file:// uris are higher
2889 // priority than authenticated http:// uris
2890 if (allowUnauth
== true && seenUntrusted
== true)
2894 if (QueueNext() == false && _error
->PendingError() == false)
2895 _error
->Error(_("Can't find a source to download version '%s' of '%s'"),
2896 Version
.VerStr(), Version
.ParentPkg().FullName(false).c_str());
2899 // AcqArchive::QueueNext - Queue the next file source /*{{{*/
2900 // ---------------------------------------------------------------------
2901 /* This queues the next available file version for download. It checks if
2902 the archive is already available in the cache and stashs the MD5 for
2904 bool pkgAcqArchive::QueueNext()
2906 for (; Vf
.end() == false; ++Vf
)
2908 pkgCache::PkgFileIterator
const PkgF
= Vf
.File();
2909 // Ignore not source sources
2910 if (PkgF
.Flagged(pkgCache::Flag::NotSource
))
2913 // Try to cross match against the source list
2914 pkgIndexFile
*Index
;
2915 if (Sources
->FindIndex(PkgF
, Index
) == false)
2917 LocalSource
= PkgF
.Flagged(pkgCache::Flag::LocalSource
);
2919 // only try to get a trusted package from another source if that source
2921 if(Trusted
&& !Index
->IsTrusted())
2924 // Grab the text package record
2925 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2926 if (_error
->PendingError() == true)
2929 string PkgFile
= Parse
.FileName();
2930 ExpectedHashes
= Parse
.Hashes();
2932 if (PkgFile
.empty() == true)
2933 return _error
->Error(_("The package index files are corrupted. No Filename: "
2934 "field for package %s."),
2935 Version
.ParentPkg().Name());
2937 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
2938 Desc
.Description
= Index
->ArchiveInfo(Version
);
2940 Desc
.ShortDesc
= Version
.ParentPkg().FullName(true);
2942 // See if we already have the file. (Legacy filenames)
2943 FileSize
= Version
->Size
;
2944 string FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile
);
2946 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2948 // Make sure the size matches
2949 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2954 StoreFilename
= DestFile
= FinalFile
;
2958 /* Hmm, we have a file and its size does not match, this means it is
2959 an old style mismatched arch */
2960 RemoveFile("pkgAcqArchive::QueueNext", FinalFile
);
2963 // Check it again using the new style output filenames
2964 FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
2965 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2967 // Make sure the size matches
2968 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2973 StoreFilename
= DestFile
= FinalFile
;
2977 /* Hmm, we have a file and its size does not match, this shouldn't
2979 RemoveFile("pkgAcqArchive::QueueNext", FinalFile
);
2982 DestFile
= _config
->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename
);
2984 // Check the destination file
2985 if (stat(DestFile
.c_str(),&Buf
) == 0)
2987 // Hmm, the partial file is too big, erase it
2988 if ((unsigned long long)Buf
.st_size
> Version
->Size
)
2989 RemoveFile("pkgAcqArchive::QueueNext", DestFile
);
2991 PartialSize
= Buf
.st_size
;
2994 // Disables download of archives - useful if no real installation follows,
2995 // e.g. if we are just interested in proposed installation order
2996 if (_config
->FindB("Debug::pkgAcqArchive::NoQueue", false) == true)
3001 StoreFilename
= DestFile
= FinalFile
;
3015 // AcqArchive::Done - Finished fetching /*{{{*/
3016 // ---------------------------------------------------------------------
3018 void pkgAcqArchive::Done(string
const &Message
, HashStringList
const &Hashes
,
3019 pkgAcquire::MethodConfig
const * const Cfg
)
3021 Item::Done(Message
, Hashes
, Cfg
);
3023 // Grab the output filename
3024 std::string
const FileName
= LookupTag(Message
,"Filename");
3025 if (DestFile
!= FileName
&& RealFileExists(DestFile
) == false)
3027 StoreFilename
= DestFile
= FileName
;
3033 // Done, move it into position
3034 string
const FinalFile
= GetFinalFilename();
3035 Rename(DestFile
,FinalFile
);
3036 StoreFilename
= DestFile
= FinalFile
;
3040 // AcqArchive::Failed - Failure handler /*{{{*/
3041 // ---------------------------------------------------------------------
3042 /* Here we try other sources */
3043 void pkgAcqArchive::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)
3045 Item::Failed(Message
,Cnf
);
3047 /* We don't really want to retry on failed media swaps, this prevents
3048 that. An interesting observation is that permanent failures are not
3050 if (Cnf
->Removable
== true &&
3051 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
3053 // Vf = Version.FileList();
3054 while (Vf
.end() == false) ++Vf
;
3055 StoreFilename
= string();
3060 if (QueueNext() == false)
3062 // This is the retry counter
3064 Cnf
->LocalOnly
== false &&
3065 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
3068 Vf
= Version
.FileList();
3069 if (QueueNext() == true)
3073 StoreFilename
= string();
3078 APT_PURE
bool pkgAcqArchive::IsTrusted() const /*{{{*/
3083 void pkgAcqArchive::Finished() /*{{{*/
3085 if (Status
== pkgAcquire::Item::StatDone
&&
3088 StoreFilename
= string();
3091 std::string
pkgAcqArchive::DescURI() const /*{{{*/
3096 std::string
pkgAcqArchive::ShortDesc() const /*{{{*/
3098 return Desc
.ShortDesc
;
3101 pkgAcqArchive::~pkgAcqArchive() {}
3103 // AcqChangelog::pkgAcqChangelog - Constructors /*{{{*/
3104 class pkgAcqChangelog::Private
3107 std::string FinalFile
;
3109 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire
* const Owner
, pkgCache::VerIterator
const &Ver
,
3110 std::string
const &DestDir
, std::string
const &DestFilename
) :
3111 pkgAcquire::Item(Owner
), d(new pkgAcqChangelog::Private()), SrcName(Ver
.SourcePkgName()), SrcVersion(Ver
.SourceVerStr())
3113 Desc
.URI
= URI(Ver
);
3114 Init(DestDir
, DestFilename
);
3116 // some parameters are char* here as they come likely from char* interfaces – which can also return NULL
3117 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire
* const Owner
, pkgCache::RlsFileIterator
const &RlsFile
,
3118 char const * const Component
, char const * const SrcName
, char const * const SrcVersion
,
3119 const string
&DestDir
, const string
&DestFilename
) :
3120 pkgAcquire::Item(Owner
), d(new pkgAcqChangelog::Private()), SrcName(SrcName
), SrcVersion(SrcVersion
)
3122 Desc
.URI
= URI(RlsFile
, Component
, SrcName
, SrcVersion
);
3123 Init(DestDir
, DestFilename
);
3125 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire
* const Owner
,
3126 std::string
const &URI
, char const * const SrcName
, char const * const SrcVersion
,
3127 const string
&DestDir
, const string
&DestFilename
) :
3128 pkgAcquire::Item(Owner
), d(new pkgAcqChangelog::Private()), SrcName(SrcName
), SrcVersion(SrcVersion
)
3131 Init(DestDir
, DestFilename
);
3133 void pkgAcqChangelog::Init(std::string
const &DestDir
, std::string
const &DestFilename
)
3135 if (Desc
.URI
.empty())
3138 // TRANSLATOR: %s=%s is sourcename=sourceversion, e.g. apt=1.1
3139 strprintf(ErrorText
, _("Changelog unavailable for %s=%s"), SrcName
.c_str(), SrcVersion
.c_str());
3140 // Let the error message print something sensible rather than "Failed to fetch /"
3141 if (DestFilename
.empty())
3142 DestFile
= SrcName
+ ".changelog";
3144 DestFile
= DestFilename
;
3145 Desc
.URI
= "changelog:/" + DestFile
;
3149 std::string DestFileName
;
3150 if (DestFilename
.empty())
3151 DestFileName
= flCombine(DestFile
, SrcName
+ ".changelog");
3153 DestFileName
= flCombine(DestFile
, DestFilename
);
3155 std::string
const SandboxUser
= _config
->Find("APT::Sandbox::User");
3156 std::string
const systemTemp
= GetTempDir(SandboxUser
);
3158 snprintf(tmpname
, sizeof(tmpname
), "%s/apt-changelog-XXXXXX", systemTemp
.c_str());
3159 if (NULL
== mkdtemp(tmpname
))
3161 _error
->Errno("mkdtemp", "mkdtemp failed in changelog acquire of %s %s", SrcName
.c_str(), SrcVersion
.c_str());
3165 TemporaryDirectory
= tmpname
;
3167 ChangeOwnerAndPermissionOfFile("Item::QueueURI", TemporaryDirectory
.c_str(),
3168 SandboxUser
.c_str(), "root", 0700);
3170 DestFile
= flCombine(TemporaryDirectory
, DestFileName
);
3171 if (DestDir
.empty() == false)
3173 d
->FinalFile
= flCombine(DestDir
, DestFileName
);
3174 if (RealFileExists(d
->FinalFile
))
3176 FileFd file1
, file2
;
3177 if (file1
.Open(DestFile
, FileFd::WriteOnly
| FileFd::Create
| FileFd::Exclusive
) &&
3178 file2
.Open(d
->FinalFile
, FileFd::ReadOnly
) && CopyFile(file2
, file1
))
3180 struct timeval times
[2];
3181 times
[0].tv_sec
= times
[1].tv_sec
= file2
.ModificationTime();
3182 times
[0].tv_usec
= times
[1].tv_usec
= 0;
3183 utimes(DestFile
.c_str(), times
);
3188 Desc
.ShortDesc
= "Changelog";
3189 strprintf(Desc
.Description
, "%s %s %s Changelog", URI::SiteOnly(Desc
.URI
).c_str(), SrcName
.c_str(), SrcVersion
.c_str());
3194 std::string
pkgAcqChangelog::URI(pkgCache::VerIterator
const &Ver
) /*{{{*/
3196 std::string
const confOnline
= "Acquire::Changelogs::AlwaysOnline";
3197 bool AlwaysOnline
= _config
->FindB(confOnline
, false);
3198 if (AlwaysOnline
== false)
3199 for (pkgCache::VerFileIterator VF
= Ver
.FileList(); VF
.end() == false; ++VF
)
3201 pkgCache::PkgFileIterator
const PF
= VF
.File();
3202 if (PF
.Flagged(pkgCache::Flag::NotSource
) || PF
->Release
== 0)
3204 pkgCache::RlsFileIterator
const RF
= PF
.ReleaseFile();
3205 if (RF
->Origin
!= 0 && _config
->FindB(confOnline
+ "::Origin::" + RF
.Origin(), false))
3207 AlwaysOnline
= true;
3211 if (AlwaysOnline
== false)
3213 pkgCache::PkgIterator
const Pkg
= Ver
.ParentPkg();
3214 if (Pkg
->CurrentVer
!= 0 && Pkg
.CurrentVer() == Ver
)
3216 std::string
const basename
= std::string("/usr/share/doc/") + Pkg
.Name() + "/changelog";
3217 std::string
const debianname
= basename
+ ".Debian";
3218 if (FileExists(debianname
))
3219 return "copy://" + debianname
;
3220 else if (FileExists(debianname
+ ".gz"))
3221 return "gzip://" + debianname
+ ".gz";
3222 else if (FileExists(basename
))
3223 return "copy://" + basename
;
3224 else if (FileExists(basename
+ ".gz"))
3225 return "gzip://" + basename
+ ".gz";
3229 char const * const SrcName
= Ver
.SourcePkgName();
3230 char const * const SrcVersion
= Ver
.SourceVerStr();
3231 // find the first source for this version which promises a changelog
3232 for (pkgCache::VerFileIterator VF
= Ver
.FileList(); VF
.end() == false; ++VF
)
3234 pkgCache::PkgFileIterator
const PF
= VF
.File();
3235 if (PF
.Flagged(pkgCache::Flag::NotSource
) || PF
->Release
== 0)
3237 pkgCache::RlsFileIterator
const RF
= PF
.ReleaseFile();
3238 std::string
const uri
= URI(RF
, PF
.Component(), SrcName
, SrcVersion
);
3245 std::string
pkgAcqChangelog::URITemplate(pkgCache::RlsFileIterator
const &Rls
)
3247 if (Rls
.end() == true || (Rls
->Label
== 0 && Rls
->Origin
== 0))
3249 std::string
const serverConfig
= "Acquire::Changelogs::URI";
3251 #define APT_EMPTY_SERVER \
3252 if (server.empty() == false) \
3254 if (server != "no") \
3258 #define APT_CHECK_SERVER(X, Y) \
3261 std::string const specialServerConfig = serverConfig + "::" + Y + #X + "::" + Rls.X(); \
3262 server = _config->Find(specialServerConfig); \
3265 // this way e.g. Debian-Security can fallback to Debian
3266 APT_CHECK_SERVER(Label
, "Override::")
3267 APT_CHECK_SERVER(Origin
, "Override::")
3269 if (RealFileExists(Rls
.FileName()))
3271 _error
->PushToStack();
3273 /* This can be costly. A caller wanting to get millions of URIs might
3274 want to do this on its own once and use Override settings.
3275 We don't do this here as Origin/Label are not as unique as they
3276 should be so this could produce request order-dependent anomalies */
3277 if (OpenMaybeClearSignedFile(Rls
.FileName(), rf
) == true)
3279 pkgTagFile
TagFile(&rf
, rf
.Size());
3280 pkgTagSection Section
;
3281 if (TagFile
.Step(Section
) == true)
3282 server
= Section
.FindS("Changelogs");
3284 _error
->RevertToStack();
3288 APT_CHECK_SERVER(Label
, "")
3289 APT_CHECK_SERVER(Origin
, "")
3290 #undef APT_CHECK_SERVER
3291 #undef APT_EMPTY_SERVER
3294 std::string
pkgAcqChangelog::URI(pkgCache::RlsFileIterator
const &Rls
,
3295 char const * const Component
, char const * const SrcName
,
3296 char const * const SrcVersion
)
3298 return URI(URITemplate(Rls
), Component
, SrcName
, SrcVersion
);
3300 std::string
pkgAcqChangelog::URI(std::string
const &Template
,
3301 char const * const Component
, char const * const SrcName
,
3302 char const * const SrcVersion
)
3304 if (Template
.find("@CHANGEPATH@") == std::string::npos
)
3307 // the path is: COMPONENT/SRC/SRCNAME/SRCNAME_SRCVER, e.g. main/a/apt/1.1 or contrib/liba/libapt/2.0
3308 std::string Src
= SrcName
;
3309 std::string path
= APT::String::Startswith(SrcName
, "lib") ? Src
.substr(0, 4) : Src
.substr(0,1);
3310 path
.append("/").append(Src
).append("/");
3311 path
.append(Src
).append("_").append(StripEpoch(SrcVersion
));
3312 // we omit component for releases without one (= flat-style repositories)
3313 if (Component
!= NULL
&& strlen(Component
) != 0)
3314 path
= std::string(Component
) + "/" + path
;
3316 return SubstVar(Template
, "@CHANGEPATH@", path
);
3319 // AcqChangelog::Failed - Failure handler /*{{{*/
3320 void pkgAcqChangelog::Failed(string
const &Message
, pkgAcquire::MethodConfig
const * const Cnf
)
3322 Item::Failed(Message
,Cnf
);
3324 std::string errText
;
3325 // TRANSLATOR: %s=%s is sourcename=sourceversion, e.g. apt=1.1
3326 strprintf(errText
, _("Changelog unavailable for %s=%s"), SrcName
.c_str(), SrcVersion
.c_str());
3328 // Error is probably something techy like 404 Not Found
3329 if (ErrorText
.empty())
3330 ErrorText
= errText
;
3332 ErrorText
= errText
+ " (" + ErrorText
+ ")";
3335 // AcqChangelog::Done - Item downloaded OK /*{{{*/
3336 void pkgAcqChangelog::Done(string
const &Message
,HashStringList
const &CalcHashes
,
3337 pkgAcquire::MethodConfig
const * const Cnf
)
3339 Item::Done(Message
,CalcHashes
,Cnf
);
3340 if (d
->FinalFile
.empty() == false)
3342 if (RemoveFile("pkgAcqChangelog::Done", d
->FinalFile
) == false ||
3343 Rename(DestFile
, d
->FinalFile
) == false)
3350 pkgAcqChangelog::~pkgAcqChangelog() /*{{{*/
3352 if (TemporaryDirectory
.empty() == false)
3354 RemoveFile("~pkgAcqChangelog", DestFile
);
3355 rmdir(TemporaryDirectory
.c_str());
3361 // AcqFile::pkgAcqFile - Constructor /*{{{*/
3362 pkgAcqFile::pkgAcqFile(pkgAcquire
* const Owner
,string
const &URI
, HashStringList
const &Hashes
,
3363 unsigned long long const Size
,string
const &Dsc
,string
const &ShortDesc
,
3364 const string
&DestDir
, const string
&DestFilename
,
3365 bool const IsIndexFile
) :
3366 Item(Owner
), d(NULL
), IsIndexFile(IsIndexFile
), ExpectedHashes(Hashes
)
3368 Retries
= _config
->FindI("Acquire::Retries",0);
3370 if(!DestFilename
.empty())
3371 DestFile
= DestFilename
;
3372 else if(!DestDir
.empty())
3373 DestFile
= DestDir
+ "/" + flNotDir(URI
);
3375 DestFile
= flNotDir(URI
);
3379 Desc
.Description
= Dsc
;
3382 // Set the short description to the archive component
3383 Desc
.ShortDesc
= ShortDesc
;
3385 // Get the transfer sizes
3388 if (stat(DestFile
.c_str(),&Buf
) == 0)
3390 // Hmm, the partial file is too big, erase it
3391 if ((Size
> 0) && (unsigned long long)Buf
.st_size
> Size
)
3392 RemoveFile("pkgAcqFile", DestFile
);
3394 PartialSize
= Buf
.st_size
;
3400 // AcqFile::Done - Item downloaded OK /*{{{*/
3401 void pkgAcqFile::Done(string
const &Message
,HashStringList
const &CalcHashes
,
3402 pkgAcquire::MethodConfig
const * const Cnf
)
3404 Item::Done(Message
,CalcHashes
,Cnf
);
3406 std::string
const FileName
= LookupTag(Message
,"Filename");
3409 // The files timestamp matches
3410 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
3413 // We have to copy it into place
3414 if (RealFileExists(DestFile
.c_str()) == false)
3417 if (_config
->FindB("Acquire::Source-Symlinks",true) == false ||
3418 Cnf
->Removable
== true)
3420 Desc
.URI
= "copy:" + FileName
;
3425 // Erase the file if it is a symlink so we can overwrite it
3427 if (lstat(DestFile
.c_str(),&St
) == 0)
3429 if (S_ISLNK(St
.st_mode
) != 0)
3430 RemoveFile("pkgAcqFile::Done", DestFile
);
3434 if (symlink(FileName
.c_str(),DestFile
.c_str()) != 0)
3436 _error
->PushToStack();
3437 _error
->Errno("pkgAcqFile::Done", "Symlinking file %s failed", DestFile
.c_str());
3438 std::stringstream msg
;
3439 _error
->DumpErrors(msg
, GlobalError::DEBUG
, false);
3440 _error
->RevertToStack();
3441 ErrorText
= msg
.str();
3448 // AcqFile::Failed - Failure handler /*{{{*/
3449 // ---------------------------------------------------------------------
3450 /* Here we try other sources */
3451 void pkgAcqFile::Failed(string
const &Message
, pkgAcquire::MethodConfig
const * const Cnf
)
3453 Item::Failed(Message
,Cnf
);
3455 // This is the retry counter
3457 Cnf
->LocalOnly
== false &&
3458 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
3468 string
pkgAcqFile::Custom600Headers() const /*{{{*/
3471 return "\nIndex-File: true";
3475 pkgAcqFile::~pkgAcqFile() {}