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 static bool RemoveFileForBootstrapLinking(bool const Debug
, std::string
const &For
, std::string
const &Boot
)/*{{{*/
1809 if (FileExists(Boot
) && RemoveFile("Bootstrap-linking", Boot
) == false)
1812 std::clog
<< "Bootstrap-linking for patching " << For
1813 << " by removing stale " << Boot
<< " failed!" << std::endl
;
1819 bool pkgAcqDiffIndex::ParseDiffIndex(string
const &IndexDiffFile
) /*{{{*/
1821 // failing here is fine: our caller will take care of trying to
1822 // get the complete file if patching fails
1824 std::clog
<< "pkgAcqDiffIndex::ParseIndexDiff() " << IndexDiffFile
1827 FileFd
Fd(IndexDiffFile
,FileFd::ReadOnly
);
1829 if (Fd
.IsOpen() == false || Fd
.Failed())
1833 if(unlikely(TF
.Step(Tags
) == false))
1836 HashStringList ServerHashes
;
1837 unsigned long long ServerSize
= 0;
1839 auto const &posix
= std::locale::classic();
1840 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
1842 std::string tagname
= *type
;
1843 tagname
.append("-Current");
1844 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1845 if (tmp
.empty() == true)
1849 unsigned long long size
;
1850 std::stringstream
ss(tmp
);
1853 if (unlikely(hash
.empty() == true))
1855 if (unlikely(ServerSize
!= 0 && ServerSize
!= size
))
1857 ServerHashes
.push_back(HashString(*type
, hash
));
1861 if (ServerHashes
.usable() == false)
1864 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": Did not find a good hashsum in the index" << std::endl
;
1868 std::string
const CurrentPackagesFile
= GetFinalFileNameFromURI(Target
.URI
);
1869 HashStringList
const TargetFileHashes
= GetExpectedHashesFor(Target
.MetaKey
);
1870 if (TargetFileHashes
.usable() == false || ServerHashes
!= TargetFileHashes
)
1874 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": Index has different hashes than parser, probably older, so fail pdiffing" << std::endl
;
1875 printHashSumComparison(CurrentPackagesFile
, ServerHashes
, TargetFileHashes
);
1880 HashStringList LocalHashes
;
1881 // try avoiding calculating the hash here as this is costly
1882 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1883 LocalHashes
= GetExpectedHashesFromFor(TransactionManager
->LastMetaIndexParser
, Target
.MetaKey
);
1884 if (LocalHashes
.usable() == false)
1886 FileFd
fd(CurrentPackagesFile
, FileFd::ReadOnly
, FileFd::Auto
);
1887 Hashes
LocalHashesCalc(ServerHashes
);
1888 LocalHashesCalc
.AddFD(fd
);
1889 LocalHashes
= LocalHashesCalc
.GetHashStringList();
1892 if (ServerHashes
== LocalHashes
)
1894 // we have the same sha1 as the server so we are done here
1896 std::clog
<< "pkgAcqDiffIndex: Package file " << CurrentPackagesFile
<< " is up-to-date" << std::endl
;
1902 std::clog
<< "Server-Current: " << ServerHashes
.find(NULL
)->toStr() << " and we start at "
1903 << CurrentPackagesFile
<< " " << LocalHashes
.FileSize() << " " << LocalHashes
.find(NULL
)->toStr() << std::endl
;
1905 // historically, older hashes have more info than newer ones, so start
1906 // collecting with older ones first to avoid implementing complicated
1907 // information merging techniques… a failure is after all always
1908 // recoverable with a complete file and hashes aren't changed that often.
1909 std::vector
<char const *> types
;
1910 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
1911 types
.push_back(*type
);
1913 // parse all of (provided) history
1914 vector
<DiffInfo
> available_patches
;
1915 bool firstAcceptedHashes
= true;
1916 for (auto type
= types
.crbegin(); type
!= types
.crend(); ++type
)
1918 if (LocalHashes
.find(*type
) == NULL
)
1921 std::string tagname
= *type
;
1922 tagname
.append("-History");
1923 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1924 if (tmp
.empty() == true)
1927 string hash
, filename
;
1928 unsigned long long size
;
1929 std::stringstream
ss(tmp
);
1932 while (ss
>> hash
>> size
>> filename
)
1934 if (unlikely(hash
.empty() == true || filename
.empty() == true))
1937 // see if we have a record for this file already
1938 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
1939 for (; cur
!= available_patches
.end(); ++cur
)
1941 if (cur
->file
!= filename
)
1943 cur
->result_hashes
.push_back(HashString(*type
, hash
));
1946 if (cur
!= available_patches
.end())
1948 if (firstAcceptedHashes
== true)
1951 next
.file
= filename
;
1952 next
.result_hashes
.push_back(HashString(*type
, hash
));
1953 next
.result_hashes
.FileSize(size
);
1954 available_patches
.push_back(next
);
1959 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
1960 << " wasn't in the list for the first parsed hash! (history)" << std::endl
;
1964 firstAcceptedHashes
= false;
1967 if (unlikely(available_patches
.empty() == true))
1970 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": "
1971 << "Couldn't find any patches for the patch series." << std::endl
;
1975 for (auto type
= types
.crbegin(); type
!= types
.crend(); ++type
)
1977 if (LocalHashes
.find(*type
) == NULL
)
1980 std::string tagname
= *type
;
1981 tagname
.append("-Patches");
1982 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1983 if (tmp
.empty() == true)
1986 string hash
, filename
;
1987 unsigned long long size
;
1988 std::stringstream
ss(tmp
);
1991 while (ss
>> hash
>> size
>> filename
)
1993 if (unlikely(hash
.empty() == true || filename
.empty() == true))
1996 // see if we have a record for this file already
1997 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
1998 for (; cur
!= available_patches
.end(); ++cur
)
2000 if (cur
->file
!= filename
)
2002 if (cur
->patch_hashes
.empty())
2003 cur
->patch_hashes
.FileSize(size
);
2004 cur
->patch_hashes
.push_back(HashString(*type
, hash
));
2007 if (cur
!= available_patches
.end())
2010 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
2011 << " wasn't in the list for the first parsed hash! (patches)" << std::endl
;
2016 for (auto type
= types
.crbegin(); type
!= types
.crend(); ++type
)
2018 std::string tagname
= *type
;
2019 tagname
.append("-Download");
2020 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
2021 if (tmp
.empty() == true)
2024 string hash
, filename
;
2025 unsigned long long size
;
2026 std::stringstream
ss(tmp
);
2029 // FIXME: all of pdiff supports only .gz compressed patches
2030 while (ss
>> hash
>> size
>> filename
)
2032 if (unlikely(hash
.empty() == true || filename
.empty() == true))
2034 if (unlikely(APT::String::Endswith(filename
, ".gz") == false))
2036 filename
.erase(filename
.length() - 3);
2038 // see if we have a record for this file already
2039 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
2040 for (; cur
!= available_patches
.end(); ++cur
)
2042 if (cur
->file
!= filename
)
2044 if (cur
->download_hashes
.empty())
2045 cur
->download_hashes
.FileSize(size
);
2046 cur
->download_hashes
.push_back(HashString(*type
, hash
));
2049 if (cur
!= available_patches
.end())
2052 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
2053 << " wasn't in the list for the first parsed hash! (download)" << std::endl
;
2059 bool foundStart
= false;
2060 for (std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
2061 cur
!= available_patches
.end(); ++cur
)
2063 if (LocalHashes
!= cur
->result_hashes
)
2066 available_patches
.erase(available_patches
.begin(), cur
);
2071 if (foundStart
== false || unlikely(available_patches
.empty() == true))
2074 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": "
2075 << "Couldn't find the start of the patch series." << std::endl
;
2079 for (auto const &patch
: available_patches
)
2080 if (patch
.result_hashes
.usable() == false ||
2081 patch
.patch_hashes
.usable() == false ||
2082 patch
.download_hashes
.usable() == false)
2085 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": provides no usable hashes for " << patch
.file
2086 << " so fallback to complete download" << std::endl
;
2090 // patching with too many files is rather slow compared to a fast download
2091 unsigned long const fileLimit
= _config
->FindI("Acquire::PDiffs::FileLimit", 0);
2092 if (fileLimit
!= 0 && fileLimit
< available_patches
.size())
2095 std::clog
<< "Need " << available_patches
.size() << " diffs (Limit is " << fileLimit
2096 << ") so fallback to complete download" << std::endl
;
2100 // calculate the size of all patches we have to get
2101 unsigned short const sizeLimitPercent
= _config
->FindI("Acquire::PDiffs::SizeLimit", 100);
2102 if (sizeLimitPercent
> 0 && TransactionManager
->MetaIndexParser
!= nullptr)
2104 unsigned long long downloadSize
= std::accumulate(available_patches
.begin(),
2105 available_patches
.end(), 0llu, [](unsigned long long const T
, DiffInfo
const &I
) {
2106 return T
+ I
.download_hashes
.FileSize();
2108 if (downloadSize
!= 0)
2110 unsigned long long downloadSizeIdx
= 0;
2111 auto const types
= VectorizeString(Target
.Option(IndexTarget::COMPRESSIONTYPES
), ' ');
2112 for (auto const &t
: types
)
2114 std::string MetaKey
= Target
.MetaKey
;
2115 if (t
!= "uncompressed")
2117 HashStringList
const hsl
= GetExpectedHashesFor(MetaKey
);
2118 if (unlikely(hsl
.usable() == false))
2120 downloadSizeIdx
= hsl
.FileSize();
2123 unsigned long long const sizeLimit
= downloadSizeIdx
* sizeLimitPercent
;
2124 if ((sizeLimit
/100) < downloadSize
)
2127 std::clog
<< "Need " << downloadSize
<< " compressed bytes (Limit is " << (sizeLimit
/100) << ", "
2128 << "original is " << downloadSizeIdx
<< ") so fallback to complete download" << std::endl
;
2134 // we have something, queue the diffs
2135 string::size_type
const last_space
= Description
.rfind(" ");
2136 if(last_space
!= string::npos
)
2137 Description
.erase(last_space
, Description
.size()-last_space
);
2139 /* decide if we should download patches one by one or in one go:
2140 The first is good if the server merges patches, but many don't so client
2141 based merging can be attempt in which case the second is better.
2142 "bad things" will happen if patches are merged on the server,
2143 but client side merging is attempt as well */
2144 bool pdiff_merge
= _config
->FindB("Acquire::PDiffs::Merge", true);
2145 if (pdiff_merge
== true)
2147 // reprepro adds this flag if it has merged patches on the server
2148 std::string
const precedence
= Tags
.FindS("X-Patch-Precedence");
2149 pdiff_merge
= (precedence
!= "merged");
2154 std::string
const Final
= GetExistingFilename(CurrentPackagesFile
);
2155 if (unlikely(Final
.empty())) // because we wouldn't be called in such a case
2157 std::string
const PartialFile
= GetPartialFileNameFromURI(Target
.URI
);
2158 std::string
const PatchedFile
= GetKeepCompressedFileName(PartialFile
+ "-patched", Target
);
2159 if (RemoveFileForBootstrapLinking(Debug
, CurrentPackagesFile
, PartialFile
) == false ||
2160 RemoveFileForBootstrapLinking(Debug
, CurrentPackagesFile
, PatchedFile
) == false)
2162 for (auto const &ext
: APT::Configuration::getCompressorExtensions())
2164 if (RemoveFileForBootstrapLinking(Debug
, CurrentPackagesFile
, PartialFile
+ ext
) == false ||
2165 RemoveFileForBootstrapLinking(Debug
, CurrentPackagesFile
, PatchedFile
+ ext
) == false)
2168 std::string
const Ext
= Final
.substr(CurrentPackagesFile
.length());
2169 std::string
const Partial
= PartialFile
+ Ext
;
2170 if (symlink(Final
.c_str(), Partial
.c_str()) != 0)
2173 std::clog
<< "Bootstrap-linking for patching " << CurrentPackagesFile
2174 << " by linking " << Final
<< " to " << Partial
<< " failed!" << std::endl
;
2179 if (pdiff_merge
== false)
2180 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
, available_patches
);
2183 diffs
= new std::vector
<pkgAcqIndexMergeDiffs
*>(available_patches
.size());
2184 for(size_t i
= 0; i
< available_patches
.size(); ++i
)
2185 (*diffs
)[i
] = new pkgAcqIndexMergeDiffs(Owner
, TransactionManager
,
2187 available_patches
[i
],
2197 void pkgAcqDiffIndex::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
2199 Item::Failed(Message
,Cnf
);
2203 std::clog
<< "pkgAcqDiffIndex failed: " << Desc
.URI
<< " with " << Message
<< std::endl
2204 << "Falling back to normal index file acquire" << std::endl
;
2206 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
2209 void pkgAcqDiffIndex::Done(string
const &Message
,HashStringList
const &Hashes
, /*{{{*/
2210 pkgAcquire::MethodConfig
const * const Cnf
)
2213 std::clog
<< "pkgAcqDiffIndex::Done(): " << Desc
.URI
<< std::endl
;
2215 Item::Done(Message
, Hashes
, Cnf
);
2217 string
const FinalFile
= GetFinalFilename();
2218 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false))
2219 DestFile
= FinalFile
;
2221 if(ParseDiffIndex(DestFile
) == false)
2223 Failed("Message: Couldn't parse pdiff index", Cnf
);
2224 // queue for final move - this should happen even if we fail
2225 // while parsing (e.g. on sizelimit) and download the complete file.
2226 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
2230 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
2239 pkgAcqDiffIndex::~pkgAcqDiffIndex()
2245 // AcqIndexDiffs::AcqIndexDiffs - Constructor /*{{{*/
2246 // ---------------------------------------------------------------------
2247 /* The package diff is added to the queue. one object is constructed
2248 * for each diff and the index
2250 pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire
* const Owner
,
2251 pkgAcqMetaClearSig
* const TransactionManager
,
2252 IndexTarget
const &Target
,
2253 vector
<DiffInfo
> const &diffs
)
2254 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
),
2255 available_patches(diffs
)
2257 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
2259 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
2262 Description
= Target
.Description
;
2263 Desc
.ShortDesc
= Target
.ShortDesc
;
2265 if(available_patches
.empty() == true)
2267 // we are done (yeah!), check hashes against the final file
2268 DestFile
= GetKeepCompressedFileName(GetFinalFileNameFromURI(Target
.URI
), Target
);
2273 State
= StateFetchDiff
;
2278 void pkgAcqIndexDiffs::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
2280 Item::Failed(Message
,Cnf
);
2283 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
2285 std::clog
<< "pkgAcqIndexDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
2286 << "Falling back to normal index file acquire " << std::endl
;
2287 RenameOnError(PDiffError
);
2288 std::string
const patchname
= GetDiffsPatchFileName(DestFile
);
2289 if (RealFileExists(patchname
))
2290 Rename(patchname
, patchname
+ ".FAILED");
2291 std::string
const UnpatchedFile
= GetExistingFilename(GetPartialFileNameFromURI(Target
.URI
));
2292 if (UnpatchedFile
.empty() == false && FileExists(UnpatchedFile
))
2293 Rename(UnpatchedFile
, UnpatchedFile
+ ".FAILED");
2294 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
2298 // Finish - helper that cleans the item out of the fetcher queue /*{{{*/
2299 void pkgAcqIndexDiffs::Finish(bool allDone
)
2302 std::clog
<< "pkgAcqIndexDiffs::Finish(): "
2304 << Desc
.URI
<< std::endl
;
2306 // we restore the original name, this is required, otherwise
2307 // the file will be cleaned
2310 std::string
const Final
= GetKeepCompressedFileName(GetFinalFilename(), Target
);
2311 TransactionManager
->TransactionStageCopy(this, DestFile
, Final
);
2313 // this is for the "real" finish
2318 std::clog
<< "\n\nallDone: " << DestFile
<< "\n" << std::endl
;
2325 std::clog
<< "Finishing: " << Desc
.URI
<< std::endl
;
2332 bool pkgAcqIndexDiffs::QueueNextDiff() /*{{{*/
2334 // calc sha1 of the just patched file
2335 std::string
const PartialFile
= GetExistingFilename(GetPartialFileNameFromURI(Target
.URI
));
2336 if(unlikely(PartialFile
.empty()))
2338 Failed("Message: The file " + GetPartialFileNameFromURI(Target
.URI
) + " isn't available", NULL
);
2342 FileFd
fd(PartialFile
, FileFd::ReadOnly
, FileFd::Extension
);
2343 Hashes LocalHashesCalc
;
2344 LocalHashesCalc
.AddFD(fd
);
2345 HashStringList
const LocalHashes
= LocalHashesCalc
.GetHashStringList();
2348 std::clog
<< "QueueNextDiff: " << PartialFile
<< " (" << LocalHashes
.find(NULL
)->toStr() << ")" << std::endl
;
2350 HashStringList
const TargetFileHashes
= GetExpectedHashesFor(Target
.MetaKey
);
2351 if (unlikely(LocalHashes
.usable() == false || TargetFileHashes
.usable() == false))
2353 Failed("Local/Expected hashes are not usable for " + PartialFile
, NULL
);
2357 // final file reached before all patches are applied
2358 if(LocalHashes
== TargetFileHashes
)
2364 // remove all patches until the next matching patch is found
2365 // this requires the Index file to be ordered
2366 available_patches
.erase(available_patches
.begin(),
2367 std::find_if(available_patches
.begin(), available_patches
.end(), [&](DiffInfo
const &I
) {
2368 return I
.result_hashes
== LocalHashes
;
2371 // error checking and falling back if no patch was found
2372 if(available_patches
.empty() == true)
2374 Failed("No patches left to reach target for " + PartialFile
, NULL
);
2378 // queue the right diff
2379 Desc
.URI
= Target
.URI
+ ".diff/" + available_patches
[0].file
+ ".gz";
2380 Desc
.Description
= Description
+ " " + available_patches
[0].file
+ string(".pdiff");
2381 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
+ ".diff/" + available_patches
[0].file
), Target
);
2384 std::clog
<< "pkgAcqIndexDiffs::QueueNextDiff(): " << Desc
.URI
<< std::endl
;
2391 void pkgAcqIndexDiffs::Done(string
const &Message
, HashStringList
const &Hashes
, /*{{{*/
2392 pkgAcquire::MethodConfig
const * const Cnf
)
2395 std::clog
<< "pkgAcqIndexDiffs::Done(): " << Desc
.URI
<< std::endl
;
2397 Item::Done(Message
, Hashes
, Cnf
);
2399 std::string
const UncompressedUnpatchedFile
= GetPartialFileNameFromURI(Target
.URI
);
2400 std::string
const UnpatchedFile
= GetExistingFilename(UncompressedUnpatchedFile
);
2401 std::string
const PatchFile
= GetDiffsPatchFileName(UnpatchedFile
);
2402 std::string
const PatchedFile
= GetKeepCompressedFileName(UncompressedUnpatchedFile
, Target
);
2406 // success in downloading a diff, enter ApplyDiff state
2407 case StateFetchDiff
:
2408 Rename(DestFile
, PatchFile
);
2409 DestFile
= GetKeepCompressedFileName(UncompressedUnpatchedFile
+ "-patched", Target
);
2411 std::clog
<< "Sending to rred method: " << UnpatchedFile
<< std::endl
;
2412 State
= StateApplyDiff
;
2414 Desc
.URI
= "rred:" + UnpatchedFile
;
2416 SetActiveSubprocess("rred");
2418 // success in download/apply a diff, queue next (if needed)
2419 case StateApplyDiff
:
2420 // remove the just applied patch and base file
2421 available_patches
.erase(available_patches
.begin());
2422 RemoveFile("pkgAcqIndexDiffs::Done", PatchFile
);
2423 RemoveFile("pkgAcqIndexDiffs::Done", UnpatchedFile
);
2425 std::clog
<< "Moving patched file in place: " << std::endl
2426 << DestFile
<< " -> " << PatchedFile
<< std::endl
;
2427 Rename(DestFile
, PatchedFile
);
2429 // see if there is more to download
2430 if(available_patches
.empty() == false)
2432 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
, available_patches
);
2435 DestFile
= PatchedFile
;
2442 std::string
pkgAcqIndexDiffs::Custom600Headers() const /*{{{*/
2444 if(State
!= StateApplyDiff
)
2445 return pkgAcqBaseIndex::Custom600Headers();
2446 std::ostringstream patchhashes
;
2447 for (auto && hs
: available_patches
[0].result_hashes
)
2448 patchhashes
<< "\nStart-" << hs
.HashType() << "-Hash: " << hs
.HashValue();
2449 for (auto && hs
: available_patches
[0].patch_hashes
)
2450 patchhashes
<< "\nPatch-0-" << hs
.HashType() << "-Hash: " << hs
.HashValue();
2451 patchhashes
<< pkgAcqBaseIndex::Custom600Headers();
2452 return patchhashes
.str();
2455 pkgAcqIndexDiffs::~pkgAcqIndexDiffs() {}
2457 // AcqIndexMergeDiffs::AcqIndexMergeDiffs - Constructor /*{{{*/
2458 pkgAcqIndexMergeDiffs::pkgAcqIndexMergeDiffs(pkgAcquire
* const Owner
,
2459 pkgAcqMetaClearSig
* const TransactionManager
,
2460 IndexTarget
const &Target
,
2461 DiffInfo
const &patch
,
2462 std::vector
<pkgAcqIndexMergeDiffs
*> const * const allPatches
)
2463 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
),
2464 patch(patch
), allPatches(allPatches
), State(StateFetchDiff
)
2466 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
2469 Description
= Target
.Description
;
2470 Desc
.ShortDesc
= Target
.ShortDesc
;
2471 Desc
.URI
= Target
.URI
+ ".diff/" + patch
.file
+ ".gz";
2472 Desc
.Description
= Description
+ " " + patch
.file
+ ".pdiff";
2473 DestFile
= GetPartialFileNameFromURI(Desc
.URI
);
2476 std::clog
<< "pkgAcqIndexMergeDiffs: " << Desc
.URI
<< std::endl
;
2481 void pkgAcqIndexMergeDiffs::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
2484 std::clog
<< "pkgAcqIndexMergeDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
;
2486 Item::Failed(Message
,Cnf
);
2489 // check if we are the first to fail, otherwise we are done here
2490 State
= StateDoneDiff
;
2491 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2492 I
!= allPatches
->end(); ++I
)
2493 if ((*I
)->State
== StateErrorDiff
)
2495 State
= StateErrorDiff
;
2499 // first failure means we should fallback
2500 State
= StateErrorDiff
;
2502 std::clog
<< "Falling back to normal index file acquire" << std::endl
;
2503 RenameOnError(PDiffError
);
2504 if (RealFileExists(DestFile
))
2505 Rename(DestFile
, DestFile
+ ".FAILED");
2506 std::string
const UnpatchedFile
= GetExistingFilename(GetPartialFileNameFromURI(Target
.URI
));
2507 if (UnpatchedFile
.empty() == false && FileExists(UnpatchedFile
))
2508 Rename(UnpatchedFile
, UnpatchedFile
+ ".FAILED");
2510 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
2513 void pkgAcqIndexMergeDiffs::Done(string
const &Message
, HashStringList
const &Hashes
, /*{{{*/
2514 pkgAcquire::MethodConfig
const * const Cnf
)
2517 std::clog
<< "pkgAcqIndexMergeDiffs::Done(): " << Desc
.URI
<< std::endl
;
2519 Item::Done(Message
, Hashes
, Cnf
);
2521 if (std::any_of(allPatches
->begin(), allPatches
->end(),
2522 [](pkgAcqIndexMergeDiffs
const * const P
) { return P
->State
== StateErrorDiff
; }))
2525 std::clog
<< "Another patch failed already, no point in processing this one." << std::endl
;
2526 State
= StateErrorDiff
;
2530 std::string
const UncompressedUnpatchedFile
= GetPartialFileNameFromURI(Target
.URI
);
2531 std::string
const UnpatchedFile
= GetExistingFilename(UncompressedUnpatchedFile
);
2532 if (UnpatchedFile
.empty())
2534 _error
->Fatal("Unpatched file %s doesn't exist (anymore)!", UncompressedUnpatchedFile
.c_str());
2535 State
= StateErrorDiff
;
2538 std::string
const PatchFile
= GetMergeDiffsPatchFileName(UnpatchedFile
, patch
.file
);
2539 std::string
const PatchedFile
= GetKeepCompressedFileName(UncompressedUnpatchedFile
, Target
);
2543 case StateFetchDiff
:
2544 Rename(DestFile
, PatchFile
);
2546 // check if this is the last completed diff
2547 State
= StateDoneDiff
;
2548 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2549 I
!= allPatches
->end(); ++I
)
2550 if ((*I
)->State
!= StateDoneDiff
)
2553 std::clog
<< "Not the last done diff in the batch: " << Desc
.URI
<< std::endl
;
2556 // this is the last completed diff, so we are ready to apply now
2557 DestFile
= GetKeepCompressedFileName(UncompressedUnpatchedFile
+ "-patched", Target
);
2559 std::clog
<< "Sending to rred method: " << UnpatchedFile
<< std::endl
;
2560 State
= StateApplyDiff
;
2562 Desc
.URI
= "rred:" + UnpatchedFile
;
2564 SetActiveSubprocess("rred");
2566 case StateApplyDiff
:
2567 // success in download & apply all diffs, finialize and clean up
2569 std::clog
<< "Queue patched file in place: " << std::endl
2570 << DestFile
<< " -> " << PatchedFile
<< std::endl
;
2572 // queue for copy by the transaction manager
2573 TransactionManager
->TransactionStageCopy(this, DestFile
, GetKeepCompressedFileName(GetFinalFilename(), Target
));
2575 // ensure the ed's are gone regardless of list-cleanup
2576 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2577 I
!= allPatches
->end(); ++I
)
2578 RemoveFile("pkgAcqIndexMergeDiffs::Done", GetMergeDiffsPatchFileName(UnpatchedFile
, (*I
)->patch
.file
));
2579 RemoveFile("pkgAcqIndexMergeDiffs::Done", UnpatchedFile
);
2584 std::clog
<< "allDone: " << DestFile
<< "\n" << std::endl
;
2586 case StateDoneDiff
: _error
->Fatal("Done called for %s which is in an invalid Done state", PatchFile
.c_str()); break;
2587 case StateErrorDiff
: _error
->Fatal("Done called for %s which is in an invalid Error state", PatchFile
.c_str()); break;
2591 std::string
pkgAcqIndexMergeDiffs::Custom600Headers() const /*{{{*/
2593 if(State
!= StateApplyDiff
)
2594 return pkgAcqBaseIndex::Custom600Headers();
2595 std::ostringstream patchhashes
;
2596 unsigned int seen_patches
= 0;
2597 for (auto && hs
: (*allPatches
)[0]->patch
.result_hashes
)
2598 patchhashes
<< "\nStart-" << hs
.HashType() << "-Hash: " << hs
.HashValue();
2599 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2600 I
!= allPatches
->end(); ++I
)
2602 HashStringList
const ExpectedHashes
= (*I
)->patch
.patch_hashes
;
2603 for (HashStringList::const_iterator hs
= ExpectedHashes
.begin(); hs
!= ExpectedHashes
.end(); ++hs
)
2604 patchhashes
<< "\nPatch-" << std::to_string(seen_patches
) << "-" << hs
->HashType() << "-Hash: " << hs
->HashValue();
2607 patchhashes
<< pkgAcqBaseIndex::Custom600Headers();
2608 return patchhashes
.str();
2611 pkgAcqIndexMergeDiffs::~pkgAcqIndexMergeDiffs() {}
2613 // AcqIndex::AcqIndex - Constructor /*{{{*/
2614 pkgAcqIndex::pkgAcqIndex(pkgAcquire
* const Owner
,
2615 pkgAcqMetaClearSig
* const TransactionManager
,
2616 IndexTarget
const &Target
)
2617 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
), Stage(STAGE_DOWNLOAD
),
2618 CompressionExtensions(Target
.Option(IndexTarget::COMPRESSIONTYPES
))
2620 Init(Target
.URI
, Target
.Description
, Target
.ShortDesc
);
2622 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
2623 std::clog
<< "New pkgIndex with TransactionManager "
2624 << TransactionManager
<< std::endl
;
2627 // AcqIndex::Init - defered Constructor /*{{{*/
2628 static void NextCompressionExtension(std::string
&CurrentCompressionExtension
, std::string
&CompressionExtensions
, bool const preview
)
2630 size_t const nextExt
= CompressionExtensions
.find(' ');
2631 if (nextExt
== std::string::npos
)
2633 CurrentCompressionExtension
= CompressionExtensions
;
2634 if (preview
== false)
2635 CompressionExtensions
.clear();
2639 CurrentCompressionExtension
= CompressionExtensions
.substr(0, nextExt
);
2640 if (preview
== false)
2641 CompressionExtensions
= CompressionExtensions
.substr(nextExt
+1);
2644 void pkgAcqIndex::Init(string
const &URI
, string
const &URIDesc
,
2645 string
const &ShortDesc
)
2647 Stage
= STAGE_DOWNLOAD
;
2649 DestFile
= GetPartialFileNameFromURI(URI
);
2650 NextCompressionExtension(CurrentCompressionExtension
, CompressionExtensions
, false);
2652 if (CurrentCompressionExtension
== "uncompressed")
2656 else if (CurrentCompressionExtension
== "by-hash")
2658 NextCompressionExtension(CurrentCompressionExtension
, CompressionExtensions
, true);
2659 if(unlikely(TransactionManager
->MetaIndexParser
== NULL
|| CurrentCompressionExtension
.empty()))
2661 if (CurrentCompressionExtension
!= "uncompressed")
2663 Desc
.URI
= URI
+ '.' + CurrentCompressionExtension
;
2664 DestFile
= DestFile
+ '.' + CurrentCompressionExtension
;
2667 HashStringList
const Hashes
= GetExpectedHashes();
2668 HashString
const * const TargetHash
= Hashes
.find(NULL
);
2669 if (unlikely(TargetHash
== nullptr))
2671 std::string
const ByHash
= "/by-hash/" + TargetHash
->HashType() + "/" + TargetHash
->HashValue();
2672 size_t const trailing_slash
= Desc
.URI
.find_last_of("/");
2673 if (unlikely(trailing_slash
== std::string::npos
))
2675 Desc
.URI
= Desc
.URI
.replace(
2677 Desc
.URI
.substr(trailing_slash
+1).size()+1,
2680 else if (unlikely(CurrentCompressionExtension
.empty()))
2684 Desc
.URI
= URI
+ '.' + CurrentCompressionExtension
;
2685 DestFile
= DestFile
+ '.' + CurrentCompressionExtension
;
2688 // store file size of the download to ensure the fetcher gives
2689 // accurate progress reporting
2690 FileSize
= GetExpectedHashes().FileSize();
2692 Desc
.Description
= URIDesc
;
2694 Desc
.ShortDesc
= ShortDesc
;
2699 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
2700 // ---------------------------------------------------------------------
2701 /* The only header we use is the last-modified header. */
2702 string
pkgAcqIndex::Custom600Headers() const
2705 string msg
= "\nIndex-File: true";
2707 if (TransactionManager
->LastMetaIndexParser
== NULL
)
2709 std::string
const Final
= GetFinalFilename();
2712 if (stat(Final
.c_str(),&Buf
) == 0)
2713 msg
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
2716 if(Target
.IsOptional
)
2717 msg
+= "\nFail-Ignore: true";
2722 // AcqIndex::Failed - getting the indexfile failed /*{{{*/
2723 void pkgAcqIndex::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)
2725 Item::Failed(Message
,Cnf
);
2727 // authorisation matches will not be fixed by other compression types
2728 if (Status
!= StatAuthError
)
2730 if (CompressionExtensions
.empty() == false)
2732 Init(Target
.URI
, Desc
.Description
, Desc
.ShortDesc
);
2738 if(Target
.IsOptional
&& GetExpectedHashes().empty() && Stage
== STAGE_DOWNLOAD
)
2741 TransactionManager
->AbortTransaction();
2744 // AcqIndex::Done - Finished a fetch /*{{{*/
2745 // ---------------------------------------------------------------------
2746 /* This goes through a number of states.. On the initial fetch the
2747 method could possibly return an alternate filename which points
2748 to the uncompressed version of the file. If this is so the file
2749 is copied into the partial directory. In all other cases the file
2750 is decompressed with a compressed uri. */
2751 void pkgAcqIndex::Done(string
const &Message
,
2752 HashStringList
const &Hashes
,
2753 pkgAcquire::MethodConfig
const * const Cfg
)
2755 Item::Done(Message
,Hashes
,Cfg
);
2759 case STAGE_DOWNLOAD
:
2760 StageDownloadDone(Message
);
2762 case STAGE_DECOMPRESS_AND_VERIFY
:
2763 StageDecompressDone();
2768 // AcqIndex::StageDownloadDone - Queue for decompress and verify /*{{{*/
2769 void pkgAcqIndex::StageDownloadDone(string
const &Message
)
2774 std::string
const AltFilename
= LookupTag(Message
,"Alt-Filename");
2775 std::string Filename
= LookupTag(Message
,"Filename");
2777 // we need to verify the file against the current Release file again
2778 // on if-modfied-since hit to avoid a stale attack against us
2779 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
2781 // copy FinalFile into partial/ so that we check the hash again
2782 string
const FinalFile
= GetExistingFilename(GetFinalFileNameFromURI(Target
.URI
));
2783 if (symlink(FinalFile
.c_str(), DestFile
.c_str()) != 0)
2784 _error
->WarningE("pkgAcqIndex::StageDownloadDone", "Symlinking final file %s back to %s failed", FinalFile
.c_str(), DestFile
.c_str());
2787 EraseFileName
= DestFile
;
2788 Filename
= DestFile
;
2790 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
2791 Desc
.URI
= "store:" + Filename
;
2793 SetActiveSubprocess(::URI(Desc
.URI
).Access
);
2796 // methods like file:// give us an alternative (uncompressed) file
2797 else if (Target
.KeepCompressed
== false && AltFilename
.empty() == false)
2799 Filename
= AltFilename
;
2800 EraseFileName
.clear();
2802 // Methods like e.g. "file:" will give us a (compressed) FileName that is
2803 // not the "DestFile" we set, in this case we uncompress from the local file
2804 else if (Filename
!= DestFile
&& RealFileExists(DestFile
) == false)
2806 // symlinking ensures that the filename can be used for compression detection
2807 // that is e.g. needed for by-hash which has no extension over file
2808 if (symlink(Filename
.c_str(),DestFile
.c_str()) != 0)
2809 _error
->WarningE("pkgAcqIndex::StageDownloadDone", "Symlinking file %s to %s failed", Filename
.c_str(), DestFile
.c_str());
2812 EraseFileName
= DestFile
;
2813 Filename
= DestFile
;
2817 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
2818 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
2819 if (Filename
!= DestFile
&& flExtension(Filename
) == flExtension(DestFile
))
2820 Desc
.URI
= "copy:" + Filename
;
2822 Desc
.URI
= "store:" + Filename
;
2823 if (DestFile
== Filename
)
2825 if (CurrentCompressionExtension
== "uncompressed")
2826 return StageDecompressDone();
2827 DestFile
= "/dev/null";
2830 if (EraseFileName
.empty() && Filename
!= AltFilename
)
2831 EraseFileName
= Filename
;
2833 // queue uri for the next stage
2835 SetActiveSubprocess(::URI(Desc
.URI
).Access
);
2838 // AcqIndex::StageDecompressDone - Final verification /*{{{*/
2839 void pkgAcqIndex::StageDecompressDone()
2841 if (DestFile
== "/dev/null")
2842 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
2844 // Done, queue for rename on transaction finished
2845 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
2848 pkgAcqIndex::~pkgAcqIndex() {}
2851 // AcqArchive::AcqArchive - Constructor /*{{{*/
2852 // ---------------------------------------------------------------------
2853 /* This just sets up the initial fetch environment and queues the first
2855 pkgAcqArchive::pkgAcqArchive(pkgAcquire
* const Owner
,pkgSourceList
* const Sources
,
2856 pkgRecords
* const Recs
,pkgCache::VerIterator
const &Version
,
2857 string
&StoreFilename
) :
2858 Item(Owner
), d(NULL
), LocalSource(false), Version(Version
), Sources(Sources
), Recs(Recs
),
2859 StoreFilename(StoreFilename
), Vf(Version
.FileList()),
2862 Retries
= _config
->FindI("Acquire::Retries",0);
2864 if (Version
.Arch() == 0)
2866 _error
->Error(_("I wasn't able to locate a file for the %s package. "
2867 "This might mean you need to manually fix this package. "
2868 "(due to missing arch)"),
2869 Version
.ParentPkg().FullName().c_str());
2873 /* We need to find a filename to determine the extension. We make the
2874 assumption here that all the available sources for this version share
2875 the same extension.. */
2876 // Skip not source sources, they do not have file fields.
2877 for (; Vf
.end() == false; ++Vf
)
2879 if (Vf
.File().Flagged(pkgCache::Flag::NotSource
))
2884 // Does not really matter here.. we are going to fail out below
2885 if (Vf
.end() != true)
2887 // If this fails to get a file name we will bomb out below.
2888 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2889 if (_error
->PendingError() == true)
2892 // Generate the final file name as: package_version_arch.foo
2893 StoreFilename
= QuoteString(Version
.ParentPkg().Name(),"_:") + '_' +
2894 QuoteString(Version
.VerStr(),"_:") + '_' +
2895 QuoteString(Version
.Arch(),"_:.") +
2896 "." + flExtension(Parse
.FileName());
2899 // check if we have one trusted source for the package. if so, switch
2900 // to "TrustedOnly" mode - but only if not in AllowUnauthenticated mode
2901 bool const allowUnauth
= _config
->FindB("APT::Get::AllowUnauthenticated", false);
2902 bool const debugAuth
= _config
->FindB("Debug::pkgAcquire::Auth", false);
2903 bool seenUntrusted
= false;
2904 for (pkgCache::VerFileIterator i
= Version
.FileList(); i
.end() == false; ++i
)
2906 pkgIndexFile
*Index
;
2907 if (Sources
->FindIndex(i
.File(),Index
) == false)
2910 if (debugAuth
== true)
2911 std::cerr
<< "Checking index: " << Index
->Describe()
2912 << "(Trusted=" << Index
->IsTrusted() << ")" << std::endl
;
2914 if (Index
->IsTrusted() == true)
2917 if (allowUnauth
== false)
2921 seenUntrusted
= true;
2924 // "allow-unauthenticated" restores apts old fetching behaviour
2925 // that means that e.g. unauthenticated file:// uris are higher
2926 // priority than authenticated http:// uris
2927 if (allowUnauth
== true && seenUntrusted
== true)
2931 if (QueueNext() == false && _error
->PendingError() == false)
2932 _error
->Error(_("Can't find a source to download version '%s' of '%s'"),
2933 Version
.VerStr(), Version
.ParentPkg().FullName(false).c_str());
2936 // AcqArchive::QueueNext - Queue the next file source /*{{{*/
2937 // ---------------------------------------------------------------------
2938 /* This queues the next available file version for download. It checks if
2939 the archive is already available in the cache and stashs the MD5 for
2941 bool pkgAcqArchive::QueueNext()
2943 for (; Vf
.end() == false; ++Vf
)
2945 pkgCache::PkgFileIterator
const PkgF
= Vf
.File();
2946 // Ignore not source sources
2947 if (PkgF
.Flagged(pkgCache::Flag::NotSource
))
2950 // Try to cross match against the source list
2951 pkgIndexFile
*Index
;
2952 if (Sources
->FindIndex(PkgF
, Index
) == false)
2954 LocalSource
= PkgF
.Flagged(pkgCache::Flag::LocalSource
);
2956 // only try to get a trusted package from another source if that source
2958 if(Trusted
&& !Index
->IsTrusted())
2961 // Grab the text package record
2962 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2963 if (_error
->PendingError() == true)
2966 string PkgFile
= Parse
.FileName();
2967 ExpectedHashes
= Parse
.Hashes();
2969 if (PkgFile
.empty() == true)
2970 return _error
->Error(_("The package index files are corrupted. No Filename: "
2971 "field for package %s."),
2972 Version
.ParentPkg().Name());
2974 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
2975 Desc
.Description
= Index
->ArchiveInfo(Version
);
2977 Desc
.ShortDesc
= Version
.ParentPkg().FullName(true);
2979 // See if we already have the file. (Legacy filenames)
2980 FileSize
= Version
->Size
;
2981 string FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile
);
2983 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2985 // Make sure the size matches
2986 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2991 StoreFilename
= DestFile
= FinalFile
;
2995 /* Hmm, we have a file and its size does not match, this means it is
2996 an old style mismatched arch */
2997 RemoveFile("pkgAcqArchive::QueueNext", FinalFile
);
3000 // Check it again using the new style output filenames
3001 FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
3002 if (stat(FinalFile
.c_str(),&Buf
) == 0)
3004 // Make sure the size matches
3005 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
3010 StoreFilename
= DestFile
= FinalFile
;
3014 /* Hmm, we have a file and its size does not match, this shouldn't
3016 RemoveFile("pkgAcqArchive::QueueNext", FinalFile
);
3019 DestFile
= _config
->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename
);
3021 // Check the destination file
3022 if (stat(DestFile
.c_str(),&Buf
) == 0)
3024 // Hmm, the partial file is too big, erase it
3025 if ((unsigned long long)Buf
.st_size
> Version
->Size
)
3026 RemoveFile("pkgAcqArchive::QueueNext", DestFile
);
3028 PartialSize
= Buf
.st_size
;
3031 // Disables download of archives - useful if no real installation follows,
3032 // e.g. if we are just interested in proposed installation order
3033 if (_config
->FindB("Debug::pkgAcqArchive::NoQueue", false) == true)
3038 StoreFilename
= DestFile
= FinalFile
;
3052 // AcqArchive::Done - Finished fetching /*{{{*/
3053 // ---------------------------------------------------------------------
3055 void pkgAcqArchive::Done(string
const &Message
, HashStringList
const &Hashes
,
3056 pkgAcquire::MethodConfig
const * const Cfg
)
3058 Item::Done(Message
, Hashes
, Cfg
);
3060 // Grab the output filename
3061 std::string
const FileName
= LookupTag(Message
,"Filename");
3062 if (DestFile
!= FileName
&& RealFileExists(DestFile
) == false)
3064 StoreFilename
= DestFile
= FileName
;
3070 // Done, move it into position
3071 string
const FinalFile
= GetFinalFilename();
3072 Rename(DestFile
,FinalFile
);
3073 StoreFilename
= DestFile
= FinalFile
;
3077 // AcqArchive::Failed - Failure handler /*{{{*/
3078 // ---------------------------------------------------------------------
3079 /* Here we try other sources */
3080 void pkgAcqArchive::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)
3082 Item::Failed(Message
,Cnf
);
3084 /* We don't really want to retry on failed media swaps, this prevents
3085 that. An interesting observation is that permanent failures are not
3087 if (Cnf
->Removable
== true &&
3088 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
3090 // Vf = Version.FileList();
3091 while (Vf
.end() == false) ++Vf
;
3092 StoreFilename
= string();
3097 if (QueueNext() == false)
3099 // This is the retry counter
3101 Cnf
->LocalOnly
== false &&
3102 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
3105 Vf
= Version
.FileList();
3106 if (QueueNext() == true)
3110 StoreFilename
= string();
3115 APT_PURE
bool pkgAcqArchive::IsTrusted() const /*{{{*/
3120 void pkgAcqArchive::Finished() /*{{{*/
3122 if (Status
== pkgAcquire::Item::StatDone
&&
3125 StoreFilename
= string();
3128 std::string
pkgAcqArchive::DescURI() const /*{{{*/
3133 std::string
pkgAcqArchive::ShortDesc() const /*{{{*/
3135 return Desc
.ShortDesc
;
3138 pkgAcqArchive::~pkgAcqArchive() {}
3140 // AcqChangelog::pkgAcqChangelog - Constructors /*{{{*/
3141 class pkgAcqChangelog::Private
3144 std::string FinalFile
;
3146 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire
* const Owner
, pkgCache::VerIterator
const &Ver
,
3147 std::string
const &DestDir
, std::string
const &DestFilename
) :
3148 pkgAcquire::Item(Owner
), d(new pkgAcqChangelog::Private()), SrcName(Ver
.SourcePkgName()), SrcVersion(Ver
.SourceVerStr())
3150 Desc
.URI
= URI(Ver
);
3151 Init(DestDir
, DestFilename
);
3153 // some parameters are char* here as they come likely from char* interfaces – which can also return NULL
3154 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire
* const Owner
, pkgCache::RlsFileIterator
const &RlsFile
,
3155 char const * const Component
, char const * const SrcName
, char const * const SrcVersion
,
3156 const string
&DestDir
, const string
&DestFilename
) :
3157 pkgAcquire::Item(Owner
), d(new pkgAcqChangelog::Private()), SrcName(SrcName
), SrcVersion(SrcVersion
)
3159 Desc
.URI
= URI(RlsFile
, Component
, SrcName
, SrcVersion
);
3160 Init(DestDir
, DestFilename
);
3162 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire
* const Owner
,
3163 std::string
const &URI
, char const * const SrcName
, char const * const SrcVersion
,
3164 const string
&DestDir
, const string
&DestFilename
) :
3165 pkgAcquire::Item(Owner
), d(new pkgAcqChangelog::Private()), SrcName(SrcName
), SrcVersion(SrcVersion
)
3168 Init(DestDir
, DestFilename
);
3170 void pkgAcqChangelog::Init(std::string
const &DestDir
, std::string
const &DestFilename
)
3172 if (Desc
.URI
.empty())
3175 // TRANSLATOR: %s=%s is sourcename=sourceversion, e.g. apt=1.1
3176 strprintf(ErrorText
, _("Changelog unavailable for %s=%s"), SrcName
.c_str(), SrcVersion
.c_str());
3177 // Let the error message print something sensible rather than "Failed to fetch /"
3178 if (DestFilename
.empty())
3179 DestFile
= SrcName
+ ".changelog";
3181 DestFile
= DestFilename
;
3182 Desc
.URI
= "changelog:/" + DestFile
;
3186 std::string DestFileName
;
3187 if (DestFilename
.empty())
3188 DestFileName
= flCombine(DestFile
, SrcName
+ ".changelog");
3190 DestFileName
= flCombine(DestFile
, DestFilename
);
3192 std::string
const SandboxUser
= _config
->Find("APT::Sandbox::User");
3193 std::string
const systemTemp
= GetTempDir(SandboxUser
);
3195 snprintf(tmpname
, sizeof(tmpname
), "%s/apt-changelog-XXXXXX", systemTemp
.c_str());
3196 if (NULL
== mkdtemp(tmpname
))
3198 _error
->Errno("mkdtemp", "mkdtemp failed in changelog acquire of %s %s", SrcName
.c_str(), SrcVersion
.c_str());
3202 TemporaryDirectory
= tmpname
;
3204 ChangeOwnerAndPermissionOfFile("Item::QueueURI", TemporaryDirectory
.c_str(),
3205 SandboxUser
.c_str(), "root", 0700);
3207 DestFile
= flCombine(TemporaryDirectory
, DestFileName
);
3208 if (DestDir
.empty() == false)
3210 d
->FinalFile
= flCombine(DestDir
, DestFileName
);
3211 if (RealFileExists(d
->FinalFile
))
3213 FileFd file1
, file2
;
3214 if (file1
.Open(DestFile
, FileFd::WriteOnly
| FileFd::Create
| FileFd::Exclusive
) &&
3215 file2
.Open(d
->FinalFile
, FileFd::ReadOnly
) && CopyFile(file2
, file1
))
3217 struct timeval times
[2];
3218 times
[0].tv_sec
= times
[1].tv_sec
= file2
.ModificationTime();
3219 times
[0].tv_usec
= times
[1].tv_usec
= 0;
3220 utimes(DestFile
.c_str(), times
);
3225 Desc
.ShortDesc
= "Changelog";
3226 strprintf(Desc
.Description
, "%s %s %s Changelog", URI::SiteOnly(Desc
.URI
).c_str(), SrcName
.c_str(), SrcVersion
.c_str());
3231 std::string
pkgAcqChangelog::URI(pkgCache::VerIterator
const &Ver
) /*{{{*/
3233 std::string
const confOnline
= "Acquire::Changelogs::AlwaysOnline";
3234 bool AlwaysOnline
= _config
->FindB(confOnline
, false);
3235 if (AlwaysOnline
== false)
3236 for (pkgCache::VerFileIterator VF
= Ver
.FileList(); VF
.end() == false; ++VF
)
3238 pkgCache::PkgFileIterator
const PF
= VF
.File();
3239 if (PF
.Flagged(pkgCache::Flag::NotSource
) || PF
->Release
== 0)
3241 pkgCache::RlsFileIterator
const RF
= PF
.ReleaseFile();
3242 if (RF
->Origin
!= 0 && _config
->FindB(confOnline
+ "::Origin::" + RF
.Origin(), false))
3244 AlwaysOnline
= true;
3248 if (AlwaysOnline
== false)
3250 pkgCache::PkgIterator
const Pkg
= Ver
.ParentPkg();
3251 if (Pkg
->CurrentVer
!= 0 && Pkg
.CurrentVer() == Ver
)
3253 std::string
const root
= _config
->FindDir("Dir");
3254 std::string
const basename
= root
+ std::string("usr/share/doc/") + Pkg
.Name() + "/changelog";
3255 std::string
const debianname
= basename
+ ".Debian";
3256 if (FileExists(debianname
))
3257 return "copy://" + debianname
;
3258 else if (FileExists(debianname
+ ".gz"))
3259 return "gzip://" + debianname
+ ".gz";
3260 else if (FileExists(basename
))
3261 return "copy://" + basename
;
3262 else if (FileExists(basename
+ ".gz"))
3263 return "gzip://" + basename
+ ".gz";
3267 char const * const SrcName
= Ver
.SourcePkgName();
3268 char const * const SrcVersion
= Ver
.SourceVerStr();
3269 // find the first source for this version which promises a changelog
3270 for (pkgCache::VerFileIterator VF
= Ver
.FileList(); VF
.end() == false; ++VF
)
3272 pkgCache::PkgFileIterator
const PF
= VF
.File();
3273 if (PF
.Flagged(pkgCache::Flag::NotSource
) || PF
->Release
== 0)
3275 pkgCache::RlsFileIterator
const RF
= PF
.ReleaseFile();
3276 std::string
const uri
= URI(RF
, PF
.Component(), SrcName
, SrcVersion
);
3283 std::string
pkgAcqChangelog::URITemplate(pkgCache::RlsFileIterator
const &Rls
)
3285 if (Rls
.end() == true || (Rls
->Label
== 0 && Rls
->Origin
== 0))
3287 std::string
const serverConfig
= "Acquire::Changelogs::URI";
3289 #define APT_EMPTY_SERVER \
3290 if (server.empty() == false) \
3292 if (server != "no") \
3296 #define APT_CHECK_SERVER(X, Y) \
3299 std::string const specialServerConfig = serverConfig + "::" + Y + #X + "::" + Rls.X(); \
3300 server = _config->Find(specialServerConfig); \
3303 // this way e.g. Debian-Security can fallback to Debian
3304 APT_CHECK_SERVER(Label
, "Override::")
3305 APT_CHECK_SERVER(Origin
, "Override::")
3307 if (RealFileExists(Rls
.FileName()))
3309 _error
->PushToStack();
3311 /* This can be costly. A caller wanting to get millions of URIs might
3312 want to do this on its own once and use Override settings.
3313 We don't do this here as Origin/Label are not as unique as they
3314 should be so this could produce request order-dependent anomalies */
3315 if (OpenMaybeClearSignedFile(Rls
.FileName(), rf
) == true)
3317 pkgTagFile
TagFile(&rf
, rf
.Size());
3318 pkgTagSection Section
;
3319 if (TagFile
.Step(Section
) == true)
3320 server
= Section
.FindS("Changelogs");
3322 _error
->RevertToStack();
3326 APT_CHECK_SERVER(Label
, "")
3327 APT_CHECK_SERVER(Origin
, "")
3328 #undef APT_CHECK_SERVER
3329 #undef APT_EMPTY_SERVER
3332 std::string
pkgAcqChangelog::URI(pkgCache::RlsFileIterator
const &Rls
,
3333 char const * const Component
, char const * const SrcName
,
3334 char const * const SrcVersion
)
3336 return URI(URITemplate(Rls
), Component
, SrcName
, SrcVersion
);
3338 std::string
pkgAcqChangelog::URI(std::string
const &Template
,
3339 char const * const Component
, char const * const SrcName
,
3340 char const * const SrcVersion
)
3342 if (Template
.find("@CHANGEPATH@") == std::string::npos
)
3345 // the path is: COMPONENT/SRC/SRCNAME/SRCNAME_SRCVER, e.g. main/a/apt/1.1 or contrib/liba/libapt/2.0
3346 std::string Src
= SrcName
;
3347 std::string path
= APT::String::Startswith(SrcName
, "lib") ? Src
.substr(0, 4) : Src
.substr(0,1);
3348 path
.append("/").append(Src
).append("/");
3349 path
.append(Src
).append("_").append(StripEpoch(SrcVersion
));
3350 // we omit component for releases without one (= flat-style repositories)
3351 if (Component
!= NULL
&& strlen(Component
) != 0)
3352 path
= std::string(Component
) + "/" + path
;
3354 return SubstVar(Template
, "@CHANGEPATH@", path
);
3357 // AcqChangelog::Failed - Failure handler /*{{{*/
3358 void pkgAcqChangelog::Failed(string
const &Message
, pkgAcquire::MethodConfig
const * const Cnf
)
3360 Item::Failed(Message
,Cnf
);
3362 std::string errText
;
3363 // TRANSLATOR: %s=%s is sourcename=sourceversion, e.g. apt=1.1
3364 strprintf(errText
, _("Changelog unavailable for %s=%s"), SrcName
.c_str(), SrcVersion
.c_str());
3366 // Error is probably something techy like 404 Not Found
3367 if (ErrorText
.empty())
3368 ErrorText
= errText
;
3370 ErrorText
= errText
+ " (" + ErrorText
+ ")";
3373 // AcqChangelog::Done - Item downloaded OK /*{{{*/
3374 void pkgAcqChangelog::Done(string
const &Message
,HashStringList
const &CalcHashes
,
3375 pkgAcquire::MethodConfig
const * const Cnf
)
3377 Item::Done(Message
,CalcHashes
,Cnf
);
3378 if (d
->FinalFile
.empty() == false)
3380 if (RemoveFile("pkgAcqChangelog::Done", d
->FinalFile
) == false ||
3381 Rename(DestFile
, d
->FinalFile
) == false)
3388 pkgAcqChangelog::~pkgAcqChangelog() /*{{{*/
3390 if (TemporaryDirectory
.empty() == false)
3392 RemoveFile("~pkgAcqChangelog", DestFile
);
3393 rmdir(TemporaryDirectory
.c_str());
3399 // AcqFile::pkgAcqFile - Constructor /*{{{*/
3400 pkgAcqFile::pkgAcqFile(pkgAcquire
* const Owner
,string
const &URI
, HashStringList
const &Hashes
,
3401 unsigned long long const Size
,string
const &Dsc
,string
const &ShortDesc
,
3402 const string
&DestDir
, const string
&DestFilename
,
3403 bool const IsIndexFile
) :
3404 Item(Owner
), d(NULL
), IsIndexFile(IsIndexFile
), ExpectedHashes(Hashes
)
3406 Retries
= _config
->FindI("Acquire::Retries",0);
3408 if(!DestFilename
.empty())
3409 DestFile
= DestFilename
;
3410 else if(!DestDir
.empty())
3411 DestFile
= DestDir
+ "/" + flNotDir(URI
);
3413 DestFile
= flNotDir(URI
);
3417 Desc
.Description
= Dsc
;
3420 // Set the short description to the archive component
3421 Desc
.ShortDesc
= ShortDesc
;
3423 // Get the transfer sizes
3426 if (stat(DestFile
.c_str(),&Buf
) == 0)
3428 // Hmm, the partial file is too big, erase it
3429 if ((Size
> 0) && (unsigned long long)Buf
.st_size
> Size
)
3430 RemoveFile("pkgAcqFile", DestFile
);
3432 PartialSize
= Buf
.st_size
;
3438 // AcqFile::Done - Item downloaded OK /*{{{*/
3439 void pkgAcqFile::Done(string
const &Message
,HashStringList
const &CalcHashes
,
3440 pkgAcquire::MethodConfig
const * const Cnf
)
3442 Item::Done(Message
,CalcHashes
,Cnf
);
3444 std::string
const FileName
= LookupTag(Message
,"Filename");
3447 // The files timestamp matches
3448 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
3451 // We have to copy it into place
3452 if (RealFileExists(DestFile
.c_str()) == false)
3455 if (_config
->FindB("Acquire::Source-Symlinks",true) == false ||
3456 Cnf
->Removable
== true)
3458 Desc
.URI
= "copy:" + FileName
;
3463 // Erase the file if it is a symlink so we can overwrite it
3465 if (lstat(DestFile
.c_str(),&St
) == 0)
3467 if (S_ISLNK(St
.st_mode
) != 0)
3468 RemoveFile("pkgAcqFile::Done", DestFile
);
3472 if (symlink(FileName
.c_str(),DestFile
.c_str()) != 0)
3474 _error
->PushToStack();
3475 _error
->Errno("pkgAcqFile::Done", "Symlinking file %s failed", DestFile
.c_str());
3476 std::stringstream msg
;
3477 _error
->DumpErrors(msg
, GlobalError::DEBUG
, false);
3478 _error
->RevertToStack();
3479 ErrorText
= msg
.str();
3486 // AcqFile::Failed - Failure handler /*{{{*/
3487 // ---------------------------------------------------------------------
3488 /* Here we try other sources */
3489 void pkgAcqFile::Failed(string
const &Message
, pkgAcquire::MethodConfig
const * const Cnf
)
3491 Item::Failed(Message
,Cnf
);
3493 // This is the retry counter
3495 Cnf
->LocalOnly
== false &&
3496 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
3506 string
pkgAcqFile::Custom600Headers() const /*{{{*/
3509 return "\nIndex-File: true";
3513 pkgAcqFile::~pkgAcqFile() {}