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 &Message
) /*{{{*/
1301 string::size_type pos
;
1303 // check for missing sigs (that where not fatal because otherwise we had
1306 string msg
= _("There is no public key available for the "
1307 "following key IDs:\n");
1308 pos
= Message
.find("NO_PUBKEY ");
1309 if (pos
!= std::string::npos
)
1311 string::size_type start
= pos
+strlen("NO_PUBKEY ");
1312 string Fingerprint
= Message
.substr(start
, Message
.find("\n")-start
);
1313 missingkeys
+= (Fingerprint
);
1315 if(!missingkeys
.empty())
1316 _error
->Warning("%s", (msg
+ missingkeys
).c_str());
1318 string Transformed
= TransactionManager
->MetaIndexParser
->GetExpectedDist();
1320 if (Transformed
== "../project/experimental")
1322 Transformed
= "experimental";
1325 pos
= Transformed
.rfind('/');
1326 if (pos
!= string::npos
)
1328 Transformed
= Transformed
.substr(0, pos
);
1331 if (Transformed
== ".")
1336 if (TransactionManager
->MetaIndexParser
->GetValidUntil() > 0)
1338 time_t const invalid_since
= time(NULL
) - TransactionManager
->MetaIndexParser
->GetValidUntil();
1339 if (invalid_since
> 0)
1343 // TRANSLATOR: The first %s is the URL of the bad Release file, the second is
1344 // the time since then the file is invalid - formatted in the same way as in
1345 // the download progress display (e.g. 7d 3h 42min 1s)
1346 _("Release file for %s is expired (invalid since %s). "
1347 "Updates for this repository will not be applied."),
1348 Target
.URI
.c_str(), TimeToStr(invalid_since
).c_str());
1349 if (ErrorText
.empty())
1351 return _error
->Error("%s", errmsg
.c_str());
1355 /* Did we get a file older than what we have? This is a last minute IMS hit and doubles
1356 as a prevention of downgrading us to older (still valid) files */
1357 if (TransactionManager
->IMSHit
== false && TransactionManager
->LastMetaIndexParser
!= NULL
&&
1358 TransactionManager
->LastMetaIndexParser
->GetDate() > TransactionManager
->MetaIndexParser
->GetDate())
1360 TransactionManager
->IMSHit
= true;
1361 RemoveFile("VerifyVendor", DestFile
);
1362 PartialFile
= DestFile
= GetFinalFilename();
1363 // load the 'old' file in the 'new' one instead of flipping pointers as
1364 // the new one isn't owned by us, while the old one is so cleanup would be confused.
1365 TransactionManager
->MetaIndexParser
->swapLoad(TransactionManager
->LastMetaIndexParser
);
1366 delete TransactionManager
->LastMetaIndexParser
;
1367 TransactionManager
->LastMetaIndexParser
= NULL
;
1370 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1372 std::cerr
<< "Got Codename: " << TransactionManager
->MetaIndexParser
->GetCodename() << std::endl
;
1373 std::cerr
<< "Expecting Dist: " << TransactionManager
->MetaIndexParser
->GetExpectedDist() << std::endl
;
1374 std::cerr
<< "Transformed Dist: " << Transformed
<< std::endl
;
1377 if (TransactionManager
->MetaIndexParser
->CheckDist(Transformed
) == false)
1379 // This might become fatal one day
1380 // Status = StatAuthError;
1381 // ErrorText = "Conflicting distribution; expected "
1382 // + MetaIndexParser->GetExpectedDist() + " but got "
1383 // + MetaIndexParser->GetCodename();
1385 if (!Transformed
.empty())
1387 _error
->Warning(_("Conflicting distribution: %s (expected %s but got %s)"),
1388 Desc
.Description
.c_str(),
1389 Transformed
.c_str(),
1390 TransactionManager
->MetaIndexParser
->GetCodename().c_str());
1397 pkgAcqMetaBase::~pkgAcqMetaBase()
1401 pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire
* const Owner
, /*{{{*/
1402 IndexTarget
const &ClearsignedTarget
,
1403 IndexTarget
const &DetachedDataTarget
, IndexTarget
const &DetachedSigTarget
,
1404 std::vector
<IndexTarget
> const &IndexTargets
,
1405 metaIndex
* const MetaIndexParser
) :
1406 pkgAcqMetaIndex(Owner
, this, ClearsignedTarget
, DetachedSigTarget
, IndexTargets
),
1407 d(NULL
), ClearsignedTarget(ClearsignedTarget
),
1408 DetachedDataTarget(DetachedDataTarget
),
1409 MetaIndexParser(MetaIndexParser
), LastMetaIndexParser(NULL
)
1411 // index targets + (worst case:) Release/Release.gpg
1412 ExpectedAdditionalItems
= IndexTargets
.size() + 2;
1413 TransactionManager
->Add(this);
1416 pkgAcqMetaClearSig::~pkgAcqMetaClearSig() /*{{{*/
1418 if (LastMetaIndexParser
!= NULL
)
1419 delete LastMetaIndexParser
;
1422 // pkgAcqMetaClearSig::Custom600Headers - Insert custom request headers /*{{{*/
1423 string
pkgAcqMetaClearSig::Custom600Headers() const
1425 string Header
= pkgAcqMetaBase::Custom600Headers();
1426 Header
+= "\nFail-Ignore: true";
1427 std::string
const key
= TransactionManager
->MetaIndexParser
->GetSignedBy();
1428 if (key
.empty() == false)
1429 Header
+= "\nSigned-By: " + key
;
1434 void pkgAcqMetaClearSig::Finished() /*{{{*/
1436 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1437 std::clog
<< "Finished: " << DestFile
<<std::endl
;
1438 if(TransactionManager
!= NULL
&& TransactionManager
->State
== TransactionStarted
&&
1439 TransactionManager
->TransactionHasError() == false)
1440 TransactionManager
->CommitTransaction();
1443 bool pkgAcqMetaClearSig::VerifyDone(std::string
const &Message
, /*{{{*/
1444 pkgAcquire::MethodConfig
const * const Cnf
)
1446 Item::VerifyDone(Message
, Cnf
);
1448 if (FileExists(DestFile
) && !StartsWithGPGClearTextSignature(DestFile
))
1449 return RenameOnError(NotClearsigned
);
1454 // pkgAcqMetaClearSig::Done - We got a file /*{{{*/
1455 void pkgAcqMetaClearSig::Done(std::string
const &Message
,
1456 HashStringList
const &Hashes
,
1457 pkgAcquire::MethodConfig
const * const Cnf
)
1459 Item::Done(Message
, Hashes
, Cnf
);
1461 if(AuthPass
== false)
1463 if(CheckDownloadDone(this, Message
, Hashes
) == true)
1464 QueueForSignatureVerify(this, DestFile
, DestFile
);
1467 else if(CheckAuthDone(Message
) == true)
1469 if (TransactionManager
->IMSHit
== false)
1470 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
1471 else if (RealFileExists(GetFinalFilename()) == false)
1473 // We got an InRelease file IMSHit, but we haven't one, which means
1474 // we had a valid Release/Release.gpg combo stepping in, which we have
1475 // to 'acquire' now to ensure list cleanup isn't removing them
1476 new NoActionItem(Owner
, DetachedDataTarget
);
1477 new NoActionItem(Owner
, DetachedSigTarget
);
1482 void pkgAcqMetaClearSig::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
) /*{{{*/
1484 Item::Failed(Message
, Cnf
);
1486 // we failed, we will not get additional items from this method
1487 ExpectedAdditionalItems
= 0;
1489 if (AuthPass
== false)
1491 if (Status
== StatAuthError
|| Status
== StatTransientNetworkError
)
1493 // if we expected a ClearTextSignature (InRelease) but got a network
1494 // error or got a file, but it wasn't valid, we end up here (see VerifyDone).
1495 // As these is usually called by web-portals we do not try Release/Release.gpg
1496 // as this is gonna fail anyway and instead abort our try (LP#346386)
1497 TransactionManager
->AbortTransaction();
1501 // Queue the 'old' InRelease file for removal if we try Release.gpg
1502 // as otherwise the file will stay around and gives a false-auth
1503 // impression (CVE-2012-0214)
1504 TransactionManager
->TransactionStageRemoval(this, GetFinalFilename());
1507 new pkgAcqMetaIndex(Owner
, TransactionManager
, DetachedDataTarget
, DetachedSigTarget
, IndexTargets
);
1511 if(CheckStopAuthentication(this, Message
))
1514 // No Release file was present, or verification failed, so fall
1515 // back to queueing Packages files without verification
1516 // only allow going further if the user explicitly wants it
1517 if(AllowInsecureRepositories(_("The repository '%s' is not signed."), ClearsignedTarget
.Description
, TransactionManager
->MetaIndexParser
, TransactionManager
, this) == true)
1521 /* InRelease files become Release files, otherwise
1522 * they would be considered as trusted later on */
1523 string
const FinalRelease
= GetFinalFileNameFromURI(DetachedDataTarget
.URI
);
1524 string
const PartialRelease
= GetPartialFileNameFromURI(DetachedDataTarget
.URI
);
1525 string
const FinalReleasegpg
= GetFinalFileNameFromURI(DetachedSigTarget
.URI
);
1526 string
const FinalInRelease
= GetFinalFilename();
1527 Rename(DestFile
, PartialRelease
);
1528 TransactionManager
->TransactionStageCopy(this, PartialRelease
, FinalRelease
);
1529 LoadLastMetaIndexParser(TransactionManager
, FinalRelease
, FinalInRelease
);
1531 // we parse the indexes here because at this point the user wanted
1532 // a repository that may potentially harm him
1533 if (TransactionManager
->MetaIndexParser
->Load(PartialRelease
, &ErrorText
) == false || VerifyVendor(Message
) == false)
1534 /* expired Release files are still a problem you need extra force for */;
1542 pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire
* const Owner
, /*{{{*/
1543 pkgAcqMetaClearSig
* const TransactionManager
,
1544 IndexTarget
const &DataTarget
,
1545 IndexTarget
const &DetachedSigTarget
,
1546 vector
<IndexTarget
> const &IndexTargets
) :
1547 pkgAcqMetaBase(Owner
, TransactionManager
, IndexTargets
, DataTarget
), d(NULL
),
1548 DetachedSigTarget(DetachedSigTarget
)
1550 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1551 std::clog
<< "New pkgAcqMetaIndex with TransactionManager "
1552 << this->TransactionManager
<< std::endl
;
1554 DestFile
= GetPartialFileNameFromURI(DataTarget
.URI
);
1557 Desc
.Description
= DataTarget
.Description
;
1559 Desc
.ShortDesc
= DataTarget
.ShortDesc
;
1560 Desc
.URI
= DataTarget
.URI
;
1562 // we expect more item
1563 ExpectedAdditionalItems
= IndexTargets
.size();
1567 void pkgAcqMetaIndex::Done(string
const &Message
, /*{{{*/
1568 HashStringList
const &Hashes
,
1569 pkgAcquire::MethodConfig
const * const Cfg
)
1571 Item::Done(Message
,Hashes
,Cfg
);
1573 if(CheckDownloadDone(this, Message
, Hashes
))
1575 // we have a Release file, now download the Signature, all further
1576 // verify/queue for additional downloads will be done in the
1577 // pkgAcqMetaSig::Done() code
1578 new pkgAcqMetaSig(Owner
, TransactionManager
, DetachedSigTarget
, this);
1582 // pkgAcqMetaIndex::Failed - no Release file present /*{{{*/
1583 void pkgAcqMetaIndex::Failed(string
const &Message
,
1584 pkgAcquire::MethodConfig
const * const Cnf
)
1586 pkgAcquire::Item::Failed(Message
, Cnf
);
1589 // No Release file was present so fall
1590 // back to queueing Packages files without verification
1591 // only allow going further if the user explicitly wants it
1592 if(AllowInsecureRepositories(_("The repository '%s' does not have a Release file."), Target
.Description
, TransactionManager
->MetaIndexParser
, TransactionManager
, this) == true)
1594 // ensure old Release files are removed
1595 TransactionManager
->TransactionStageRemoval(this, GetFinalFilename());
1597 // queue without any kind of hashsum support
1598 QueueIndexes(false);
1602 std::string
pkgAcqMetaIndex::DescURI() const /*{{{*/
1607 pkgAcqMetaIndex::~pkgAcqMetaIndex() {}
1609 // AcqMetaSig::AcqMetaSig - Constructor /*{{{*/
1610 pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire
* const Owner
,
1611 pkgAcqMetaClearSig
* const TransactionManager
,
1612 IndexTarget
const &Target
,
1613 pkgAcqMetaIndex
* const MetaIndex
) :
1614 pkgAcqTransactionItem(Owner
, TransactionManager
, Target
), d(NULL
), MetaIndex(MetaIndex
)
1616 DestFile
= GetPartialFileNameFromURI(Target
.URI
);
1618 // remove any partial downloaded sig-file in partial/.
1619 // it may confuse proxies and is too small to warrant a
1620 // partial download anyway
1621 RemoveFile("pkgAcqMetaSig", DestFile
);
1623 // set the TransactionManager
1624 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1625 std::clog
<< "New pkgAcqMetaSig with TransactionManager "
1626 << TransactionManager
<< std::endl
;
1629 Desc
.Description
= Target
.Description
;
1631 Desc
.ShortDesc
= Target
.ShortDesc
;
1632 Desc
.URI
= Target
.URI
;
1634 // If we got a hit for Release, we will get one for Release.gpg too (or obscure errors),
1635 // so we skip the download step and go instantly to verification
1636 if (TransactionManager
->IMSHit
== true && RealFileExists(GetFinalFilename()))
1640 PartialFile
= DestFile
= GetFinalFilename();
1641 MetaIndexFileSignature
= DestFile
;
1642 MetaIndex
->QueueForSignatureVerify(this, MetaIndex
->DestFile
, DestFile
);
1648 pkgAcqMetaSig::~pkgAcqMetaSig() /*{{{*/
1652 // pkgAcqMetaSig::Custom600Headers - Insert custom request headers /*{{{*/
1653 std::string
pkgAcqMetaSig::Custom600Headers() const
1655 std::string Header
= pkgAcqTransactionItem::Custom600Headers();
1656 std::string
const key
= TransactionManager
->MetaIndexParser
->GetSignedBy();
1657 if (key
.empty() == false)
1658 Header
+= "\nSigned-By: " + key
;
1662 // AcqMetaSig::Done - The signature was downloaded/verified /*{{{*/
1663 void pkgAcqMetaSig::Done(string
const &Message
, HashStringList
const &Hashes
,
1664 pkgAcquire::MethodConfig
const * const Cfg
)
1666 if (MetaIndexFileSignature
.empty() == false)
1668 DestFile
= MetaIndexFileSignature
;
1669 MetaIndexFileSignature
.clear();
1671 Item::Done(Message
, Hashes
, Cfg
);
1673 if(MetaIndex
->AuthPass
== false)
1675 if(MetaIndex
->CheckDownloadDone(this, Message
, Hashes
) == true)
1677 // destfile will be modified to point to MetaIndexFile for the
1678 // gpgv method, so we need to save it here
1679 MetaIndexFileSignature
= DestFile
;
1680 MetaIndex
->QueueForSignatureVerify(this, MetaIndex
->DestFile
, DestFile
);
1684 else if(MetaIndex
->CheckAuthDone(Message
) == true)
1686 if (TransactionManager
->IMSHit
== false)
1688 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
1689 TransactionManager
->TransactionStageCopy(MetaIndex
, MetaIndex
->DestFile
, MetaIndex
->GetFinalFilename());
1694 void pkgAcqMetaSig::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
1696 Item::Failed(Message
,Cnf
);
1698 // check if we need to fail at this point
1699 if (MetaIndex
->AuthPass
== true && MetaIndex
->CheckStopAuthentication(this, Message
))
1702 string
const FinalRelease
= MetaIndex
->GetFinalFilename();
1703 string
const FinalReleasegpg
= GetFinalFilename();
1704 string
const FinalInRelease
= TransactionManager
->GetFinalFilename();
1706 if (RealFileExists(FinalReleasegpg
) || RealFileExists(FinalInRelease
))
1708 std::string downgrade_msg
;
1709 strprintf(downgrade_msg
, _("The repository '%s' is no longer signed."),
1710 MetaIndex
->Target
.Description
.c_str());
1711 if(_config
->FindB("Acquire::AllowDowngradeToInsecureRepositories"))
1713 // meh, the users wants to take risks (we still mark the packages
1714 // from this repository as unauthenticated)
1715 _error
->Warning("%s", downgrade_msg
.c_str());
1716 _error
->Warning(_("This is normally not allowed, but the option "
1717 "Acquire::AllowDowngradeToInsecureRepositories was "
1718 "given to override it."));
1721 MessageInsecureRepository(true, downgrade_msg
);
1722 if (TransactionManager
->IMSHit
== false)
1723 Rename(MetaIndex
->DestFile
, MetaIndex
->DestFile
+ ".FAILED");
1724 Item::Failed("Message: " + downgrade_msg
, Cnf
);
1725 TransactionManager
->AbortTransaction();
1730 // ensures that a Release.gpg file in the lists/ is removed by the transaction
1731 TransactionManager
->TransactionStageRemoval(this, DestFile
);
1733 // only allow going further if the user explicitly wants it
1734 if (AllowInsecureRepositories(_("The repository '%s' is not signed."), MetaIndex
->Target
.Description
, TransactionManager
->MetaIndexParser
, TransactionManager
, this) == true)
1736 LoadLastMetaIndexParser(TransactionManager
, FinalRelease
, FinalInRelease
);
1738 // we parse the indexes here because at this point the user wanted
1739 // a repository that may potentially harm him
1740 bool const GoodLoad
= TransactionManager
->MetaIndexParser
->Load(MetaIndex
->DestFile
, &ErrorText
);
1741 if (MetaIndex
->VerifyVendor(Message
) == false)
1742 /* expired Release files are still a problem you need extra force for */;
1744 MetaIndex
->QueueIndexes(GoodLoad
);
1746 TransactionManager
->TransactionStageCopy(MetaIndex
, MetaIndex
->DestFile
, MetaIndex
->GetFinalFilename());
1749 // FIXME: this is used often (e.g. in pkgAcqIndexTrans) so refactor
1750 if (Cnf
->LocalOnly
== true ||
1751 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1760 // AcqBaseIndex - Constructor /*{{{*/
1761 pkgAcqBaseIndex::pkgAcqBaseIndex(pkgAcquire
* const Owner
,
1762 pkgAcqMetaClearSig
* const TransactionManager
,
1763 IndexTarget
const &Target
)
1764 : pkgAcqTransactionItem(Owner
, TransactionManager
, Target
), d(NULL
)
1768 pkgAcqBaseIndex::~pkgAcqBaseIndex() {}
1770 // AcqDiffIndex::AcqDiffIndex - Constructor /*{{{*/
1771 // ---------------------------------------------------------------------
1772 /* Get the DiffIndex file first and see if there are patches available
1773 * If so, create a pkgAcqIndexDiffs fetcher that will get and apply the
1774 * patches. If anything goes wrong in that process, it will fall back to
1775 * the original packages file
1777 pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire
* const Owner
,
1778 pkgAcqMetaClearSig
* const TransactionManager
,
1779 IndexTarget
const &Target
)
1780 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
), diffs(NULL
)
1782 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
1785 Desc
.Description
= GetDiffIndexFileName(Target
.Description
);
1786 Desc
.ShortDesc
= Target
.ShortDesc
;
1787 Desc
.URI
= GetDiffIndexURI(Target
);
1789 DestFile
= GetPartialFileNameFromURI(Desc
.URI
);
1792 std::clog
<< "pkgAcqDiffIndex: " << Desc
.URI
<< std::endl
;
1797 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
1798 // ---------------------------------------------------------------------
1799 /* The only header we use is the last-modified header. */
1800 string
pkgAcqDiffIndex::Custom600Headers() const
1802 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1803 return "\nIndex-File: true";
1805 string
const Final
= GetFinalFilename();
1808 std::clog
<< "Custom600Header-IMS: " << Final
<< std::endl
;
1811 if (stat(Final
.c_str(),&Buf
) != 0)
1812 return "\nIndex-File: true";
1814 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1817 void pkgAcqDiffIndex::QueueOnIMSHit() const /*{{{*/
1819 // list cleanup needs to know that this file as well as the already
1820 // present index is ours, so we create an empty diff to save it for us
1821 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
);
1824 bool pkgAcqDiffIndex::ParseDiffIndex(string
const &IndexDiffFile
) /*{{{*/
1826 // failing here is fine: our caller will take care of trying to
1827 // get the complete file if patching fails
1829 std::clog
<< "pkgAcqDiffIndex::ParseIndexDiff() " << IndexDiffFile
1832 FileFd
Fd(IndexDiffFile
,FileFd::ReadOnly
);
1834 if (Fd
.IsOpen() == false || Fd
.Failed())
1838 if(unlikely(TF
.Step(Tags
) == false))
1841 HashStringList ServerHashes
;
1842 unsigned long long ServerSize
= 0;
1844 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
1846 std::string tagname
= *type
;
1847 tagname
.append("-Current");
1848 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1849 if (tmp
.empty() == true)
1853 unsigned long long size
;
1854 std::stringstream
ss(tmp
);
1856 if (unlikely(hash
.empty() == true))
1858 if (unlikely(ServerSize
!= 0 && ServerSize
!= size
))
1860 ServerHashes
.push_back(HashString(*type
, hash
));
1864 if (ServerHashes
.usable() == false)
1867 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": Did not find a good hashsum in the index" << std::endl
;
1871 std::string
const CurrentPackagesFile
= GetFinalFileNameFromURI(Target
.URI
);
1872 HashStringList
const TargetFileHashes
= GetExpectedHashesFor(Target
.MetaKey
);
1873 if (TargetFileHashes
.usable() == false || ServerHashes
!= TargetFileHashes
)
1877 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": Index has different hashes than parser, probably older, so fail pdiffing" << std::endl
;
1878 printHashSumComparison(CurrentPackagesFile
, ServerHashes
, TargetFileHashes
);
1883 HashStringList LocalHashes
;
1884 // try avoiding calculating the hash here as this is costly
1885 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1886 LocalHashes
= GetExpectedHashesFromFor(TransactionManager
->LastMetaIndexParser
, Target
.MetaKey
);
1887 if (LocalHashes
.usable() == false)
1889 FileFd
fd(CurrentPackagesFile
, FileFd::ReadOnly
, FileFd::Auto
);
1890 Hashes
LocalHashesCalc(ServerHashes
);
1891 LocalHashesCalc
.AddFD(fd
);
1892 LocalHashes
= LocalHashesCalc
.GetHashStringList();
1895 if (ServerHashes
== LocalHashes
)
1897 // we have the same sha1 as the server so we are done here
1899 std::clog
<< "pkgAcqDiffIndex: Package file " << CurrentPackagesFile
<< " is up-to-date" << std::endl
;
1905 std::clog
<< "Server-Current: " << ServerHashes
.find(NULL
)->toStr() << " and we start at "
1906 << CurrentPackagesFile
<< " " << LocalHashes
.FileSize() << " " << LocalHashes
.find(NULL
)->toStr() << std::endl
;
1908 // historically, older hashes have more info than newer ones, so start
1909 // collecting with older ones first to avoid implementing complicated
1910 // information merging techniques… a failure is after all always
1911 // recoverable with a complete file and hashes aren't changed that often.
1912 std::vector
<char const *> types
;
1913 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
1914 types
.push_back(*type
);
1916 // parse all of (provided) history
1917 vector
<DiffInfo
> available_patches
;
1918 bool firstAcceptedHashes
= true;
1919 for (auto type
= types
.crbegin(); type
!= types
.crend(); ++type
)
1921 if (LocalHashes
.find(*type
) == NULL
)
1924 std::string tagname
= *type
;
1925 tagname
.append("-History");
1926 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1927 if (tmp
.empty() == true)
1930 string hash
, filename
;
1931 unsigned long long size
;
1932 std::stringstream
ss(tmp
);
1934 while (ss
>> hash
>> size
>> filename
)
1936 if (unlikely(hash
.empty() == true || filename
.empty() == true))
1939 // see if we have a record for this file already
1940 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
1941 for (; cur
!= available_patches
.end(); ++cur
)
1943 if (cur
->file
!= filename
)
1945 cur
->result_hashes
.push_back(HashString(*type
, hash
));
1948 if (cur
!= available_patches
.end())
1950 if (firstAcceptedHashes
== true)
1953 next
.file
= filename
;
1954 next
.result_hashes
.push_back(HashString(*type
, hash
));
1955 next
.result_hashes
.FileSize(size
);
1956 available_patches
.push_back(next
);
1961 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
1962 << " wasn't in the list for the first parsed hash! (history)" << std::endl
;
1966 firstAcceptedHashes
= false;
1969 if (unlikely(available_patches
.empty() == true))
1972 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": "
1973 << "Couldn't find any patches for the patch series." << std::endl
;
1977 for (auto type
= types
.crbegin(); type
!= types
.crend(); ++type
)
1979 if (LocalHashes
.find(*type
) == NULL
)
1982 std::string tagname
= *type
;
1983 tagname
.append("-Patches");
1984 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1985 if (tmp
.empty() == true)
1988 string hash
, filename
;
1989 unsigned long long size
;
1990 std::stringstream
ss(tmp
);
1992 while (ss
>> hash
>> size
>> filename
)
1994 if (unlikely(hash
.empty() == true || filename
.empty() == true))
1997 // see if we have a record for this file already
1998 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
1999 for (; cur
!= available_patches
.end(); ++cur
)
2001 if (cur
->file
!= filename
)
2003 if (cur
->patch_hashes
.empty())
2004 cur
->patch_hashes
.FileSize(size
);
2005 cur
->patch_hashes
.push_back(HashString(*type
, hash
));
2008 if (cur
!= available_patches
.end())
2011 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
2012 << " wasn't in the list for the first parsed hash! (patches)" << std::endl
;
2017 for (auto type
= types
.crbegin(); type
!= types
.crend(); ++type
)
2019 std::string tagname
= *type
;
2020 tagname
.append("-Download");
2021 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
2022 if (tmp
.empty() == true)
2025 string hash
, filename
;
2026 unsigned long long size
;
2027 std::stringstream
ss(tmp
);
2029 // FIXME: all of pdiff supports only .gz compressed patches
2030 while (ss
>> hash
>> size
>> filename
)
2032 if (unlikely(hash
.empty() == true || filename
.empty() == true))
2034 if (unlikely(APT::String::Endswith(filename
, ".gz") == false))
2036 filename
.erase(filename
.length() - 3);
2038 // see if we have a record for this file already
2039 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
2040 for (; cur
!= available_patches
.end(); ++cur
)
2042 if (cur
->file
!= filename
)
2044 if (cur
->download_hashes
.empty())
2045 cur
->download_hashes
.FileSize(size
);
2046 cur
->download_hashes
.push_back(HashString(*type
, hash
));
2049 if (cur
!= available_patches
.end())
2052 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
2053 << " wasn't in the list for the first parsed hash! (download)" << std::endl
;
2059 bool foundStart
= false;
2060 for (std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
2061 cur
!= available_patches
.end(); ++cur
)
2063 if (LocalHashes
!= cur
->result_hashes
)
2066 available_patches
.erase(available_patches
.begin(), cur
);
2071 if (foundStart
== false || unlikely(available_patches
.empty() == true))
2074 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": "
2075 << "Couldn't find the start of the patch series." << std::endl
;
2079 for (auto const &patch
: available_patches
)
2080 if (patch
.result_hashes
.usable() == false ||
2081 patch
.patch_hashes
.usable() == false ||
2082 patch
.download_hashes
.usable() == false)
2085 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": provides no usable hashes for " << patch
.file
2086 << " so fallback to complete download" << std::endl
;
2090 // patching with too many files is rather slow compared to a fast download
2091 unsigned long const fileLimit
= _config
->FindI("Acquire::PDiffs::FileLimit", 0);
2092 if (fileLimit
!= 0 && fileLimit
< available_patches
.size())
2095 std::clog
<< "Need " << available_patches
.size() << " diffs (Limit is " << fileLimit
2096 << ") so fallback to complete download" << std::endl
;
2100 // calculate the size of all patches we have to get
2101 unsigned short const sizeLimitPercent
= _config
->FindI("Acquire::PDiffs::SizeLimit", 100);
2102 if (sizeLimitPercent
> 0 && TransactionManager
->MetaIndexParser
!= nullptr)
2104 unsigned long long downloadSize
= std::accumulate(available_patches
.begin(),
2105 available_patches
.end(), 0llu, [](unsigned long long const T
, DiffInfo
const &I
) {
2106 return T
+ I
.download_hashes
.FileSize();
2108 if (downloadSize
!= 0)
2110 unsigned long long downloadSizeIdx
= 0;
2111 auto const types
= VectorizeString(Target
.Option(IndexTarget::COMPRESSIONTYPES
), ' ');
2112 for (auto const &t
: types
)
2114 std::string MetaKey
= Target
.MetaKey
;
2115 if (t
!= "uncompressed")
2117 HashStringList
const hsl
= GetExpectedHashesFor(MetaKey
);
2118 if (unlikely(hsl
.usable() == false))
2120 downloadSizeIdx
= hsl
.FileSize();
2123 unsigned long long const sizeLimit
= downloadSizeIdx
* sizeLimitPercent
;
2124 if ((sizeLimit
/100) < downloadSize
)
2127 std::clog
<< "Need " << downloadSize
<< " compressed bytes (Limit is " << (sizeLimit
/100) << ", "
2128 << "original is " << downloadSizeIdx
<< ") so fallback to complete download" << std::endl
;
2134 // we have something, queue the diffs
2135 string::size_type
const last_space
= Description
.rfind(" ");
2136 if(last_space
!= string::npos
)
2137 Description
.erase(last_space
, Description
.size()-last_space
);
2139 /* decide if we should download patches one by one or in one go:
2140 The first is good if the server merges patches, but many don't so client
2141 based merging can be attempt in which case the second is better.
2142 "bad things" will happen if patches are merged on the server,
2143 but client side merging is attempt as well */
2144 bool pdiff_merge
= _config
->FindB("Acquire::PDiffs::Merge", true);
2145 if (pdiff_merge
== true)
2147 // reprepro adds this flag if it has merged patches on the server
2148 std::string
const precedence
= Tags
.FindS("X-Patch-Precedence");
2149 pdiff_merge
= (precedence
!= "merged");
2154 std::string
const Final
= GetExistingFilename(CurrentPackagesFile
);
2155 if (unlikely(Final
.empty())) // because we wouldn't be called in such a case
2157 std::string
const PartialFile
= GetPartialFileNameFromURI(Target
.URI
);
2158 if (FileExists(PartialFile
) && RemoveFile("Bootstrap-linking", PartialFile
) == false)
2161 std::clog
<< "Bootstrap-linking for patching " << CurrentPackagesFile
2162 << " by removing stale " << PartialFile
<< " failed!" << std::endl
;
2165 for (auto const &ext
: APT::Configuration::getCompressorExtensions())
2167 std::string
const Partial
= PartialFile
+ ext
;
2168 if (FileExists(Partial
) && RemoveFile("Bootstrap-linking", Partial
) == false)
2171 std::clog
<< "Bootstrap-linking for patching " << CurrentPackagesFile
2172 << " by removing stale " << Partial
<< " failed!" << std::endl
;
2176 std::string
const Ext
= Final
.substr(CurrentPackagesFile
.length());
2177 std::string
const Partial
= PartialFile
+ Ext
;
2178 if (symlink(Final
.c_str(), Partial
.c_str()) != 0)
2181 std::clog
<< "Bootstrap-linking for patching " << CurrentPackagesFile
2182 << " by linking " << Final
<< " to " << Partial
<< " failed!" << std::endl
;
2187 if (pdiff_merge
== false)
2188 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
, available_patches
);
2191 diffs
= new std::vector
<pkgAcqIndexMergeDiffs
*>(available_patches
.size());
2192 for(size_t i
= 0; i
< available_patches
.size(); ++i
)
2193 (*diffs
)[i
] = new pkgAcqIndexMergeDiffs(Owner
, TransactionManager
,
2195 available_patches
[i
],
2205 void pkgAcqDiffIndex::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
2207 Item::Failed(Message
,Cnf
);
2211 std::clog
<< "pkgAcqDiffIndex failed: " << Desc
.URI
<< " with " << Message
<< std::endl
2212 << "Falling back to normal index file acquire" << std::endl
;
2214 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
2217 void pkgAcqDiffIndex::Done(string
const &Message
,HashStringList
const &Hashes
, /*{{{*/
2218 pkgAcquire::MethodConfig
const * const Cnf
)
2221 std::clog
<< "pkgAcqDiffIndex::Done(): " << Desc
.URI
<< std::endl
;
2223 Item::Done(Message
, Hashes
, Cnf
);
2225 string
const FinalFile
= GetFinalFilename();
2226 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false))
2227 DestFile
= FinalFile
;
2229 if(ParseDiffIndex(DestFile
) == false)
2231 Failed("Message: Couldn't parse pdiff index", Cnf
);
2232 // queue for final move - this should happen even if we fail
2233 // while parsing (e.g. on sizelimit) and download the complete file.
2234 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
2238 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
2247 pkgAcqDiffIndex::~pkgAcqDiffIndex()
2253 // AcqIndexDiffs::AcqIndexDiffs - Constructor /*{{{*/
2254 // ---------------------------------------------------------------------
2255 /* The package diff is added to the queue. one object is constructed
2256 * for each diff and the index
2258 pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire
* const Owner
,
2259 pkgAcqMetaClearSig
* const TransactionManager
,
2260 IndexTarget
const &Target
,
2261 vector
<DiffInfo
> const &diffs
)
2262 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
),
2263 available_patches(diffs
)
2265 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
2267 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
2270 Description
= Target
.Description
;
2271 Desc
.ShortDesc
= Target
.ShortDesc
;
2273 if(available_patches
.empty() == true)
2275 // we are done (yeah!), check hashes against the final file
2276 DestFile
= GetKeepCompressedFileName(GetFinalFileNameFromURI(Target
.URI
), Target
);
2281 State
= StateFetchDiff
;
2286 void pkgAcqIndexDiffs::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
2288 Item::Failed(Message
,Cnf
);
2291 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
2293 std::clog
<< "pkgAcqIndexDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
2294 << "Falling back to normal index file acquire " << std::endl
;
2295 RenameOnError(PDiffError
);
2296 std::string
const patchname
= GetDiffsPatchFileName(DestFile
);
2297 if (RealFileExists(patchname
))
2298 Rename(patchname
, patchname
+ ".FAILED");
2299 std::string
const UnpatchedFile
= GetExistingFilename(GetPartialFileNameFromURI(Target
.URI
));
2300 if (UnpatchedFile
.empty() == false && FileExists(UnpatchedFile
))
2301 Rename(UnpatchedFile
, UnpatchedFile
+ ".FAILED");
2302 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
2306 // Finish - helper that cleans the item out of the fetcher queue /*{{{*/
2307 void pkgAcqIndexDiffs::Finish(bool allDone
)
2310 std::clog
<< "pkgAcqIndexDiffs::Finish(): "
2312 << Desc
.URI
<< std::endl
;
2314 // we restore the original name, this is required, otherwise
2315 // the file will be cleaned
2318 std::string
const Final
= GetKeepCompressedFileName(GetFinalFilename(), Target
);
2319 TransactionManager
->TransactionStageCopy(this, DestFile
, Final
);
2321 // this is for the "real" finish
2326 std::clog
<< "\n\nallDone: " << DestFile
<< "\n" << std::endl
;
2333 std::clog
<< "Finishing: " << Desc
.URI
<< std::endl
;
2340 bool pkgAcqIndexDiffs::QueueNextDiff() /*{{{*/
2342 // calc sha1 of the just patched file
2343 std::string
const PartialFile
= GetExistingFilename(GetPartialFileNameFromURI(Target
.URI
));
2344 if(unlikely(PartialFile
.empty()))
2346 Failed("Message: The file " + GetPartialFileNameFromURI(Target
.URI
) + " isn't available", NULL
);
2350 FileFd
fd(PartialFile
, FileFd::ReadOnly
, FileFd::Extension
);
2351 Hashes LocalHashesCalc
;
2352 LocalHashesCalc
.AddFD(fd
);
2353 HashStringList
const LocalHashes
= LocalHashesCalc
.GetHashStringList();
2356 std::clog
<< "QueueNextDiff: " << PartialFile
<< " (" << LocalHashes
.find(NULL
)->toStr() << ")" << std::endl
;
2358 HashStringList
const TargetFileHashes
= GetExpectedHashesFor(Target
.MetaKey
);
2359 if (unlikely(LocalHashes
.usable() == false || TargetFileHashes
.usable() == false))
2361 Failed("Local/Expected hashes are not usable for " + PartialFile
, NULL
);
2365 // final file reached before all patches are applied
2366 if(LocalHashes
== TargetFileHashes
)
2372 // remove all patches until the next matching patch is found
2373 // this requires the Index file to be ordered
2374 available_patches
.erase(available_patches
.begin(),
2375 std::find_if(available_patches
.begin(), available_patches
.end(), [&](DiffInfo
const &I
) {
2376 return I
.result_hashes
== LocalHashes
;
2379 // error checking and falling back if no patch was found
2380 if(available_patches
.empty() == true)
2382 Failed("No patches left to reach target for " + PartialFile
, NULL
);
2386 // queue the right diff
2387 Desc
.URI
= Target
.URI
+ ".diff/" + available_patches
[0].file
+ ".gz";
2388 Desc
.Description
= Description
+ " " + available_patches
[0].file
+ string(".pdiff");
2389 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
+ ".diff/" + available_patches
[0].file
), Target
);
2392 std::clog
<< "pkgAcqIndexDiffs::QueueNextDiff(): " << Desc
.URI
<< std::endl
;
2399 void pkgAcqIndexDiffs::Done(string
const &Message
, HashStringList
const &Hashes
, /*{{{*/
2400 pkgAcquire::MethodConfig
const * const Cnf
)
2403 std::clog
<< "pkgAcqIndexDiffs::Done(): " << Desc
.URI
<< std::endl
;
2405 Item::Done(Message
, Hashes
, Cnf
);
2407 std::string
const UncompressedUnpatchedFile
= GetPartialFileNameFromURI(Target
.URI
);
2408 std::string
const UnpatchedFile
= GetExistingFilename(UncompressedUnpatchedFile
);
2409 std::string
const PatchFile
= GetDiffsPatchFileName(UnpatchedFile
);
2410 std::string
const PatchedFile
= GetKeepCompressedFileName(UncompressedUnpatchedFile
, Target
);
2414 // success in downloading a diff, enter ApplyDiff state
2415 case StateFetchDiff
:
2416 Rename(DestFile
, PatchFile
);
2417 DestFile
= GetKeepCompressedFileName(UncompressedUnpatchedFile
+ "-patched", Target
);
2419 std::clog
<< "Sending to rred method: " << UnpatchedFile
<< std::endl
;
2420 State
= StateApplyDiff
;
2422 Desc
.URI
= "rred:" + UnpatchedFile
;
2424 SetActiveSubprocess("rred");
2426 // success in download/apply a diff, queue next (if needed)
2427 case StateApplyDiff
:
2428 // remove the just applied patch and base file
2429 available_patches
.erase(available_patches
.begin());
2430 RemoveFile("pkgAcqIndexDiffs::Done", PatchFile
);
2431 RemoveFile("pkgAcqIndexDiffs::Done", UnpatchedFile
);
2433 std::clog
<< "Moving patched file in place: " << std::endl
2434 << DestFile
<< " -> " << PatchedFile
<< std::endl
;
2435 Rename(DestFile
, PatchedFile
);
2437 // see if there is more to download
2438 if(available_patches
.empty() == false)
2440 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
, available_patches
);
2443 DestFile
= PatchedFile
;
2450 std::string
pkgAcqIndexDiffs::Custom600Headers() const /*{{{*/
2452 if(State
!= StateApplyDiff
)
2453 return pkgAcqBaseIndex::Custom600Headers();
2454 std::ostringstream patchhashes
;
2455 HashStringList
const ExpectedHashes
= available_patches
[0].patch_hashes
;
2456 for (HashStringList::const_iterator hs
= ExpectedHashes
.begin(); hs
!= ExpectedHashes
.end(); ++hs
)
2457 patchhashes
<< "\nPatch-0-" << hs
->HashType() << "-Hash: " << hs
->HashValue();
2458 patchhashes
<< pkgAcqBaseIndex::Custom600Headers();
2459 return patchhashes
.str();
2462 pkgAcqIndexDiffs::~pkgAcqIndexDiffs() {}
2464 // AcqIndexMergeDiffs::AcqIndexMergeDiffs - Constructor /*{{{*/
2465 pkgAcqIndexMergeDiffs::pkgAcqIndexMergeDiffs(pkgAcquire
* const Owner
,
2466 pkgAcqMetaClearSig
* const TransactionManager
,
2467 IndexTarget
const &Target
,
2468 DiffInfo
const &patch
,
2469 std::vector
<pkgAcqIndexMergeDiffs
*> const * const allPatches
)
2470 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
),
2471 patch(patch
), allPatches(allPatches
), State(StateFetchDiff
)
2473 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
2476 Description
= Target
.Description
;
2477 Desc
.ShortDesc
= Target
.ShortDesc
;
2478 Desc
.URI
= Target
.URI
+ ".diff/" + patch
.file
+ ".gz";
2479 Desc
.Description
= Description
+ " " + patch
.file
+ ".pdiff";
2480 DestFile
= GetPartialFileNameFromURI(Desc
.URI
);
2483 std::clog
<< "pkgAcqIndexMergeDiffs: " << Desc
.URI
<< std::endl
;
2488 void pkgAcqIndexMergeDiffs::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
2491 std::clog
<< "pkgAcqIndexMergeDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
;
2493 Item::Failed(Message
,Cnf
);
2496 // check if we are the first to fail, otherwise we are done here
2497 State
= StateDoneDiff
;
2498 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2499 I
!= allPatches
->end(); ++I
)
2500 if ((*I
)->State
== StateErrorDiff
)
2502 State
= StateErrorDiff
;
2506 // first failure means we should fallback
2507 State
= StateErrorDiff
;
2509 std::clog
<< "Falling back to normal index file acquire" << std::endl
;
2510 RenameOnError(PDiffError
);
2511 if (RealFileExists(DestFile
))
2512 Rename(DestFile
, DestFile
+ ".FAILED");
2513 std::string
const UnpatchedFile
= GetExistingFilename(GetPartialFileNameFromURI(Target
.URI
));
2514 if (UnpatchedFile
.empty() == false && FileExists(UnpatchedFile
))
2515 Rename(UnpatchedFile
, UnpatchedFile
+ ".FAILED");
2517 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
2520 void pkgAcqIndexMergeDiffs::Done(string
const &Message
, HashStringList
const &Hashes
, /*{{{*/
2521 pkgAcquire::MethodConfig
const * const Cnf
)
2524 std::clog
<< "pkgAcqIndexMergeDiffs::Done(): " << Desc
.URI
<< std::endl
;
2526 Item::Done(Message
, Hashes
, Cnf
);
2528 if (std::any_of(allPatches
->begin(), allPatches
->end(),
2529 [](pkgAcqIndexMergeDiffs
const * const P
) { return P
->State
== StateErrorDiff
; }))
2532 std::clog
<< "Another patch failed already, no point in processing this one." << std::endl
;
2533 State
= StateErrorDiff
;
2537 std::string
const UncompressedUnpatchedFile
= GetPartialFileNameFromURI(Target
.URI
);
2538 std::string
const UnpatchedFile
= GetExistingFilename(UncompressedUnpatchedFile
);
2539 if (UnpatchedFile
.empty())
2541 _error
->Fatal("Unpatched file %s doesn't exist (anymore)!", UncompressedUnpatchedFile
.c_str());
2542 State
= StateErrorDiff
;
2545 std::string
const PatchFile
= GetMergeDiffsPatchFileName(UnpatchedFile
, patch
.file
);
2546 std::string
const PatchedFile
= GetKeepCompressedFileName(UncompressedUnpatchedFile
, Target
);
2550 case StateFetchDiff
:
2551 Rename(DestFile
, PatchFile
);
2553 // check if this is the last completed diff
2554 State
= StateDoneDiff
;
2555 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2556 I
!= allPatches
->end(); ++I
)
2557 if ((*I
)->State
!= StateDoneDiff
)
2560 std::clog
<< "Not the last done diff in the batch: " << Desc
.URI
<< std::endl
;
2563 // this is the last completed diff, so we are ready to apply now
2564 DestFile
= GetKeepCompressedFileName(UncompressedUnpatchedFile
+ "-patched", Target
);
2566 std::clog
<< "Sending to rred method: " << UnpatchedFile
<< std::endl
;
2567 State
= StateApplyDiff
;
2569 Desc
.URI
= "rred:" + UnpatchedFile
;
2571 SetActiveSubprocess("rred");
2573 case StateApplyDiff
:
2574 // success in download & apply all diffs, finialize and clean up
2576 std::clog
<< "Queue patched file in place: " << std::endl
2577 << DestFile
<< " -> " << PatchedFile
<< std::endl
;
2579 // queue for copy by the transaction manager
2580 TransactionManager
->TransactionStageCopy(this, DestFile
, GetKeepCompressedFileName(GetFinalFilename(), Target
));
2582 // ensure the ed's are gone regardless of list-cleanup
2583 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2584 I
!= allPatches
->end(); ++I
)
2585 RemoveFile("pkgAcqIndexMergeDiffs::Done", GetMergeDiffsPatchFileName(UnpatchedFile
, (*I
)->patch
.file
));
2586 RemoveFile("pkgAcqIndexMergeDiffs::Done", UnpatchedFile
);
2591 std::clog
<< "allDone: " << DestFile
<< "\n" << std::endl
;
2593 case StateDoneDiff
: _error
->Fatal("Done called for %s which is in an invalid Done state", PatchFile
.c_str()); break;
2594 case StateErrorDiff
: _error
->Fatal("Done called for %s which is in an invalid Error state", PatchFile
.c_str()); break;
2598 std::string
pkgAcqIndexMergeDiffs::Custom600Headers() const /*{{{*/
2600 if(State
!= StateApplyDiff
)
2601 return pkgAcqBaseIndex::Custom600Headers();
2602 std::ostringstream patchhashes
;
2603 unsigned int seen_patches
= 0;
2604 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2605 I
!= allPatches
->end(); ++I
)
2607 HashStringList
const ExpectedHashes
= (*I
)->patch
.patch_hashes
;
2608 for (HashStringList::const_iterator hs
= ExpectedHashes
.begin(); hs
!= ExpectedHashes
.end(); ++hs
)
2609 patchhashes
<< "\nPatch-" << seen_patches
<< "-" << hs
->HashType() << "-Hash: " << hs
->HashValue();
2612 patchhashes
<< pkgAcqBaseIndex::Custom600Headers();
2613 return patchhashes
.str();
2616 pkgAcqIndexMergeDiffs::~pkgAcqIndexMergeDiffs() {}
2618 // AcqIndex::AcqIndex - Constructor /*{{{*/
2619 pkgAcqIndex::pkgAcqIndex(pkgAcquire
* const Owner
,
2620 pkgAcqMetaClearSig
* const TransactionManager
,
2621 IndexTarget
const &Target
)
2622 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
), Stage(STAGE_DOWNLOAD
),
2623 CompressionExtensions(Target
.Option(IndexTarget::COMPRESSIONTYPES
))
2625 Init(Target
.URI
, Target
.Description
, Target
.ShortDesc
);
2627 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
2628 std::clog
<< "New pkgIndex with TransactionManager "
2629 << TransactionManager
<< std::endl
;
2632 // AcqIndex::Init - defered Constructor /*{{{*/
2633 static void NextCompressionExtension(std::string
&CurrentCompressionExtension
, std::string
&CompressionExtensions
, bool const preview
)
2635 size_t const nextExt
= CompressionExtensions
.find(' ');
2636 if (nextExt
== std::string::npos
)
2638 CurrentCompressionExtension
= CompressionExtensions
;
2639 if (preview
== false)
2640 CompressionExtensions
.clear();
2644 CurrentCompressionExtension
= CompressionExtensions
.substr(0, nextExt
);
2645 if (preview
== false)
2646 CompressionExtensions
= CompressionExtensions
.substr(nextExt
+1);
2649 void pkgAcqIndex::Init(string
const &URI
, string
const &URIDesc
,
2650 string
const &ShortDesc
)
2652 Stage
= STAGE_DOWNLOAD
;
2654 DestFile
= GetPartialFileNameFromURI(URI
);
2655 NextCompressionExtension(CurrentCompressionExtension
, CompressionExtensions
, false);
2657 // store file size of the download to ensure the fetcher gives
2658 // accurate progress reporting
2659 FileSize
= GetExpectedHashes().FileSize();
2661 if (CurrentCompressionExtension
== "uncompressed")
2665 else if (CurrentCompressionExtension
== "by-hash")
2667 NextCompressionExtension(CurrentCompressionExtension
, CompressionExtensions
, true);
2668 if(unlikely(TransactionManager
->MetaIndexParser
== NULL
|| CurrentCompressionExtension
.empty()))
2670 if (CurrentCompressionExtension
!= "uncompressed")
2672 Desc
.URI
= URI
+ '.' + CurrentCompressionExtension
;
2673 DestFile
= DestFile
+ '.' + CurrentCompressionExtension
;
2676 HashStringList
const Hashes
= GetExpectedHashes();
2677 HashString
const * const TargetHash
= Hashes
.find(NULL
);
2678 if (unlikely(TargetHash
== nullptr))
2680 std::string
const ByHash
= "/by-hash/" + TargetHash
->HashType() + "/" + TargetHash
->HashValue();
2681 size_t const trailing_slash
= Desc
.URI
.find_last_of("/");
2682 if (unlikely(trailing_slash
== std::string::npos
))
2684 Desc
.URI
= Desc
.URI
.replace(
2686 Desc
.URI
.substr(trailing_slash
+1).size()+1,
2689 else if (unlikely(CurrentCompressionExtension
.empty()))
2693 Desc
.URI
= URI
+ '.' + CurrentCompressionExtension
;
2694 DestFile
= DestFile
+ '.' + CurrentCompressionExtension
;
2698 Desc
.Description
= URIDesc
;
2700 Desc
.ShortDesc
= ShortDesc
;
2705 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
2706 // ---------------------------------------------------------------------
2707 /* The only header we use is the last-modified header. */
2708 string
pkgAcqIndex::Custom600Headers() const
2711 string msg
= "\nIndex-File: true";
2713 if (TransactionManager
->LastMetaIndexParser
== NULL
)
2715 std::string
const Final
= GetFinalFilename();
2718 if (stat(Final
.c_str(),&Buf
) == 0)
2719 msg
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
2722 if(Target
.IsOptional
)
2723 msg
+= "\nFail-Ignore: true";
2728 // AcqIndex::Failed - getting the indexfile failed /*{{{*/
2729 void pkgAcqIndex::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)
2731 Item::Failed(Message
,Cnf
);
2733 // authorisation matches will not be fixed by other compression types
2734 if (Status
!= StatAuthError
)
2736 if (CompressionExtensions
.empty() == false)
2738 Init(Target
.URI
, Desc
.Description
, Desc
.ShortDesc
);
2744 if(Target
.IsOptional
&& GetExpectedHashes().empty() && Stage
== STAGE_DOWNLOAD
)
2747 TransactionManager
->AbortTransaction();
2750 // AcqIndex::Done - Finished a fetch /*{{{*/
2751 // ---------------------------------------------------------------------
2752 /* This goes through a number of states.. On the initial fetch the
2753 method could possibly return an alternate filename which points
2754 to the uncompressed version of the file. If this is so the file
2755 is copied into the partial directory. In all other cases the file
2756 is decompressed with a compressed uri. */
2757 void pkgAcqIndex::Done(string
const &Message
,
2758 HashStringList
const &Hashes
,
2759 pkgAcquire::MethodConfig
const * const Cfg
)
2761 Item::Done(Message
,Hashes
,Cfg
);
2765 case STAGE_DOWNLOAD
:
2766 StageDownloadDone(Message
);
2768 case STAGE_DECOMPRESS_AND_VERIFY
:
2769 StageDecompressDone();
2774 // AcqIndex::StageDownloadDone - Queue for decompress and verify /*{{{*/
2775 void pkgAcqIndex::StageDownloadDone(string
const &Message
)
2780 std::string
const AltFilename
= LookupTag(Message
,"Alt-Filename");
2781 std::string Filename
= LookupTag(Message
,"Filename");
2783 // we need to verify the file against the current Release file again
2784 // on if-modfied-since hit to avoid a stale attack against us
2785 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
2787 // copy FinalFile into partial/ so that we check the hash again
2788 string
const FinalFile
= GetExistingFilename(GetFinalFileNameFromURI(Target
.URI
));
2789 if (symlink(FinalFile
.c_str(), DestFile
.c_str()) != 0)
2790 _error
->WarningE("pkgAcqIndex::StageDownloadDone", "Symlinking final file %s back to %s failed", FinalFile
.c_str(), DestFile
.c_str());
2793 EraseFileName
= DestFile
;
2794 Filename
= DestFile
;
2796 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
2797 Desc
.URI
= "store:" + Filename
;
2799 SetActiveSubprocess(::URI(Desc
.URI
).Access
);
2802 // methods like file:// give us an alternative (uncompressed) file
2803 else if (Target
.KeepCompressed
== false && AltFilename
.empty() == false)
2805 Filename
= AltFilename
;
2806 EraseFileName
.clear();
2808 // Methods like e.g. "file:" will give us a (compressed) FileName that is
2809 // not the "DestFile" we set, in this case we uncompress from the local file
2810 else if (Filename
!= DestFile
&& RealFileExists(DestFile
) == false)
2812 // symlinking ensures that the filename can be used for compression detection
2813 // that is e.g. needed for by-hash which has no extension over file
2814 if (symlink(Filename
.c_str(),DestFile
.c_str()) != 0)
2815 _error
->WarningE("pkgAcqIndex::StageDownloadDone", "Symlinking file %s to %s failed", Filename
.c_str(), DestFile
.c_str());
2818 EraseFileName
= DestFile
;
2819 Filename
= DestFile
;
2823 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
2824 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
2825 if (Filename
!= DestFile
&& flExtension(Filename
) == flExtension(DestFile
))
2826 Desc
.URI
= "copy:" + Filename
;
2828 Desc
.URI
= "store:" + Filename
;
2829 if (DestFile
== Filename
)
2831 if (CurrentCompressionExtension
== "uncompressed")
2832 return StageDecompressDone();
2833 DestFile
= "/dev/null";
2836 if (EraseFileName
.empty() && Filename
!= AltFilename
)
2837 EraseFileName
= Filename
;
2839 // queue uri for the next stage
2841 SetActiveSubprocess(::URI(Desc
.URI
).Access
);
2844 // AcqIndex::StageDecompressDone - Final verification /*{{{*/
2845 void pkgAcqIndex::StageDecompressDone()
2847 if (DestFile
== "/dev/null")
2848 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
2850 // Done, queue for rename on transaction finished
2851 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
2854 pkgAcqIndex::~pkgAcqIndex() {}
2857 // AcqArchive::AcqArchive - Constructor /*{{{*/
2858 // ---------------------------------------------------------------------
2859 /* This just sets up the initial fetch environment and queues the first
2861 pkgAcqArchive::pkgAcqArchive(pkgAcquire
* const Owner
,pkgSourceList
* const Sources
,
2862 pkgRecords
* const Recs
,pkgCache::VerIterator
const &Version
,
2863 string
&StoreFilename
) :
2864 Item(Owner
), d(NULL
), LocalSource(false), Version(Version
), Sources(Sources
), Recs(Recs
),
2865 StoreFilename(StoreFilename
), Vf(Version
.FileList()),
2868 Retries
= _config
->FindI("Acquire::Retries",0);
2870 if (Version
.Arch() == 0)
2872 _error
->Error(_("I wasn't able to locate a file for the %s package. "
2873 "This might mean you need to manually fix this package. "
2874 "(due to missing arch)"),
2875 Version
.ParentPkg().FullName().c_str());
2879 /* We need to find a filename to determine the extension. We make the
2880 assumption here that all the available sources for this version share
2881 the same extension.. */
2882 // Skip not source sources, they do not have file fields.
2883 for (; Vf
.end() == false; ++Vf
)
2885 if (Vf
.File().Flagged(pkgCache::Flag::NotSource
))
2890 // Does not really matter here.. we are going to fail out below
2891 if (Vf
.end() != true)
2893 // If this fails to get a file name we will bomb out below.
2894 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2895 if (_error
->PendingError() == true)
2898 // Generate the final file name as: package_version_arch.foo
2899 StoreFilename
= QuoteString(Version
.ParentPkg().Name(),"_:") + '_' +
2900 QuoteString(Version
.VerStr(),"_:") + '_' +
2901 QuoteString(Version
.Arch(),"_:.") +
2902 "." + flExtension(Parse
.FileName());
2905 // check if we have one trusted source for the package. if so, switch
2906 // to "TrustedOnly" mode - but only if not in AllowUnauthenticated mode
2907 bool const allowUnauth
= _config
->FindB("APT::Get::AllowUnauthenticated", false);
2908 bool const debugAuth
= _config
->FindB("Debug::pkgAcquire::Auth", false);
2909 bool seenUntrusted
= false;
2910 for (pkgCache::VerFileIterator i
= Version
.FileList(); i
.end() == false; ++i
)
2912 pkgIndexFile
*Index
;
2913 if (Sources
->FindIndex(i
.File(),Index
) == false)
2916 if (debugAuth
== true)
2917 std::cerr
<< "Checking index: " << Index
->Describe()
2918 << "(Trusted=" << Index
->IsTrusted() << ")" << std::endl
;
2920 if (Index
->IsTrusted() == true)
2923 if (allowUnauth
== false)
2927 seenUntrusted
= true;
2930 // "allow-unauthenticated" restores apts old fetching behaviour
2931 // that means that e.g. unauthenticated file:// uris are higher
2932 // priority than authenticated http:// uris
2933 if (allowUnauth
== true && seenUntrusted
== true)
2937 if (QueueNext() == false && _error
->PendingError() == false)
2938 _error
->Error(_("Can't find a source to download version '%s' of '%s'"),
2939 Version
.VerStr(), Version
.ParentPkg().FullName(false).c_str());
2942 // AcqArchive::QueueNext - Queue the next file source /*{{{*/
2943 // ---------------------------------------------------------------------
2944 /* This queues the next available file version for download. It checks if
2945 the archive is already available in the cache and stashs the MD5 for
2947 bool pkgAcqArchive::QueueNext()
2949 for (; Vf
.end() == false; ++Vf
)
2951 pkgCache::PkgFileIterator
const PkgF
= Vf
.File();
2952 // Ignore not source sources
2953 if (PkgF
.Flagged(pkgCache::Flag::NotSource
))
2956 // Try to cross match against the source list
2957 pkgIndexFile
*Index
;
2958 if (Sources
->FindIndex(PkgF
, Index
) == false)
2960 LocalSource
= PkgF
.Flagged(pkgCache::Flag::LocalSource
);
2962 // only try to get a trusted package from another source if that source
2964 if(Trusted
&& !Index
->IsTrusted())
2967 // Grab the text package record
2968 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2969 if (_error
->PendingError() == true)
2972 string PkgFile
= Parse
.FileName();
2973 ExpectedHashes
= Parse
.Hashes();
2975 if (PkgFile
.empty() == true)
2976 return _error
->Error(_("The package index files are corrupted. No Filename: "
2977 "field for package %s."),
2978 Version
.ParentPkg().Name());
2980 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
2981 Desc
.Description
= Index
->ArchiveInfo(Version
);
2983 Desc
.ShortDesc
= Version
.ParentPkg().FullName(true);
2985 // See if we already have the file. (Legacy filenames)
2986 FileSize
= Version
->Size
;
2987 string FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile
);
2989 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2991 // Make sure the size matches
2992 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2997 StoreFilename
= DestFile
= FinalFile
;
3001 /* Hmm, we have a file and its size does not match, this means it is
3002 an old style mismatched arch */
3003 RemoveFile("pkgAcqArchive::QueueNext", FinalFile
);
3006 // Check it again using the new style output filenames
3007 FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
3008 if (stat(FinalFile
.c_str(),&Buf
) == 0)
3010 // Make sure the size matches
3011 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
3016 StoreFilename
= DestFile
= FinalFile
;
3020 /* Hmm, we have a file and its size does not match, this shouldn't
3022 RemoveFile("pkgAcqArchive::QueueNext", FinalFile
);
3025 DestFile
= _config
->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename
);
3027 // Check the destination file
3028 if (stat(DestFile
.c_str(),&Buf
) == 0)
3030 // Hmm, the partial file is too big, erase it
3031 if ((unsigned long long)Buf
.st_size
> Version
->Size
)
3032 RemoveFile("pkgAcqArchive::QueueNext", DestFile
);
3034 PartialSize
= Buf
.st_size
;
3037 // Disables download of archives - useful if no real installation follows,
3038 // e.g. if we are just interested in proposed installation order
3039 if (_config
->FindB("Debug::pkgAcqArchive::NoQueue", false) == true)
3044 StoreFilename
= DestFile
= FinalFile
;
3058 // AcqArchive::Done - Finished fetching /*{{{*/
3059 // ---------------------------------------------------------------------
3061 void pkgAcqArchive::Done(string
const &Message
, HashStringList
const &Hashes
,
3062 pkgAcquire::MethodConfig
const * const Cfg
)
3064 Item::Done(Message
, Hashes
, Cfg
);
3066 // Grab the output filename
3067 std::string
const FileName
= LookupTag(Message
,"Filename");
3068 if (DestFile
!= FileName
&& RealFileExists(DestFile
) == false)
3070 StoreFilename
= DestFile
= FileName
;
3076 // Done, move it into position
3077 string
const FinalFile
= GetFinalFilename();
3078 Rename(DestFile
,FinalFile
);
3079 StoreFilename
= DestFile
= FinalFile
;
3083 // AcqArchive::Failed - Failure handler /*{{{*/
3084 // ---------------------------------------------------------------------
3085 /* Here we try other sources */
3086 void pkgAcqArchive::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)
3088 Item::Failed(Message
,Cnf
);
3090 /* We don't really want to retry on failed media swaps, this prevents
3091 that. An interesting observation is that permanent failures are not
3093 if (Cnf
->Removable
== true &&
3094 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
3096 // Vf = Version.FileList();
3097 while (Vf
.end() == false) ++Vf
;
3098 StoreFilename
= string();
3103 if (QueueNext() == false)
3105 // This is the retry counter
3107 Cnf
->LocalOnly
== false &&
3108 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
3111 Vf
= Version
.FileList();
3112 if (QueueNext() == true)
3116 StoreFilename
= string();
3121 APT_PURE
bool pkgAcqArchive::IsTrusted() const /*{{{*/
3126 void pkgAcqArchive::Finished() /*{{{*/
3128 if (Status
== pkgAcquire::Item::StatDone
&&
3131 StoreFilename
= string();
3134 std::string
pkgAcqArchive::DescURI() const /*{{{*/
3139 std::string
pkgAcqArchive::ShortDesc() const /*{{{*/
3141 return Desc
.ShortDesc
;
3144 pkgAcqArchive::~pkgAcqArchive() {}
3146 // AcqChangelog::pkgAcqChangelog - Constructors /*{{{*/
3147 class pkgAcqChangelog::Private
3150 std::string FinalFile
;
3152 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire
* const Owner
, pkgCache::VerIterator
const &Ver
,
3153 std::string
const &DestDir
, std::string
const &DestFilename
) :
3154 pkgAcquire::Item(Owner
), d(new pkgAcqChangelog::Private()), SrcName(Ver
.SourcePkgName()), SrcVersion(Ver
.SourceVerStr())
3156 Desc
.URI
= URI(Ver
);
3157 Init(DestDir
, DestFilename
);
3159 // some parameters are char* here as they come likely from char* interfaces – which can also return NULL
3160 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire
* const Owner
, pkgCache::RlsFileIterator
const &RlsFile
,
3161 char const * const Component
, char const * const SrcName
, char const * const SrcVersion
,
3162 const string
&DestDir
, const string
&DestFilename
) :
3163 pkgAcquire::Item(Owner
), d(new pkgAcqChangelog::Private()), SrcName(SrcName
), SrcVersion(SrcVersion
)
3165 Desc
.URI
= URI(RlsFile
, Component
, SrcName
, SrcVersion
);
3166 Init(DestDir
, DestFilename
);
3168 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire
* const Owner
,
3169 std::string
const &URI
, char const * const SrcName
, char const * const SrcVersion
,
3170 const string
&DestDir
, const string
&DestFilename
) :
3171 pkgAcquire::Item(Owner
), d(new pkgAcqChangelog::Private()), SrcName(SrcName
), SrcVersion(SrcVersion
)
3174 Init(DestDir
, DestFilename
);
3176 void pkgAcqChangelog::Init(std::string
const &DestDir
, std::string
const &DestFilename
)
3178 if (Desc
.URI
.empty())
3181 // TRANSLATOR: %s=%s is sourcename=sourceversion, e.g. apt=1.1
3182 strprintf(ErrorText
, _("Changelog unavailable for %s=%s"), SrcName
.c_str(), SrcVersion
.c_str());
3183 // Let the error message print something sensible rather than "Failed to fetch /"
3184 if (DestFilename
.empty())
3185 DestFile
= SrcName
+ ".changelog";
3187 DestFile
= DestFilename
;
3188 Desc
.URI
= "changelog:/" + DestFile
;
3192 std::string DestFileName
;
3193 if (DestFilename
.empty())
3194 DestFileName
= flCombine(DestFile
, SrcName
+ ".changelog");
3196 DestFileName
= flCombine(DestFile
, DestFilename
);
3198 std::string
const SandboxUser
= _config
->Find("APT::Sandbox::User");
3199 std::string
const systemTemp
= GetTempDir(SandboxUser
);
3201 snprintf(tmpname
, sizeof(tmpname
), "%s/apt-changelog-XXXXXX", systemTemp
.c_str());
3202 if (NULL
== mkdtemp(tmpname
))
3204 _error
->Errno("mkdtemp", "mkdtemp failed in changelog acquire of %s %s", SrcName
.c_str(), SrcVersion
.c_str());
3208 TemporaryDirectory
= tmpname
;
3210 ChangeOwnerAndPermissionOfFile("Item::QueueURI", TemporaryDirectory
.c_str(),
3211 SandboxUser
.c_str(), "root", 0700);
3213 DestFile
= flCombine(TemporaryDirectory
, DestFileName
);
3214 if (DestDir
.empty() == false)
3216 d
->FinalFile
= flCombine(DestDir
, DestFileName
);
3217 if (RealFileExists(d
->FinalFile
))
3219 FileFd file1
, file2
;
3220 if (file1
.Open(DestFile
, FileFd::WriteOnly
| FileFd::Create
| FileFd::Exclusive
) &&
3221 file2
.Open(d
->FinalFile
, FileFd::ReadOnly
) && CopyFile(file2
, file1
))
3223 struct timeval times
[2];
3224 times
[0].tv_sec
= times
[1].tv_sec
= file2
.ModificationTime();
3225 times
[0].tv_usec
= times
[1].tv_usec
= 0;
3226 utimes(DestFile
.c_str(), times
);
3231 Desc
.ShortDesc
= "Changelog";
3232 strprintf(Desc
.Description
, "%s %s %s Changelog", URI::SiteOnly(Desc
.URI
).c_str(), SrcName
.c_str(), SrcVersion
.c_str());
3237 std::string
pkgAcqChangelog::URI(pkgCache::VerIterator
const &Ver
) /*{{{*/
3239 std::string
const confOnline
= "Acquire::Changelogs::AlwaysOnline";
3240 bool AlwaysOnline
= _config
->FindB(confOnline
, false);
3241 if (AlwaysOnline
== false)
3242 for (pkgCache::VerFileIterator VF
= Ver
.FileList(); VF
.end() == false; ++VF
)
3244 pkgCache::PkgFileIterator
const PF
= VF
.File();
3245 if (PF
.Flagged(pkgCache::Flag::NotSource
) || PF
->Release
== 0)
3247 pkgCache::RlsFileIterator
const RF
= PF
.ReleaseFile();
3248 if (RF
->Origin
!= 0 && _config
->FindB(confOnline
+ "::Origin::" + RF
.Origin(), false))
3250 AlwaysOnline
= true;
3254 if (AlwaysOnline
== false)
3256 pkgCache::PkgIterator
const Pkg
= Ver
.ParentPkg();
3257 if (Pkg
->CurrentVer
!= 0 && Pkg
.CurrentVer() == Ver
)
3259 std::string
const basename
= std::string("/usr/share/doc/") + Pkg
.Name() + "/changelog";
3260 std::string
const debianname
= basename
+ ".Debian";
3261 if (FileExists(debianname
))
3262 return "copy://" + debianname
;
3263 else if (FileExists(debianname
+ ".gz"))
3264 return "gzip://" + debianname
+ ".gz";
3265 else if (FileExists(basename
))
3266 return "copy://" + basename
;
3267 else if (FileExists(basename
+ ".gz"))
3268 return "gzip://" + basename
+ ".gz";
3272 char const * const SrcName
= Ver
.SourcePkgName();
3273 char const * const SrcVersion
= Ver
.SourceVerStr();
3274 // find the first source for this version which promises a changelog
3275 for (pkgCache::VerFileIterator VF
= Ver
.FileList(); VF
.end() == false; ++VF
)
3277 pkgCache::PkgFileIterator
const PF
= VF
.File();
3278 if (PF
.Flagged(pkgCache::Flag::NotSource
) || PF
->Release
== 0)
3280 pkgCache::RlsFileIterator
const RF
= PF
.ReleaseFile();
3281 std::string
const uri
= URI(RF
, PF
.Component(), SrcName
, SrcVersion
);
3288 std::string
pkgAcqChangelog::URITemplate(pkgCache::RlsFileIterator
const &Rls
)
3290 if (Rls
.end() == true || (Rls
->Label
== 0 && Rls
->Origin
== 0))
3292 std::string
const serverConfig
= "Acquire::Changelogs::URI";
3294 #define APT_EMPTY_SERVER \
3295 if (server.empty() == false) \
3297 if (server != "no") \
3301 #define APT_CHECK_SERVER(X, Y) \
3304 std::string const specialServerConfig = serverConfig + "::" + Y + #X + "::" + Rls.X(); \
3305 server = _config->Find(specialServerConfig); \
3308 // this way e.g. Debian-Security can fallback to Debian
3309 APT_CHECK_SERVER(Label
, "Override::")
3310 APT_CHECK_SERVER(Origin
, "Override::")
3312 if (RealFileExists(Rls
.FileName()))
3314 _error
->PushToStack();
3316 /* This can be costly. A caller wanting to get millions of URIs might
3317 want to do this on its own once and use Override settings.
3318 We don't do this here as Origin/Label are not as unique as they
3319 should be so this could produce request order-dependent anomalies */
3320 if (OpenMaybeClearSignedFile(Rls
.FileName(), rf
) == true)
3322 pkgTagFile
TagFile(&rf
, rf
.Size());
3323 pkgTagSection Section
;
3324 if (TagFile
.Step(Section
) == true)
3325 server
= Section
.FindS("Changelogs");
3327 _error
->RevertToStack();
3331 APT_CHECK_SERVER(Label
, "")
3332 APT_CHECK_SERVER(Origin
, "")
3333 #undef APT_CHECK_SERVER
3334 #undef APT_EMPTY_SERVER
3337 std::string
pkgAcqChangelog::URI(pkgCache::RlsFileIterator
const &Rls
,
3338 char const * const Component
, char const * const SrcName
,
3339 char const * const SrcVersion
)
3341 return URI(URITemplate(Rls
), Component
, SrcName
, SrcVersion
);
3343 std::string
pkgAcqChangelog::URI(std::string
const &Template
,
3344 char const * const Component
, char const * const SrcName
,
3345 char const * const SrcVersion
)
3347 if (Template
.find("@CHANGEPATH@") == std::string::npos
)
3350 // the path is: COMPONENT/SRC/SRCNAME/SRCNAME_SRCVER, e.g. main/a/apt/1.1 or contrib/liba/libapt/2.0
3351 std::string Src
= SrcName
;
3352 std::string path
= APT::String::Startswith(SrcName
, "lib") ? Src
.substr(0, 4) : Src
.substr(0,1);
3353 path
.append("/").append(Src
).append("/");
3354 path
.append(Src
).append("_").append(StripEpoch(SrcVersion
));
3355 // we omit component for releases without one (= flat-style repositories)
3356 if (Component
!= NULL
&& strlen(Component
) != 0)
3357 path
= std::string(Component
) + "/" + path
;
3359 return SubstVar(Template
, "@CHANGEPATH@", path
);
3362 // AcqChangelog::Failed - Failure handler /*{{{*/
3363 void pkgAcqChangelog::Failed(string
const &Message
, pkgAcquire::MethodConfig
const * const Cnf
)
3365 Item::Failed(Message
,Cnf
);
3367 std::string errText
;
3368 // TRANSLATOR: %s=%s is sourcename=sourceversion, e.g. apt=1.1
3369 strprintf(errText
, _("Changelog unavailable for %s=%s"), SrcName
.c_str(), SrcVersion
.c_str());
3371 // Error is probably something techy like 404 Not Found
3372 if (ErrorText
.empty())
3373 ErrorText
= errText
;
3375 ErrorText
= errText
+ " (" + ErrorText
+ ")";
3378 // AcqChangelog::Done - Item downloaded OK /*{{{*/
3379 void pkgAcqChangelog::Done(string
const &Message
,HashStringList
const &CalcHashes
,
3380 pkgAcquire::MethodConfig
const * const Cnf
)
3382 Item::Done(Message
,CalcHashes
,Cnf
);
3383 if (d
->FinalFile
.empty() == false)
3385 if (RemoveFile("pkgAcqChangelog::Done", d
->FinalFile
) == false ||
3386 Rename(DestFile
, d
->FinalFile
) == false)
3393 pkgAcqChangelog::~pkgAcqChangelog() /*{{{*/
3395 if (TemporaryDirectory
.empty() == false)
3397 RemoveFile("~pkgAcqChangelog", DestFile
);
3398 rmdir(TemporaryDirectory
.c_str());
3404 // AcqFile::pkgAcqFile - Constructor /*{{{*/
3405 pkgAcqFile::pkgAcqFile(pkgAcquire
* const Owner
,string
const &URI
, HashStringList
const &Hashes
,
3406 unsigned long long const Size
,string
const &Dsc
,string
const &ShortDesc
,
3407 const string
&DestDir
, const string
&DestFilename
,
3408 bool const IsIndexFile
) :
3409 Item(Owner
), d(NULL
), IsIndexFile(IsIndexFile
), ExpectedHashes(Hashes
)
3411 Retries
= _config
->FindI("Acquire::Retries",0);
3413 if(!DestFilename
.empty())
3414 DestFile
= DestFilename
;
3415 else if(!DestDir
.empty())
3416 DestFile
= DestDir
+ "/" + flNotDir(URI
);
3418 DestFile
= flNotDir(URI
);
3422 Desc
.Description
= Dsc
;
3425 // Set the short description to the archive component
3426 Desc
.ShortDesc
= ShortDesc
;
3428 // Get the transfer sizes
3431 if (stat(DestFile
.c_str(),&Buf
) == 0)
3433 // Hmm, the partial file is too big, erase it
3434 if ((Size
> 0) && (unsigned long long)Buf
.st_size
> Size
)
3435 RemoveFile("pkgAcqFile", DestFile
);
3437 PartialSize
= Buf
.st_size
;
3443 // AcqFile::Done - Item downloaded OK /*{{{*/
3444 void pkgAcqFile::Done(string
const &Message
,HashStringList
const &CalcHashes
,
3445 pkgAcquire::MethodConfig
const * const Cnf
)
3447 Item::Done(Message
,CalcHashes
,Cnf
);
3449 std::string
const FileName
= LookupTag(Message
,"Filename");
3452 // The files timestamp matches
3453 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
3456 // We have to copy it into place
3457 if (RealFileExists(DestFile
.c_str()) == false)
3460 if (_config
->FindB("Acquire::Source-Symlinks",true) == false ||
3461 Cnf
->Removable
== true)
3463 Desc
.URI
= "copy:" + FileName
;
3468 // Erase the file if it is a symlink so we can overwrite it
3470 if (lstat(DestFile
.c_str(),&St
) == 0)
3472 if (S_ISLNK(St
.st_mode
) != 0)
3473 RemoveFile("pkgAcqFile::Done", DestFile
);
3477 if (symlink(FileName
.c_str(),DestFile
.c_str()) != 0)
3479 _error
->PushToStack();
3480 _error
->Errno("pkgAcqFile::Done", "Symlinking file %s failed", DestFile
.c_str());
3481 std::stringstream msg
;
3482 _error
->DumpErrors(msg
, GlobalError::DEBUG
, false);
3483 _error
->RevertToStack();
3484 ErrorText
= msg
.str();
3491 // AcqFile::Failed - Failure handler /*{{{*/
3492 // ---------------------------------------------------------------------
3493 /* Here we try other sources */
3494 void pkgAcqFile::Failed(string
const &Message
, pkgAcquire::MethodConfig
const * const Cnf
)
3496 Item::Failed(Message
,Cnf
);
3498 // This is the retry counter
3500 Cnf
->LocalOnly
== false &&
3501 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
3511 string
pkgAcqFile::Custom600Headers() const /*{{{*/
3514 return "\nIndex-File: true";
3518 pkgAcqFile::~pkgAcqFile() {}