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 if (TransactionManager
->State
!= TransactionStarted
)
286 if (_config
->FindB("Debug::Acquire::Transaction", false))
287 std::clog
<< "Skip " << Target
.URI
<< " as transaction was already dealt with!" << std::endl
;
290 std::string
const FinalFile
= GetFinalFilename();
291 if (TransactionManager
!= NULL
&& TransactionManager
->IMSHit
== true &&
292 FileExists(FinalFile
) == true)
294 PartialFile
= DestFile
= FinalFile
;
298 return pkgAcquire::Item::QueueURI(Item
);
300 /* The transition manager InRelease itself (or its older sisters-in-law
301 Release & Release.gpg) is always queued as this allows us to rerun gpgv
302 on it to verify that we aren't stalled with old files */
303 bool pkgAcqMetaBase::QueueURI(pkgAcquire::ItemDesc
&Item
)
305 return pkgAcquire::Item::QueueURI(Item
);
307 /* the Diff/Index needs to queue also the up-to-date complete index file
308 to ensure that the list cleaner isn't eating it */
309 bool pkgAcqDiffIndex::QueueURI(pkgAcquire::ItemDesc
&Item
)
311 if (pkgAcqTransactionItem::QueueURI(Item
) == true)
317 // Acquire::Item::GetFinalFilename and specialisations for child classes /*{{{*/
318 std::string
pkgAcquire::Item::GetFinalFilename() const
320 // Beware: Desc.URI is modified by redirections
321 return GetFinalFileNameFromURI(Desc
.URI
);
323 std::string
pkgAcqDiffIndex::GetFinalFilename() const
325 return GetFinalFileNameFromURI(GetDiffIndexURI(Target
));
327 std::string
pkgAcqIndex::GetFinalFilename() const
329 std::string
const FinalFile
= GetFinalFileNameFromURI(Target
.URI
);
330 return GetKeepCompressedFileName(FinalFile
, Target
);
332 std::string
pkgAcqMetaSig::GetFinalFilename() const
334 return GetFinalFileNameFromURI(Target
.URI
);
336 std::string
pkgAcqBaseIndex::GetFinalFilename() const
338 return GetFinalFileNameFromURI(Target
.URI
);
340 std::string
pkgAcqMetaBase::GetFinalFilename() const
342 return GetFinalFileNameFromURI(Target
.URI
);
344 std::string
pkgAcqArchive::GetFinalFilename() const
346 return _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
349 // pkgAcqTransactionItem::GetMetaKey and specialisations for child classes /*{{{*/
350 std::string
pkgAcqTransactionItem::GetMetaKey() const
352 return Target
.MetaKey
;
354 std::string
pkgAcqIndex::GetMetaKey() const
356 if (Stage
== STAGE_DECOMPRESS_AND_VERIFY
|| CurrentCompressionExtension
== "uncompressed")
357 return Target
.MetaKey
;
358 return Target
.MetaKey
+ "." + CurrentCompressionExtension
;
360 std::string
pkgAcqDiffIndex::GetMetaKey() const
362 return GetDiffIndexFileName(Target
.MetaKey
);
365 //pkgAcqTransactionItem::TransactionState and specialisations for child classes /*{{{*/
366 bool pkgAcqTransactionItem::TransactionState(TransactionStates
const state
)
368 bool const Debug
= _config
->FindB("Debug::Acquire::Transaction", false);
371 case TransactionStarted
: _error
->Fatal("Item %s changed to invalid transaction start state!", Target
.URI
.c_str()); break;
372 case TransactionAbort
:
374 std::clog
<< " Cancel: " << DestFile
<< std::endl
;
375 if (Status
== pkgAcquire::Item::StatIdle
)
377 Status
= pkgAcquire::Item::StatDone
;
381 case TransactionCommit
:
382 if(PartialFile
.empty() == false)
384 bool sameFile
= (PartialFile
== DestFile
);
385 // we use symlinks on IMS-Hit to avoid copies
386 if (RealFileExists(DestFile
))
389 if (lstat(PartialFile
.c_str(), &Buf
) != -1)
391 if (S_ISLNK(Buf
.st_mode
) && Buf
.st_size
> 0)
393 char partial
[Buf
.st_size
+ 1];
394 ssize_t
const sp
= readlink(PartialFile
.c_str(), partial
, Buf
.st_size
);
396 _error
->Errno("pkgAcqTransactionItem::TransactionState-sp", _("Failed to readlink %s"), PartialFile
.c_str());
400 sameFile
= (DestFile
== partial
);
405 _error
->Errno("pkgAcqTransactionItem::TransactionState-stat", _("Failed to stat %s"), PartialFile
.c_str());
407 if (sameFile
== false)
409 // ensure that even without lists-cleanup all compressions are nuked
410 std::string FinalFile
= GetFinalFileNameFromURI(Target
.URI
);
411 if (FileExists(FinalFile
))
414 std::clog
<< "rm " << FinalFile
<< " # " << DescURI() << std::endl
;
415 if (RemoveFile("TransactionStates-Cleanup", FinalFile
) == false)
418 for (auto const &ext
: APT::Configuration::getCompressorExtensions())
420 auto const Final
= FinalFile
+ ext
;
421 if (FileExists(Final
))
424 std::clog
<< "rm " << Final
<< " # " << DescURI() << std::endl
;
425 if (RemoveFile("TransactionStates-Cleanup", Final
) == false)
430 std::clog
<< "mv " << PartialFile
<< " -> "<< DestFile
<< " # " << DescURI() << std::endl
;
431 if (Rename(PartialFile
, DestFile
) == false)
434 else if(Debug
== true)
435 std::clog
<< "keep " << PartialFile
<< " # " << DescURI() << std::endl
;
439 std::clog
<< "rm " << DestFile
<< " # " << DescURI() << std::endl
;
440 if (RemoveFile("TransItem::TransactionCommit", DestFile
) == false)
447 bool pkgAcqMetaBase::TransactionState(TransactionStates
const state
)
449 // Do not remove InRelease on IMSHit of Release.gpg [yes, this is very edgecasey]
450 if (TransactionManager
->IMSHit
== false)
451 return pkgAcqTransactionItem::TransactionState(state
);
454 bool pkgAcqIndex::TransactionState(TransactionStates
const state
)
456 if (pkgAcqTransactionItem::TransactionState(state
) == false)
461 case TransactionStarted
: _error
->Fatal("AcqIndex %s changed to invalid transaction start state!", Target
.URI
.c_str()); break;
462 case TransactionAbort
:
463 if (Stage
== STAGE_DECOMPRESS_AND_VERIFY
)
465 // keep the compressed file, but drop the decompressed
466 EraseFileName
.clear();
467 if (PartialFile
.empty() == false && flExtension(PartialFile
) != CurrentCompressionExtension
)
468 RemoveFile("TransactionAbort", PartialFile
);
471 case TransactionCommit
:
472 if (EraseFileName
.empty() == false)
473 RemoveFile("AcqIndex::TransactionCommit", EraseFileName
);
478 bool pkgAcqDiffIndex::TransactionState(TransactionStates
const state
)
480 if (pkgAcqTransactionItem::TransactionState(state
) == false)
485 case TransactionStarted
: _error
->Fatal("Item %s changed to invalid transaction start state!", Target
.URI
.c_str()); break;
486 case TransactionCommit
:
488 case TransactionAbort
:
489 std::string
const Partial
= GetPartialFileNameFromURI(Target
.URI
);
490 RemoveFile("TransactionAbort", Partial
);
498 class APT_HIDDEN NoActionItem
: public pkgAcquire::Item
/*{{{*/
499 /* The sole purpose of this class is having an item which does nothing to
500 reach its done state to prevent cleanup deleting the mentioned file.
501 Handy in cases in which we know we have the file already, like IMS-Hits. */
503 IndexTarget
const Target
;
505 virtual std::string
DescURI() const APT_OVERRIDE
{return Target
.URI
;};
506 virtual HashStringList
GetExpectedHashes() const APT_OVERRIDE
{return HashStringList();};
508 NoActionItem(pkgAcquire
* const Owner
, IndexTarget
const &Target
) :
509 pkgAcquire::Item(Owner
), Target(Target
)
512 DestFile
= GetFinalFileNameFromURI(Target
.URI
);
514 NoActionItem(pkgAcquire
* const Owner
, IndexTarget
const &Target
, std::string
const &FinalFile
) :
515 pkgAcquire::Item(Owner
), Target(Target
)
518 DestFile
= FinalFile
;
522 class APT_HIDDEN CleanupItem
: public pkgAcqTransactionItem
/*{{{*/
523 /* This class ensures that a file which was configured but isn't downloaded
524 for various reasons isn't kept in an old version in the lists directory.
525 In a way its the reverse of NoActionItem as it helps with removing files
526 even if the lists-cleanup is deactivated. */
529 virtual std::string
DescURI() const APT_OVERRIDE
{return Target
.URI
;};
530 virtual HashStringList
GetExpectedHashes() const APT_OVERRIDE
{return HashStringList();};
532 CleanupItem(pkgAcquire
* const Owner
, pkgAcqMetaClearSig
* const TransactionManager
, IndexTarget
const &Target
) :
533 pkgAcqTransactionItem(Owner
, TransactionManager
, Target
)
536 DestFile
= GetFinalFileNameFromURI(Target
.URI
);
538 bool TransactionState(TransactionStates
const state
) APT_OVERRIDE
542 case TransactionStarted
:
544 case TransactionAbort
:
546 case TransactionCommit
:
547 if (_config
->FindB("Debug::Acquire::Transaction", false) == true)
548 std::clog
<< "rm " << DestFile
<< " # " << DescURI() << std::endl
;
549 if (RemoveFile("TransItem::TransactionCommit", DestFile
) == false)
558 // Acquire::Item::Item - Constructor /*{{{*/
559 APT_IGNORE_DEPRECATED_PUSH
560 pkgAcquire::Item::Item(pkgAcquire
* const owner
) :
561 FileSize(0), PartialSize(0), Mode(0), ID(0), Complete(false), Local(false),
562 QueueCounter(0), ExpectedAdditionalItems(0), Owner(owner
), d(NULL
)
567 APT_IGNORE_DEPRECATED_POP
569 // Acquire::Item::~Item - Destructor /*{{{*/
570 pkgAcquire::Item::~Item()
575 std::string
pkgAcquire::Item::Custom600Headers() const /*{{{*/
577 return std::string();
580 std::string
pkgAcquire::Item::ShortDesc() const /*{{{*/
585 APT_CONST
void pkgAcquire::Item::Finished() /*{{{*/
589 APT_PURE pkgAcquire
* pkgAcquire::Item::GetOwner() const /*{{{*/
594 APT_CONST
pkgAcquire::ItemDesc
&pkgAcquire::Item::GetItemDesc() /*{{{*/
599 APT_CONST
bool pkgAcquire::Item::IsTrusted() const /*{{{*/
604 // Acquire::Item::Failed - Item failed to download /*{{{*/
605 // ---------------------------------------------------------------------
606 /* We return to an idle state if there are still other queues that could
608 void pkgAcquire::Item::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)
610 if(ErrorText
.empty())
611 ErrorText
= LookupTag(Message
,"Message");
612 if (QueueCounter
<= 1)
614 /* This indicates that the file is not available right now but might
615 be sometime later. If we do a retry cycle then this should be
617 if (Cnf
!= NULL
&& Cnf
->LocalOnly
== true &&
618 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
634 case StatTransientNetworkError
:
641 string
const FailReason
= LookupTag(Message
, "FailReason");
642 if (FailReason
== "MaximumSizeExceeded")
643 RenameOnError(MaximumSizeExceeded
);
644 else if (Status
== StatAuthError
)
645 RenameOnError(HashSumMismatch
);
647 // report mirror failure back to LP if we actually use a mirror
648 if (FailReason
.empty() == false)
649 ReportMirrorFailure(FailReason
);
651 ReportMirrorFailure(ErrorText
);
653 if (QueueCounter
> 1)
657 // Acquire::Item::Start - Item has begun to download /*{{{*/
658 // ---------------------------------------------------------------------
659 /* Stash status and the file size. Note that setting Complete means
660 sub-phases of the acquire process such as decompresion are operating */
661 void pkgAcquire::Item::Start(string
const &/*Message*/, unsigned long long const Size
)
663 Status
= StatFetching
;
665 if (FileSize
== 0 && Complete
== false)
669 // Acquire::Item::VerifyDone - check if Item was downloaded OK /*{{{*/
670 /* Note that hash-verification is 'hardcoded' in acquire-worker and has
671 * already passed if this method is called. */
672 bool pkgAcquire::Item::VerifyDone(std::string
const &Message
,
673 pkgAcquire::MethodConfig
const * const /*Cnf*/)
675 std::string
const FileName
= LookupTag(Message
,"Filename");
676 if (FileName
.empty() == true)
679 ErrorText
= "Method gave a blank filename";
686 // Acquire::Item::Done - Item downloaded OK /*{{{*/
687 void pkgAcquire::Item::Done(string
const &/*Message*/, HashStringList
const &Hashes
,
688 pkgAcquire::MethodConfig
const * const /*Cnf*/)
690 // We just downloaded something..
693 unsigned long long const downloadedSize
= Hashes
.FileSize();
694 if (downloadedSize
!= 0)
696 FileSize
= downloadedSize
;
700 ErrorText
= string();
701 Owner
->Dequeue(this);
704 // Acquire::Item::Rename - Rename a file /*{{{*/
705 // ---------------------------------------------------------------------
706 /* This helper function is used by a lot of item methods as their final
708 bool pkgAcquire::Item::Rename(string
const &From
,string
const &To
)
710 if (From
== To
|| rename(From
.c_str(),To
.c_str()) == 0)
714 strprintf(S
, _("rename failed, %s (%s -> %s)."), strerror(errno
),
715 From
.c_str(),To
.c_str());
717 if (ErrorText
.empty())
720 ErrorText
= ErrorText
+ ": " + S
;
724 void pkgAcquire::Item::Dequeue() /*{{{*/
726 Owner
->Dequeue(this);
729 bool pkgAcquire::Item::RenameOnError(pkgAcquire::Item::RenameOnErrorState
const error
)/*{{{*/
731 if (RealFileExists(DestFile
))
732 Rename(DestFile
, DestFile
+ ".FAILED");
737 case HashSumMismatch
:
738 errtext
= _("Hash Sum mismatch");
739 Status
= StatAuthError
;
740 ReportMirrorFailure("HashChecksumFailure");
743 errtext
= _("Size mismatch");
744 Status
= StatAuthError
;
745 ReportMirrorFailure("SizeFailure");
748 errtext
= _("Invalid file format");
750 // do not report as usually its not the mirrors fault, but Portal/Proxy
753 errtext
= _("Signature error");
757 strprintf(errtext
, _("Clearsigned file isn't valid, got '%s' (does the network require authentication?)"), "NOSPLIT");
758 Status
= StatAuthError
;
760 case MaximumSizeExceeded
:
761 // the method is expected to report a good error for this
765 // no handling here, done by callers
768 if (ErrorText
.empty())
773 void pkgAcquire::Item::SetActiveSubprocess(const std::string
&subprocess
)/*{{{*/
775 ActiveSubprocess
= subprocess
;
776 APT_IGNORE_DEPRECATED(Mode
= ActiveSubprocess
.c_str();)
779 // Acquire::Item::ReportMirrorFailure /*{{{*/
780 void pkgAcquire::Item::ReportMirrorFailure(string
const &FailCode
)
782 // we only act if a mirror was used at all
783 if(UsedMirror
.empty())
786 std::cerr
<< "\nReportMirrorFailure: "
788 << " Uri: " << DescURI()
790 << FailCode
<< std::endl
;
792 string report
= _config
->Find("Methods::Mirror::ProblemReporting",
793 "/usr/lib/apt/apt-report-mirror-failure");
794 if(!FileExists(report
))
797 std::vector
<char const*> Args
;
798 Args
.push_back(report
.c_str());
799 Args
.push_back(UsedMirror
.c_str());
800 Args
.push_back(DescURI().c_str());
801 Args
.push_back(FailCode
.c_str());
802 Args
.push_back(NULL
);
804 pid_t pid
= ExecFork();
807 _error
->Error("ReportMirrorFailure Fork failed");
812 execvp(Args
[0], (char**)Args
.data());
813 std::cerr
<< "Could not exec " << Args
[0] << std::endl
;
816 if(!ExecWait(pid
, "report-mirror-failure"))
818 _error
->Warning("Couldn't report problem to '%s'",
819 _config
->Find("Methods::Mirror::ProblemReporting").c_str());
823 std::string
pkgAcquire::Item::HashSum() const /*{{{*/
825 HashStringList
const hashes
= GetExpectedHashes();
826 HashString
const * const hs
= hashes
.find(NULL
);
827 return hs
!= NULL
? hs
->toStr() : "";
831 pkgAcqTransactionItem::pkgAcqTransactionItem(pkgAcquire
* const Owner
, /*{{{*/
832 pkgAcqMetaClearSig
* const transactionManager
, IndexTarget
const &target
) :
833 pkgAcquire::Item(Owner
), d(NULL
), Target(target
), TransactionManager(transactionManager
)
835 if (TransactionManager
!= this)
836 TransactionManager
->Add(this);
839 pkgAcqTransactionItem::~pkgAcqTransactionItem() /*{{{*/
843 HashStringList
pkgAcqTransactionItem::GetExpectedHashesFor(std::string
const &MetaKey
) const /*{{{*/
845 return GetExpectedHashesFromFor(TransactionManager
->MetaIndexParser
, MetaKey
);
849 static void LoadLastMetaIndexParser(pkgAcqMetaClearSig
* const TransactionManager
, std::string
const &FinalRelease
, std::string
const &FinalInRelease
)/*{{{*/
851 if (TransactionManager
->IMSHit
== true)
853 if (RealFileExists(FinalInRelease
) || RealFileExists(FinalRelease
))
855 TransactionManager
->LastMetaIndexParser
= TransactionManager
->MetaIndexParser
->UnloadedClone();
856 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
858 _error
->PushToStack();
859 if (RealFileExists(FinalInRelease
))
860 TransactionManager
->LastMetaIndexParser
->Load(FinalInRelease
, NULL
);
862 TransactionManager
->LastMetaIndexParser
->Load(FinalRelease
, NULL
);
863 // its unlikely to happen, but if what we have is bad ignore it
864 if (_error
->PendingError())
866 delete TransactionManager
->LastMetaIndexParser
;
867 TransactionManager
->LastMetaIndexParser
= NULL
;
869 _error
->RevertToStack();
875 // AcqMetaBase - Constructor /*{{{*/
876 pkgAcqMetaBase::pkgAcqMetaBase(pkgAcquire
* const Owner
,
877 pkgAcqMetaClearSig
* const TransactionManager
,
878 std::vector
<IndexTarget
> const &IndexTargets
,
879 IndexTarget
const &DataTarget
)
880 : pkgAcqTransactionItem(Owner
, TransactionManager
, DataTarget
), d(NULL
),
881 IndexTargets(IndexTargets
),
882 AuthPass(false), IMSHit(false), State(TransactionStarted
)
886 // AcqMetaBase::Add - Add a item to the current Transaction /*{{{*/
887 void pkgAcqMetaBase::Add(pkgAcqTransactionItem
* const I
)
889 Transaction
.push_back(I
);
892 // AcqMetaBase::AbortTransaction - Abort the current Transaction /*{{{*/
893 void pkgAcqMetaBase::AbortTransaction()
895 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
896 std::clog
<< "AbortTransaction: " << TransactionManager
<< std::endl
;
898 switch (TransactionManager
->State
)
900 case TransactionStarted
: break;
901 case TransactionAbort
: _error
->Fatal("Transaction %s was already aborted and is aborted again", TransactionManager
->Target
.URI
.c_str()); return;
902 case TransactionCommit
: _error
->Fatal("Transaction %s was already aborted and is now commited", TransactionManager
->Target
.URI
.c_str()); return;
904 TransactionManager
->State
= TransactionAbort
;
906 // ensure the toplevel is in error state too
907 for (std::vector
<pkgAcqTransactionItem
*>::iterator I
= Transaction
.begin();
908 I
!= Transaction
.end(); ++I
)
910 if ((*I
)->Status
!= pkgAcquire::Item::StatFetching
)
912 (*I
)->TransactionState(TransactionAbort
);
917 // AcqMetaBase::TransactionHasError - Check for errors in Transaction /*{{{*/
918 APT_PURE
bool pkgAcqMetaBase::TransactionHasError() const
920 for (std::vector
<pkgAcqTransactionItem
*>::const_iterator I
= Transaction
.begin();
921 I
!= Transaction
.end(); ++I
)
923 switch((*I
)->Status
) {
924 case StatDone
: break;
925 case StatIdle
: break;
926 case StatAuthError
: return true;
927 case StatError
: return true;
928 case StatTransientNetworkError
: return true;
929 case StatFetching
: break;
935 // AcqMetaBase::CommitTransaction - Commit a transaction /*{{{*/
936 void pkgAcqMetaBase::CommitTransaction()
938 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
939 std::clog
<< "CommitTransaction: " << this << std::endl
;
941 switch (TransactionManager
->State
)
943 case TransactionStarted
: break;
944 case TransactionAbort
: _error
->Fatal("Transaction %s was already commited and is now aborted", TransactionManager
->Target
.URI
.c_str()); return;
945 case TransactionCommit
: _error
->Fatal("Transaction %s was already commited and is again commited", TransactionManager
->Target
.URI
.c_str()); return;
947 TransactionManager
->State
= TransactionCommit
;
949 // move new files into place *and* remove files that are not
950 // part of the transaction but are still on disk
951 for (std::vector
<pkgAcqTransactionItem
*>::iterator I
= Transaction
.begin();
952 I
!= Transaction
.end(); ++I
)
954 (*I
)->TransactionState(TransactionCommit
);
959 // AcqMetaBase::TransactionStageCopy - Stage a file for copying /*{{{*/
960 void pkgAcqMetaBase::TransactionStageCopy(pkgAcqTransactionItem
* const I
,
961 const std::string
&From
,
962 const std::string
&To
)
964 I
->PartialFile
= From
;
968 // AcqMetaBase::TransactionStageRemoval - Stage a file for removal /*{{{*/
969 void pkgAcqMetaBase::TransactionStageRemoval(pkgAcqTransactionItem
* const I
,
970 const std::string
&FinalFile
)
973 I
->DestFile
= FinalFile
;
976 // AcqMetaBase::GenerateAuthWarning - Check gpg authentication error /*{{{*/
977 bool pkgAcqMetaBase::CheckStopAuthentication(pkgAcquire::Item
* const I
, const std::string
&Message
)
979 // FIXME: this entire function can do now that we disallow going to
980 // a unauthenticated state and can cleanly rollback
982 string
const Final
= I
->GetFinalFilename();
983 if(FileExists(Final
))
985 I
->Status
= StatTransientNetworkError
;
986 _error
->Warning(_("An error occurred during the signature "
987 "verification. The repository is not updated "
988 "and the previous index files will be used. "
989 "GPG error: %s: %s"),
990 Desc
.Description
.c_str(),
991 LookupTag(Message
,"Message").c_str());
992 RunScripts("APT::Update::Auth-Failure");
994 } else if (LookupTag(Message
,"Message").find("NODATA") != string::npos
) {
995 /* Invalid signature file, reject (LP: #346386) (Closes: #627642) */
996 _error
->Error(_("GPG error: %s: %s"),
997 Desc
.Description
.c_str(),
998 LookupTag(Message
,"Message").c_str());
999 I
->Status
= StatAuthError
;
1002 _error
->Warning(_("GPG error: %s: %s"),
1003 Desc
.Description
.c_str(),
1004 LookupTag(Message
,"Message").c_str());
1006 // gpgv method failed
1007 ReportMirrorFailure("GPGFailure");
1011 // AcqMetaBase::Custom600Headers - Get header for AcqMetaBase /*{{{*/
1012 // ---------------------------------------------------------------------
1013 string
pkgAcqMetaBase::Custom600Headers() const
1015 std::string Header
= "\nIndex-File: true";
1016 std::string MaximumSize
;
1017 strprintf(MaximumSize
, "\nMaximum-Size: %i",
1018 _config
->FindI("Acquire::MaxReleaseFileSize", 10*1000*1000));
1019 Header
+= MaximumSize
;
1021 string
const FinalFile
= GetFinalFilename();
1023 if (stat(FinalFile
.c_str(),&Buf
) == 0)
1024 Header
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1029 // AcqMetaBase::QueueForSignatureVerify /*{{{*/
1030 void pkgAcqMetaBase::QueueForSignatureVerify(pkgAcqTransactionItem
* const I
, std::string
const &File
, std::string
const &Signature
)
1033 I
->Desc
.URI
= "gpgv:" + Signature
;
1036 I
->SetActiveSubprocess("gpgv");
1039 // AcqMetaBase::CheckDownloadDone /*{{{*/
1040 bool pkgAcqMetaBase::CheckDownloadDone(pkgAcqTransactionItem
* const I
, const std::string
&Message
, HashStringList
const &Hashes
) const
1042 // We have just finished downloading a Release file (it is not
1045 std::string
const FileName
= LookupTag(Message
,"Filename");
1046 if (FileName
!= I
->DestFile
&& RealFileExists(I
->DestFile
) == false)
1049 I
->Desc
.URI
= "copy:" + FileName
;
1050 I
->QueueURI(I
->Desc
);
1054 // make sure to verify against the right file on I-M-S hit
1055 bool IMSHit
= StringToBool(LookupTag(Message
,"IMS-Hit"), false);
1056 if (IMSHit
== false && Hashes
.usable())
1058 // detect IMS-Hits servers haven't detected by Hash comparison
1059 std::string
const FinalFile
= I
->GetFinalFilename();
1060 if (RealFileExists(FinalFile
) && Hashes
.VerifyFile(FinalFile
) == true)
1063 RemoveFile("CheckDownloadDone", I
->DestFile
);
1069 // for simplicity, the transaction manager is always InRelease
1070 // even if it doesn't exist.
1071 if (TransactionManager
!= NULL
)
1072 TransactionManager
->IMSHit
= true;
1073 I
->PartialFile
= I
->DestFile
= I
->GetFinalFilename();
1076 // set Item to complete as the remaining work is all local (verify etc)
1082 bool pkgAcqMetaBase::CheckAuthDone(string
const &Message
) /*{{{*/
1084 // At this point, the gpgv method has succeeded, so there is a
1085 // valid signature from a key in the trusted keyring. We
1086 // perform additional verification of its contents, and use them
1087 // to verify the indexes we are about to download
1089 if (TransactionManager
->IMSHit
== false)
1091 // open the last (In)Release if we have it
1092 std::string
const FinalFile
= GetFinalFilename();
1093 std::string FinalRelease
;
1094 std::string FinalInRelease
;
1095 if (APT::String::Endswith(FinalFile
, "InRelease"))
1097 FinalInRelease
= FinalFile
;
1098 FinalRelease
= FinalFile
.substr(0, FinalFile
.length() - strlen("InRelease")) + "Release";
1102 FinalInRelease
= FinalFile
.substr(0, FinalFile
.length() - strlen("Release")) + "InRelease";
1103 FinalRelease
= FinalFile
;
1105 LoadLastMetaIndexParser(TransactionManager
, FinalRelease
, FinalInRelease
);
1108 if (TransactionManager
->MetaIndexParser
->Load(DestFile
, &ErrorText
) == false)
1110 Status
= StatAuthError
;
1114 if (!VerifyVendor(Message
))
1116 Status
= StatAuthError
;
1120 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1121 std::cerr
<< "Signature verification succeeded: "
1122 << DestFile
<< std::endl
;
1124 // Download further indexes with verification
1130 void pkgAcqMetaBase::QueueIndexes(bool const verify
) /*{{{*/
1132 // at this point the real Items are loaded in the fetcher
1133 ExpectedAdditionalItems
= 0;
1135 bool metaBaseSupportsByHash
= false;
1136 if (TransactionManager
!= NULL
&& TransactionManager
->MetaIndexParser
!= NULL
)
1137 metaBaseSupportsByHash
= TransactionManager
->MetaIndexParser
->GetSupportsAcquireByHash();
1139 for (std::vector
<IndexTarget
>::iterator Target
= IndexTargets
.begin();
1140 Target
!= IndexTargets
.end();
1143 // all is an implementation detail. Users shouldn't use this as arch
1144 // We need this support trickery here as e.g. Debian has binary-all files already,
1145 // but arch:all packages are still in the arch:any files, so we would waste precious
1146 // download time, bandwidth and diskspace for nothing, BUT Debian doesn't feature all
1147 // in the set of supported architectures, so we can filter based on this property rather
1148 // than invent an entirely new flag we would need to carry for all of eternity.
1149 if (Target
->Option(IndexTarget::ARCHITECTURE
) == "all")
1151 if (TransactionManager
->MetaIndexParser
->IsArchitectureSupported("all") == false ||
1152 TransactionManager
->MetaIndexParser
->IsArchitectureAllSupportedFor(*Target
) == false)
1154 new CleanupItem(Owner
, TransactionManager
, *Target
);
1159 bool trypdiff
= Target
->OptionBool(IndexTarget::PDIFFS
);
1162 if (TransactionManager
->MetaIndexParser
->Exists(Target
->MetaKey
) == false)
1164 // optional targets that we do not have in the Release file are skipped
1165 if (Target
->IsOptional
)
1167 new CleanupItem(Owner
, TransactionManager
, *Target
);
1171 std::string
const &arch
= Target
->Option(IndexTarget::ARCHITECTURE
);
1172 if (arch
.empty() == false)
1174 if (TransactionManager
->MetaIndexParser
->IsArchitectureSupported(arch
) == false)
1176 new CleanupItem(Owner
, TransactionManager
, *Target
);
1177 _error
->Notice(_("Skipping acquire of configured file '%s' as repository '%s' doesn't support architecture '%s'"),
1178 Target
->MetaKey
.c_str(), TransactionManager
->Target
.Description
.c_str(), arch
.c_str());
1181 // if the architecture is officially supported but currently no packages for it available,
1182 // ignore silently as this is pretty much the same as just shipping an empty file.
1183 // if we don't know which architectures are supported, we do NOT ignore it to notify user about this
1184 if (TransactionManager
->MetaIndexParser
->IsArchitectureSupported("*undefined*") == false)
1186 new CleanupItem(Owner
, TransactionManager
, *Target
);
1191 Status
= StatAuthError
;
1192 strprintf(ErrorText
, _("Unable to find expected entry '%s' in Release file (Wrong sources.list entry or malformed file)"), Target
->MetaKey
.c_str());
1197 auto const hashes
= GetExpectedHashesFor(Target
->MetaKey
);
1198 if (hashes
.empty() == false)
1200 if (hashes
.usable() == false)
1202 new CleanupItem(Owner
, TransactionManager
, *Target
);
1203 _error
->Warning(_("Skipping acquire of configured file '%s' as repository '%s' provides only weak security information for it"),
1204 Target
->MetaKey
.c_str(), TransactionManager
->Target
.Description
.c_str());
1207 // empty files are skipped as acquiring the very small compressed files is a waste of time
1208 else if (hashes
.FileSize() == 0)
1210 new CleanupItem(Owner
, TransactionManager
, *Target
);
1216 // autoselect the compression method
1217 std::vector
<std::string
> types
= VectorizeString(Target
->Option(IndexTarget::COMPRESSIONTYPES
), ' ');
1218 types
.erase(std::remove_if(types
.begin(), types
.end(), [&](std::string
const &t
) {
1219 if (t
== "uncompressed")
1220 return TransactionManager
->MetaIndexParser
->Exists(Target
->MetaKey
) == false;
1221 std::string
const MetaKey
= Target
->MetaKey
+ "." + t
;
1222 return TransactionManager
->MetaIndexParser
->Exists(MetaKey
) == false;
1224 if (types
.empty() == false)
1226 std::ostringstream os
;
1227 // add the special compressiontype byhash first if supported
1228 std::string
const useByHashConf
= Target
->Option(IndexTarget::BY_HASH
);
1229 bool useByHash
= false;
1230 if(useByHashConf
== "force")
1233 useByHash
= StringToBool(useByHashConf
) == true && metaBaseSupportsByHash
;
1234 if (useByHash
== true)
1236 std::copy(types
.begin(), types
.end()-1, std::ostream_iterator
<std::string
>(os
, " "));
1237 os
<< *types
.rbegin();
1238 Target
->Options
["COMPRESSIONTYPES"] = os
.str();
1241 Target
->Options
["COMPRESSIONTYPES"].clear();
1243 std::string filename
= GetExistingFilename(GetFinalFileNameFromURI(Target
->URI
));
1244 if (filename
.empty() == false)
1246 // if the Release file is a hit and we have an index it must be the current one
1247 if (TransactionManager
->IMSHit
== true)
1249 else if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1251 // see if the file changed since the last Release file
1252 // we use the uncompressed files as we might compress differently compared to the server,
1253 // so the hashes might not match, even if they contain the same data.
1254 HashStringList
const newFile
= GetExpectedHashesFromFor(TransactionManager
->MetaIndexParser
, Target
->MetaKey
);
1255 HashStringList
const oldFile
= GetExpectedHashesFromFor(TransactionManager
->LastMetaIndexParser
, Target
->MetaKey
);
1256 if (newFile
!= oldFile
)
1263 trypdiff
= false; // no file to patch
1265 if (filename
.empty() == false)
1267 new NoActionItem(Owner
, *Target
, filename
);
1268 std::string
const idxfilename
= GetFinalFileNameFromURI(GetDiffIndexURI(*Target
));
1269 if (FileExists(idxfilename
))
1270 new NoActionItem(Owner
, *Target
, idxfilename
);
1274 // check if we have patches available
1275 trypdiff
&= TransactionManager
->MetaIndexParser
->Exists(GetDiffIndexFileName(Target
->MetaKey
));
1279 // if we have no file to patch, no point in trying
1280 trypdiff
&= (GetExistingFilename(GetFinalFileNameFromURI(Target
->URI
)).empty() == false);
1283 // no point in patching from local sources
1286 std::string
const proto
= Target
->URI
.substr(0, strlen("file:/"));
1287 if (proto
== "file:/" || proto
== "copy:/" || proto
== "cdrom:")
1291 // Queue the Index file (Packages, Sources, Translation-$foo, …)
1293 new pkgAcqDiffIndex(Owner
, TransactionManager
, *Target
);
1295 new pkgAcqIndex(Owner
, TransactionManager
, *Target
);
1299 bool pkgAcqMetaBase::VerifyVendor(string
const &) /*{{{*/
1301 string Transformed
= TransactionManager
->MetaIndexParser
->GetExpectedDist();
1303 if (Transformed
== "../project/experimental")
1305 Transformed
= "experimental";
1308 auto pos
= Transformed
.rfind('/');
1309 if (pos
!= string::npos
)
1311 Transformed
= Transformed
.substr(0, pos
);
1314 if (Transformed
== ".")
1319 if (TransactionManager
->MetaIndexParser
->GetValidUntil() > 0)
1321 time_t const invalid_since
= time(NULL
) - TransactionManager
->MetaIndexParser
->GetValidUntil();
1322 if (invalid_since
> 0)
1326 // TRANSLATOR: The first %s is the URL of the bad Release file, the second is
1327 // the time since then the file is invalid - formatted in the same way as in
1328 // the download progress display (e.g. 7d 3h 42min 1s)
1329 _("Release file for %s is expired (invalid since %s). "
1330 "Updates for this repository will not be applied."),
1331 Target
.URI
.c_str(), TimeToStr(invalid_since
).c_str());
1332 if (ErrorText
.empty())
1334 return _error
->Error("%s", errmsg
.c_str());
1338 /* Did we get a file older than what we have? This is a last minute IMS hit and doubles
1339 as a prevention of downgrading us to older (still valid) files */
1340 if (TransactionManager
->IMSHit
== false && TransactionManager
->LastMetaIndexParser
!= NULL
&&
1341 TransactionManager
->LastMetaIndexParser
->GetDate() > TransactionManager
->MetaIndexParser
->GetDate())
1343 TransactionManager
->IMSHit
= true;
1344 RemoveFile("VerifyVendor", DestFile
);
1345 PartialFile
= DestFile
= GetFinalFilename();
1346 // load the 'old' file in the 'new' one instead of flipping pointers as
1347 // the new one isn't owned by us, while the old one is so cleanup would be confused.
1348 TransactionManager
->MetaIndexParser
->swapLoad(TransactionManager
->LastMetaIndexParser
);
1349 delete TransactionManager
->LastMetaIndexParser
;
1350 TransactionManager
->LastMetaIndexParser
= NULL
;
1353 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1355 std::cerr
<< "Got Codename: " << TransactionManager
->MetaIndexParser
->GetCodename() << std::endl
;
1356 std::cerr
<< "Expecting Dist: " << TransactionManager
->MetaIndexParser
->GetExpectedDist() << std::endl
;
1357 std::cerr
<< "Transformed Dist: " << Transformed
<< std::endl
;
1360 if (TransactionManager
->MetaIndexParser
->CheckDist(Transformed
) == false)
1362 // This might become fatal one day
1363 // Status = StatAuthError;
1364 // ErrorText = "Conflicting distribution; expected "
1365 // + MetaIndexParser->GetExpectedDist() + " but got "
1366 // + MetaIndexParser->GetCodename();
1368 if (!Transformed
.empty())
1370 _error
->Warning(_("Conflicting distribution: %s (expected %s but got %s)"),
1371 Desc
.Description
.c_str(),
1372 Transformed
.c_str(),
1373 TransactionManager
->MetaIndexParser
->GetCodename().c_str());
1380 pkgAcqMetaBase::~pkgAcqMetaBase()
1384 pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire
* const Owner
, /*{{{*/
1385 IndexTarget
const &ClearsignedTarget
,
1386 IndexTarget
const &DetachedDataTarget
, IndexTarget
const &DetachedSigTarget
,
1387 std::vector
<IndexTarget
> const &IndexTargets
,
1388 metaIndex
* const MetaIndexParser
) :
1389 pkgAcqMetaIndex(Owner
, this, ClearsignedTarget
, DetachedSigTarget
, IndexTargets
),
1390 d(NULL
), ClearsignedTarget(ClearsignedTarget
),
1391 DetachedDataTarget(DetachedDataTarget
),
1392 MetaIndexParser(MetaIndexParser
), LastMetaIndexParser(NULL
)
1394 // index targets + (worst case:) Release/Release.gpg
1395 ExpectedAdditionalItems
= IndexTargets
.size() + 2;
1396 TransactionManager
->Add(this);
1399 pkgAcqMetaClearSig::~pkgAcqMetaClearSig() /*{{{*/
1401 if (LastMetaIndexParser
!= NULL
)
1402 delete LastMetaIndexParser
;
1405 // pkgAcqMetaClearSig::Custom600Headers - Insert custom request headers /*{{{*/
1406 string
pkgAcqMetaClearSig::Custom600Headers() const
1408 string Header
= pkgAcqMetaBase::Custom600Headers();
1409 Header
+= "\nFail-Ignore: true";
1410 std::string
const key
= TransactionManager
->MetaIndexParser
->GetSignedBy();
1411 if (key
.empty() == false)
1412 Header
+= "\nSigned-By: " + key
;
1417 void pkgAcqMetaClearSig::Finished() /*{{{*/
1419 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1420 std::clog
<< "Finished: " << DestFile
<<std::endl
;
1421 if(TransactionManager
!= NULL
&& TransactionManager
->State
== TransactionStarted
&&
1422 TransactionManager
->TransactionHasError() == false)
1423 TransactionManager
->CommitTransaction();
1426 bool pkgAcqMetaClearSig::VerifyDone(std::string
const &Message
, /*{{{*/
1427 pkgAcquire::MethodConfig
const * const Cnf
)
1429 Item::VerifyDone(Message
, Cnf
);
1431 if (FileExists(DestFile
) && !StartsWithGPGClearTextSignature(DestFile
))
1432 return RenameOnError(NotClearsigned
);
1437 // pkgAcqMetaClearSig::Done - We got a file /*{{{*/
1438 void pkgAcqMetaClearSig::Done(std::string
const &Message
,
1439 HashStringList
const &Hashes
,
1440 pkgAcquire::MethodConfig
const * const Cnf
)
1442 Item::Done(Message
, Hashes
, Cnf
);
1444 if(AuthPass
== false)
1446 if(CheckDownloadDone(this, Message
, Hashes
) == true)
1447 QueueForSignatureVerify(this, DestFile
, DestFile
);
1450 else if(CheckAuthDone(Message
) == true)
1452 if (TransactionManager
->IMSHit
== false)
1453 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
1454 else if (RealFileExists(GetFinalFilename()) == false)
1456 // We got an InRelease file IMSHit, but we haven't one, which means
1457 // we had a valid Release/Release.gpg combo stepping in, which we have
1458 // to 'acquire' now to ensure list cleanup isn't removing them
1459 new NoActionItem(Owner
, DetachedDataTarget
);
1460 new NoActionItem(Owner
, DetachedSigTarget
);
1465 void pkgAcqMetaClearSig::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
) /*{{{*/
1467 Item::Failed(Message
, Cnf
);
1469 // we failed, we will not get additional items from this method
1470 ExpectedAdditionalItems
= 0;
1472 if (AuthPass
== false)
1474 if (Status
== StatAuthError
|| Status
== StatTransientNetworkError
)
1476 // if we expected a ClearTextSignature (InRelease) but got a network
1477 // error or got a file, but it wasn't valid, we end up here (see VerifyDone).
1478 // As these is usually called by web-portals we do not try Release/Release.gpg
1479 // as this is gonna fail anyway and instead abort our try (LP#346386)
1480 TransactionManager
->AbortTransaction();
1484 // Queue the 'old' InRelease file for removal if we try Release.gpg
1485 // as otherwise the file will stay around and gives a false-auth
1486 // impression (CVE-2012-0214)
1487 TransactionManager
->TransactionStageRemoval(this, GetFinalFilename());
1490 new pkgAcqMetaIndex(Owner
, TransactionManager
, DetachedDataTarget
, DetachedSigTarget
, IndexTargets
);
1494 if(CheckStopAuthentication(this, Message
))
1497 // No Release file was present, or verification failed, so fall
1498 // back to queueing Packages files without verification
1499 // only allow going further if the user explicitly wants it
1500 if(AllowInsecureRepositories(_("The repository '%s' is not signed."), ClearsignedTarget
.Description
, TransactionManager
->MetaIndexParser
, TransactionManager
, this) == true)
1504 /* InRelease files become Release files, otherwise
1505 * they would be considered as trusted later on */
1506 string
const FinalRelease
= GetFinalFileNameFromURI(DetachedDataTarget
.URI
);
1507 string
const PartialRelease
= GetPartialFileNameFromURI(DetachedDataTarget
.URI
);
1508 string
const FinalReleasegpg
= GetFinalFileNameFromURI(DetachedSigTarget
.URI
);
1509 string
const FinalInRelease
= GetFinalFilename();
1510 Rename(DestFile
, PartialRelease
);
1511 TransactionManager
->TransactionStageCopy(this, PartialRelease
, FinalRelease
);
1512 LoadLastMetaIndexParser(TransactionManager
, FinalRelease
, FinalInRelease
);
1514 // we parse the indexes here because at this point the user wanted
1515 // a repository that may potentially harm him
1516 if (TransactionManager
->MetaIndexParser
->Load(PartialRelease
, &ErrorText
) == false || VerifyVendor(Message
) == false)
1517 /* expired Release files are still a problem you need extra force for */;
1525 pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire
* const Owner
, /*{{{*/
1526 pkgAcqMetaClearSig
* const TransactionManager
,
1527 IndexTarget
const &DataTarget
,
1528 IndexTarget
const &DetachedSigTarget
,
1529 vector
<IndexTarget
> const &IndexTargets
) :
1530 pkgAcqMetaBase(Owner
, TransactionManager
, IndexTargets
, DataTarget
), d(NULL
),
1531 DetachedSigTarget(DetachedSigTarget
)
1533 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1534 std::clog
<< "New pkgAcqMetaIndex with TransactionManager "
1535 << this->TransactionManager
<< std::endl
;
1537 DestFile
= GetPartialFileNameFromURI(DataTarget
.URI
);
1540 Desc
.Description
= DataTarget
.Description
;
1542 Desc
.ShortDesc
= DataTarget
.ShortDesc
;
1543 Desc
.URI
= DataTarget
.URI
;
1545 // we expect more item
1546 ExpectedAdditionalItems
= IndexTargets
.size();
1550 void pkgAcqMetaIndex::Done(string
const &Message
, /*{{{*/
1551 HashStringList
const &Hashes
,
1552 pkgAcquire::MethodConfig
const * const Cfg
)
1554 Item::Done(Message
,Hashes
,Cfg
);
1556 if(CheckDownloadDone(this, Message
, Hashes
))
1558 // we have a Release file, now download the Signature, all further
1559 // verify/queue for additional downloads will be done in the
1560 // pkgAcqMetaSig::Done() code
1561 new pkgAcqMetaSig(Owner
, TransactionManager
, DetachedSigTarget
, this);
1565 // pkgAcqMetaIndex::Failed - no Release file present /*{{{*/
1566 void pkgAcqMetaIndex::Failed(string
const &Message
,
1567 pkgAcquire::MethodConfig
const * const Cnf
)
1569 pkgAcquire::Item::Failed(Message
, Cnf
);
1572 // No Release file was present so fall
1573 // back to queueing Packages files without verification
1574 // only allow going further if the user explicitly wants it
1575 if(AllowInsecureRepositories(_("The repository '%s' does not have a Release file."), Target
.Description
, TransactionManager
->MetaIndexParser
, TransactionManager
, this) == true)
1577 // ensure old Release files are removed
1578 TransactionManager
->TransactionStageRemoval(this, GetFinalFilename());
1580 // queue without any kind of hashsum support
1581 QueueIndexes(false);
1585 std::string
pkgAcqMetaIndex::DescURI() const /*{{{*/
1590 pkgAcqMetaIndex::~pkgAcqMetaIndex() {}
1592 // AcqMetaSig::AcqMetaSig - Constructor /*{{{*/
1593 pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire
* const Owner
,
1594 pkgAcqMetaClearSig
* const TransactionManager
,
1595 IndexTarget
const &Target
,
1596 pkgAcqMetaIndex
* const MetaIndex
) :
1597 pkgAcqTransactionItem(Owner
, TransactionManager
, Target
), d(NULL
), MetaIndex(MetaIndex
)
1599 DestFile
= GetPartialFileNameFromURI(Target
.URI
);
1601 // remove any partial downloaded sig-file in partial/.
1602 // it may confuse proxies and is too small to warrant a
1603 // partial download anyway
1604 RemoveFile("pkgAcqMetaSig", DestFile
);
1606 // set the TransactionManager
1607 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1608 std::clog
<< "New pkgAcqMetaSig with TransactionManager "
1609 << TransactionManager
<< std::endl
;
1612 Desc
.Description
= Target
.Description
;
1614 Desc
.ShortDesc
= Target
.ShortDesc
;
1615 Desc
.URI
= Target
.URI
;
1617 // If we got a hit for Release, we will get one for Release.gpg too (or obscure errors),
1618 // so we skip the download step and go instantly to verification
1619 if (TransactionManager
->IMSHit
== true && RealFileExists(GetFinalFilename()))
1623 PartialFile
= DestFile
= GetFinalFilename();
1624 MetaIndexFileSignature
= DestFile
;
1625 MetaIndex
->QueueForSignatureVerify(this, MetaIndex
->DestFile
, DestFile
);
1631 pkgAcqMetaSig::~pkgAcqMetaSig() /*{{{*/
1635 // pkgAcqMetaSig::Custom600Headers - Insert custom request headers /*{{{*/
1636 std::string
pkgAcqMetaSig::Custom600Headers() const
1638 std::string Header
= pkgAcqTransactionItem::Custom600Headers();
1639 std::string
const key
= TransactionManager
->MetaIndexParser
->GetSignedBy();
1640 if (key
.empty() == false)
1641 Header
+= "\nSigned-By: " + key
;
1645 // AcqMetaSig::Done - The signature was downloaded/verified /*{{{*/
1646 void pkgAcqMetaSig::Done(string
const &Message
, HashStringList
const &Hashes
,
1647 pkgAcquire::MethodConfig
const * const Cfg
)
1649 if (MetaIndexFileSignature
.empty() == false)
1651 DestFile
= MetaIndexFileSignature
;
1652 MetaIndexFileSignature
.clear();
1654 Item::Done(Message
, Hashes
, Cfg
);
1656 if(MetaIndex
->AuthPass
== false)
1658 if(MetaIndex
->CheckDownloadDone(this, Message
, Hashes
) == true)
1660 // destfile will be modified to point to MetaIndexFile for the
1661 // gpgv method, so we need to save it here
1662 MetaIndexFileSignature
= DestFile
;
1663 MetaIndex
->QueueForSignatureVerify(this, MetaIndex
->DestFile
, DestFile
);
1667 else if(MetaIndex
->CheckAuthDone(Message
) == true)
1669 if (TransactionManager
->IMSHit
== false)
1671 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
1672 TransactionManager
->TransactionStageCopy(MetaIndex
, MetaIndex
->DestFile
, MetaIndex
->GetFinalFilename());
1677 void pkgAcqMetaSig::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
1679 Item::Failed(Message
,Cnf
);
1681 // check if we need to fail at this point
1682 if (MetaIndex
->AuthPass
== true && MetaIndex
->CheckStopAuthentication(this, Message
))
1685 string
const FinalRelease
= MetaIndex
->GetFinalFilename();
1686 string
const FinalReleasegpg
= GetFinalFilename();
1687 string
const FinalInRelease
= TransactionManager
->GetFinalFilename();
1689 if (RealFileExists(FinalReleasegpg
) || RealFileExists(FinalInRelease
))
1691 std::string downgrade_msg
;
1692 strprintf(downgrade_msg
, _("The repository '%s' is no longer signed."),
1693 MetaIndex
->Target
.Description
.c_str());
1694 if(_config
->FindB("Acquire::AllowDowngradeToInsecureRepositories"))
1696 // meh, the users wants to take risks (we still mark the packages
1697 // from this repository as unauthenticated)
1698 _error
->Warning("%s", downgrade_msg
.c_str());
1699 _error
->Warning(_("This is normally not allowed, but the option "
1700 "Acquire::AllowDowngradeToInsecureRepositories was "
1701 "given to override it."));
1704 MessageInsecureRepository(true, downgrade_msg
);
1705 if (TransactionManager
->IMSHit
== false)
1706 Rename(MetaIndex
->DestFile
, MetaIndex
->DestFile
+ ".FAILED");
1707 Item::Failed("Message: " + downgrade_msg
, Cnf
);
1708 TransactionManager
->AbortTransaction();
1713 // ensures that a Release.gpg file in the lists/ is removed by the transaction
1714 TransactionManager
->TransactionStageRemoval(this, DestFile
);
1716 // only allow going further if the user explicitly wants it
1717 if (AllowInsecureRepositories(_("The repository '%s' is not signed."), MetaIndex
->Target
.Description
, TransactionManager
->MetaIndexParser
, TransactionManager
, this) == true)
1719 LoadLastMetaIndexParser(TransactionManager
, FinalRelease
, FinalInRelease
);
1721 // we parse the indexes here because at this point the user wanted
1722 // a repository that may potentially harm him
1723 bool const GoodLoad
= TransactionManager
->MetaIndexParser
->Load(MetaIndex
->DestFile
, &ErrorText
);
1724 if (MetaIndex
->VerifyVendor(Message
) == false)
1725 /* expired Release files are still a problem you need extra force for */;
1727 MetaIndex
->QueueIndexes(GoodLoad
);
1729 TransactionManager
->TransactionStageCopy(MetaIndex
, MetaIndex
->DestFile
, MetaIndex
->GetFinalFilename());
1732 // FIXME: this is used often (e.g. in pkgAcqIndexTrans) so refactor
1733 if (Cnf
->LocalOnly
== true ||
1734 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1743 // AcqBaseIndex - Constructor /*{{{*/
1744 pkgAcqBaseIndex::pkgAcqBaseIndex(pkgAcquire
* const Owner
,
1745 pkgAcqMetaClearSig
* const TransactionManager
,
1746 IndexTarget
const &Target
)
1747 : pkgAcqTransactionItem(Owner
, TransactionManager
, Target
), d(NULL
)
1751 pkgAcqBaseIndex::~pkgAcqBaseIndex() {}
1753 // AcqDiffIndex::AcqDiffIndex - Constructor /*{{{*/
1754 // ---------------------------------------------------------------------
1755 /* Get the DiffIndex file first and see if there are patches available
1756 * If so, create a pkgAcqIndexDiffs fetcher that will get and apply the
1757 * patches. If anything goes wrong in that process, it will fall back to
1758 * the original packages file
1760 pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire
* const Owner
,
1761 pkgAcqMetaClearSig
* const TransactionManager
,
1762 IndexTarget
const &Target
)
1763 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
), diffs(NULL
)
1765 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
1768 Desc
.Description
= GetDiffIndexFileName(Target
.Description
);
1769 Desc
.ShortDesc
= Target
.ShortDesc
;
1770 Desc
.URI
= GetDiffIndexURI(Target
);
1772 DestFile
= GetPartialFileNameFromURI(Desc
.URI
);
1775 std::clog
<< "pkgAcqDiffIndex: " << Desc
.URI
<< std::endl
;
1780 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
1781 // ---------------------------------------------------------------------
1782 /* The only header we use is the last-modified header. */
1783 string
pkgAcqDiffIndex::Custom600Headers() const
1785 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1786 return "\nIndex-File: true";
1788 string
const Final
= GetFinalFilename();
1791 std::clog
<< "Custom600Header-IMS: " << Final
<< std::endl
;
1794 if (stat(Final
.c_str(),&Buf
) != 0)
1795 return "\nIndex-File: true";
1797 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1800 void pkgAcqDiffIndex::QueueOnIMSHit() const /*{{{*/
1802 // list cleanup needs to know that this file as well as the already
1803 // present index is ours, so we create an empty diff to save it for us
1804 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
);
1807 bool pkgAcqDiffIndex::ParseDiffIndex(string
const &IndexDiffFile
) /*{{{*/
1809 // failing here is fine: our caller will take care of trying to
1810 // get the complete file if patching fails
1812 std::clog
<< "pkgAcqDiffIndex::ParseIndexDiff() " << IndexDiffFile
1815 FileFd
Fd(IndexDiffFile
,FileFd::ReadOnly
);
1817 if (Fd
.IsOpen() == false || Fd
.Failed())
1821 if(unlikely(TF
.Step(Tags
) == false))
1824 HashStringList ServerHashes
;
1825 unsigned long long ServerSize
= 0;
1827 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
1829 std::string tagname
= *type
;
1830 tagname
.append("-Current");
1831 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1832 if (tmp
.empty() == true)
1836 unsigned long long size
;
1837 std::stringstream
ss(tmp
);
1839 if (unlikely(hash
.empty() == true))
1841 if (unlikely(ServerSize
!= 0 && ServerSize
!= size
))
1843 ServerHashes
.push_back(HashString(*type
, hash
));
1847 if (ServerHashes
.usable() == false)
1850 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": Did not find a good hashsum in the index" << std::endl
;
1854 std::string
const CurrentPackagesFile
= GetFinalFileNameFromURI(Target
.URI
);
1855 HashStringList
const TargetFileHashes
= GetExpectedHashesFor(Target
.MetaKey
);
1856 if (TargetFileHashes
.usable() == false || ServerHashes
!= TargetFileHashes
)
1860 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": Index has different hashes than parser, probably older, so fail pdiffing" << std::endl
;
1861 printHashSumComparison(CurrentPackagesFile
, ServerHashes
, TargetFileHashes
);
1866 HashStringList LocalHashes
;
1867 // try avoiding calculating the hash here as this is costly
1868 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1869 LocalHashes
= GetExpectedHashesFromFor(TransactionManager
->LastMetaIndexParser
, Target
.MetaKey
);
1870 if (LocalHashes
.usable() == false)
1872 FileFd
fd(CurrentPackagesFile
, FileFd::ReadOnly
, FileFd::Auto
);
1873 Hashes
LocalHashesCalc(ServerHashes
);
1874 LocalHashesCalc
.AddFD(fd
);
1875 LocalHashes
= LocalHashesCalc
.GetHashStringList();
1878 if (ServerHashes
== LocalHashes
)
1880 // we have the same sha1 as the server so we are done here
1882 std::clog
<< "pkgAcqDiffIndex: Package file " << CurrentPackagesFile
<< " is up-to-date" << std::endl
;
1888 std::clog
<< "Server-Current: " << ServerHashes
.find(NULL
)->toStr() << " and we start at "
1889 << CurrentPackagesFile
<< " " << LocalHashes
.FileSize() << " " << LocalHashes
.find(NULL
)->toStr() << std::endl
;
1891 // historically, older hashes have more info than newer ones, so start
1892 // collecting with older ones first to avoid implementing complicated
1893 // information merging techniques… a failure is after all always
1894 // recoverable with a complete file and hashes aren't changed that often.
1895 std::vector
<char const *> types
;
1896 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
1897 types
.push_back(*type
);
1899 // parse all of (provided) history
1900 vector
<DiffInfo
> available_patches
;
1901 bool firstAcceptedHashes
= true;
1902 for (auto type
= types
.crbegin(); type
!= types
.crend(); ++type
)
1904 if (LocalHashes
.find(*type
) == NULL
)
1907 std::string tagname
= *type
;
1908 tagname
.append("-History");
1909 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1910 if (tmp
.empty() == true)
1913 string hash
, filename
;
1914 unsigned long long size
;
1915 std::stringstream
ss(tmp
);
1917 while (ss
>> hash
>> size
>> filename
)
1919 if (unlikely(hash
.empty() == true || filename
.empty() == true))
1922 // see if we have a record for this file already
1923 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
1924 for (; cur
!= available_patches
.end(); ++cur
)
1926 if (cur
->file
!= filename
)
1928 cur
->result_hashes
.push_back(HashString(*type
, hash
));
1931 if (cur
!= available_patches
.end())
1933 if (firstAcceptedHashes
== true)
1936 next
.file
= filename
;
1937 next
.result_hashes
.push_back(HashString(*type
, hash
));
1938 next
.result_hashes
.FileSize(size
);
1939 available_patches
.push_back(next
);
1944 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
1945 << " wasn't in the list for the first parsed hash! (history)" << std::endl
;
1949 firstAcceptedHashes
= false;
1952 if (unlikely(available_patches
.empty() == true))
1955 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": "
1956 << "Couldn't find any patches for the patch series." << std::endl
;
1960 for (auto type
= types
.crbegin(); type
!= types
.crend(); ++type
)
1962 if (LocalHashes
.find(*type
) == NULL
)
1965 std::string tagname
= *type
;
1966 tagname
.append("-Patches");
1967 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1968 if (tmp
.empty() == true)
1971 string hash
, filename
;
1972 unsigned long long size
;
1973 std::stringstream
ss(tmp
);
1975 while (ss
>> hash
>> size
>> filename
)
1977 if (unlikely(hash
.empty() == true || filename
.empty() == true))
1980 // see if we have a record for this file already
1981 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
1982 for (; cur
!= available_patches
.end(); ++cur
)
1984 if (cur
->file
!= filename
)
1986 if (cur
->patch_hashes
.empty())
1987 cur
->patch_hashes
.FileSize(size
);
1988 cur
->patch_hashes
.push_back(HashString(*type
, hash
));
1991 if (cur
!= available_patches
.end())
1994 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
1995 << " wasn't in the list for the first parsed hash! (patches)" << std::endl
;
2000 for (auto type
= types
.crbegin(); type
!= types
.crend(); ++type
)
2002 std::string tagname
= *type
;
2003 tagname
.append("-Download");
2004 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
2005 if (tmp
.empty() == true)
2008 string hash
, filename
;
2009 unsigned long long size
;
2010 std::stringstream
ss(tmp
);
2012 // FIXME: all of pdiff supports only .gz compressed patches
2013 while (ss
>> hash
>> size
>> filename
)
2015 if (unlikely(hash
.empty() == true || filename
.empty() == true))
2017 if (unlikely(APT::String::Endswith(filename
, ".gz") == false))
2019 filename
.erase(filename
.length() - 3);
2021 // see if we have a record for this file already
2022 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
2023 for (; cur
!= available_patches
.end(); ++cur
)
2025 if (cur
->file
!= filename
)
2027 if (cur
->download_hashes
.empty())
2028 cur
->download_hashes
.FileSize(size
);
2029 cur
->download_hashes
.push_back(HashString(*type
, hash
));
2032 if (cur
!= available_patches
.end())
2035 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
2036 << " wasn't in the list for the first parsed hash! (download)" << std::endl
;
2042 bool foundStart
= false;
2043 for (std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
2044 cur
!= available_patches
.end(); ++cur
)
2046 if (LocalHashes
!= cur
->result_hashes
)
2049 available_patches
.erase(available_patches
.begin(), cur
);
2054 if (foundStart
== false || unlikely(available_patches
.empty() == true))
2057 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": "
2058 << "Couldn't find the start of the patch series." << std::endl
;
2062 for (auto const &patch
: available_patches
)
2063 if (patch
.result_hashes
.usable() == false ||
2064 patch
.patch_hashes
.usable() == false ||
2065 patch
.download_hashes
.usable() == false)
2068 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": provides no usable hashes for " << patch
.file
2069 << " so fallback to complete download" << std::endl
;
2073 // patching with too many files is rather slow compared to a fast download
2074 unsigned long const fileLimit
= _config
->FindI("Acquire::PDiffs::FileLimit", 0);
2075 if (fileLimit
!= 0 && fileLimit
< available_patches
.size())
2078 std::clog
<< "Need " << available_patches
.size() << " diffs (Limit is " << fileLimit
2079 << ") so fallback to complete download" << std::endl
;
2083 // calculate the size of all patches we have to get
2084 unsigned short const sizeLimitPercent
= _config
->FindI("Acquire::PDiffs::SizeLimit", 100);
2085 if (sizeLimitPercent
> 0 && TransactionManager
->MetaIndexParser
!= nullptr)
2087 unsigned long long downloadSize
= std::accumulate(available_patches
.begin(),
2088 available_patches
.end(), 0llu, [](unsigned long long const T
, DiffInfo
const &I
) {
2089 return T
+ I
.download_hashes
.FileSize();
2091 if (downloadSize
!= 0)
2093 unsigned long long downloadSizeIdx
= 0;
2094 auto const types
= VectorizeString(Target
.Option(IndexTarget::COMPRESSIONTYPES
), ' ');
2095 for (auto const &t
: types
)
2097 std::string MetaKey
= Target
.MetaKey
;
2098 if (t
!= "uncompressed")
2100 HashStringList
const hsl
= GetExpectedHashesFor(MetaKey
);
2101 if (unlikely(hsl
.usable() == false))
2103 downloadSizeIdx
= hsl
.FileSize();
2106 unsigned long long const sizeLimit
= downloadSizeIdx
* sizeLimitPercent
;
2107 if ((sizeLimit
/100) < downloadSize
)
2110 std::clog
<< "Need " << downloadSize
<< " compressed bytes (Limit is " << (sizeLimit
/100) << ", "
2111 << "original is " << downloadSizeIdx
<< ") so fallback to complete download" << std::endl
;
2117 // we have something, queue the diffs
2118 string::size_type
const last_space
= Description
.rfind(" ");
2119 if(last_space
!= string::npos
)
2120 Description
.erase(last_space
, Description
.size()-last_space
);
2122 /* decide if we should download patches one by one or in one go:
2123 The first is good if the server merges patches, but many don't so client
2124 based merging can be attempt in which case the second is better.
2125 "bad things" will happen if patches are merged on the server,
2126 but client side merging is attempt as well */
2127 bool pdiff_merge
= _config
->FindB("Acquire::PDiffs::Merge", true);
2128 if (pdiff_merge
== true)
2130 // reprepro adds this flag if it has merged patches on the server
2131 std::string
const precedence
= Tags
.FindS("X-Patch-Precedence");
2132 pdiff_merge
= (precedence
!= "merged");
2137 std::string
const Final
= GetExistingFilename(CurrentPackagesFile
);
2138 if (unlikely(Final
.empty())) // because we wouldn't be called in such a case
2140 std::string
const PartialFile
= GetPartialFileNameFromURI(Target
.URI
);
2141 if (FileExists(PartialFile
) && RemoveFile("Bootstrap-linking", PartialFile
) == false)
2144 std::clog
<< "Bootstrap-linking for patching " << CurrentPackagesFile
2145 << " by removing stale " << PartialFile
<< " failed!" << std::endl
;
2148 for (auto const &ext
: APT::Configuration::getCompressorExtensions())
2150 std::string
const Partial
= PartialFile
+ ext
;
2151 if (FileExists(Partial
) && RemoveFile("Bootstrap-linking", Partial
) == false)
2154 std::clog
<< "Bootstrap-linking for patching " << CurrentPackagesFile
2155 << " by removing stale " << Partial
<< " failed!" << std::endl
;
2159 std::string
const Ext
= Final
.substr(CurrentPackagesFile
.length());
2160 std::string
const Partial
= PartialFile
+ Ext
;
2161 if (symlink(Final
.c_str(), Partial
.c_str()) != 0)
2164 std::clog
<< "Bootstrap-linking for patching " << CurrentPackagesFile
2165 << " by linking " << Final
<< " to " << Partial
<< " failed!" << std::endl
;
2170 if (pdiff_merge
== false)
2171 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
, available_patches
);
2174 diffs
= new std::vector
<pkgAcqIndexMergeDiffs
*>(available_patches
.size());
2175 for(size_t i
= 0; i
< available_patches
.size(); ++i
)
2176 (*diffs
)[i
] = new pkgAcqIndexMergeDiffs(Owner
, TransactionManager
,
2178 available_patches
[i
],
2188 void pkgAcqDiffIndex::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
2190 Item::Failed(Message
,Cnf
);
2194 std::clog
<< "pkgAcqDiffIndex failed: " << Desc
.URI
<< " with " << Message
<< std::endl
2195 << "Falling back to normal index file acquire" << std::endl
;
2197 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
2200 void pkgAcqDiffIndex::Done(string
const &Message
,HashStringList
const &Hashes
, /*{{{*/
2201 pkgAcquire::MethodConfig
const * const Cnf
)
2204 std::clog
<< "pkgAcqDiffIndex::Done(): " << Desc
.URI
<< std::endl
;
2206 Item::Done(Message
, Hashes
, Cnf
);
2208 string
const FinalFile
= GetFinalFilename();
2209 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false))
2210 DestFile
= FinalFile
;
2212 if(ParseDiffIndex(DestFile
) == false)
2214 Failed("Message: Couldn't parse pdiff index", Cnf
);
2215 // queue for final move - this should happen even if we fail
2216 // while parsing (e.g. on sizelimit) and download the complete file.
2217 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
2221 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
2230 pkgAcqDiffIndex::~pkgAcqDiffIndex()
2236 // AcqIndexDiffs::AcqIndexDiffs - Constructor /*{{{*/
2237 // ---------------------------------------------------------------------
2238 /* The package diff is added to the queue. one object is constructed
2239 * for each diff and the index
2241 pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire
* const Owner
,
2242 pkgAcqMetaClearSig
* const TransactionManager
,
2243 IndexTarget
const &Target
,
2244 vector
<DiffInfo
> const &diffs
)
2245 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
),
2246 available_patches(diffs
)
2248 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
2250 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
2253 Description
= Target
.Description
;
2254 Desc
.ShortDesc
= Target
.ShortDesc
;
2256 if(available_patches
.empty() == true)
2258 // we are done (yeah!), check hashes against the final file
2259 DestFile
= GetKeepCompressedFileName(GetFinalFileNameFromURI(Target
.URI
), Target
);
2264 State
= StateFetchDiff
;
2269 void pkgAcqIndexDiffs::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
2271 Item::Failed(Message
,Cnf
);
2274 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
2276 std::clog
<< "pkgAcqIndexDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
2277 << "Falling back to normal index file acquire " << std::endl
;
2278 RenameOnError(PDiffError
);
2279 std::string
const patchname
= GetDiffsPatchFileName(DestFile
);
2280 if (RealFileExists(patchname
))
2281 Rename(patchname
, patchname
+ ".FAILED");
2282 std::string
const UnpatchedFile
= GetExistingFilename(GetPartialFileNameFromURI(Target
.URI
));
2283 if (UnpatchedFile
.empty() == false && FileExists(UnpatchedFile
))
2284 Rename(UnpatchedFile
, UnpatchedFile
+ ".FAILED");
2285 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
2289 // Finish - helper that cleans the item out of the fetcher queue /*{{{*/
2290 void pkgAcqIndexDiffs::Finish(bool allDone
)
2293 std::clog
<< "pkgAcqIndexDiffs::Finish(): "
2295 << Desc
.URI
<< std::endl
;
2297 // we restore the original name, this is required, otherwise
2298 // the file will be cleaned
2301 std::string
const Final
= GetKeepCompressedFileName(GetFinalFilename(), Target
);
2302 TransactionManager
->TransactionStageCopy(this, DestFile
, Final
);
2304 // this is for the "real" finish
2309 std::clog
<< "\n\nallDone: " << DestFile
<< "\n" << std::endl
;
2316 std::clog
<< "Finishing: " << Desc
.URI
<< std::endl
;
2323 bool pkgAcqIndexDiffs::QueueNextDiff() /*{{{*/
2325 // calc sha1 of the just patched file
2326 std::string
const PartialFile
= GetExistingFilename(GetPartialFileNameFromURI(Target
.URI
));
2327 if(unlikely(PartialFile
.empty()))
2329 Failed("Message: The file " + GetPartialFileNameFromURI(Target
.URI
) + " isn't available", NULL
);
2333 FileFd
fd(PartialFile
, FileFd::ReadOnly
, FileFd::Extension
);
2334 Hashes LocalHashesCalc
;
2335 LocalHashesCalc
.AddFD(fd
);
2336 HashStringList
const LocalHashes
= LocalHashesCalc
.GetHashStringList();
2339 std::clog
<< "QueueNextDiff: " << PartialFile
<< " (" << LocalHashes
.find(NULL
)->toStr() << ")" << std::endl
;
2341 HashStringList
const TargetFileHashes
= GetExpectedHashesFor(Target
.MetaKey
);
2342 if (unlikely(LocalHashes
.usable() == false || TargetFileHashes
.usable() == false))
2344 Failed("Local/Expected hashes are not usable for " + PartialFile
, NULL
);
2348 // final file reached before all patches are applied
2349 if(LocalHashes
== TargetFileHashes
)
2355 // remove all patches until the next matching patch is found
2356 // this requires the Index file to be ordered
2357 available_patches
.erase(available_patches
.begin(),
2358 std::find_if(available_patches
.begin(), available_patches
.end(), [&](DiffInfo
const &I
) {
2359 return I
.result_hashes
== LocalHashes
;
2362 // error checking and falling back if no patch was found
2363 if(available_patches
.empty() == true)
2365 Failed("No patches left to reach target for " + PartialFile
, NULL
);
2369 // queue the right diff
2370 Desc
.URI
= Target
.URI
+ ".diff/" + available_patches
[0].file
+ ".gz";
2371 Desc
.Description
= Description
+ " " + available_patches
[0].file
+ string(".pdiff");
2372 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
+ ".diff/" + available_patches
[0].file
), Target
);
2375 std::clog
<< "pkgAcqIndexDiffs::QueueNextDiff(): " << Desc
.URI
<< std::endl
;
2382 void pkgAcqIndexDiffs::Done(string
const &Message
, HashStringList
const &Hashes
, /*{{{*/
2383 pkgAcquire::MethodConfig
const * const Cnf
)
2386 std::clog
<< "pkgAcqIndexDiffs::Done(): " << Desc
.URI
<< std::endl
;
2388 Item::Done(Message
, Hashes
, Cnf
);
2390 std::string
const UncompressedUnpatchedFile
= GetPartialFileNameFromURI(Target
.URI
);
2391 std::string
const UnpatchedFile
= GetExistingFilename(UncompressedUnpatchedFile
);
2392 std::string
const PatchFile
= GetDiffsPatchFileName(UnpatchedFile
);
2393 std::string
const PatchedFile
= GetKeepCompressedFileName(UncompressedUnpatchedFile
, Target
);
2397 // success in downloading a diff, enter ApplyDiff state
2398 case StateFetchDiff
:
2399 Rename(DestFile
, PatchFile
);
2400 DestFile
= GetKeepCompressedFileName(UncompressedUnpatchedFile
+ "-patched", Target
);
2402 std::clog
<< "Sending to rred method: " << UnpatchedFile
<< std::endl
;
2403 State
= StateApplyDiff
;
2405 Desc
.URI
= "rred:" + UnpatchedFile
;
2407 SetActiveSubprocess("rred");
2409 // success in download/apply a diff, queue next (if needed)
2410 case StateApplyDiff
:
2411 // remove the just applied patch and base file
2412 available_patches
.erase(available_patches
.begin());
2413 RemoveFile("pkgAcqIndexDiffs::Done", PatchFile
);
2414 RemoveFile("pkgAcqIndexDiffs::Done", UnpatchedFile
);
2416 std::clog
<< "Moving patched file in place: " << std::endl
2417 << DestFile
<< " -> " << PatchedFile
<< std::endl
;
2418 Rename(DestFile
, PatchedFile
);
2420 // see if there is more to download
2421 if(available_patches
.empty() == false)
2423 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
, available_patches
);
2426 DestFile
= PatchedFile
;
2433 std::string
pkgAcqIndexDiffs::Custom600Headers() const /*{{{*/
2435 if(State
!= StateApplyDiff
)
2436 return pkgAcqBaseIndex::Custom600Headers();
2437 std::ostringstream patchhashes
;
2438 HashStringList
const ExpectedHashes
= available_patches
[0].patch_hashes
;
2439 for (HashStringList::const_iterator hs
= ExpectedHashes
.begin(); hs
!= ExpectedHashes
.end(); ++hs
)
2440 patchhashes
<< "\nPatch-0-" << hs
->HashType() << "-Hash: " << hs
->HashValue();
2441 patchhashes
<< pkgAcqBaseIndex::Custom600Headers();
2442 return patchhashes
.str();
2445 pkgAcqIndexDiffs::~pkgAcqIndexDiffs() {}
2447 // AcqIndexMergeDiffs::AcqIndexMergeDiffs - Constructor /*{{{*/
2448 pkgAcqIndexMergeDiffs::pkgAcqIndexMergeDiffs(pkgAcquire
* const Owner
,
2449 pkgAcqMetaClearSig
* const TransactionManager
,
2450 IndexTarget
const &Target
,
2451 DiffInfo
const &patch
,
2452 std::vector
<pkgAcqIndexMergeDiffs
*> const * const allPatches
)
2453 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
),
2454 patch(patch
), allPatches(allPatches
), State(StateFetchDiff
)
2456 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
2459 Description
= Target
.Description
;
2460 Desc
.ShortDesc
= Target
.ShortDesc
;
2461 Desc
.URI
= Target
.URI
+ ".diff/" + patch
.file
+ ".gz";
2462 Desc
.Description
= Description
+ " " + patch
.file
+ ".pdiff";
2463 DestFile
= GetPartialFileNameFromURI(Desc
.URI
);
2466 std::clog
<< "pkgAcqIndexMergeDiffs: " << Desc
.URI
<< std::endl
;
2471 void pkgAcqIndexMergeDiffs::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
2474 std::clog
<< "pkgAcqIndexMergeDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
;
2476 Item::Failed(Message
,Cnf
);
2479 // check if we are the first to fail, otherwise we are done here
2480 State
= StateDoneDiff
;
2481 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2482 I
!= allPatches
->end(); ++I
)
2483 if ((*I
)->State
== StateErrorDiff
)
2485 State
= StateErrorDiff
;
2489 // first failure means we should fallback
2490 State
= StateErrorDiff
;
2492 std::clog
<< "Falling back to normal index file acquire" << std::endl
;
2493 RenameOnError(PDiffError
);
2494 if (RealFileExists(DestFile
))
2495 Rename(DestFile
, DestFile
+ ".FAILED");
2496 std::string
const UnpatchedFile
= GetExistingFilename(GetPartialFileNameFromURI(Target
.URI
));
2497 if (UnpatchedFile
.empty() == false && FileExists(UnpatchedFile
))
2498 Rename(UnpatchedFile
, UnpatchedFile
+ ".FAILED");
2500 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
2503 void pkgAcqIndexMergeDiffs::Done(string
const &Message
, HashStringList
const &Hashes
, /*{{{*/
2504 pkgAcquire::MethodConfig
const * const Cnf
)
2507 std::clog
<< "pkgAcqIndexMergeDiffs::Done(): " << Desc
.URI
<< std::endl
;
2509 Item::Done(Message
, Hashes
, Cnf
);
2511 if (std::any_of(allPatches
->begin(), allPatches
->end(),
2512 [](pkgAcqIndexMergeDiffs
const * const P
) { return P
->State
== StateErrorDiff
; }))
2515 std::clog
<< "Another patch failed already, no point in processing this one." << std::endl
;
2516 State
= StateErrorDiff
;
2520 std::string
const UncompressedUnpatchedFile
= GetPartialFileNameFromURI(Target
.URI
);
2521 std::string
const UnpatchedFile
= GetExistingFilename(UncompressedUnpatchedFile
);
2522 if (UnpatchedFile
.empty())
2524 _error
->Fatal("Unpatched file %s doesn't exist (anymore)!", UncompressedUnpatchedFile
.c_str());
2525 State
= StateErrorDiff
;
2528 std::string
const PatchFile
= GetMergeDiffsPatchFileName(UnpatchedFile
, patch
.file
);
2529 std::string
const PatchedFile
= GetKeepCompressedFileName(UncompressedUnpatchedFile
, Target
);
2533 case StateFetchDiff
:
2534 Rename(DestFile
, PatchFile
);
2536 // check if this is the last completed diff
2537 State
= StateDoneDiff
;
2538 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2539 I
!= allPatches
->end(); ++I
)
2540 if ((*I
)->State
!= StateDoneDiff
)
2543 std::clog
<< "Not the last done diff in the batch: " << Desc
.URI
<< std::endl
;
2546 // this is the last completed diff, so we are ready to apply now
2547 DestFile
= GetKeepCompressedFileName(UncompressedUnpatchedFile
+ "-patched", Target
);
2549 std::clog
<< "Sending to rred method: " << UnpatchedFile
<< std::endl
;
2550 State
= StateApplyDiff
;
2552 Desc
.URI
= "rred:" + UnpatchedFile
;
2554 SetActiveSubprocess("rred");
2556 case StateApplyDiff
:
2557 // success in download & apply all diffs, finialize and clean up
2559 std::clog
<< "Queue patched file in place: " << std::endl
2560 << DestFile
<< " -> " << PatchedFile
<< std::endl
;
2562 // queue for copy by the transaction manager
2563 TransactionManager
->TransactionStageCopy(this, DestFile
, GetKeepCompressedFileName(GetFinalFilename(), Target
));
2565 // ensure the ed's are gone regardless of list-cleanup
2566 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2567 I
!= allPatches
->end(); ++I
)
2568 RemoveFile("pkgAcqIndexMergeDiffs::Done", GetMergeDiffsPatchFileName(UnpatchedFile
, (*I
)->patch
.file
));
2569 RemoveFile("pkgAcqIndexMergeDiffs::Done", UnpatchedFile
);
2574 std::clog
<< "allDone: " << DestFile
<< "\n" << std::endl
;
2576 case StateDoneDiff
: _error
->Fatal("Done called for %s which is in an invalid Done state", PatchFile
.c_str()); break;
2577 case StateErrorDiff
: _error
->Fatal("Done called for %s which is in an invalid Error state", PatchFile
.c_str()); break;
2581 std::string
pkgAcqIndexMergeDiffs::Custom600Headers() const /*{{{*/
2583 if(State
!= StateApplyDiff
)
2584 return pkgAcqBaseIndex::Custom600Headers();
2585 std::ostringstream patchhashes
;
2586 unsigned int seen_patches
= 0;
2587 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2588 I
!= allPatches
->end(); ++I
)
2590 HashStringList
const ExpectedHashes
= (*I
)->patch
.patch_hashes
;
2591 for (HashStringList::const_iterator hs
= ExpectedHashes
.begin(); hs
!= ExpectedHashes
.end(); ++hs
)
2592 patchhashes
<< "\nPatch-" << seen_patches
<< "-" << hs
->HashType() << "-Hash: " << hs
->HashValue();
2595 patchhashes
<< pkgAcqBaseIndex::Custom600Headers();
2596 return patchhashes
.str();
2599 pkgAcqIndexMergeDiffs::~pkgAcqIndexMergeDiffs() {}
2601 // AcqIndex::AcqIndex - Constructor /*{{{*/
2602 pkgAcqIndex::pkgAcqIndex(pkgAcquire
* const Owner
,
2603 pkgAcqMetaClearSig
* const TransactionManager
,
2604 IndexTarget
const &Target
)
2605 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
), Stage(STAGE_DOWNLOAD
),
2606 CompressionExtensions(Target
.Option(IndexTarget::COMPRESSIONTYPES
))
2608 Init(Target
.URI
, Target
.Description
, Target
.ShortDesc
);
2610 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
2611 std::clog
<< "New pkgIndex with TransactionManager "
2612 << TransactionManager
<< std::endl
;
2615 // AcqIndex::Init - defered Constructor /*{{{*/
2616 static void NextCompressionExtension(std::string
&CurrentCompressionExtension
, std::string
&CompressionExtensions
, bool const preview
)
2618 size_t const nextExt
= CompressionExtensions
.find(' ');
2619 if (nextExt
== std::string::npos
)
2621 CurrentCompressionExtension
= CompressionExtensions
;
2622 if (preview
== false)
2623 CompressionExtensions
.clear();
2627 CurrentCompressionExtension
= CompressionExtensions
.substr(0, nextExt
);
2628 if (preview
== false)
2629 CompressionExtensions
= CompressionExtensions
.substr(nextExt
+1);
2632 void pkgAcqIndex::Init(string
const &URI
, string
const &URIDesc
,
2633 string
const &ShortDesc
)
2635 Stage
= STAGE_DOWNLOAD
;
2637 DestFile
= GetPartialFileNameFromURI(URI
);
2638 NextCompressionExtension(CurrentCompressionExtension
, CompressionExtensions
, false);
2640 // store file size of the download to ensure the fetcher gives
2641 // accurate progress reporting
2642 FileSize
= GetExpectedHashes().FileSize();
2644 if (CurrentCompressionExtension
== "uncompressed")
2648 else if (CurrentCompressionExtension
== "by-hash")
2650 NextCompressionExtension(CurrentCompressionExtension
, CompressionExtensions
, true);
2651 if(unlikely(TransactionManager
->MetaIndexParser
== NULL
|| CurrentCompressionExtension
.empty()))
2653 if (CurrentCompressionExtension
!= "uncompressed")
2655 Desc
.URI
= URI
+ '.' + CurrentCompressionExtension
;
2656 DestFile
= DestFile
+ '.' + CurrentCompressionExtension
;
2659 HashStringList
const Hashes
= GetExpectedHashes();
2660 HashString
const * const TargetHash
= Hashes
.find(NULL
);
2661 if (unlikely(TargetHash
== nullptr))
2663 std::string
const ByHash
= "/by-hash/" + TargetHash
->HashType() + "/" + TargetHash
->HashValue();
2664 size_t const trailing_slash
= Desc
.URI
.find_last_of("/");
2665 if (unlikely(trailing_slash
== std::string::npos
))
2667 Desc
.URI
= Desc
.URI
.replace(
2669 Desc
.URI
.substr(trailing_slash
+1).size()+1,
2672 else if (unlikely(CurrentCompressionExtension
.empty()))
2676 Desc
.URI
= URI
+ '.' + CurrentCompressionExtension
;
2677 DestFile
= DestFile
+ '.' + CurrentCompressionExtension
;
2681 Desc
.Description
= URIDesc
;
2683 Desc
.ShortDesc
= ShortDesc
;
2688 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
2689 // ---------------------------------------------------------------------
2690 /* The only header we use is the last-modified header. */
2691 string
pkgAcqIndex::Custom600Headers() const
2694 string msg
= "\nIndex-File: true";
2696 if (TransactionManager
->LastMetaIndexParser
== NULL
)
2698 std::string
const Final
= GetFinalFilename();
2701 if (stat(Final
.c_str(),&Buf
) == 0)
2702 msg
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
2705 if(Target
.IsOptional
)
2706 msg
+= "\nFail-Ignore: true";
2711 // AcqIndex::Failed - getting the indexfile failed /*{{{*/
2712 void pkgAcqIndex::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)
2714 Item::Failed(Message
,Cnf
);
2716 // authorisation matches will not be fixed by other compression types
2717 if (Status
!= StatAuthError
)
2719 if (CompressionExtensions
.empty() == false)
2721 Init(Target
.URI
, Desc
.Description
, Desc
.ShortDesc
);
2727 if(Target
.IsOptional
&& GetExpectedHashes().empty() && Stage
== STAGE_DOWNLOAD
)
2730 TransactionManager
->AbortTransaction();
2733 // AcqIndex::Done - Finished a fetch /*{{{*/
2734 // ---------------------------------------------------------------------
2735 /* This goes through a number of states.. On the initial fetch the
2736 method could possibly return an alternate filename which points
2737 to the uncompressed version of the file. If this is so the file
2738 is copied into the partial directory. In all other cases the file
2739 is decompressed with a compressed uri. */
2740 void pkgAcqIndex::Done(string
const &Message
,
2741 HashStringList
const &Hashes
,
2742 pkgAcquire::MethodConfig
const * const Cfg
)
2744 Item::Done(Message
,Hashes
,Cfg
);
2748 case STAGE_DOWNLOAD
:
2749 StageDownloadDone(Message
);
2751 case STAGE_DECOMPRESS_AND_VERIFY
:
2752 StageDecompressDone();
2757 // AcqIndex::StageDownloadDone - Queue for decompress and verify /*{{{*/
2758 void pkgAcqIndex::StageDownloadDone(string
const &Message
)
2763 std::string
const AltFilename
= LookupTag(Message
,"Alt-Filename");
2764 std::string Filename
= LookupTag(Message
,"Filename");
2766 // we need to verify the file against the current Release file again
2767 // on if-modfied-since hit to avoid a stale attack against us
2768 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
2770 // copy FinalFile into partial/ so that we check the hash again
2771 string
const FinalFile
= GetExistingFilename(GetFinalFileNameFromURI(Target
.URI
));
2772 if (symlink(FinalFile
.c_str(), DestFile
.c_str()) != 0)
2773 _error
->WarningE("pkgAcqIndex::StageDownloadDone", "Symlinking final file %s back to %s failed", FinalFile
.c_str(), DestFile
.c_str());
2776 EraseFileName
= DestFile
;
2777 Filename
= DestFile
;
2779 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
2780 Desc
.URI
= "store:" + Filename
;
2782 SetActiveSubprocess(::URI(Desc
.URI
).Access
);
2785 // methods like file:// give us an alternative (uncompressed) file
2786 else if (Target
.KeepCompressed
== false && AltFilename
.empty() == false)
2788 Filename
= AltFilename
;
2789 EraseFileName
.clear();
2791 // Methods like e.g. "file:" will give us a (compressed) FileName that is
2792 // not the "DestFile" we set, in this case we uncompress from the local file
2793 else if (Filename
!= DestFile
&& RealFileExists(DestFile
) == false)
2795 // symlinking ensures that the filename can be used for compression detection
2796 // that is e.g. needed for by-hash which has no extension over file
2797 if (symlink(Filename
.c_str(),DestFile
.c_str()) != 0)
2798 _error
->WarningE("pkgAcqIndex::StageDownloadDone", "Symlinking file %s to %s failed", Filename
.c_str(), DestFile
.c_str());
2801 EraseFileName
= DestFile
;
2802 Filename
= DestFile
;
2806 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
2807 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
2808 if (Filename
!= DestFile
&& flExtension(Filename
) == flExtension(DestFile
))
2809 Desc
.URI
= "copy:" + Filename
;
2811 Desc
.URI
= "store:" + Filename
;
2812 if (DestFile
== Filename
)
2814 if (CurrentCompressionExtension
== "uncompressed")
2815 return StageDecompressDone();
2816 DestFile
= "/dev/null";
2819 if (EraseFileName
.empty() && Filename
!= AltFilename
)
2820 EraseFileName
= Filename
;
2822 // queue uri for the next stage
2824 SetActiveSubprocess(::URI(Desc
.URI
).Access
);
2827 // AcqIndex::StageDecompressDone - Final verification /*{{{*/
2828 void pkgAcqIndex::StageDecompressDone()
2830 if (DestFile
== "/dev/null")
2831 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
2833 // Done, queue for rename on transaction finished
2834 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
2837 pkgAcqIndex::~pkgAcqIndex() {}
2840 // AcqArchive::AcqArchive - Constructor /*{{{*/
2841 // ---------------------------------------------------------------------
2842 /* This just sets up the initial fetch environment and queues the first
2844 pkgAcqArchive::pkgAcqArchive(pkgAcquire
* const Owner
,pkgSourceList
* const Sources
,
2845 pkgRecords
* const Recs
,pkgCache::VerIterator
const &Version
,
2846 string
&StoreFilename
) :
2847 Item(Owner
), d(NULL
), LocalSource(false), Version(Version
), Sources(Sources
), Recs(Recs
),
2848 StoreFilename(StoreFilename
), Vf(Version
.FileList()),
2851 Retries
= _config
->FindI("Acquire::Retries",0);
2853 if (Version
.Arch() == 0)
2855 _error
->Error(_("I wasn't able to locate a file for the %s package. "
2856 "This might mean you need to manually fix this package. "
2857 "(due to missing arch)"),
2858 Version
.ParentPkg().FullName().c_str());
2862 /* We need to find a filename to determine the extension. We make the
2863 assumption here that all the available sources for this version share
2864 the same extension.. */
2865 // Skip not source sources, they do not have file fields.
2866 for (; Vf
.end() == false; ++Vf
)
2868 if (Vf
.File().Flagged(pkgCache::Flag::NotSource
))
2873 // Does not really matter here.. we are going to fail out below
2874 if (Vf
.end() != true)
2876 // If this fails to get a file name we will bomb out below.
2877 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2878 if (_error
->PendingError() == true)
2881 // Generate the final file name as: package_version_arch.foo
2882 StoreFilename
= QuoteString(Version
.ParentPkg().Name(),"_:") + '_' +
2883 QuoteString(Version
.VerStr(),"_:") + '_' +
2884 QuoteString(Version
.Arch(),"_:.") +
2885 "." + flExtension(Parse
.FileName());
2888 // check if we have one trusted source for the package. if so, switch
2889 // to "TrustedOnly" mode - but only if not in AllowUnauthenticated mode
2890 bool const allowUnauth
= _config
->FindB("APT::Get::AllowUnauthenticated", false);
2891 bool const debugAuth
= _config
->FindB("Debug::pkgAcquire::Auth", false);
2892 bool seenUntrusted
= false;
2893 for (pkgCache::VerFileIterator i
= Version
.FileList(); i
.end() == false; ++i
)
2895 pkgIndexFile
*Index
;
2896 if (Sources
->FindIndex(i
.File(),Index
) == false)
2899 if (debugAuth
== true)
2900 std::cerr
<< "Checking index: " << Index
->Describe()
2901 << "(Trusted=" << Index
->IsTrusted() << ")" << std::endl
;
2903 if (Index
->IsTrusted() == true)
2906 if (allowUnauth
== false)
2910 seenUntrusted
= true;
2913 // "allow-unauthenticated" restores apts old fetching behaviour
2914 // that means that e.g. unauthenticated file:// uris are higher
2915 // priority than authenticated http:// uris
2916 if (allowUnauth
== true && seenUntrusted
== true)
2920 if (QueueNext() == false && _error
->PendingError() == false)
2921 _error
->Error(_("Can't find a source to download version '%s' of '%s'"),
2922 Version
.VerStr(), Version
.ParentPkg().FullName(false).c_str());
2925 // AcqArchive::QueueNext - Queue the next file source /*{{{*/
2926 // ---------------------------------------------------------------------
2927 /* This queues the next available file version for download. It checks if
2928 the archive is already available in the cache and stashs the MD5 for
2930 bool pkgAcqArchive::QueueNext()
2932 for (; Vf
.end() == false; ++Vf
)
2934 pkgCache::PkgFileIterator
const PkgF
= Vf
.File();
2935 // Ignore not source sources
2936 if (PkgF
.Flagged(pkgCache::Flag::NotSource
))
2939 // Try to cross match against the source list
2940 pkgIndexFile
*Index
;
2941 if (Sources
->FindIndex(PkgF
, Index
) == false)
2943 LocalSource
= PkgF
.Flagged(pkgCache::Flag::LocalSource
);
2945 // only try to get a trusted package from another source if that source
2947 if(Trusted
&& !Index
->IsTrusted())
2950 // Grab the text package record
2951 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2952 if (_error
->PendingError() == true)
2955 string PkgFile
= Parse
.FileName();
2956 ExpectedHashes
= Parse
.Hashes();
2958 if (PkgFile
.empty() == true)
2959 return _error
->Error(_("The package index files are corrupted. No Filename: "
2960 "field for package %s."),
2961 Version
.ParentPkg().Name());
2963 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
2964 Desc
.Description
= Index
->ArchiveInfo(Version
);
2966 Desc
.ShortDesc
= Version
.ParentPkg().FullName(true);
2968 // See if we already have the file. (Legacy filenames)
2969 FileSize
= Version
->Size
;
2970 string FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile
);
2972 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2974 // Make sure the size matches
2975 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2980 StoreFilename
= DestFile
= FinalFile
;
2984 /* Hmm, we have a file and its size does not match, this means it is
2985 an old style mismatched arch */
2986 RemoveFile("pkgAcqArchive::QueueNext", FinalFile
);
2989 // Check it again using the new style output filenames
2990 FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
2991 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2993 // Make sure the size matches
2994 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2999 StoreFilename
= DestFile
= FinalFile
;
3003 /* Hmm, we have a file and its size does not match, this shouldn't
3005 RemoveFile("pkgAcqArchive::QueueNext", FinalFile
);
3008 DestFile
= _config
->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename
);
3010 // Check the destination file
3011 if (stat(DestFile
.c_str(),&Buf
) == 0)
3013 // Hmm, the partial file is too big, erase it
3014 if ((unsigned long long)Buf
.st_size
> Version
->Size
)
3015 RemoveFile("pkgAcqArchive::QueueNext", DestFile
);
3017 PartialSize
= Buf
.st_size
;
3020 // Disables download of archives - useful if no real installation follows,
3021 // e.g. if we are just interested in proposed installation order
3022 if (_config
->FindB("Debug::pkgAcqArchive::NoQueue", false) == true)
3027 StoreFilename
= DestFile
= FinalFile
;
3041 // AcqArchive::Done - Finished fetching /*{{{*/
3042 // ---------------------------------------------------------------------
3044 void pkgAcqArchive::Done(string
const &Message
, HashStringList
const &Hashes
,
3045 pkgAcquire::MethodConfig
const * const Cfg
)
3047 Item::Done(Message
, Hashes
, Cfg
);
3049 // Grab the output filename
3050 std::string
const FileName
= LookupTag(Message
,"Filename");
3051 if (DestFile
!= FileName
&& RealFileExists(DestFile
) == false)
3053 StoreFilename
= DestFile
= FileName
;
3059 // Done, move it into position
3060 string
const FinalFile
= GetFinalFilename();
3061 Rename(DestFile
,FinalFile
);
3062 StoreFilename
= DestFile
= FinalFile
;
3066 // AcqArchive::Failed - Failure handler /*{{{*/
3067 // ---------------------------------------------------------------------
3068 /* Here we try other sources */
3069 void pkgAcqArchive::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)
3071 Item::Failed(Message
,Cnf
);
3073 /* We don't really want to retry on failed media swaps, this prevents
3074 that. An interesting observation is that permanent failures are not
3076 if (Cnf
->Removable
== true &&
3077 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
3079 // Vf = Version.FileList();
3080 while (Vf
.end() == false) ++Vf
;
3081 StoreFilename
= string();
3086 if (QueueNext() == false)
3088 // This is the retry counter
3090 Cnf
->LocalOnly
== false &&
3091 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
3094 Vf
= Version
.FileList();
3095 if (QueueNext() == true)
3099 StoreFilename
= string();
3104 APT_PURE
bool pkgAcqArchive::IsTrusted() const /*{{{*/
3109 void pkgAcqArchive::Finished() /*{{{*/
3111 if (Status
== pkgAcquire::Item::StatDone
&&
3114 StoreFilename
= string();
3117 std::string
pkgAcqArchive::DescURI() const /*{{{*/
3122 std::string
pkgAcqArchive::ShortDesc() const /*{{{*/
3124 return Desc
.ShortDesc
;
3127 pkgAcqArchive::~pkgAcqArchive() {}
3129 // AcqChangelog::pkgAcqChangelog - Constructors /*{{{*/
3130 class pkgAcqChangelog::Private
3133 std::string FinalFile
;
3135 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire
* const Owner
, pkgCache::VerIterator
const &Ver
,
3136 std::string
const &DestDir
, std::string
const &DestFilename
) :
3137 pkgAcquire::Item(Owner
), d(new pkgAcqChangelog::Private()), SrcName(Ver
.SourcePkgName()), SrcVersion(Ver
.SourceVerStr())
3139 Desc
.URI
= URI(Ver
);
3140 Init(DestDir
, DestFilename
);
3142 // some parameters are char* here as they come likely from char* interfaces – which can also return NULL
3143 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire
* const Owner
, pkgCache::RlsFileIterator
const &RlsFile
,
3144 char const * const Component
, char const * const SrcName
, char const * const SrcVersion
,
3145 const string
&DestDir
, const string
&DestFilename
) :
3146 pkgAcquire::Item(Owner
), d(new pkgAcqChangelog::Private()), SrcName(SrcName
), SrcVersion(SrcVersion
)
3148 Desc
.URI
= URI(RlsFile
, Component
, SrcName
, SrcVersion
);
3149 Init(DestDir
, DestFilename
);
3151 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire
* const Owner
,
3152 std::string
const &URI
, char const * const SrcName
, char const * const SrcVersion
,
3153 const string
&DestDir
, const string
&DestFilename
) :
3154 pkgAcquire::Item(Owner
), d(new pkgAcqChangelog::Private()), SrcName(SrcName
), SrcVersion(SrcVersion
)
3157 Init(DestDir
, DestFilename
);
3159 void pkgAcqChangelog::Init(std::string
const &DestDir
, std::string
const &DestFilename
)
3161 if (Desc
.URI
.empty())
3164 // TRANSLATOR: %s=%s is sourcename=sourceversion, e.g. apt=1.1
3165 strprintf(ErrorText
, _("Changelog unavailable for %s=%s"), SrcName
.c_str(), SrcVersion
.c_str());
3166 // Let the error message print something sensible rather than "Failed to fetch /"
3167 if (DestFilename
.empty())
3168 DestFile
= SrcName
+ ".changelog";
3170 DestFile
= DestFilename
;
3171 Desc
.URI
= "changelog:/" + DestFile
;
3175 std::string DestFileName
;
3176 if (DestFilename
.empty())
3177 DestFileName
= flCombine(DestFile
, SrcName
+ ".changelog");
3179 DestFileName
= flCombine(DestFile
, DestFilename
);
3181 std::string
const SandboxUser
= _config
->Find("APT::Sandbox::User");
3182 std::string
const systemTemp
= GetTempDir(SandboxUser
);
3184 snprintf(tmpname
, sizeof(tmpname
), "%s/apt-changelog-XXXXXX", systemTemp
.c_str());
3185 if (NULL
== mkdtemp(tmpname
))
3187 _error
->Errno("mkdtemp", "mkdtemp failed in changelog acquire of %s %s", SrcName
.c_str(), SrcVersion
.c_str());
3191 TemporaryDirectory
= tmpname
;
3193 ChangeOwnerAndPermissionOfFile("Item::QueueURI", TemporaryDirectory
.c_str(),
3194 SandboxUser
.c_str(), "root", 0700);
3196 DestFile
= flCombine(TemporaryDirectory
, DestFileName
);
3197 if (DestDir
.empty() == false)
3199 d
->FinalFile
= flCombine(DestDir
, DestFileName
);
3200 if (RealFileExists(d
->FinalFile
))
3202 FileFd file1
, file2
;
3203 if (file1
.Open(DestFile
, FileFd::WriteOnly
| FileFd::Create
| FileFd::Exclusive
) &&
3204 file2
.Open(d
->FinalFile
, FileFd::ReadOnly
) && CopyFile(file2
, file1
))
3206 struct timeval times
[2];
3207 times
[0].tv_sec
= times
[1].tv_sec
= file2
.ModificationTime();
3208 times
[0].tv_usec
= times
[1].tv_usec
= 0;
3209 utimes(DestFile
.c_str(), times
);
3214 Desc
.ShortDesc
= "Changelog";
3215 strprintf(Desc
.Description
, "%s %s %s Changelog", URI::SiteOnly(Desc
.URI
).c_str(), SrcName
.c_str(), SrcVersion
.c_str());
3220 std::string
pkgAcqChangelog::URI(pkgCache::VerIterator
const &Ver
) /*{{{*/
3222 std::string
const confOnline
= "Acquire::Changelogs::AlwaysOnline";
3223 bool AlwaysOnline
= _config
->FindB(confOnline
, false);
3224 if (AlwaysOnline
== false)
3225 for (pkgCache::VerFileIterator VF
= Ver
.FileList(); VF
.end() == false; ++VF
)
3227 pkgCache::PkgFileIterator
const PF
= VF
.File();
3228 if (PF
.Flagged(pkgCache::Flag::NotSource
) || PF
->Release
== 0)
3230 pkgCache::RlsFileIterator
const RF
= PF
.ReleaseFile();
3231 if (RF
->Origin
!= 0 && _config
->FindB(confOnline
+ "::Origin::" + RF
.Origin(), false))
3233 AlwaysOnline
= true;
3237 if (AlwaysOnline
== false)
3239 pkgCache::PkgIterator
const Pkg
= Ver
.ParentPkg();
3240 if (Pkg
->CurrentVer
!= 0 && Pkg
.CurrentVer() == Ver
)
3242 std::string
const basename
= std::string("/usr/share/doc/") + Pkg
.Name() + "/changelog";
3243 std::string
const debianname
= basename
+ ".Debian";
3244 if (FileExists(debianname
))
3245 return "copy://" + debianname
;
3246 else if (FileExists(debianname
+ ".gz"))
3247 return "gzip://" + debianname
+ ".gz";
3248 else if (FileExists(basename
))
3249 return "copy://" + basename
;
3250 else if (FileExists(basename
+ ".gz"))
3251 return "gzip://" + basename
+ ".gz";
3255 char const * const SrcName
= Ver
.SourcePkgName();
3256 char const * const SrcVersion
= Ver
.SourceVerStr();
3257 // find the first source for this version which promises a changelog
3258 for (pkgCache::VerFileIterator VF
= Ver
.FileList(); VF
.end() == false; ++VF
)
3260 pkgCache::PkgFileIterator
const PF
= VF
.File();
3261 if (PF
.Flagged(pkgCache::Flag::NotSource
) || PF
->Release
== 0)
3263 pkgCache::RlsFileIterator
const RF
= PF
.ReleaseFile();
3264 std::string
const uri
= URI(RF
, PF
.Component(), SrcName
, SrcVersion
);
3271 std::string
pkgAcqChangelog::URITemplate(pkgCache::RlsFileIterator
const &Rls
)
3273 if (Rls
.end() == true || (Rls
->Label
== 0 && Rls
->Origin
== 0))
3275 std::string
const serverConfig
= "Acquire::Changelogs::URI";
3277 #define APT_EMPTY_SERVER \
3278 if (server.empty() == false) \
3280 if (server != "no") \
3284 #define APT_CHECK_SERVER(X, Y) \
3287 std::string const specialServerConfig = serverConfig + "::" + Y + #X + "::" + Rls.X(); \
3288 server = _config->Find(specialServerConfig); \
3291 // this way e.g. Debian-Security can fallback to Debian
3292 APT_CHECK_SERVER(Label
, "Override::")
3293 APT_CHECK_SERVER(Origin
, "Override::")
3295 if (RealFileExists(Rls
.FileName()))
3297 _error
->PushToStack();
3299 /* This can be costly. A caller wanting to get millions of URIs might
3300 want to do this on its own once and use Override settings.
3301 We don't do this here as Origin/Label are not as unique as they
3302 should be so this could produce request order-dependent anomalies */
3303 if (OpenMaybeClearSignedFile(Rls
.FileName(), rf
) == true)
3305 pkgTagFile
TagFile(&rf
, rf
.Size());
3306 pkgTagSection Section
;
3307 if (TagFile
.Step(Section
) == true)
3308 server
= Section
.FindS("Changelogs");
3310 _error
->RevertToStack();
3314 APT_CHECK_SERVER(Label
, "")
3315 APT_CHECK_SERVER(Origin
, "")
3316 #undef APT_CHECK_SERVER
3317 #undef APT_EMPTY_SERVER
3320 std::string
pkgAcqChangelog::URI(pkgCache::RlsFileIterator
const &Rls
,
3321 char const * const Component
, char const * const SrcName
,
3322 char const * const SrcVersion
)
3324 return URI(URITemplate(Rls
), Component
, SrcName
, SrcVersion
);
3326 std::string
pkgAcqChangelog::URI(std::string
const &Template
,
3327 char const * const Component
, char const * const SrcName
,
3328 char const * const SrcVersion
)
3330 if (Template
.find("@CHANGEPATH@") == std::string::npos
)
3333 // the path is: COMPONENT/SRC/SRCNAME/SRCNAME_SRCVER, e.g. main/a/apt/1.1 or contrib/liba/libapt/2.0
3334 std::string Src
= SrcName
;
3335 std::string path
= APT::String::Startswith(SrcName
, "lib") ? Src
.substr(0, 4) : Src
.substr(0,1);
3336 path
.append("/").append(Src
).append("/");
3337 path
.append(Src
).append("_").append(StripEpoch(SrcVersion
));
3338 // we omit component for releases without one (= flat-style repositories)
3339 if (Component
!= NULL
&& strlen(Component
) != 0)
3340 path
= std::string(Component
) + "/" + path
;
3342 return SubstVar(Template
, "@CHANGEPATH@", path
);
3345 // AcqChangelog::Failed - Failure handler /*{{{*/
3346 void pkgAcqChangelog::Failed(string
const &Message
, pkgAcquire::MethodConfig
const * const Cnf
)
3348 Item::Failed(Message
,Cnf
);
3350 std::string errText
;
3351 // TRANSLATOR: %s=%s is sourcename=sourceversion, e.g. apt=1.1
3352 strprintf(errText
, _("Changelog unavailable for %s=%s"), SrcName
.c_str(), SrcVersion
.c_str());
3354 // Error is probably something techy like 404 Not Found
3355 if (ErrorText
.empty())
3356 ErrorText
= errText
;
3358 ErrorText
= errText
+ " (" + ErrorText
+ ")";
3361 // AcqChangelog::Done - Item downloaded OK /*{{{*/
3362 void pkgAcqChangelog::Done(string
const &Message
,HashStringList
const &CalcHashes
,
3363 pkgAcquire::MethodConfig
const * const Cnf
)
3365 Item::Done(Message
,CalcHashes
,Cnf
);
3366 if (d
->FinalFile
.empty() == false)
3368 if (RemoveFile("pkgAcqChangelog::Done", d
->FinalFile
) == false ||
3369 Rename(DestFile
, d
->FinalFile
) == false)
3376 pkgAcqChangelog::~pkgAcqChangelog() /*{{{*/
3378 if (TemporaryDirectory
.empty() == false)
3380 RemoveFile("~pkgAcqChangelog", DestFile
);
3381 rmdir(TemporaryDirectory
.c_str());
3387 // AcqFile::pkgAcqFile - Constructor /*{{{*/
3388 pkgAcqFile::pkgAcqFile(pkgAcquire
* const Owner
,string
const &URI
, HashStringList
const &Hashes
,
3389 unsigned long long const Size
,string
const &Dsc
,string
const &ShortDesc
,
3390 const string
&DestDir
, const string
&DestFilename
,
3391 bool const IsIndexFile
) :
3392 Item(Owner
), d(NULL
), IsIndexFile(IsIndexFile
), ExpectedHashes(Hashes
)
3394 Retries
= _config
->FindI("Acquire::Retries",0);
3396 if(!DestFilename
.empty())
3397 DestFile
= DestFilename
;
3398 else if(!DestDir
.empty())
3399 DestFile
= DestDir
+ "/" + flNotDir(URI
);
3401 DestFile
= flNotDir(URI
);
3405 Desc
.Description
= Dsc
;
3408 // Set the short description to the archive component
3409 Desc
.ShortDesc
= ShortDesc
;
3411 // Get the transfer sizes
3414 if (stat(DestFile
.c_str(),&Buf
) == 0)
3416 // Hmm, the partial file is too big, erase it
3417 if ((Size
> 0) && (unsigned long long)Buf
.st_size
> Size
)
3418 RemoveFile("pkgAcqFile", DestFile
);
3420 PartialSize
= Buf
.st_size
;
3426 // AcqFile::Done - Item downloaded OK /*{{{*/
3427 void pkgAcqFile::Done(string
const &Message
,HashStringList
const &CalcHashes
,
3428 pkgAcquire::MethodConfig
const * const Cnf
)
3430 Item::Done(Message
,CalcHashes
,Cnf
);
3432 std::string
const FileName
= LookupTag(Message
,"Filename");
3435 // The files timestamp matches
3436 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
3439 // We have to copy it into place
3440 if (RealFileExists(DestFile
.c_str()) == false)
3443 if (_config
->FindB("Acquire::Source-Symlinks",true) == false ||
3444 Cnf
->Removable
== true)
3446 Desc
.URI
= "copy:" + FileName
;
3451 // Erase the file if it is a symlink so we can overwrite it
3453 if (lstat(DestFile
.c_str(),&St
) == 0)
3455 if (S_ISLNK(St
.st_mode
) != 0)
3456 RemoveFile("pkgAcqFile::Done", DestFile
);
3460 if (symlink(FileName
.c_str(),DestFile
.c_str()) != 0)
3462 _error
->PushToStack();
3463 _error
->Errno("pkgAcqFile::Done", "Symlinking file %s failed", DestFile
.c_str());
3464 std::stringstream msg
;
3465 _error
->DumpErrors(msg
, GlobalError::DEBUG
, false);
3466 _error
->RevertToStack();
3467 ErrorText
= msg
.str();
3474 // AcqFile::Failed - Failure handler /*{{{*/
3475 // ---------------------------------------------------------------------
3476 /* Here we try other sources */
3477 void pkgAcqFile::Failed(string
const &Message
, pkgAcquire::MethodConfig
const * const Cnf
)
3479 Item::Failed(Message
,Cnf
);
3481 // This is the retry counter
3483 Cnf
->LocalOnly
== false &&
3484 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
3494 string
pkgAcqFile::Custom600Headers() const /*{{{*/
3497 return "\nIndex-File: true";
3501 pkgAcqFile::~pkgAcqFile() {}