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 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
1841 std::string tagname
= *type
;
1842 tagname
.append("-Current");
1843 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1844 if (tmp
.empty() == true)
1848 unsigned long long size
;
1849 std::stringstream
ss(tmp
);
1851 if (unlikely(hash
.empty() == true))
1853 if (unlikely(ServerSize
!= 0 && ServerSize
!= size
))
1855 ServerHashes
.push_back(HashString(*type
, hash
));
1859 if (ServerHashes
.usable() == false)
1862 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": Did not find a good hashsum in the index" << std::endl
;
1866 std::string
const CurrentPackagesFile
= GetFinalFileNameFromURI(Target
.URI
);
1867 HashStringList
const TargetFileHashes
= GetExpectedHashesFor(Target
.MetaKey
);
1868 if (TargetFileHashes
.usable() == false || ServerHashes
!= TargetFileHashes
)
1872 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": Index has different hashes than parser, probably older, so fail pdiffing" << std::endl
;
1873 printHashSumComparison(CurrentPackagesFile
, ServerHashes
, TargetFileHashes
);
1878 HashStringList LocalHashes
;
1879 // try avoiding calculating the hash here as this is costly
1880 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1881 LocalHashes
= GetExpectedHashesFromFor(TransactionManager
->LastMetaIndexParser
, Target
.MetaKey
);
1882 if (LocalHashes
.usable() == false)
1884 FileFd
fd(CurrentPackagesFile
, FileFd::ReadOnly
, FileFd::Auto
);
1885 Hashes
LocalHashesCalc(ServerHashes
);
1886 LocalHashesCalc
.AddFD(fd
);
1887 LocalHashes
= LocalHashesCalc
.GetHashStringList();
1890 if (ServerHashes
== LocalHashes
)
1892 // we have the same sha1 as the server so we are done here
1894 std::clog
<< "pkgAcqDiffIndex: Package file " << CurrentPackagesFile
<< " is up-to-date" << std::endl
;
1900 std::clog
<< "Server-Current: " << ServerHashes
.find(NULL
)->toStr() << " and we start at "
1901 << CurrentPackagesFile
<< " " << LocalHashes
.FileSize() << " " << LocalHashes
.find(NULL
)->toStr() << std::endl
;
1903 // historically, older hashes have more info than newer ones, so start
1904 // collecting with older ones first to avoid implementing complicated
1905 // information merging techniques… a failure is after all always
1906 // recoverable with a complete file and hashes aren't changed that often.
1907 std::vector
<char const *> types
;
1908 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
1909 types
.push_back(*type
);
1911 // parse all of (provided) history
1912 vector
<DiffInfo
> available_patches
;
1913 bool firstAcceptedHashes
= true;
1914 for (auto type
= types
.crbegin(); type
!= types
.crend(); ++type
)
1916 if (LocalHashes
.find(*type
) == NULL
)
1919 std::string tagname
= *type
;
1920 tagname
.append("-History");
1921 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1922 if (tmp
.empty() == true)
1925 string hash
, filename
;
1926 unsigned long long size
;
1927 std::stringstream
ss(tmp
);
1929 while (ss
>> hash
>> size
>> filename
)
1931 if (unlikely(hash
.empty() == true || filename
.empty() == true))
1934 // see if we have a record for this file already
1935 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
1936 for (; cur
!= available_patches
.end(); ++cur
)
1938 if (cur
->file
!= filename
)
1940 cur
->result_hashes
.push_back(HashString(*type
, hash
));
1943 if (cur
!= available_patches
.end())
1945 if (firstAcceptedHashes
== true)
1948 next
.file
= filename
;
1949 next
.result_hashes
.push_back(HashString(*type
, hash
));
1950 next
.result_hashes
.FileSize(size
);
1951 available_patches
.push_back(next
);
1956 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
1957 << " wasn't in the list for the first parsed hash! (history)" << std::endl
;
1961 firstAcceptedHashes
= false;
1964 if (unlikely(available_patches
.empty() == true))
1967 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": "
1968 << "Couldn't find any patches for the patch series." << std::endl
;
1972 for (auto type
= types
.crbegin(); type
!= types
.crend(); ++type
)
1974 if (LocalHashes
.find(*type
) == NULL
)
1977 std::string tagname
= *type
;
1978 tagname
.append("-Patches");
1979 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1980 if (tmp
.empty() == true)
1983 string hash
, filename
;
1984 unsigned long long size
;
1985 std::stringstream
ss(tmp
);
1987 while (ss
>> hash
>> size
>> filename
)
1989 if (unlikely(hash
.empty() == true || filename
.empty() == true))
1992 // see if we have a record for this file already
1993 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
1994 for (; cur
!= available_patches
.end(); ++cur
)
1996 if (cur
->file
!= filename
)
1998 if (cur
->patch_hashes
.empty())
1999 cur
->patch_hashes
.FileSize(size
);
2000 cur
->patch_hashes
.push_back(HashString(*type
, hash
));
2003 if (cur
!= available_patches
.end())
2006 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
2007 << " wasn't in the list for the first parsed hash! (patches)" << std::endl
;
2012 for (auto type
= types
.crbegin(); type
!= types
.crend(); ++type
)
2014 std::string tagname
= *type
;
2015 tagname
.append("-Download");
2016 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
2017 if (tmp
.empty() == true)
2020 string hash
, filename
;
2021 unsigned long long size
;
2022 std::stringstream
ss(tmp
);
2024 // FIXME: all of pdiff supports only .gz compressed patches
2025 while (ss
>> hash
>> size
>> filename
)
2027 if (unlikely(hash
.empty() == true || filename
.empty() == true))
2029 if (unlikely(APT::String::Endswith(filename
, ".gz") == false))
2031 filename
.erase(filename
.length() - 3);
2033 // see if we have a record for this file already
2034 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
2035 for (; cur
!= available_patches
.end(); ++cur
)
2037 if (cur
->file
!= filename
)
2039 if (cur
->download_hashes
.empty())
2040 cur
->download_hashes
.FileSize(size
);
2041 cur
->download_hashes
.push_back(HashString(*type
, hash
));
2044 if (cur
!= available_patches
.end())
2047 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
2048 << " wasn't in the list for the first parsed hash! (download)" << std::endl
;
2054 bool foundStart
= false;
2055 for (std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
2056 cur
!= available_patches
.end(); ++cur
)
2058 if (LocalHashes
!= cur
->result_hashes
)
2061 available_patches
.erase(available_patches
.begin(), cur
);
2066 if (foundStart
== false || unlikely(available_patches
.empty() == true))
2069 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": "
2070 << "Couldn't find the start of the patch series." << std::endl
;
2074 for (auto const &patch
: available_patches
)
2075 if (patch
.result_hashes
.usable() == false ||
2076 patch
.patch_hashes
.usable() == false ||
2077 patch
.download_hashes
.usable() == false)
2080 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": provides no usable hashes for " << patch
.file
2081 << " so fallback to complete download" << std::endl
;
2085 // patching with too many files is rather slow compared to a fast download
2086 unsigned long const fileLimit
= _config
->FindI("Acquire::PDiffs::FileLimit", 0);
2087 if (fileLimit
!= 0 && fileLimit
< available_patches
.size())
2090 std::clog
<< "Need " << available_patches
.size() << " diffs (Limit is " << fileLimit
2091 << ") so fallback to complete download" << std::endl
;
2095 // calculate the size of all patches we have to get
2096 unsigned short const sizeLimitPercent
= _config
->FindI("Acquire::PDiffs::SizeLimit", 100);
2097 if (sizeLimitPercent
> 0 && TransactionManager
->MetaIndexParser
!= nullptr)
2099 unsigned long long downloadSize
= std::accumulate(available_patches
.begin(),
2100 available_patches
.end(), 0llu, [](unsigned long long const T
, DiffInfo
const &I
) {
2101 return T
+ I
.download_hashes
.FileSize();
2103 if (downloadSize
!= 0)
2105 unsigned long long downloadSizeIdx
= 0;
2106 auto const types
= VectorizeString(Target
.Option(IndexTarget::COMPRESSIONTYPES
), ' ');
2107 for (auto const &t
: types
)
2109 std::string MetaKey
= Target
.MetaKey
;
2110 if (t
!= "uncompressed")
2112 HashStringList
const hsl
= GetExpectedHashesFor(MetaKey
);
2113 if (unlikely(hsl
.usable() == false))
2115 downloadSizeIdx
= hsl
.FileSize();
2118 unsigned long long const sizeLimit
= downloadSizeIdx
* sizeLimitPercent
;
2119 if ((sizeLimit
/100) < downloadSize
)
2122 std::clog
<< "Need " << downloadSize
<< " compressed bytes (Limit is " << (sizeLimit
/100) << ", "
2123 << "original is " << downloadSizeIdx
<< ") so fallback to complete download" << std::endl
;
2129 // we have something, queue the diffs
2130 string::size_type
const last_space
= Description
.rfind(" ");
2131 if(last_space
!= string::npos
)
2132 Description
.erase(last_space
, Description
.size()-last_space
);
2134 /* decide if we should download patches one by one or in one go:
2135 The first is good if the server merges patches, but many don't so client
2136 based merging can be attempt in which case the second is better.
2137 "bad things" will happen if patches are merged on the server,
2138 but client side merging is attempt as well */
2139 bool pdiff_merge
= _config
->FindB("Acquire::PDiffs::Merge", true);
2140 if (pdiff_merge
== true)
2142 // reprepro adds this flag if it has merged patches on the server
2143 std::string
const precedence
= Tags
.FindS("X-Patch-Precedence");
2144 pdiff_merge
= (precedence
!= "merged");
2149 std::string
const Final
= GetExistingFilename(CurrentPackagesFile
);
2150 if (unlikely(Final
.empty())) // because we wouldn't be called in such a case
2152 std::string
const PartialFile
= GetPartialFileNameFromURI(Target
.URI
);
2153 std::string
const PatchedFile
= GetKeepCompressedFileName(PartialFile
+ "-patched", Target
);
2154 if (RemoveFileForBootstrapLinking(Debug
, CurrentPackagesFile
, PartialFile
) == false ||
2155 RemoveFileForBootstrapLinking(Debug
, CurrentPackagesFile
, PatchedFile
) == false)
2157 for (auto const &ext
: APT::Configuration::getCompressorExtensions())
2159 if (RemoveFileForBootstrapLinking(Debug
, CurrentPackagesFile
, PartialFile
+ ext
) == false ||
2160 RemoveFileForBootstrapLinking(Debug
, CurrentPackagesFile
, PatchedFile
+ ext
) == false)
2163 std::string
const Ext
= Final
.substr(CurrentPackagesFile
.length());
2164 std::string
const Partial
= PartialFile
+ Ext
;
2165 if (symlink(Final
.c_str(), Partial
.c_str()) != 0)
2168 std::clog
<< "Bootstrap-linking for patching " << CurrentPackagesFile
2169 << " by linking " << Final
<< " to " << Partial
<< " failed!" << std::endl
;
2174 if (pdiff_merge
== false)
2175 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
, available_patches
);
2178 diffs
= new std::vector
<pkgAcqIndexMergeDiffs
*>(available_patches
.size());
2179 for(size_t i
= 0; i
< available_patches
.size(); ++i
)
2180 (*diffs
)[i
] = new pkgAcqIndexMergeDiffs(Owner
, TransactionManager
,
2182 available_patches
[i
],
2192 void pkgAcqDiffIndex::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
2194 Item::Failed(Message
,Cnf
);
2198 std::clog
<< "pkgAcqDiffIndex failed: " << Desc
.URI
<< " with " << Message
<< std::endl
2199 << "Falling back to normal index file acquire" << std::endl
;
2201 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
2204 void pkgAcqDiffIndex::Done(string
const &Message
,HashStringList
const &Hashes
, /*{{{*/
2205 pkgAcquire::MethodConfig
const * const Cnf
)
2208 std::clog
<< "pkgAcqDiffIndex::Done(): " << Desc
.URI
<< std::endl
;
2210 Item::Done(Message
, Hashes
, Cnf
);
2212 string
const FinalFile
= GetFinalFilename();
2213 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false))
2214 DestFile
= FinalFile
;
2216 if(ParseDiffIndex(DestFile
) == false)
2218 Failed("Message: Couldn't parse pdiff index", Cnf
);
2219 // queue for final move - this should happen even if we fail
2220 // while parsing (e.g. on sizelimit) and download the complete file.
2221 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
2225 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
2234 pkgAcqDiffIndex::~pkgAcqDiffIndex()
2240 // AcqIndexDiffs::AcqIndexDiffs - Constructor /*{{{*/
2241 // ---------------------------------------------------------------------
2242 /* The package diff is added to the queue. one object is constructed
2243 * for each diff and the index
2245 pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire
* const Owner
,
2246 pkgAcqMetaClearSig
* const TransactionManager
,
2247 IndexTarget
const &Target
,
2248 vector
<DiffInfo
> const &diffs
)
2249 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
),
2250 available_patches(diffs
)
2252 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
2254 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
2257 Description
= Target
.Description
;
2258 Desc
.ShortDesc
= Target
.ShortDesc
;
2260 if(available_patches
.empty() == true)
2262 // we are done (yeah!), check hashes against the final file
2263 DestFile
= GetKeepCompressedFileName(GetFinalFileNameFromURI(Target
.URI
), Target
);
2268 State
= StateFetchDiff
;
2273 void pkgAcqIndexDiffs::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
2275 Item::Failed(Message
,Cnf
);
2278 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
2280 std::clog
<< "pkgAcqIndexDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
2281 << "Falling back to normal index file acquire " << std::endl
;
2282 RenameOnError(PDiffError
);
2283 std::string
const patchname
= GetDiffsPatchFileName(DestFile
);
2284 if (RealFileExists(patchname
))
2285 Rename(patchname
, patchname
+ ".FAILED");
2286 std::string
const UnpatchedFile
= GetExistingFilename(GetPartialFileNameFromURI(Target
.URI
));
2287 if (UnpatchedFile
.empty() == false && FileExists(UnpatchedFile
))
2288 Rename(UnpatchedFile
, UnpatchedFile
+ ".FAILED");
2289 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
2293 // Finish - helper that cleans the item out of the fetcher queue /*{{{*/
2294 void pkgAcqIndexDiffs::Finish(bool allDone
)
2297 std::clog
<< "pkgAcqIndexDiffs::Finish(): "
2299 << Desc
.URI
<< std::endl
;
2301 // we restore the original name, this is required, otherwise
2302 // the file will be cleaned
2305 std::string
const Final
= GetKeepCompressedFileName(GetFinalFilename(), Target
);
2306 TransactionManager
->TransactionStageCopy(this, DestFile
, Final
);
2308 // this is for the "real" finish
2313 std::clog
<< "\n\nallDone: " << DestFile
<< "\n" << std::endl
;
2320 std::clog
<< "Finishing: " << Desc
.URI
<< std::endl
;
2327 bool pkgAcqIndexDiffs::QueueNextDiff() /*{{{*/
2329 // calc sha1 of the just patched file
2330 std::string
const PartialFile
= GetExistingFilename(GetPartialFileNameFromURI(Target
.URI
));
2331 if(unlikely(PartialFile
.empty()))
2333 Failed("Message: The file " + GetPartialFileNameFromURI(Target
.URI
) + " isn't available", NULL
);
2337 FileFd
fd(PartialFile
, FileFd::ReadOnly
, FileFd::Extension
);
2338 Hashes LocalHashesCalc
;
2339 LocalHashesCalc
.AddFD(fd
);
2340 HashStringList
const LocalHashes
= LocalHashesCalc
.GetHashStringList();
2343 std::clog
<< "QueueNextDiff: " << PartialFile
<< " (" << LocalHashes
.find(NULL
)->toStr() << ")" << std::endl
;
2345 HashStringList
const TargetFileHashes
= GetExpectedHashesFor(Target
.MetaKey
);
2346 if (unlikely(LocalHashes
.usable() == false || TargetFileHashes
.usable() == false))
2348 Failed("Local/Expected hashes are not usable for " + PartialFile
, NULL
);
2352 // final file reached before all patches are applied
2353 if(LocalHashes
== TargetFileHashes
)
2359 // remove all patches until the next matching patch is found
2360 // this requires the Index file to be ordered
2361 available_patches
.erase(available_patches
.begin(),
2362 std::find_if(available_patches
.begin(), available_patches
.end(), [&](DiffInfo
const &I
) {
2363 return I
.result_hashes
== LocalHashes
;
2366 // error checking and falling back if no patch was found
2367 if(available_patches
.empty() == true)
2369 Failed("No patches left to reach target for " + PartialFile
, NULL
);
2373 // queue the right diff
2374 Desc
.URI
= Target
.URI
+ ".diff/" + available_patches
[0].file
+ ".gz";
2375 Desc
.Description
= Description
+ " " + available_patches
[0].file
+ string(".pdiff");
2376 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
+ ".diff/" + available_patches
[0].file
), Target
);
2379 std::clog
<< "pkgAcqIndexDiffs::QueueNextDiff(): " << Desc
.URI
<< std::endl
;
2386 void pkgAcqIndexDiffs::Done(string
const &Message
, HashStringList
const &Hashes
, /*{{{*/
2387 pkgAcquire::MethodConfig
const * const Cnf
)
2390 std::clog
<< "pkgAcqIndexDiffs::Done(): " << Desc
.URI
<< std::endl
;
2392 Item::Done(Message
, Hashes
, Cnf
);
2394 std::string
const UncompressedUnpatchedFile
= GetPartialFileNameFromURI(Target
.URI
);
2395 std::string
const UnpatchedFile
= GetExistingFilename(UncompressedUnpatchedFile
);
2396 std::string
const PatchFile
= GetDiffsPatchFileName(UnpatchedFile
);
2397 std::string
const PatchedFile
= GetKeepCompressedFileName(UncompressedUnpatchedFile
, Target
);
2401 // success in downloading a diff, enter ApplyDiff state
2402 case StateFetchDiff
:
2403 Rename(DestFile
, PatchFile
);
2404 DestFile
= GetKeepCompressedFileName(UncompressedUnpatchedFile
+ "-patched", Target
);
2406 std::clog
<< "Sending to rred method: " << UnpatchedFile
<< std::endl
;
2407 State
= StateApplyDiff
;
2409 Desc
.URI
= "rred:" + UnpatchedFile
;
2411 SetActiveSubprocess("rred");
2413 // success in download/apply a diff, queue next (if needed)
2414 case StateApplyDiff
:
2415 // remove the just applied patch and base file
2416 available_patches
.erase(available_patches
.begin());
2417 RemoveFile("pkgAcqIndexDiffs::Done", PatchFile
);
2418 RemoveFile("pkgAcqIndexDiffs::Done", UnpatchedFile
);
2420 std::clog
<< "Moving patched file in place: " << std::endl
2421 << DestFile
<< " -> " << PatchedFile
<< std::endl
;
2422 Rename(DestFile
, PatchedFile
);
2424 // see if there is more to download
2425 if(available_patches
.empty() == false)
2427 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
, available_patches
);
2430 DestFile
= PatchedFile
;
2437 std::string
pkgAcqIndexDiffs::Custom600Headers() const /*{{{*/
2439 if(State
!= StateApplyDiff
)
2440 return pkgAcqBaseIndex::Custom600Headers();
2441 std::ostringstream patchhashes
;
2442 for (auto && hs
: available_patches
[0].result_hashes
)
2443 patchhashes
<< "\nStart-" << hs
.HashType() << "-Hash: " << hs
.HashValue();
2444 for (auto && hs
: available_patches
[0].patch_hashes
)
2445 patchhashes
<< "\nPatch-0-" << hs
.HashType() << "-Hash: " << hs
.HashValue();
2446 patchhashes
<< pkgAcqBaseIndex::Custom600Headers();
2447 return patchhashes
.str();
2450 pkgAcqIndexDiffs::~pkgAcqIndexDiffs() {}
2452 // AcqIndexMergeDiffs::AcqIndexMergeDiffs - Constructor /*{{{*/
2453 pkgAcqIndexMergeDiffs::pkgAcqIndexMergeDiffs(pkgAcquire
* const Owner
,
2454 pkgAcqMetaClearSig
* const TransactionManager
,
2455 IndexTarget
const &Target
,
2456 DiffInfo
const &patch
,
2457 std::vector
<pkgAcqIndexMergeDiffs
*> const * const allPatches
)
2458 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
),
2459 patch(patch
), allPatches(allPatches
), State(StateFetchDiff
)
2461 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
2464 Description
= Target
.Description
;
2465 Desc
.ShortDesc
= Target
.ShortDesc
;
2466 Desc
.URI
= Target
.URI
+ ".diff/" + patch
.file
+ ".gz";
2467 Desc
.Description
= Description
+ " " + patch
.file
+ ".pdiff";
2468 DestFile
= GetPartialFileNameFromURI(Desc
.URI
);
2471 std::clog
<< "pkgAcqIndexMergeDiffs: " << Desc
.URI
<< std::endl
;
2476 void pkgAcqIndexMergeDiffs::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
2479 std::clog
<< "pkgAcqIndexMergeDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
;
2481 Item::Failed(Message
,Cnf
);
2484 // check if we are the first to fail, otherwise we are done here
2485 State
= StateDoneDiff
;
2486 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2487 I
!= allPatches
->end(); ++I
)
2488 if ((*I
)->State
== StateErrorDiff
)
2490 State
= StateErrorDiff
;
2494 // first failure means we should fallback
2495 State
= StateErrorDiff
;
2497 std::clog
<< "Falling back to normal index file acquire" << std::endl
;
2498 RenameOnError(PDiffError
);
2499 if (RealFileExists(DestFile
))
2500 Rename(DestFile
, DestFile
+ ".FAILED");
2501 std::string
const UnpatchedFile
= GetExistingFilename(GetPartialFileNameFromURI(Target
.URI
));
2502 if (UnpatchedFile
.empty() == false && FileExists(UnpatchedFile
))
2503 Rename(UnpatchedFile
, UnpatchedFile
+ ".FAILED");
2505 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
2508 void pkgAcqIndexMergeDiffs::Done(string
const &Message
, HashStringList
const &Hashes
, /*{{{*/
2509 pkgAcquire::MethodConfig
const * const Cnf
)
2512 std::clog
<< "pkgAcqIndexMergeDiffs::Done(): " << Desc
.URI
<< std::endl
;
2514 Item::Done(Message
, Hashes
, Cnf
);
2516 if (std::any_of(allPatches
->begin(), allPatches
->end(),
2517 [](pkgAcqIndexMergeDiffs
const * const P
) { return P
->State
== StateErrorDiff
; }))
2520 std::clog
<< "Another patch failed already, no point in processing this one." << std::endl
;
2521 State
= StateErrorDiff
;
2525 std::string
const UncompressedUnpatchedFile
= GetPartialFileNameFromURI(Target
.URI
);
2526 std::string
const UnpatchedFile
= GetExistingFilename(UncompressedUnpatchedFile
);
2527 if (UnpatchedFile
.empty())
2529 _error
->Fatal("Unpatched file %s doesn't exist (anymore)!", UncompressedUnpatchedFile
.c_str());
2530 State
= StateErrorDiff
;
2533 std::string
const PatchFile
= GetMergeDiffsPatchFileName(UnpatchedFile
, patch
.file
);
2534 std::string
const PatchedFile
= GetKeepCompressedFileName(UncompressedUnpatchedFile
, Target
);
2538 case StateFetchDiff
:
2539 Rename(DestFile
, PatchFile
);
2541 // check if this is the last completed diff
2542 State
= StateDoneDiff
;
2543 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2544 I
!= allPatches
->end(); ++I
)
2545 if ((*I
)->State
!= StateDoneDiff
)
2548 std::clog
<< "Not the last done diff in the batch: " << Desc
.URI
<< std::endl
;
2551 // this is the last completed diff, so we are ready to apply now
2552 DestFile
= GetKeepCompressedFileName(UncompressedUnpatchedFile
+ "-patched", Target
);
2554 std::clog
<< "Sending to rred method: " << UnpatchedFile
<< std::endl
;
2555 State
= StateApplyDiff
;
2557 Desc
.URI
= "rred:" + UnpatchedFile
;
2559 SetActiveSubprocess("rred");
2561 case StateApplyDiff
:
2562 // success in download & apply all diffs, finialize and clean up
2564 std::clog
<< "Queue patched file in place: " << std::endl
2565 << DestFile
<< " -> " << PatchedFile
<< std::endl
;
2567 // queue for copy by the transaction manager
2568 TransactionManager
->TransactionStageCopy(this, DestFile
, GetKeepCompressedFileName(GetFinalFilename(), Target
));
2570 // ensure the ed's are gone regardless of list-cleanup
2571 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2572 I
!= allPatches
->end(); ++I
)
2573 RemoveFile("pkgAcqIndexMergeDiffs::Done", GetMergeDiffsPatchFileName(UnpatchedFile
, (*I
)->patch
.file
));
2574 RemoveFile("pkgAcqIndexMergeDiffs::Done", UnpatchedFile
);
2579 std::clog
<< "allDone: " << DestFile
<< "\n" << std::endl
;
2581 case StateDoneDiff
: _error
->Fatal("Done called for %s which is in an invalid Done state", PatchFile
.c_str()); break;
2582 case StateErrorDiff
: _error
->Fatal("Done called for %s which is in an invalid Error state", PatchFile
.c_str()); break;
2586 std::string
pkgAcqIndexMergeDiffs::Custom600Headers() const /*{{{*/
2588 if(State
!= StateApplyDiff
)
2589 return pkgAcqBaseIndex::Custom600Headers();
2590 std::ostringstream patchhashes
;
2591 unsigned int seen_patches
= 0;
2592 for (auto && hs
: (*allPatches
)[0]->patch
.result_hashes
)
2593 patchhashes
<< "\nStart-" << hs
.HashType() << "-Hash: " << hs
.HashValue();
2594 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2595 I
!= allPatches
->end(); ++I
)
2597 HashStringList
const ExpectedHashes
= (*I
)->patch
.patch_hashes
;
2598 for (HashStringList::const_iterator hs
= ExpectedHashes
.begin(); hs
!= ExpectedHashes
.end(); ++hs
)
2599 patchhashes
<< "\nPatch-" << seen_patches
<< "-" << hs
->HashType() << "-Hash: " << hs
->HashValue();
2602 patchhashes
<< pkgAcqBaseIndex::Custom600Headers();
2603 return patchhashes
.str();
2606 pkgAcqIndexMergeDiffs::~pkgAcqIndexMergeDiffs() {}
2608 // AcqIndex::AcqIndex - Constructor /*{{{*/
2609 pkgAcqIndex::pkgAcqIndex(pkgAcquire
* const Owner
,
2610 pkgAcqMetaClearSig
* const TransactionManager
,
2611 IndexTarget
const &Target
)
2612 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
), Stage(STAGE_DOWNLOAD
),
2613 CompressionExtensions(Target
.Option(IndexTarget::COMPRESSIONTYPES
))
2615 Init(Target
.URI
, Target
.Description
, Target
.ShortDesc
);
2617 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
2618 std::clog
<< "New pkgIndex with TransactionManager "
2619 << TransactionManager
<< std::endl
;
2622 // AcqIndex::Init - defered Constructor /*{{{*/
2623 static void NextCompressionExtension(std::string
&CurrentCompressionExtension
, std::string
&CompressionExtensions
, bool const preview
)
2625 size_t const nextExt
= CompressionExtensions
.find(' ');
2626 if (nextExt
== std::string::npos
)
2628 CurrentCompressionExtension
= CompressionExtensions
;
2629 if (preview
== false)
2630 CompressionExtensions
.clear();
2634 CurrentCompressionExtension
= CompressionExtensions
.substr(0, nextExt
);
2635 if (preview
== false)
2636 CompressionExtensions
= CompressionExtensions
.substr(nextExt
+1);
2639 void pkgAcqIndex::Init(string
const &URI
, string
const &URIDesc
,
2640 string
const &ShortDesc
)
2642 Stage
= STAGE_DOWNLOAD
;
2644 DestFile
= GetPartialFileNameFromURI(URI
);
2645 NextCompressionExtension(CurrentCompressionExtension
, CompressionExtensions
, false);
2647 if (CurrentCompressionExtension
== "uncompressed")
2651 else if (CurrentCompressionExtension
== "by-hash")
2653 NextCompressionExtension(CurrentCompressionExtension
, CompressionExtensions
, true);
2654 if(unlikely(TransactionManager
->MetaIndexParser
== NULL
|| CurrentCompressionExtension
.empty()))
2656 if (CurrentCompressionExtension
!= "uncompressed")
2658 Desc
.URI
= URI
+ '.' + CurrentCompressionExtension
;
2659 DestFile
= DestFile
+ '.' + CurrentCompressionExtension
;
2662 HashStringList
const Hashes
= GetExpectedHashes();
2663 HashString
const * const TargetHash
= Hashes
.find(NULL
);
2664 if (unlikely(TargetHash
== nullptr))
2666 std::string
const ByHash
= "/by-hash/" + TargetHash
->HashType() + "/" + TargetHash
->HashValue();
2667 size_t const trailing_slash
= Desc
.URI
.find_last_of("/");
2668 if (unlikely(trailing_slash
== std::string::npos
))
2670 Desc
.URI
= Desc
.URI
.replace(
2672 Desc
.URI
.substr(trailing_slash
+1).size()+1,
2675 else if (unlikely(CurrentCompressionExtension
.empty()))
2679 Desc
.URI
= URI
+ '.' + CurrentCompressionExtension
;
2680 DestFile
= DestFile
+ '.' + CurrentCompressionExtension
;
2683 // store file size of the download to ensure the fetcher gives
2684 // accurate progress reporting
2685 FileSize
= GetExpectedHashes().FileSize();
2687 Desc
.Description
= URIDesc
;
2689 Desc
.ShortDesc
= ShortDesc
;
2694 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
2695 // ---------------------------------------------------------------------
2696 /* The only header we use is the last-modified header. */
2697 string
pkgAcqIndex::Custom600Headers() const
2700 string msg
= "\nIndex-File: true";
2702 if (TransactionManager
->LastMetaIndexParser
== NULL
)
2704 std::string
const Final
= GetFinalFilename();
2707 if (stat(Final
.c_str(),&Buf
) == 0)
2708 msg
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
2711 if(Target
.IsOptional
)
2712 msg
+= "\nFail-Ignore: true";
2717 // AcqIndex::Failed - getting the indexfile failed /*{{{*/
2718 void pkgAcqIndex::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)
2720 Item::Failed(Message
,Cnf
);
2722 // authorisation matches will not be fixed by other compression types
2723 if (Status
!= StatAuthError
)
2725 if (CompressionExtensions
.empty() == false)
2727 Init(Target
.URI
, Desc
.Description
, Desc
.ShortDesc
);
2733 if(Target
.IsOptional
&& GetExpectedHashes().empty() && Stage
== STAGE_DOWNLOAD
)
2736 TransactionManager
->AbortTransaction();
2739 // AcqIndex::Done - Finished a fetch /*{{{*/
2740 // ---------------------------------------------------------------------
2741 /* This goes through a number of states.. On the initial fetch the
2742 method could possibly return an alternate filename which points
2743 to the uncompressed version of the file. If this is so the file
2744 is copied into the partial directory. In all other cases the file
2745 is decompressed with a compressed uri. */
2746 void pkgAcqIndex::Done(string
const &Message
,
2747 HashStringList
const &Hashes
,
2748 pkgAcquire::MethodConfig
const * const Cfg
)
2750 Item::Done(Message
,Hashes
,Cfg
);
2754 case STAGE_DOWNLOAD
:
2755 StageDownloadDone(Message
);
2757 case STAGE_DECOMPRESS_AND_VERIFY
:
2758 StageDecompressDone();
2763 // AcqIndex::StageDownloadDone - Queue for decompress and verify /*{{{*/
2764 void pkgAcqIndex::StageDownloadDone(string
const &Message
)
2769 std::string
const AltFilename
= LookupTag(Message
,"Alt-Filename");
2770 std::string Filename
= LookupTag(Message
,"Filename");
2772 // we need to verify the file against the current Release file again
2773 // on if-modfied-since hit to avoid a stale attack against us
2774 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
2776 // copy FinalFile into partial/ so that we check the hash again
2777 string
const FinalFile
= GetExistingFilename(GetFinalFileNameFromURI(Target
.URI
));
2778 if (symlink(FinalFile
.c_str(), DestFile
.c_str()) != 0)
2779 _error
->WarningE("pkgAcqIndex::StageDownloadDone", "Symlinking final file %s back to %s failed", FinalFile
.c_str(), DestFile
.c_str());
2782 EraseFileName
= DestFile
;
2783 Filename
= DestFile
;
2785 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
2786 Desc
.URI
= "store:" + Filename
;
2788 SetActiveSubprocess(::URI(Desc
.URI
).Access
);
2791 // methods like file:// give us an alternative (uncompressed) file
2792 else if (Target
.KeepCompressed
== false && AltFilename
.empty() == false)
2794 Filename
= AltFilename
;
2795 EraseFileName
.clear();
2797 // Methods like e.g. "file:" will give us a (compressed) FileName that is
2798 // not the "DestFile" we set, in this case we uncompress from the local file
2799 else if (Filename
!= DestFile
&& RealFileExists(DestFile
) == false)
2801 // symlinking ensures that the filename can be used for compression detection
2802 // that is e.g. needed for by-hash which has no extension over file
2803 if (symlink(Filename
.c_str(),DestFile
.c_str()) != 0)
2804 _error
->WarningE("pkgAcqIndex::StageDownloadDone", "Symlinking file %s to %s failed", Filename
.c_str(), DestFile
.c_str());
2807 EraseFileName
= DestFile
;
2808 Filename
= DestFile
;
2812 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
2813 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
2814 if (Filename
!= DestFile
&& flExtension(Filename
) == flExtension(DestFile
))
2815 Desc
.URI
= "copy:" + Filename
;
2817 Desc
.URI
= "store:" + Filename
;
2818 if (DestFile
== Filename
)
2820 if (CurrentCompressionExtension
== "uncompressed")
2821 return StageDecompressDone();
2822 DestFile
= "/dev/null";
2825 if (EraseFileName
.empty() && Filename
!= AltFilename
)
2826 EraseFileName
= Filename
;
2828 // queue uri for the next stage
2830 SetActiveSubprocess(::URI(Desc
.URI
).Access
);
2833 // AcqIndex::StageDecompressDone - Final verification /*{{{*/
2834 void pkgAcqIndex::StageDecompressDone()
2836 if (DestFile
== "/dev/null")
2837 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
2839 // Done, queue for rename on transaction finished
2840 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
2843 pkgAcqIndex::~pkgAcqIndex() {}
2846 // AcqArchive::AcqArchive - Constructor /*{{{*/
2847 // ---------------------------------------------------------------------
2848 /* This just sets up the initial fetch environment and queues the first
2850 pkgAcqArchive::pkgAcqArchive(pkgAcquire
* const Owner
,pkgSourceList
* const Sources
,
2851 pkgRecords
* const Recs
,pkgCache::VerIterator
const &Version
,
2852 string
&StoreFilename
) :
2853 Item(Owner
), d(NULL
), LocalSource(false), Version(Version
), Sources(Sources
), Recs(Recs
),
2854 StoreFilename(StoreFilename
), Vf(Version
.FileList()),
2857 Retries
= _config
->FindI("Acquire::Retries",0);
2859 if (Version
.Arch() == 0)
2861 _error
->Error(_("I wasn't able to locate a file for the %s package. "
2862 "This might mean you need to manually fix this package. "
2863 "(due to missing arch)"),
2864 Version
.ParentPkg().FullName().c_str());
2868 /* We need to find a filename to determine the extension. We make the
2869 assumption here that all the available sources for this version share
2870 the same extension.. */
2871 // Skip not source sources, they do not have file fields.
2872 for (; Vf
.end() == false; ++Vf
)
2874 if (Vf
.File().Flagged(pkgCache::Flag::NotSource
))
2879 // Does not really matter here.. we are going to fail out below
2880 if (Vf
.end() != true)
2882 // If this fails to get a file name we will bomb out below.
2883 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2884 if (_error
->PendingError() == true)
2887 // Generate the final file name as: package_version_arch.foo
2888 StoreFilename
= QuoteString(Version
.ParentPkg().Name(),"_:") + '_' +
2889 QuoteString(Version
.VerStr(),"_:") + '_' +
2890 QuoteString(Version
.Arch(),"_:.") +
2891 "." + flExtension(Parse
.FileName());
2894 // check if we have one trusted source for the package. if so, switch
2895 // to "TrustedOnly" mode - but only if not in AllowUnauthenticated mode
2896 bool const allowUnauth
= _config
->FindB("APT::Get::AllowUnauthenticated", false);
2897 bool const debugAuth
= _config
->FindB("Debug::pkgAcquire::Auth", false);
2898 bool seenUntrusted
= false;
2899 for (pkgCache::VerFileIterator i
= Version
.FileList(); i
.end() == false; ++i
)
2901 pkgIndexFile
*Index
;
2902 if (Sources
->FindIndex(i
.File(),Index
) == false)
2905 if (debugAuth
== true)
2906 std::cerr
<< "Checking index: " << Index
->Describe()
2907 << "(Trusted=" << Index
->IsTrusted() << ")" << std::endl
;
2909 if (Index
->IsTrusted() == true)
2912 if (allowUnauth
== false)
2916 seenUntrusted
= true;
2919 // "allow-unauthenticated" restores apts old fetching behaviour
2920 // that means that e.g. unauthenticated file:// uris are higher
2921 // priority than authenticated http:// uris
2922 if (allowUnauth
== true && seenUntrusted
== true)
2926 if (QueueNext() == false && _error
->PendingError() == false)
2927 _error
->Error(_("Can't find a source to download version '%s' of '%s'"),
2928 Version
.VerStr(), Version
.ParentPkg().FullName(false).c_str());
2931 // AcqArchive::QueueNext - Queue the next file source /*{{{*/
2932 // ---------------------------------------------------------------------
2933 /* This queues the next available file version for download. It checks if
2934 the archive is already available in the cache and stashs the MD5 for
2936 bool pkgAcqArchive::QueueNext()
2938 for (; Vf
.end() == false; ++Vf
)
2940 pkgCache::PkgFileIterator
const PkgF
= Vf
.File();
2941 // Ignore not source sources
2942 if (PkgF
.Flagged(pkgCache::Flag::NotSource
))
2945 // Try to cross match against the source list
2946 pkgIndexFile
*Index
;
2947 if (Sources
->FindIndex(PkgF
, Index
) == false)
2949 LocalSource
= PkgF
.Flagged(pkgCache::Flag::LocalSource
);
2951 // only try to get a trusted package from another source if that source
2953 if(Trusted
&& !Index
->IsTrusted())
2956 // Grab the text package record
2957 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2958 if (_error
->PendingError() == true)
2961 string PkgFile
= Parse
.FileName();
2962 ExpectedHashes
= Parse
.Hashes();
2964 if (PkgFile
.empty() == true)
2965 return _error
->Error(_("The package index files are corrupted. No Filename: "
2966 "field for package %s."),
2967 Version
.ParentPkg().Name());
2969 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
2970 Desc
.Description
= Index
->ArchiveInfo(Version
);
2972 Desc
.ShortDesc
= Version
.ParentPkg().FullName(true);
2974 // See if we already have the file. (Legacy filenames)
2975 FileSize
= Version
->Size
;
2976 string FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile
);
2978 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2980 // Make sure the size matches
2981 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2986 StoreFilename
= DestFile
= FinalFile
;
2990 /* Hmm, we have a file and its size does not match, this means it is
2991 an old style mismatched arch */
2992 RemoveFile("pkgAcqArchive::QueueNext", FinalFile
);
2995 // Check it again using the new style output filenames
2996 FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
2997 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2999 // Make sure the size matches
3000 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
3005 StoreFilename
= DestFile
= FinalFile
;
3009 /* Hmm, we have a file and its size does not match, this shouldn't
3011 RemoveFile("pkgAcqArchive::QueueNext", FinalFile
);
3014 DestFile
= _config
->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename
);
3016 // Check the destination file
3017 if (stat(DestFile
.c_str(),&Buf
) == 0)
3019 // Hmm, the partial file is too big, erase it
3020 if ((unsigned long long)Buf
.st_size
> Version
->Size
)
3021 RemoveFile("pkgAcqArchive::QueueNext", DestFile
);
3023 PartialSize
= Buf
.st_size
;
3026 // Disables download of archives - useful if no real installation follows,
3027 // e.g. if we are just interested in proposed installation order
3028 if (_config
->FindB("Debug::pkgAcqArchive::NoQueue", false) == true)
3033 StoreFilename
= DestFile
= FinalFile
;
3047 // AcqArchive::Done - Finished fetching /*{{{*/
3048 // ---------------------------------------------------------------------
3050 void pkgAcqArchive::Done(string
const &Message
, HashStringList
const &Hashes
,
3051 pkgAcquire::MethodConfig
const * const Cfg
)
3053 Item::Done(Message
, Hashes
, Cfg
);
3055 // Grab the output filename
3056 std::string
const FileName
= LookupTag(Message
,"Filename");
3057 if (DestFile
!= FileName
&& RealFileExists(DestFile
) == false)
3059 StoreFilename
= DestFile
= FileName
;
3065 // Done, move it into position
3066 string
const FinalFile
= GetFinalFilename();
3067 Rename(DestFile
,FinalFile
);
3068 StoreFilename
= DestFile
= FinalFile
;
3072 // AcqArchive::Failed - Failure handler /*{{{*/
3073 // ---------------------------------------------------------------------
3074 /* Here we try other sources */
3075 void pkgAcqArchive::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)
3077 Item::Failed(Message
,Cnf
);
3079 /* We don't really want to retry on failed media swaps, this prevents
3080 that. An interesting observation is that permanent failures are not
3082 if (Cnf
->Removable
== true &&
3083 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
3085 // Vf = Version.FileList();
3086 while (Vf
.end() == false) ++Vf
;
3087 StoreFilename
= string();
3092 if (QueueNext() == false)
3094 // This is the retry counter
3096 Cnf
->LocalOnly
== false &&
3097 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
3100 Vf
= Version
.FileList();
3101 if (QueueNext() == true)
3105 StoreFilename
= string();
3110 APT_PURE
bool pkgAcqArchive::IsTrusted() const /*{{{*/
3115 void pkgAcqArchive::Finished() /*{{{*/
3117 if (Status
== pkgAcquire::Item::StatDone
&&
3120 StoreFilename
= string();
3123 std::string
pkgAcqArchive::DescURI() const /*{{{*/
3128 std::string
pkgAcqArchive::ShortDesc() const /*{{{*/
3130 return Desc
.ShortDesc
;
3133 pkgAcqArchive::~pkgAcqArchive() {}
3135 // AcqChangelog::pkgAcqChangelog - Constructors /*{{{*/
3136 class pkgAcqChangelog::Private
3139 std::string FinalFile
;
3141 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire
* const Owner
, pkgCache::VerIterator
const &Ver
,
3142 std::string
const &DestDir
, std::string
const &DestFilename
) :
3143 pkgAcquire::Item(Owner
), d(new pkgAcqChangelog::Private()), SrcName(Ver
.SourcePkgName()), SrcVersion(Ver
.SourceVerStr())
3145 Desc
.URI
= URI(Ver
);
3146 Init(DestDir
, DestFilename
);
3148 // some parameters are char* here as they come likely from char* interfaces – which can also return NULL
3149 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire
* const Owner
, pkgCache::RlsFileIterator
const &RlsFile
,
3150 char const * const Component
, char const * const SrcName
, char const * const SrcVersion
,
3151 const string
&DestDir
, const string
&DestFilename
) :
3152 pkgAcquire::Item(Owner
), d(new pkgAcqChangelog::Private()), SrcName(SrcName
), SrcVersion(SrcVersion
)
3154 Desc
.URI
= URI(RlsFile
, Component
, SrcName
, SrcVersion
);
3155 Init(DestDir
, DestFilename
);
3157 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire
* const Owner
,
3158 std::string
const &URI
, char const * const SrcName
, char const * const SrcVersion
,
3159 const string
&DestDir
, const string
&DestFilename
) :
3160 pkgAcquire::Item(Owner
), d(new pkgAcqChangelog::Private()), SrcName(SrcName
), SrcVersion(SrcVersion
)
3163 Init(DestDir
, DestFilename
);
3165 void pkgAcqChangelog::Init(std::string
const &DestDir
, std::string
const &DestFilename
)
3167 if (Desc
.URI
.empty())
3170 // TRANSLATOR: %s=%s is sourcename=sourceversion, e.g. apt=1.1
3171 strprintf(ErrorText
, _("Changelog unavailable for %s=%s"), SrcName
.c_str(), SrcVersion
.c_str());
3172 // Let the error message print something sensible rather than "Failed to fetch /"
3173 if (DestFilename
.empty())
3174 DestFile
= SrcName
+ ".changelog";
3176 DestFile
= DestFilename
;
3177 Desc
.URI
= "changelog:/" + DestFile
;
3181 std::string DestFileName
;
3182 if (DestFilename
.empty())
3183 DestFileName
= flCombine(DestFile
, SrcName
+ ".changelog");
3185 DestFileName
= flCombine(DestFile
, DestFilename
);
3187 std::string
const SandboxUser
= _config
->Find("APT::Sandbox::User");
3188 std::string
const systemTemp
= GetTempDir(SandboxUser
);
3190 snprintf(tmpname
, sizeof(tmpname
), "%s/apt-changelog-XXXXXX", systemTemp
.c_str());
3191 if (NULL
== mkdtemp(tmpname
))
3193 _error
->Errno("mkdtemp", "mkdtemp failed in changelog acquire of %s %s", SrcName
.c_str(), SrcVersion
.c_str());
3197 TemporaryDirectory
= tmpname
;
3199 ChangeOwnerAndPermissionOfFile("Item::QueueURI", TemporaryDirectory
.c_str(),
3200 SandboxUser
.c_str(), "root", 0700);
3202 DestFile
= flCombine(TemporaryDirectory
, DestFileName
);
3203 if (DestDir
.empty() == false)
3205 d
->FinalFile
= flCombine(DestDir
, DestFileName
);
3206 if (RealFileExists(d
->FinalFile
))
3208 FileFd file1
, file2
;
3209 if (file1
.Open(DestFile
, FileFd::WriteOnly
| FileFd::Create
| FileFd::Exclusive
) &&
3210 file2
.Open(d
->FinalFile
, FileFd::ReadOnly
) && CopyFile(file2
, file1
))
3212 struct timeval times
[2];
3213 times
[0].tv_sec
= times
[1].tv_sec
= file2
.ModificationTime();
3214 times
[0].tv_usec
= times
[1].tv_usec
= 0;
3215 utimes(DestFile
.c_str(), times
);
3220 Desc
.ShortDesc
= "Changelog";
3221 strprintf(Desc
.Description
, "%s %s %s Changelog", URI::SiteOnly(Desc
.URI
).c_str(), SrcName
.c_str(), SrcVersion
.c_str());
3226 std::string
pkgAcqChangelog::URI(pkgCache::VerIterator
const &Ver
) /*{{{*/
3228 std::string
const confOnline
= "Acquire::Changelogs::AlwaysOnline";
3229 bool AlwaysOnline
= _config
->FindB(confOnline
, false);
3230 if (AlwaysOnline
== false)
3231 for (pkgCache::VerFileIterator VF
= Ver
.FileList(); VF
.end() == false; ++VF
)
3233 pkgCache::PkgFileIterator
const PF
= VF
.File();
3234 if (PF
.Flagged(pkgCache::Flag::NotSource
) || PF
->Release
== 0)
3236 pkgCache::RlsFileIterator
const RF
= PF
.ReleaseFile();
3237 if (RF
->Origin
!= 0 && _config
->FindB(confOnline
+ "::Origin::" + RF
.Origin(), false))
3239 AlwaysOnline
= true;
3243 if (AlwaysOnline
== false)
3245 pkgCache::PkgIterator
const Pkg
= Ver
.ParentPkg();
3246 if (Pkg
->CurrentVer
!= 0 && Pkg
.CurrentVer() == Ver
)
3248 std::string
const basename
= std::string("/usr/share/doc/") + Pkg
.Name() + "/changelog";
3249 std::string
const debianname
= basename
+ ".Debian";
3250 if (FileExists(debianname
))
3251 return "copy://" + debianname
;
3252 else if (FileExists(debianname
+ ".gz"))
3253 return "gzip://" + debianname
+ ".gz";
3254 else if (FileExists(basename
))
3255 return "copy://" + basename
;
3256 else if (FileExists(basename
+ ".gz"))
3257 return "gzip://" + basename
+ ".gz";
3261 char const * const SrcName
= Ver
.SourcePkgName();
3262 char const * const SrcVersion
= Ver
.SourceVerStr();
3263 // find the first source for this version which promises a changelog
3264 for (pkgCache::VerFileIterator VF
= Ver
.FileList(); VF
.end() == false; ++VF
)
3266 pkgCache::PkgFileIterator
const PF
= VF
.File();
3267 if (PF
.Flagged(pkgCache::Flag::NotSource
) || PF
->Release
== 0)
3269 pkgCache::RlsFileIterator
const RF
= PF
.ReleaseFile();
3270 std::string
const uri
= URI(RF
, PF
.Component(), SrcName
, SrcVersion
);
3277 std::string
pkgAcqChangelog::URITemplate(pkgCache::RlsFileIterator
const &Rls
)
3279 if (Rls
.end() == true || (Rls
->Label
== 0 && Rls
->Origin
== 0))
3281 std::string
const serverConfig
= "Acquire::Changelogs::URI";
3283 #define APT_EMPTY_SERVER \
3284 if (server.empty() == false) \
3286 if (server != "no") \
3290 #define APT_CHECK_SERVER(X, Y) \
3293 std::string const specialServerConfig = serverConfig + "::" + Y + #X + "::" + Rls.X(); \
3294 server = _config->Find(specialServerConfig); \
3297 // this way e.g. Debian-Security can fallback to Debian
3298 APT_CHECK_SERVER(Label
, "Override::")
3299 APT_CHECK_SERVER(Origin
, "Override::")
3301 if (RealFileExists(Rls
.FileName()))
3303 _error
->PushToStack();
3305 /* This can be costly. A caller wanting to get millions of URIs might
3306 want to do this on its own once and use Override settings.
3307 We don't do this here as Origin/Label are not as unique as they
3308 should be so this could produce request order-dependent anomalies */
3309 if (OpenMaybeClearSignedFile(Rls
.FileName(), rf
) == true)
3311 pkgTagFile
TagFile(&rf
, rf
.Size());
3312 pkgTagSection Section
;
3313 if (TagFile
.Step(Section
) == true)
3314 server
= Section
.FindS("Changelogs");
3316 _error
->RevertToStack();
3320 APT_CHECK_SERVER(Label
, "")
3321 APT_CHECK_SERVER(Origin
, "")
3322 #undef APT_CHECK_SERVER
3323 #undef APT_EMPTY_SERVER
3326 std::string
pkgAcqChangelog::URI(pkgCache::RlsFileIterator
const &Rls
,
3327 char const * const Component
, char const * const SrcName
,
3328 char const * const SrcVersion
)
3330 return URI(URITemplate(Rls
), Component
, SrcName
, SrcVersion
);
3332 std::string
pkgAcqChangelog::URI(std::string
const &Template
,
3333 char const * const Component
, char const * const SrcName
,
3334 char const * const SrcVersion
)
3336 if (Template
.find("@CHANGEPATH@") == std::string::npos
)
3339 // the path is: COMPONENT/SRC/SRCNAME/SRCNAME_SRCVER, e.g. main/a/apt/1.1 or contrib/liba/libapt/2.0
3340 std::string Src
= SrcName
;
3341 std::string path
= APT::String::Startswith(SrcName
, "lib") ? Src
.substr(0, 4) : Src
.substr(0,1);
3342 path
.append("/").append(Src
).append("/");
3343 path
.append(Src
).append("_").append(StripEpoch(SrcVersion
));
3344 // we omit component for releases without one (= flat-style repositories)
3345 if (Component
!= NULL
&& strlen(Component
) != 0)
3346 path
= std::string(Component
) + "/" + path
;
3348 return SubstVar(Template
, "@CHANGEPATH@", path
);
3351 // AcqChangelog::Failed - Failure handler /*{{{*/
3352 void pkgAcqChangelog::Failed(string
const &Message
, pkgAcquire::MethodConfig
const * const Cnf
)
3354 Item::Failed(Message
,Cnf
);
3356 std::string errText
;
3357 // TRANSLATOR: %s=%s is sourcename=sourceversion, e.g. apt=1.1
3358 strprintf(errText
, _("Changelog unavailable for %s=%s"), SrcName
.c_str(), SrcVersion
.c_str());
3360 // Error is probably something techy like 404 Not Found
3361 if (ErrorText
.empty())
3362 ErrorText
= errText
;
3364 ErrorText
= errText
+ " (" + ErrorText
+ ")";
3367 // AcqChangelog::Done - Item downloaded OK /*{{{*/
3368 void pkgAcqChangelog::Done(string
const &Message
,HashStringList
const &CalcHashes
,
3369 pkgAcquire::MethodConfig
const * const Cnf
)
3371 Item::Done(Message
,CalcHashes
,Cnf
);
3372 if (d
->FinalFile
.empty() == false)
3374 if (RemoveFile("pkgAcqChangelog::Done", d
->FinalFile
) == false ||
3375 Rename(DestFile
, d
->FinalFile
) == false)
3382 pkgAcqChangelog::~pkgAcqChangelog() /*{{{*/
3384 if (TemporaryDirectory
.empty() == false)
3386 RemoveFile("~pkgAcqChangelog", DestFile
);
3387 rmdir(TemporaryDirectory
.c_str());
3393 // AcqFile::pkgAcqFile - Constructor /*{{{*/
3394 pkgAcqFile::pkgAcqFile(pkgAcquire
* const Owner
,string
const &URI
, HashStringList
const &Hashes
,
3395 unsigned long long const Size
,string
const &Dsc
,string
const &ShortDesc
,
3396 const string
&DestDir
, const string
&DestFilename
,
3397 bool const IsIndexFile
) :
3398 Item(Owner
), d(NULL
), IsIndexFile(IsIndexFile
), ExpectedHashes(Hashes
)
3400 Retries
= _config
->FindI("Acquire::Retries",0);
3402 if(!DestFilename
.empty())
3403 DestFile
= DestFilename
;
3404 else if(!DestDir
.empty())
3405 DestFile
= DestDir
+ "/" + flNotDir(URI
);
3407 DestFile
= flNotDir(URI
);
3411 Desc
.Description
= Dsc
;
3414 // Set the short description to the archive component
3415 Desc
.ShortDesc
= ShortDesc
;
3417 // Get the transfer sizes
3420 if (stat(DestFile
.c_str(),&Buf
) == 0)
3422 // Hmm, the partial file is too big, erase it
3423 if ((Size
> 0) && (unsigned long long)Buf
.st_size
> Size
)
3424 RemoveFile("pkgAcqFile", DestFile
);
3426 PartialSize
= Buf
.st_size
;
3432 // AcqFile::Done - Item downloaded OK /*{{{*/
3433 void pkgAcqFile::Done(string
const &Message
,HashStringList
const &CalcHashes
,
3434 pkgAcquire::MethodConfig
const * const Cnf
)
3436 Item::Done(Message
,CalcHashes
,Cnf
);
3438 std::string
const FileName
= LookupTag(Message
,"Filename");
3441 // The files timestamp matches
3442 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
3445 // We have to copy it into place
3446 if (RealFileExists(DestFile
.c_str()) == false)
3449 if (_config
->FindB("Acquire::Source-Symlinks",true) == false ||
3450 Cnf
->Removable
== true)
3452 Desc
.URI
= "copy:" + FileName
;
3457 // Erase the file if it is a symlink so we can overwrite it
3459 if (lstat(DestFile
.c_str(),&St
) == 0)
3461 if (S_ISLNK(St
.st_mode
) != 0)
3462 RemoveFile("pkgAcqFile::Done", DestFile
);
3466 if (symlink(FileName
.c_str(),DestFile
.c_str()) != 0)
3468 _error
->PushToStack();
3469 _error
->Errno("pkgAcqFile::Done", "Symlinking file %s failed", DestFile
.c_str());
3470 std::stringstream msg
;
3471 _error
->DumpErrors(msg
, GlobalError::DEBUG
, false);
3472 _error
->RevertToStack();
3473 ErrorText
= msg
.str();
3480 // AcqFile::Failed - Failure handler /*{{{*/
3481 // ---------------------------------------------------------------------
3482 /* Here we try other sources */
3483 void pkgAcqFile::Failed(string
const &Message
, pkgAcquire::MethodConfig
const * const Cnf
)
3485 Item::Failed(Message
,Cnf
);
3487 // This is the retry counter
3489 Cnf
->LocalOnly
== false &&
3490 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
3500 string
pkgAcqFile::Custom600Headers() const /*{{{*/
3503 return "\nIndex-File: true";
3507 pkgAcqFile::~pkgAcqFile() {}