1 // -*- mode: cpp; mode: fold -*-
3 // $Id: acquire-item.cc,v 1.46.2.9 2004/01/16 18:51:11 mdz Exp $
4 /* ######################################################################
6 Acquire Item - Item to acquire
8 Each item can download to exactly one file at a time. This means you
9 cannot create an item that fetches two uri's to two files at the same
10 time. The pkgAcqIndex class creates a second class upon instantiation
11 to fetch the other index files because of this.
13 ##################################################################### */
15 // Include Files /*{{{*/
18 #include <apt-pkg/acquire-item.h>
19 #include <apt-pkg/configuration.h>
20 #include <apt-pkg/aptconfiguration.h>
21 #include <apt-pkg/sourcelist.h>
22 #include <apt-pkg/error.h>
23 #include <apt-pkg/strutl.h>
24 #include <apt-pkg/fileutl.h>
25 #include <apt-pkg/tagfile.h>
26 #include <apt-pkg/metaindex.h>
27 #include <apt-pkg/acquire.h>
28 #include <apt-pkg/hashes.h>
29 #include <apt-pkg/indexfile.h>
30 #include <apt-pkg/pkgcache.h>
31 #include <apt-pkg/cacheiterators.h>
32 #include <apt-pkg/pkgrecords.h>
33 #include <apt-pkg/gpgv.h>
55 static void printHashSumComparison(std::string
const &URI
, HashStringList
const &Expected
, HashStringList
const &Actual
) /*{{{*/
57 if (_config
->FindB("Debug::Acquire::HashSumMismatch", false) == false)
59 std::cerr
<< std::endl
<< URI
<< ":" << std::endl
<< " Expected Hash: " << std::endl
;
60 for (HashStringList::const_iterator hs
= Expected
.begin(); hs
!= Expected
.end(); ++hs
)
61 std::cerr
<< "\t- " << hs
->toStr() << std::endl
;
62 std::cerr
<< " Actual Hash: " << std::endl
;
63 for (HashStringList::const_iterator hs
= Actual
.begin(); hs
!= Actual
.end(); ++hs
)
64 std::cerr
<< "\t- " << hs
->toStr() << std::endl
;
67 static std::string
GetPartialFileName(std::string
const &file
) /*{{{*/
69 std::string DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
74 static std::string
GetPartialFileNameFromURI(std::string
const &uri
) /*{{{*/
76 return GetPartialFileName(URItoFileName(uri
));
79 static std::string
GetFinalFileNameFromURI(std::string
const &uri
) /*{{{*/
81 return _config
->FindDir("Dir::State::lists") + URItoFileName(uri
);
84 static std::string
GetKeepCompressedFileName(std::string file
, IndexTarget
const &Target
)/*{{{*/
86 if (Target
.KeepCompressed
== false)
89 std::string
const KeepCompressedAs
= Target
.Option(IndexTarget::KEEPCOMPRESSEDAS
);
90 if (KeepCompressedAs
.empty() == false)
92 std::string
const ext
= KeepCompressedAs
.substr(0, KeepCompressedAs
.find(' '));
93 if (ext
!= "uncompressed")
94 file
.append(".").append(ext
);
99 static std::string
GetMergeDiffsPatchFileName(std::string
const &Final
, std::string
const &Patch
)/*{{{*/
101 // rred expects the patch as $FinalFile.ed.$patchname.gz
102 return Final
+ ".ed." + Patch
+ ".gz";
105 static std::string
GetDiffsPatchFileName(std::string
const &Final
) /*{{{*/
107 // rred expects the patch as $FinalFile.ed
108 return Final
+ ".ed";
111 static std::string
GetExistingFilename(std::string
const &File
) /*{{{*/
113 if (RealFileExists(File
))
115 for (auto const &type
: APT::Configuration::getCompressorExtensions())
117 std::string
const Final
= File
+ type
;
118 if (RealFileExists(Final
))
124 static std::string
GetDiffIndexFileName(std::string
const &Name
) /*{{{*/
126 return Name
+ ".diff/Index";
129 static std::string
GetDiffIndexURI(IndexTarget
const &Target
) /*{{{*/
131 return Target
.URI
+ ".diff/Index";
135 static bool MessageInsecureRepository(bool const isError
, std::string
const &msg
)/*{{{*/
139 _error
->Error("%s", msg
.c_str());
140 _error
->Notice("%s", _("Updating from such a repository can't be done securely, and is therefore disabled by default."));
144 _error
->Warning("%s", msg
.c_str());
145 _error
->Notice("%s", _("Data from such a repository can't be authenticated and is therefore potentially dangerous to use."));
147 _error
->Notice("%s", _("See apt-secure(8) manpage for repository creation and user configuration details."));
150 static bool MessageInsecureRepository(bool const isError
, char const * const msg
, std::string
const &repo
)
153 strprintf(m
, msg
, repo
.c_str());
154 return MessageInsecureRepository(isError
, m
);
157 static bool AllowInsecureRepositories(char const * const msg
, std::string
const &repo
,/*{{{*/
158 metaIndex
const * const MetaIndexParser
, pkgAcqMetaClearSig
* const TransactionManager
, pkgAcquire::Item
* const I
)
160 if(MetaIndexParser
->GetTrusted() == metaIndex::TRI_YES
)
163 if (_config
->FindB("Acquire::AllowInsecureRepositories") == true)
165 MessageInsecureRepository(false, msg
, repo
);
169 MessageInsecureRepository(true, msg
, repo
);
170 TransactionManager
->AbortTransaction();
171 I
->Status
= pkgAcquire::Item::StatError
;
175 static HashStringList
GetExpectedHashesFromFor(metaIndex
* const Parser
, std::string
const &MetaKey
)/*{{{*/
178 return HashStringList();
179 metaIndex::checkSum
* const R
= Parser
->Lookup(MetaKey
);
181 return HashStringList();
186 // all ::HashesRequired and ::GetExpectedHashes implementations /*{{{*/
187 /* ::GetExpectedHashes is abstract and has to be implemented by all subclasses.
188 It is best to implement it as broadly as possible, while ::HashesRequired defaults
189 to true and should be as restrictive as possible for false cases. Note that if
190 a hash is returned by ::GetExpectedHashes it must match. Only if it doesn't
191 ::HashesRequired is called to evaluate if its okay to have no hashes. */
192 APT_CONST
bool pkgAcqTransactionItem::HashesRequired() const
194 /* signed repositories obviously have a parser and good hashes.
195 unsigned repositories, too, as even if we can't trust them for security,
196 we can at least trust them for integrity of the download itself.
197 Only repositories without a Release file can (obviously) not have
198 hashes – and they are very uncommon and strongly discouraged */
199 return TransactionManager
->MetaIndexParser
!= NULL
&&
200 TransactionManager
->MetaIndexParser
->GetLoadedSuccessfully() == metaIndex::TRI_YES
;
202 HashStringList
pkgAcqTransactionItem::GetExpectedHashes() const
204 return GetExpectedHashesFor(GetMetaKey());
207 APT_CONST
bool pkgAcqMetaBase::HashesRequired() const
209 // Release and co have no hashes 'by design'.
212 HashStringList
pkgAcqMetaBase::GetExpectedHashes() const
214 return HashStringList();
217 APT_CONST
bool pkgAcqIndexDiffs::HashesRequired() const
219 /* We can't check hashes of rred result as we don't know what the
220 hash of the file will be. We just know the hash of the patch(es),
221 the hash of the file they will apply on and the hash of the resulting
223 if (State
== StateFetchDiff
)
227 HashStringList
pkgAcqIndexDiffs::GetExpectedHashes() const
229 if (State
== StateFetchDiff
)
230 return available_patches
[0].download_hashes
;
231 return HashStringList();
234 APT_CONST
bool pkgAcqIndexMergeDiffs::HashesRequired() const
236 /* @see #pkgAcqIndexDiffs::HashesRequired, with the difference that
237 we can check the rred result after all patches are applied as
238 we know the expected result rather than potentially apply more patches */
239 if (State
== StateFetchDiff
)
241 return State
== StateApplyDiff
;
243 HashStringList
pkgAcqIndexMergeDiffs::GetExpectedHashes() const
245 if (State
== StateFetchDiff
)
246 return patch
.download_hashes
;
247 else if (State
== StateApplyDiff
)
248 return GetExpectedHashesFor(Target
.MetaKey
);
249 return HashStringList();
252 APT_CONST
bool pkgAcqArchive::HashesRequired() const
254 return LocalSource
== false;
256 HashStringList
pkgAcqArchive::GetExpectedHashes() const
258 // figured out while parsing the records
259 return ExpectedHashes
;
262 APT_CONST
bool pkgAcqFile::HashesRequired() const
264 // supplied as parameter at creation time, so the caller decides
265 return ExpectedHashes
.usable();
267 HashStringList
pkgAcqFile::GetExpectedHashes() const
269 return ExpectedHashes
;
272 // Acquire::Item::QueueURI and specialisations from child classes /*{{{*/
273 bool pkgAcquire::Item::QueueURI(pkgAcquire::ItemDesc
&Item
)
275 Owner
->Enqueue(Item
);
278 /* The idea here is that an item isn't queued if it exists on disk and the
279 transition manager was a hit as this means that the files it contains
280 the checksums for can't be updated either (or they are and we are asking
281 for a hashsum mismatch to happen which helps nobody) */
282 bool pkgAcqTransactionItem::QueueURI(pkgAcquire::ItemDesc
&Item
)
284 if (TransactionManager
->State
!= TransactionStarted
)
286 if (_config
->FindB("Debug::Acquire::Transaction", false))
287 std::clog
<< "Skip " << Target
.URI
<< " as transaction was already dealt with!" << std::endl
;
290 std::string
const FinalFile
= GetFinalFilename();
291 if (TransactionManager
!= NULL
&& TransactionManager
->IMSHit
== true &&
292 FileExists(FinalFile
) == true)
294 PartialFile
= DestFile
= FinalFile
;
298 return pkgAcquire::Item::QueueURI(Item
);
300 /* The transition manager InRelease itself (or its older sisters-in-law
301 Release & Release.gpg) is always queued as this allows us to rerun gpgv
302 on it to verify that we aren't stalled with old files */
303 bool pkgAcqMetaBase::QueueURI(pkgAcquire::ItemDesc
&Item
)
305 return pkgAcquire::Item::QueueURI(Item
);
307 /* the Diff/Index needs to queue also the up-to-date complete index file
308 to ensure that the list cleaner isn't eating it */
309 bool pkgAcqDiffIndex::QueueURI(pkgAcquire::ItemDesc
&Item
)
311 if (pkgAcqTransactionItem::QueueURI(Item
) == true)
317 // Acquire::Item::GetFinalFilename and specialisations for child classes /*{{{*/
318 std::string
pkgAcquire::Item::GetFinalFilename() const
320 // Beware: Desc.URI is modified by redirections
321 return GetFinalFileNameFromURI(Desc
.URI
);
323 std::string
pkgAcqDiffIndex::GetFinalFilename() const
325 return GetFinalFileNameFromURI(GetDiffIndexURI(Target
));
327 std::string
pkgAcqIndex::GetFinalFilename() const
329 std::string
const FinalFile
= GetFinalFileNameFromURI(Target
.URI
);
330 return GetKeepCompressedFileName(FinalFile
, Target
);
332 std::string
pkgAcqMetaSig::GetFinalFilename() const
334 return GetFinalFileNameFromURI(Target
.URI
);
336 std::string
pkgAcqBaseIndex::GetFinalFilename() const
338 return GetFinalFileNameFromURI(Target
.URI
);
340 std::string
pkgAcqMetaBase::GetFinalFilename() const
342 return GetFinalFileNameFromURI(Target
.URI
);
344 std::string
pkgAcqArchive::GetFinalFilename() const
346 return _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
349 // pkgAcqTransactionItem::GetMetaKey and specialisations for child classes /*{{{*/
350 std::string
pkgAcqTransactionItem::GetMetaKey() const
352 return Target
.MetaKey
;
354 std::string
pkgAcqIndex::GetMetaKey() const
356 if (Stage
== STAGE_DECOMPRESS_AND_VERIFY
|| CurrentCompressionExtension
== "uncompressed")
357 return Target
.MetaKey
;
358 return Target
.MetaKey
+ "." + CurrentCompressionExtension
;
360 std::string
pkgAcqDiffIndex::GetMetaKey() const
362 return GetDiffIndexFileName(Target
.MetaKey
);
365 //pkgAcqTransactionItem::TransactionState and specialisations for child classes /*{{{*/
366 bool pkgAcqTransactionItem::TransactionState(TransactionStates
const state
)
368 bool const Debug
= _config
->FindB("Debug::Acquire::Transaction", false);
371 case TransactionStarted
: _error
->Fatal("Item %s changed to invalid transaction start state!", Target
.URI
.c_str()); break;
372 case TransactionAbort
:
374 std::clog
<< " Cancel: " << DestFile
<< std::endl
;
375 if (Status
== pkgAcquire::Item::StatIdle
)
377 Status
= pkgAcquire::Item::StatDone
;
381 case TransactionCommit
:
382 if(PartialFile
.empty() == false)
384 bool sameFile
= (PartialFile
== DestFile
);
385 // we use symlinks on IMS-Hit to avoid copies
386 if (RealFileExists(DestFile
))
389 if (lstat(PartialFile
.c_str(), &Buf
) != -1)
391 if (S_ISLNK(Buf
.st_mode
) && Buf
.st_size
> 0)
393 char partial
[Buf
.st_size
+ 1];
394 ssize_t
const sp
= readlink(PartialFile
.c_str(), partial
, Buf
.st_size
);
396 _error
->Errno("pkgAcqTransactionItem::TransactionState-sp", _("Failed to readlink %s"), PartialFile
.c_str());
400 sameFile
= (DestFile
== partial
);
405 _error
->Errno("pkgAcqTransactionItem::TransactionState-stat", _("Failed to stat %s"), PartialFile
.c_str());
407 if (sameFile
== false)
409 // ensure that even without lists-cleanup all compressions are nuked
410 std::string FinalFile
= GetFinalFileNameFromURI(Target
.URI
);
411 if (FileExists(FinalFile
))
414 std::clog
<< "rm " << FinalFile
<< " # " << DescURI() << std::endl
;
415 if (RemoveFile("TransactionStates-Cleanup", FinalFile
) == false)
418 for (auto const &ext
: APT::Configuration::getCompressorExtensions())
420 auto const Final
= FinalFile
+ ext
;
421 if (FileExists(Final
))
424 std::clog
<< "rm " << Final
<< " # " << DescURI() << std::endl
;
425 if (RemoveFile("TransactionStates-Cleanup", Final
) == false)
430 std::clog
<< "mv " << PartialFile
<< " -> "<< DestFile
<< " # " << DescURI() << std::endl
;
431 if (Rename(PartialFile
, DestFile
) == false)
434 else if(Debug
== true)
435 std::clog
<< "keep " << PartialFile
<< " # " << DescURI() << std::endl
;
439 std::clog
<< "rm " << DestFile
<< " # " << DescURI() << std::endl
;
440 if (RemoveFile("TransItem::TransactionCommit", DestFile
) == false)
447 bool pkgAcqMetaBase::TransactionState(TransactionStates
const state
)
449 // Do not remove InRelease on IMSHit of Release.gpg [yes, this is very edgecasey]
450 if (TransactionManager
->IMSHit
== false)
451 return pkgAcqTransactionItem::TransactionState(state
);
454 bool pkgAcqIndex::TransactionState(TransactionStates
const state
)
456 if (pkgAcqTransactionItem::TransactionState(state
) == false)
461 case TransactionStarted
: _error
->Fatal("AcqIndex %s changed to invalid transaction start state!", Target
.URI
.c_str()); break;
462 case TransactionAbort
:
463 if (Stage
== STAGE_DECOMPRESS_AND_VERIFY
)
465 // keep the compressed file, but drop the decompressed
466 EraseFileName
.clear();
467 if (PartialFile
.empty() == false && flExtension(PartialFile
) != CurrentCompressionExtension
)
468 RemoveFile("TransactionAbort", PartialFile
);
471 case TransactionCommit
:
472 if (EraseFileName
.empty() == false)
473 RemoveFile("AcqIndex::TransactionCommit", EraseFileName
);
478 bool pkgAcqDiffIndex::TransactionState(TransactionStates
const state
)
480 if (pkgAcqTransactionItem::TransactionState(state
) == false)
485 case TransactionStarted
: _error
->Fatal("Item %s changed to invalid transaction start state!", Target
.URI
.c_str()); break;
486 case TransactionCommit
:
488 case TransactionAbort
:
489 std::string
const Partial
= GetPartialFileNameFromURI(Target
.URI
);
490 RemoveFile("TransactionAbort", Partial
);
498 class APT_HIDDEN NoActionItem
: public pkgAcquire::Item
/*{{{*/
499 /* The sole purpose of this class is having an item which does nothing to
500 reach its done state to prevent cleanup deleting the mentioned file.
501 Handy in cases in which we know we have the file already, like IMS-Hits. */
503 IndexTarget
const Target
;
505 virtual std::string
DescURI() const APT_OVERRIDE
{return Target
.URI
;};
506 virtual HashStringList
GetExpectedHashes() const APT_OVERRIDE
{return HashStringList();};
508 NoActionItem(pkgAcquire
* const Owner
, IndexTarget
const &Target
) :
509 pkgAcquire::Item(Owner
), Target(Target
)
512 DestFile
= GetFinalFileNameFromURI(Target
.URI
);
514 NoActionItem(pkgAcquire
* const Owner
, IndexTarget
const &Target
, std::string
const &FinalFile
) :
515 pkgAcquire::Item(Owner
), Target(Target
)
518 DestFile
= FinalFile
;
522 class APT_HIDDEN CleanupItem
: public pkgAcqTransactionItem
/*{{{*/
523 /* This class ensures that a file which was configured but isn't downloaded
524 for various reasons isn't kept in an old version in the lists directory.
525 In a way its the reverse of NoActionItem as it helps with removing files
526 even if the lists-cleanup is deactivated. */
529 virtual std::string
DescURI() const APT_OVERRIDE
{return Target
.URI
;};
530 virtual HashStringList
GetExpectedHashes() const APT_OVERRIDE
{return HashStringList();};
532 CleanupItem(pkgAcquire
* const Owner
, pkgAcqMetaClearSig
* const TransactionManager
, IndexTarget
const &Target
) :
533 pkgAcqTransactionItem(Owner
, TransactionManager
, Target
)
536 DestFile
= GetFinalFileNameFromURI(Target
.URI
);
538 bool TransactionState(TransactionStates
const state
) APT_OVERRIDE
542 case TransactionStarted
:
544 case TransactionAbort
:
546 case TransactionCommit
:
547 if (_config
->FindB("Debug::Acquire::Transaction", false) == true)
548 std::clog
<< "rm " << DestFile
<< " # " << DescURI() << std::endl
;
549 if (RemoveFile("TransItem::TransactionCommit", DestFile
) == false)
558 // Acquire::Item::Item - Constructor /*{{{*/
559 APT_IGNORE_DEPRECATED_PUSH
560 pkgAcquire::Item::Item(pkgAcquire
* const owner
) :
561 FileSize(0), PartialSize(0), Mode(0), ID(0), Complete(false), Local(false),
562 QueueCounter(0), ExpectedAdditionalItems(0), Owner(owner
), d(NULL
)
567 APT_IGNORE_DEPRECATED_POP
569 // Acquire::Item::~Item - Destructor /*{{{*/
570 pkgAcquire::Item::~Item()
575 std::string
pkgAcquire::Item::Custom600Headers() const /*{{{*/
577 return std::string();
580 std::string
pkgAcquire::Item::ShortDesc() const /*{{{*/
585 APT_CONST
void pkgAcquire::Item::Finished() /*{{{*/
589 APT_PURE pkgAcquire
* pkgAcquire::Item::GetOwner() const /*{{{*/
594 APT_CONST
pkgAcquire::ItemDesc
&pkgAcquire::Item::GetItemDesc() /*{{{*/
599 APT_CONST
bool pkgAcquire::Item::IsTrusted() const /*{{{*/
604 // Acquire::Item::Failed - Item failed to download /*{{{*/
605 // ---------------------------------------------------------------------
606 /* We return to an idle state if there are still other queues that could
608 void pkgAcquire::Item::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)
610 if(ErrorText
.empty())
611 ErrorText
= LookupTag(Message
,"Message");
612 if (QueueCounter
<= 1)
614 /* This indicates that the file is not available right now but might
615 be sometime later. If we do a retry cycle then this should be
617 if (Cnf
!= NULL
&& Cnf
->LocalOnly
== true &&
618 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
634 case StatTransientNetworkError
:
641 string
const FailReason
= LookupTag(Message
, "FailReason");
642 if (FailReason
== "MaximumSizeExceeded")
643 RenameOnError(MaximumSizeExceeded
);
644 else if (Status
== StatAuthError
)
645 RenameOnError(HashSumMismatch
);
647 // report mirror failure back to LP if we actually use a mirror
648 if (FailReason
.empty() == false)
649 ReportMirrorFailure(FailReason
);
651 ReportMirrorFailure(ErrorText
);
653 if (QueueCounter
> 1)
657 // Acquire::Item::Start - Item has begun to download /*{{{*/
658 // ---------------------------------------------------------------------
659 /* Stash status and the file size. Note that setting Complete means
660 sub-phases of the acquire process such as decompresion are operating */
661 void pkgAcquire::Item::Start(string
const &/*Message*/, unsigned long long const Size
)
663 Status
= StatFetching
;
665 if (FileSize
== 0 && Complete
== false)
669 // Acquire::Item::VerifyDone - check if Item was downloaded OK /*{{{*/
670 /* Note that hash-verification is 'hardcoded' in acquire-worker and has
671 * already passed if this method is called. */
672 bool pkgAcquire::Item::VerifyDone(std::string
const &Message
,
673 pkgAcquire::MethodConfig
const * const /*Cnf*/)
675 std::string
const FileName
= LookupTag(Message
,"Filename");
676 if (FileName
.empty() == true)
679 ErrorText
= "Method gave a blank filename";
686 // Acquire::Item::Done - Item downloaded OK /*{{{*/
687 void pkgAcquire::Item::Done(string
const &/*Message*/, HashStringList
const &Hashes
,
688 pkgAcquire::MethodConfig
const * const /*Cnf*/)
690 // We just downloaded something..
693 unsigned long long const downloadedSize
= Hashes
.FileSize();
694 if (downloadedSize
!= 0)
696 FileSize
= downloadedSize
;
700 ErrorText
= string();
701 Owner
->Dequeue(this);
704 // Acquire::Item::Rename - Rename a file /*{{{*/
705 // ---------------------------------------------------------------------
706 /* This helper function is used by a lot of item methods as their final
708 bool pkgAcquire::Item::Rename(string
const &From
,string
const &To
)
710 if (From
== To
|| rename(From
.c_str(),To
.c_str()) == 0)
714 strprintf(S
, _("rename failed, %s (%s -> %s)."), strerror(errno
),
715 From
.c_str(),To
.c_str());
717 if (ErrorText
.empty())
720 ErrorText
= ErrorText
+ ": " + S
;
724 void pkgAcquire::Item::Dequeue() /*{{{*/
726 Owner
->Dequeue(this);
729 bool pkgAcquire::Item::RenameOnError(pkgAcquire::Item::RenameOnErrorState
const error
)/*{{{*/
731 if (RealFileExists(DestFile
))
732 Rename(DestFile
, DestFile
+ ".FAILED");
737 case HashSumMismatch
:
738 errtext
= _("Hash Sum mismatch");
739 Status
= StatAuthError
;
740 ReportMirrorFailure("HashChecksumFailure");
743 errtext
= _("Size mismatch");
744 Status
= StatAuthError
;
745 ReportMirrorFailure("SizeFailure");
748 errtext
= _("Invalid file format");
750 // do not report as usually its not the mirrors fault, but Portal/Proxy
753 errtext
= _("Signature error");
757 strprintf(errtext
, _("Clearsigned file isn't valid, got '%s' (does the network require authentication?)"), "NOSPLIT");
758 Status
= StatAuthError
;
760 case MaximumSizeExceeded
:
761 // the method is expected to report a good error for this
765 // no handling here, done by callers
768 if (ErrorText
.empty())
773 void pkgAcquire::Item::SetActiveSubprocess(const std::string
&subprocess
)/*{{{*/
775 ActiveSubprocess
= subprocess
;
776 APT_IGNORE_DEPRECATED(Mode
= ActiveSubprocess
.c_str();)
779 // Acquire::Item::ReportMirrorFailure /*{{{*/
780 void pkgAcquire::Item::ReportMirrorFailure(string
const &FailCode
)
782 // we only act if a mirror was used at all
783 if(UsedMirror
.empty())
786 std::cerr
<< "\nReportMirrorFailure: "
788 << " Uri: " << DescURI()
790 << FailCode
<< std::endl
;
792 string report
= _config
->Find("Methods::Mirror::ProblemReporting",
793 "/usr/lib/apt/apt-report-mirror-failure");
794 if(!FileExists(report
))
797 std::vector
<char const*> Args
;
798 Args
.push_back(report
.c_str());
799 Args
.push_back(UsedMirror
.c_str());
800 Args
.push_back(DescURI().c_str());
801 Args
.push_back(FailCode
.c_str());
802 Args
.push_back(NULL
);
804 pid_t pid
= ExecFork();
807 _error
->Error("ReportMirrorFailure Fork failed");
812 execvp(Args
[0], (char**)Args
.data());
813 std::cerr
<< "Could not exec " << Args
[0] << std::endl
;
816 if(!ExecWait(pid
, "report-mirror-failure"))
818 _error
->Warning("Couldn't report problem to '%s'",
819 _config
->Find("Methods::Mirror::ProblemReporting").c_str());
823 std::string
pkgAcquire::Item::HashSum() const /*{{{*/
825 HashStringList
const hashes
= GetExpectedHashes();
826 HashString
const * const hs
= hashes
.find(NULL
);
827 return hs
!= NULL
? hs
->toStr() : "";
831 pkgAcqTransactionItem::pkgAcqTransactionItem(pkgAcquire
* const Owner
, /*{{{*/
832 pkgAcqMetaClearSig
* const transactionManager
, IndexTarget
const &target
) :
833 pkgAcquire::Item(Owner
), d(NULL
), Target(target
), TransactionManager(transactionManager
)
835 if (TransactionManager
!= this)
836 TransactionManager
->Add(this);
839 pkgAcqTransactionItem::~pkgAcqTransactionItem() /*{{{*/
843 HashStringList
pkgAcqTransactionItem::GetExpectedHashesFor(std::string
const &MetaKey
) const /*{{{*/
845 return GetExpectedHashesFromFor(TransactionManager
->MetaIndexParser
, MetaKey
);
849 static void LoadLastMetaIndexParser(pkgAcqMetaClearSig
* const TransactionManager
, std::string
const &FinalRelease
, std::string
const &FinalInRelease
)/*{{{*/
851 if (TransactionManager
->IMSHit
== true)
853 if (RealFileExists(FinalInRelease
) || RealFileExists(FinalRelease
))
855 TransactionManager
->LastMetaIndexParser
= TransactionManager
->MetaIndexParser
->UnloadedClone();
856 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
858 _error
->PushToStack();
859 if (RealFileExists(FinalInRelease
))
860 TransactionManager
->LastMetaIndexParser
->Load(FinalInRelease
, NULL
);
862 TransactionManager
->LastMetaIndexParser
->Load(FinalRelease
, NULL
);
863 // its unlikely to happen, but if what we have is bad ignore it
864 if (_error
->PendingError())
866 delete TransactionManager
->LastMetaIndexParser
;
867 TransactionManager
->LastMetaIndexParser
= NULL
;
869 _error
->RevertToStack();
875 // AcqMetaBase - Constructor /*{{{*/
876 pkgAcqMetaBase::pkgAcqMetaBase(pkgAcquire
* const Owner
,
877 pkgAcqMetaClearSig
* const TransactionManager
,
878 std::vector
<IndexTarget
> const &IndexTargets
,
879 IndexTarget
const &DataTarget
)
880 : pkgAcqTransactionItem(Owner
, TransactionManager
, DataTarget
), d(NULL
),
881 IndexTargets(IndexTargets
),
882 AuthPass(false), IMSHit(false), State(TransactionStarted
)
886 // AcqMetaBase::Add - Add a item to the current Transaction /*{{{*/
887 void pkgAcqMetaBase::Add(pkgAcqTransactionItem
* const I
)
889 Transaction
.push_back(I
);
892 // AcqMetaBase::AbortTransaction - Abort the current Transaction /*{{{*/
893 void pkgAcqMetaBase::AbortTransaction()
895 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
896 std::clog
<< "AbortTransaction: " << TransactionManager
<< std::endl
;
898 switch (TransactionManager
->State
)
900 case TransactionStarted
: break;
901 case TransactionAbort
: _error
->Fatal("Transaction %s was already aborted and is aborted again", TransactionManager
->Target
.URI
.c_str()); return;
902 case TransactionCommit
: _error
->Fatal("Transaction %s was already aborted and is now commited", TransactionManager
->Target
.URI
.c_str()); return;
904 TransactionManager
->State
= TransactionAbort
;
906 // ensure the toplevel is in error state too
907 for (std::vector
<pkgAcqTransactionItem
*>::iterator I
= Transaction
.begin();
908 I
!= Transaction
.end(); ++I
)
910 if ((*I
)->Status
!= pkgAcquire::Item::StatFetching
)
912 (*I
)->TransactionState(TransactionAbort
);
917 // AcqMetaBase::TransactionHasError - Check for errors in Transaction /*{{{*/
918 APT_PURE
bool pkgAcqMetaBase::TransactionHasError() const
920 for (std::vector
<pkgAcqTransactionItem
*>::const_iterator I
= Transaction
.begin();
921 I
!= Transaction
.end(); ++I
)
923 switch((*I
)->Status
) {
924 case StatDone
: break;
925 case StatIdle
: break;
926 case StatAuthError
: return true;
927 case StatError
: return true;
928 case StatTransientNetworkError
: return true;
929 case StatFetching
: break;
935 // AcqMetaBase::CommitTransaction - Commit a transaction /*{{{*/
936 void pkgAcqMetaBase::CommitTransaction()
938 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
939 std::clog
<< "CommitTransaction: " << this << std::endl
;
941 switch (TransactionManager
->State
)
943 case TransactionStarted
: break;
944 case TransactionAbort
: _error
->Fatal("Transaction %s was already commited and is now aborted", TransactionManager
->Target
.URI
.c_str()); return;
945 case TransactionCommit
: _error
->Fatal("Transaction %s was already commited and is again commited", TransactionManager
->Target
.URI
.c_str()); return;
947 TransactionManager
->State
= TransactionCommit
;
949 // move new files into place *and* remove files that are not
950 // part of the transaction but are still on disk
951 for (std::vector
<pkgAcqTransactionItem
*>::iterator I
= Transaction
.begin();
952 I
!= Transaction
.end(); ++I
)
954 (*I
)->TransactionState(TransactionCommit
);
959 // AcqMetaBase::TransactionStageCopy - Stage a file for copying /*{{{*/
960 void pkgAcqMetaBase::TransactionStageCopy(pkgAcqTransactionItem
* const I
,
961 const std::string
&From
,
962 const std::string
&To
)
964 I
->PartialFile
= From
;
968 // AcqMetaBase::TransactionStageRemoval - Stage a file for removal /*{{{*/
969 void pkgAcqMetaBase::TransactionStageRemoval(pkgAcqTransactionItem
* const I
,
970 const std::string
&FinalFile
)
973 I
->DestFile
= FinalFile
;
976 // AcqMetaBase::GenerateAuthWarning - Check gpg authentication error /*{{{*/
977 bool pkgAcqMetaBase::CheckStopAuthentication(pkgAcquire::Item
* const I
, const std::string
&Message
)
979 // FIXME: this entire function can do now that we disallow going to
980 // a unauthenticated state and can cleanly rollback
982 string
const Final
= I
->GetFinalFilename();
983 if(FileExists(Final
))
985 I
->Status
= StatTransientNetworkError
;
986 _error
->Warning(_("An error occurred during the signature "
987 "verification. The repository is not updated "
988 "and the previous index files will be used. "
989 "GPG error: %s: %s"),
990 Desc
.Description
.c_str(),
991 LookupTag(Message
,"Message").c_str());
992 RunScripts("APT::Update::Auth-Failure");
994 } else if (LookupTag(Message
,"Message").find("NODATA") != string::npos
) {
995 /* Invalid signature file, reject (LP: #346386) (Closes: #627642) */
996 _error
->Error(_("GPG error: %s: %s"),
997 Desc
.Description
.c_str(),
998 LookupTag(Message
,"Message").c_str());
999 I
->Status
= StatAuthError
;
1002 _error
->Warning(_("GPG error: %s: %s"),
1003 Desc
.Description
.c_str(),
1004 LookupTag(Message
,"Message").c_str());
1006 // gpgv method failed
1007 ReportMirrorFailure("GPGFailure");
1011 // AcqMetaBase::Custom600Headers - Get header for AcqMetaBase /*{{{*/
1012 // ---------------------------------------------------------------------
1013 string
pkgAcqMetaBase::Custom600Headers() const
1015 std::string Header
= "\nIndex-File: true";
1016 std::string MaximumSize
;
1017 strprintf(MaximumSize
, "\nMaximum-Size: %i",
1018 _config
->FindI("Acquire::MaxReleaseFileSize", 10*1000*1000));
1019 Header
+= MaximumSize
;
1021 string
const FinalFile
= GetFinalFilename();
1023 if (stat(FinalFile
.c_str(),&Buf
) == 0)
1024 Header
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1029 // AcqMetaBase::QueueForSignatureVerify /*{{{*/
1030 void pkgAcqMetaBase::QueueForSignatureVerify(pkgAcqTransactionItem
* const I
, std::string
const &File
, std::string
const &Signature
)
1033 I
->Desc
.URI
= "gpgv:" + Signature
;
1036 I
->SetActiveSubprocess("gpgv");
1039 // AcqMetaBase::CheckDownloadDone /*{{{*/
1040 bool pkgAcqMetaBase::CheckDownloadDone(pkgAcqTransactionItem
* const I
, const std::string
&Message
, HashStringList
const &Hashes
) const
1042 // We have just finished downloading a Release file (it is not
1045 std::string
const FileName
= LookupTag(Message
,"Filename");
1046 if (FileName
!= I
->DestFile
&& RealFileExists(I
->DestFile
) == false)
1049 I
->Desc
.URI
= "copy:" + FileName
;
1050 I
->QueueURI(I
->Desc
);
1054 // make sure to verify against the right file on I-M-S hit
1055 bool IMSHit
= StringToBool(LookupTag(Message
,"IMS-Hit"), false);
1056 if (IMSHit
== false && Hashes
.usable())
1058 // detect IMS-Hits servers haven't detected by Hash comparison
1059 std::string
const FinalFile
= I
->GetFinalFilename();
1060 if (RealFileExists(FinalFile
) && Hashes
.VerifyFile(FinalFile
) == true)
1063 RemoveFile("CheckDownloadDone", I
->DestFile
);
1069 // for simplicity, the transaction manager is always InRelease
1070 // even if it doesn't exist.
1071 if (TransactionManager
!= NULL
)
1072 TransactionManager
->IMSHit
= true;
1073 I
->PartialFile
= I
->DestFile
= I
->GetFinalFilename();
1076 // set Item to complete as the remaining work is all local (verify etc)
1082 bool pkgAcqMetaBase::CheckAuthDone(string
const &Message
) /*{{{*/
1084 // At this point, the gpgv method has succeeded, so there is a
1085 // valid signature from a key in the trusted keyring. We
1086 // perform additional verification of its contents, and use them
1087 // to verify the indexes we are about to download
1089 if (TransactionManager
->IMSHit
== false)
1091 // open the last (In)Release if we have it
1092 std::string
const FinalFile
= GetFinalFilename();
1093 std::string FinalRelease
;
1094 std::string FinalInRelease
;
1095 if (APT::String::Endswith(FinalFile
, "InRelease"))
1097 FinalInRelease
= FinalFile
;
1098 FinalRelease
= FinalFile
.substr(0, FinalFile
.length() - strlen("InRelease")) + "Release";
1102 FinalInRelease
= FinalFile
.substr(0, FinalFile
.length() - strlen("Release")) + "InRelease";
1103 FinalRelease
= FinalFile
;
1105 LoadLastMetaIndexParser(TransactionManager
, FinalRelease
, FinalInRelease
);
1108 if (TransactionManager
->MetaIndexParser
->Load(DestFile
, &ErrorText
) == false)
1110 Status
= StatAuthError
;
1114 if (!VerifyVendor(Message
))
1116 Status
= StatAuthError
;
1120 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1121 std::cerr
<< "Signature verification succeeded: "
1122 << DestFile
<< std::endl
;
1124 // Download further indexes with verification
1130 void pkgAcqMetaBase::QueueIndexes(bool const verify
) /*{{{*/
1132 // at this point the real Items are loaded in the fetcher
1133 ExpectedAdditionalItems
= 0;
1135 bool metaBaseSupportsByHash
= false;
1136 if (TransactionManager
!= NULL
&& TransactionManager
->MetaIndexParser
!= NULL
)
1137 metaBaseSupportsByHash
= TransactionManager
->MetaIndexParser
->GetSupportsAcquireByHash();
1139 for (std::vector
<IndexTarget
>::iterator Target
= IndexTargets
.begin();
1140 Target
!= IndexTargets
.end();
1143 // all is an implementation detail. Users shouldn't use this as arch
1144 // We need this support trickery here as e.g. Debian has binary-all files already,
1145 // but arch:all packages are still in the arch:any files, so we would waste precious
1146 // download time, bandwidth and diskspace for nothing, BUT Debian doesn't feature all
1147 // in the set of supported architectures, so we can filter based on this property rather
1148 // than invent an entirely new flag we would need to carry for all of eternity.
1149 if (Target
->Option(IndexTarget::ARCHITECTURE
) == "all")
1151 if (TransactionManager
->MetaIndexParser
->IsArchitectureSupported("all") == false ||
1152 TransactionManager
->MetaIndexParser
->IsArchitectureAllSupportedFor(*Target
) == false)
1154 new CleanupItem(Owner
, TransactionManager
, *Target
);
1159 bool trypdiff
= Target
->OptionBool(IndexTarget::PDIFFS
);
1162 if (TransactionManager
->MetaIndexParser
->Exists(Target
->MetaKey
) == false)
1164 // optional targets that we do not have in the Release file are skipped
1165 if (Target
->IsOptional
)
1167 new CleanupItem(Owner
, TransactionManager
, *Target
);
1171 std::string
const &arch
= Target
->Option(IndexTarget::ARCHITECTURE
);
1172 if (arch
.empty() == false)
1174 if (TransactionManager
->MetaIndexParser
->IsArchitectureSupported(arch
) == false)
1176 new CleanupItem(Owner
, TransactionManager
, *Target
);
1177 _error
->Notice(_("Skipping acquire of configured file '%s' as repository '%s' doesn't support architecture '%s'"),
1178 Target
->MetaKey
.c_str(), TransactionManager
->Target
.Description
.c_str(), arch
.c_str());
1181 // if the architecture is officially supported but currently no packages for it available,
1182 // ignore silently as this is pretty much the same as just shipping an empty file.
1183 // if we don't know which architectures are supported, we do NOT ignore it to notify user about this
1184 if (TransactionManager
->MetaIndexParser
->IsArchitectureSupported("*undefined*") == false)
1186 new CleanupItem(Owner
, TransactionManager
, *Target
);
1191 Status
= StatAuthError
;
1192 strprintf(ErrorText
, _("Unable to find expected entry '%s' in Release file (Wrong sources.list entry or malformed file)"), Target
->MetaKey
.c_str());
1197 auto const hashes
= GetExpectedHashesFor(Target
->MetaKey
);
1198 if (hashes
.empty() == false)
1200 if (hashes
.usable() == false)
1202 new CleanupItem(Owner
, TransactionManager
, *Target
);
1203 _error
->Warning(_("Skipping acquire of configured file '%s' as repository '%s' provides only weak security information for it"),
1204 Target
->MetaKey
.c_str(), TransactionManager
->Target
.Description
.c_str());
1207 // empty files are skipped as acquiring the very small compressed files is a waste of time
1208 else if (hashes
.FileSize() == 0)
1210 new CleanupItem(Owner
, TransactionManager
, *Target
);
1216 // autoselect the compression method
1217 std::vector
<std::string
> types
= VectorizeString(Target
->Option(IndexTarget::COMPRESSIONTYPES
), ' ');
1218 types
.erase(std::remove_if(types
.begin(), types
.end(), [&](std::string
const &t
) {
1219 if (t
== "uncompressed")
1220 return TransactionManager
->MetaIndexParser
->Exists(Target
->MetaKey
) == false;
1221 std::string
const MetaKey
= Target
->MetaKey
+ "." + t
;
1222 return TransactionManager
->MetaIndexParser
->Exists(MetaKey
) == false;
1224 if (types
.empty() == false)
1226 std::ostringstream os
;
1227 // add the special compressiontype byhash first if supported
1228 std::string
const useByHashConf
= Target
->Option(IndexTarget::BY_HASH
);
1229 bool useByHash
= false;
1230 if(useByHashConf
== "force")
1233 useByHash
= StringToBool(useByHashConf
) == true && metaBaseSupportsByHash
;
1234 if (useByHash
== true)
1236 std::copy(types
.begin(), types
.end()-1, std::ostream_iterator
<std::string
>(os
, " "));
1237 os
<< *types
.rbegin();
1238 Target
->Options
["COMPRESSIONTYPES"] = os
.str();
1241 Target
->Options
["COMPRESSIONTYPES"].clear();
1243 std::string filename
= GetExistingFilename(GetFinalFileNameFromURI(Target
->URI
));
1244 if (filename
.empty() == false)
1246 // if the Release file is a hit and we have an index it must be the current one
1247 if (TransactionManager
->IMSHit
== true)
1249 else if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1251 // see if the file changed since the last Release file
1252 // we use the uncompressed files as we might compress differently compared to the server,
1253 // so the hashes might not match, even if they contain the same data.
1254 HashStringList
const newFile
= GetExpectedHashesFromFor(TransactionManager
->MetaIndexParser
, Target
->MetaKey
);
1255 HashStringList
const oldFile
= GetExpectedHashesFromFor(TransactionManager
->LastMetaIndexParser
, Target
->MetaKey
);
1256 if (newFile
!= oldFile
)
1263 trypdiff
= false; // no file to patch
1265 if (filename
.empty() == false)
1267 new NoActionItem(Owner
, *Target
, filename
);
1268 std::string
const idxfilename
= GetFinalFileNameFromURI(GetDiffIndexURI(*Target
));
1269 if (FileExists(idxfilename
))
1270 new NoActionItem(Owner
, *Target
, idxfilename
);
1274 // check if we have patches available
1275 trypdiff
&= TransactionManager
->MetaIndexParser
->Exists(GetDiffIndexFileName(Target
->MetaKey
));
1279 // if we have no file to patch, no point in trying
1280 trypdiff
&= (GetExistingFilename(GetFinalFileNameFromURI(Target
->URI
)).empty() == false);
1283 // no point in patching from local sources
1286 std::string
const proto
= Target
->URI
.substr(0, strlen("file:/"));
1287 if (proto
== "file:/" || proto
== "copy:/" || proto
== "cdrom:")
1291 // Queue the Index file (Packages, Sources, Translation-$foo, …)
1293 new pkgAcqDiffIndex(Owner
, TransactionManager
, *Target
);
1295 new pkgAcqIndex(Owner
, TransactionManager
, *Target
);
1299 bool pkgAcqMetaBase::VerifyVendor(string
const &) /*{{{*/
1301 string Transformed
= TransactionManager
->MetaIndexParser
->GetExpectedDist();
1303 if (Transformed
== "../project/experimental")
1305 Transformed
= "experimental";
1308 auto pos
= Transformed
.rfind('/');
1309 if (pos
!= string::npos
)
1311 Transformed
= Transformed
.substr(0, pos
);
1314 if (Transformed
== ".")
1319 if (TransactionManager
->MetaIndexParser
->GetValidUntil() > 0)
1321 time_t const invalid_since
= time(NULL
) - TransactionManager
->MetaIndexParser
->GetValidUntil();
1322 if (invalid_since
> 0)
1326 // TRANSLATOR: The first %s is the URL of the bad Release file, the second is
1327 // the time since then the file is invalid - formatted in the same way as in
1328 // the download progress display (e.g. 7d 3h 42min 1s)
1329 _("Release file for %s is expired (invalid since %s). "
1330 "Updates for this repository will not be applied."),
1331 Target
.URI
.c_str(), TimeToStr(invalid_since
).c_str());
1332 if (ErrorText
.empty())
1334 return _error
->Error("%s", errmsg
.c_str());
1338 /* Did we get a file older than what we have? This is a last minute IMS hit and doubles
1339 as a prevention of downgrading us to older (still valid) files */
1340 if (TransactionManager
->IMSHit
== false && TransactionManager
->LastMetaIndexParser
!= NULL
&&
1341 TransactionManager
->LastMetaIndexParser
->GetDate() > TransactionManager
->MetaIndexParser
->GetDate())
1343 TransactionManager
->IMSHit
= true;
1344 RemoveFile("VerifyVendor", DestFile
);
1345 PartialFile
= DestFile
= GetFinalFilename();
1346 // load the 'old' file in the 'new' one instead of flipping pointers as
1347 // the new one isn't owned by us, while the old one is so cleanup would be confused.
1348 TransactionManager
->MetaIndexParser
->swapLoad(TransactionManager
->LastMetaIndexParser
);
1349 delete TransactionManager
->LastMetaIndexParser
;
1350 TransactionManager
->LastMetaIndexParser
= NULL
;
1353 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1355 std::cerr
<< "Got Codename: " << TransactionManager
->MetaIndexParser
->GetCodename() << std::endl
;
1356 std::cerr
<< "Expecting Dist: " << TransactionManager
->MetaIndexParser
->GetExpectedDist() << std::endl
;
1357 std::cerr
<< "Transformed Dist: " << Transformed
<< std::endl
;
1360 if (TransactionManager
->MetaIndexParser
->CheckDist(Transformed
) == false)
1362 // This might become fatal one day
1363 // Status = StatAuthError;
1364 // ErrorText = "Conflicting distribution; expected "
1365 // + MetaIndexParser->GetExpectedDist() + " but got "
1366 // + MetaIndexParser->GetCodename();
1368 if (!Transformed
.empty())
1370 _error
->Warning(_("Conflicting distribution: %s (expected %s but got %s)"),
1371 Desc
.Description
.c_str(),
1372 Transformed
.c_str(),
1373 TransactionManager
->MetaIndexParser
->GetCodename().c_str());
1380 pkgAcqMetaBase::~pkgAcqMetaBase()
1384 pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire
* const Owner
, /*{{{*/
1385 IndexTarget
const &ClearsignedTarget
,
1386 IndexTarget
const &DetachedDataTarget
, IndexTarget
const &DetachedSigTarget
,
1387 std::vector
<IndexTarget
> const &IndexTargets
,
1388 metaIndex
* const MetaIndexParser
) :
1389 pkgAcqMetaIndex(Owner
, this, ClearsignedTarget
, DetachedSigTarget
, IndexTargets
),
1390 d(NULL
), ClearsignedTarget(ClearsignedTarget
),
1391 DetachedDataTarget(DetachedDataTarget
),
1392 MetaIndexParser(MetaIndexParser
), LastMetaIndexParser(NULL
)
1394 // index targets + (worst case:) Release/Release.gpg
1395 ExpectedAdditionalItems
= IndexTargets
.size() + 2;
1396 TransactionManager
->Add(this);
1399 pkgAcqMetaClearSig::~pkgAcqMetaClearSig() /*{{{*/
1401 if (LastMetaIndexParser
!= NULL
)
1402 delete LastMetaIndexParser
;
1405 // pkgAcqMetaClearSig::Custom600Headers - Insert custom request headers /*{{{*/
1406 string
pkgAcqMetaClearSig::Custom600Headers() const
1408 string Header
= pkgAcqMetaBase::Custom600Headers();
1409 Header
+= "\nFail-Ignore: true";
1410 std::string
const key
= TransactionManager
->MetaIndexParser
->GetSignedBy();
1411 if (key
.empty() == false)
1412 Header
+= "\nSigned-By: " + key
;
1417 void pkgAcqMetaClearSig::Finished() /*{{{*/
1419 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1420 std::clog
<< "Finished: " << DestFile
<<std::endl
;
1421 if(TransactionManager
!= NULL
&& TransactionManager
->State
== TransactionStarted
&&
1422 TransactionManager
->TransactionHasError() == false)
1423 TransactionManager
->CommitTransaction();
1426 bool pkgAcqMetaClearSig::VerifyDone(std::string
const &Message
, /*{{{*/
1427 pkgAcquire::MethodConfig
const * const Cnf
)
1429 Item::VerifyDone(Message
, Cnf
);
1431 if (FileExists(DestFile
) && !StartsWithGPGClearTextSignature(DestFile
))
1432 return RenameOnError(NotClearsigned
);
1437 // pkgAcqMetaClearSig::Done - We got a file /*{{{*/
1438 void pkgAcqMetaClearSig::Done(std::string
const &Message
,
1439 HashStringList
const &Hashes
,
1440 pkgAcquire::MethodConfig
const * const Cnf
)
1442 Item::Done(Message
, Hashes
, Cnf
);
1444 if(AuthPass
== false)
1446 if(CheckDownloadDone(this, Message
, Hashes
) == true)
1447 QueueForSignatureVerify(this, DestFile
, DestFile
);
1450 else if(CheckAuthDone(Message
) == true)
1452 if (TransactionManager
->IMSHit
== false)
1453 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
1454 else if (RealFileExists(GetFinalFilename()) == false)
1456 // We got an InRelease file IMSHit, but we haven't one, which means
1457 // we had a valid Release/Release.gpg combo stepping in, which we have
1458 // to 'acquire' now to ensure list cleanup isn't removing them
1459 new NoActionItem(Owner
, DetachedDataTarget
);
1460 new NoActionItem(Owner
, DetachedSigTarget
);
1465 void pkgAcqMetaClearSig::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
) /*{{{*/
1467 Item::Failed(Message
, Cnf
);
1469 // we failed, we will not get additional items from this method
1470 ExpectedAdditionalItems
= 0;
1472 if (AuthPass
== false)
1474 if (Status
== StatAuthError
|| Status
== StatTransientNetworkError
)
1476 // if we expected a ClearTextSignature (InRelease) but got a network
1477 // error or got a file, but it wasn't valid, we end up here (see VerifyDone).
1478 // As these is usually called by web-portals we do not try Release/Release.gpg
1479 // as this is gonna fail anyway and instead abort our try (LP#346386)
1480 TransactionManager
->AbortTransaction();
1484 // Queue the 'old' InRelease file for removal if we try Release.gpg
1485 // as otherwise the file will stay around and gives a false-auth
1486 // impression (CVE-2012-0214)
1487 TransactionManager
->TransactionStageRemoval(this, GetFinalFilename());
1490 new pkgAcqMetaIndex(Owner
, TransactionManager
, DetachedDataTarget
, DetachedSigTarget
, IndexTargets
);
1494 if(CheckStopAuthentication(this, Message
))
1497 // No Release file was present, or verification failed, so fall
1498 // back to queueing Packages files without verification
1499 // only allow going further if the user explicitly wants it
1500 if(AllowInsecureRepositories(_("The repository '%s' is not signed."), ClearsignedTarget
.Description
, TransactionManager
->MetaIndexParser
, TransactionManager
, this) == true)
1504 /* InRelease files become Release files, otherwise
1505 * they would be considered as trusted later on */
1506 string
const FinalRelease
= GetFinalFileNameFromURI(DetachedDataTarget
.URI
);
1507 string
const PartialRelease
= GetPartialFileNameFromURI(DetachedDataTarget
.URI
);
1508 string
const FinalReleasegpg
= GetFinalFileNameFromURI(DetachedSigTarget
.URI
);
1509 string
const FinalInRelease
= GetFinalFilename();
1510 Rename(DestFile
, PartialRelease
);
1511 TransactionManager
->TransactionStageCopy(this, PartialRelease
, FinalRelease
);
1512 LoadLastMetaIndexParser(TransactionManager
, FinalRelease
, FinalInRelease
);
1514 // we parse the indexes here because at this point the user wanted
1515 // a repository that may potentially harm him
1516 if (TransactionManager
->MetaIndexParser
->Load(PartialRelease
, &ErrorText
) == false || VerifyVendor(Message
) == false)
1517 /* expired Release files are still a problem you need extra force for */;
1525 pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire
* const Owner
, /*{{{*/
1526 pkgAcqMetaClearSig
* const TransactionManager
,
1527 IndexTarget
const &DataTarget
,
1528 IndexTarget
const &DetachedSigTarget
,
1529 vector
<IndexTarget
> const &IndexTargets
) :
1530 pkgAcqMetaBase(Owner
, TransactionManager
, IndexTargets
, DataTarget
), d(NULL
),
1531 DetachedSigTarget(DetachedSigTarget
)
1533 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1534 std::clog
<< "New pkgAcqMetaIndex with TransactionManager "
1535 << this->TransactionManager
<< std::endl
;
1537 DestFile
= GetPartialFileNameFromURI(DataTarget
.URI
);
1540 Desc
.Description
= DataTarget
.Description
;
1542 Desc
.ShortDesc
= DataTarget
.ShortDesc
;
1543 Desc
.URI
= DataTarget
.URI
;
1545 // we expect more item
1546 ExpectedAdditionalItems
= IndexTargets
.size();
1550 void pkgAcqMetaIndex::Done(string
const &Message
, /*{{{*/
1551 HashStringList
const &Hashes
,
1552 pkgAcquire::MethodConfig
const * const Cfg
)
1554 Item::Done(Message
,Hashes
,Cfg
);
1556 if(CheckDownloadDone(this, Message
, Hashes
))
1558 // we have a Release file, now download the Signature, all further
1559 // verify/queue for additional downloads will be done in the
1560 // pkgAcqMetaSig::Done() code
1561 new pkgAcqMetaSig(Owner
, TransactionManager
, DetachedSigTarget
, this);
1565 // pkgAcqMetaIndex::Failed - no Release file present /*{{{*/
1566 void pkgAcqMetaIndex::Failed(string
const &Message
,
1567 pkgAcquire::MethodConfig
const * const Cnf
)
1569 pkgAcquire::Item::Failed(Message
, Cnf
);
1572 // No Release file was present so fall
1573 // back to queueing Packages files without verification
1574 // only allow going further if the user explicitly wants it
1575 if(AllowInsecureRepositories(_("The repository '%s' does not have a Release file."), Target
.Description
, TransactionManager
->MetaIndexParser
, TransactionManager
, this) == true)
1577 // ensure old Release files are removed
1578 TransactionManager
->TransactionStageRemoval(this, GetFinalFilename());
1580 // queue without any kind of hashsum support
1581 QueueIndexes(false);
1585 std::string
pkgAcqMetaIndex::DescURI() const /*{{{*/
1590 pkgAcqMetaIndex::~pkgAcqMetaIndex() {}
1592 // AcqMetaSig::AcqMetaSig - Constructor /*{{{*/
1593 pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire
* const Owner
,
1594 pkgAcqMetaClearSig
* const TransactionManager
,
1595 IndexTarget
const &Target
,
1596 pkgAcqMetaIndex
* const MetaIndex
) :
1597 pkgAcqTransactionItem(Owner
, TransactionManager
, Target
), d(NULL
), MetaIndex(MetaIndex
)
1599 DestFile
= GetPartialFileNameFromURI(Target
.URI
);
1601 // remove any partial downloaded sig-file in partial/.
1602 // it may confuse proxies and is too small to warrant a
1603 // partial download anyway
1604 RemoveFile("pkgAcqMetaSig", DestFile
);
1606 // set the TransactionManager
1607 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1608 std::clog
<< "New pkgAcqMetaSig with TransactionManager "
1609 << TransactionManager
<< std::endl
;
1612 Desc
.Description
= Target
.Description
;
1614 Desc
.ShortDesc
= Target
.ShortDesc
;
1615 Desc
.URI
= Target
.URI
;
1617 // If we got a hit for Release, we will get one for Release.gpg too (or obscure errors),
1618 // so we skip the download step and go instantly to verification
1619 if (TransactionManager
->IMSHit
== true && RealFileExists(GetFinalFilename()))
1623 PartialFile
= DestFile
= GetFinalFilename();
1624 MetaIndexFileSignature
= DestFile
;
1625 MetaIndex
->QueueForSignatureVerify(this, MetaIndex
->DestFile
, DestFile
);
1631 pkgAcqMetaSig::~pkgAcqMetaSig() /*{{{*/
1635 // pkgAcqMetaSig::Custom600Headers - Insert custom request headers /*{{{*/
1636 std::string
pkgAcqMetaSig::Custom600Headers() const
1638 std::string Header
= pkgAcqTransactionItem::Custom600Headers();
1639 std::string
const key
= TransactionManager
->MetaIndexParser
->GetSignedBy();
1640 if (key
.empty() == false)
1641 Header
+= "\nSigned-By: " + key
;
1645 // AcqMetaSig::Done - The signature was downloaded/verified /*{{{*/
1646 void pkgAcqMetaSig::Done(string
const &Message
, HashStringList
const &Hashes
,
1647 pkgAcquire::MethodConfig
const * const Cfg
)
1649 if (MetaIndexFileSignature
.empty() == false)
1651 DestFile
= MetaIndexFileSignature
;
1652 MetaIndexFileSignature
.clear();
1654 Item::Done(Message
, Hashes
, Cfg
);
1656 if(MetaIndex
->AuthPass
== false)
1658 if(MetaIndex
->CheckDownloadDone(this, Message
, Hashes
) == true)
1660 // destfile will be modified to point to MetaIndexFile for the
1661 // gpgv method, so we need to save it here
1662 MetaIndexFileSignature
= DestFile
;
1663 MetaIndex
->QueueForSignatureVerify(this, MetaIndex
->DestFile
, DestFile
);
1667 else if(MetaIndex
->CheckAuthDone(Message
) == true)
1669 if (TransactionManager
->IMSHit
== false)
1671 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
1672 TransactionManager
->TransactionStageCopy(MetaIndex
, MetaIndex
->DestFile
, MetaIndex
->GetFinalFilename());
1677 void pkgAcqMetaSig::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
1679 Item::Failed(Message
,Cnf
);
1681 // check if we need to fail at this point
1682 if (MetaIndex
->AuthPass
== true && MetaIndex
->CheckStopAuthentication(this, Message
))
1685 string
const FinalRelease
= MetaIndex
->GetFinalFilename();
1686 string
const FinalReleasegpg
= GetFinalFilename();
1687 string
const FinalInRelease
= TransactionManager
->GetFinalFilename();
1689 if (RealFileExists(FinalReleasegpg
) || RealFileExists(FinalInRelease
))
1691 std::string downgrade_msg
;
1692 strprintf(downgrade_msg
, _("The repository '%s' is no longer signed."),
1693 MetaIndex
->Target
.Description
.c_str());
1694 if(_config
->FindB("Acquire::AllowDowngradeToInsecureRepositories"))
1696 // meh, the users wants to take risks (we still mark the packages
1697 // from this repository as unauthenticated)
1698 _error
->Warning("%s", downgrade_msg
.c_str());
1699 _error
->Warning(_("This is normally not allowed, but the option "
1700 "Acquire::AllowDowngradeToInsecureRepositories was "
1701 "given to override it."));
1704 MessageInsecureRepository(true, downgrade_msg
);
1705 if (TransactionManager
->IMSHit
== false)
1706 Rename(MetaIndex
->DestFile
, MetaIndex
->DestFile
+ ".FAILED");
1707 Item::Failed("Message: " + downgrade_msg
, Cnf
);
1708 TransactionManager
->AbortTransaction();
1713 // ensures that a Release.gpg file in the lists/ is removed by the transaction
1714 TransactionManager
->TransactionStageRemoval(this, DestFile
);
1716 // only allow going further if the user explicitly wants it
1717 if (AllowInsecureRepositories(_("The repository '%s' is not signed."), MetaIndex
->Target
.Description
, TransactionManager
->MetaIndexParser
, TransactionManager
, this) == true)
1719 LoadLastMetaIndexParser(TransactionManager
, FinalRelease
, FinalInRelease
);
1721 // we parse the indexes here because at this point the user wanted
1722 // a repository that may potentially harm him
1723 bool const GoodLoad
= TransactionManager
->MetaIndexParser
->Load(MetaIndex
->DestFile
, &ErrorText
);
1724 if (MetaIndex
->VerifyVendor(Message
) == false)
1725 /* expired Release files are still a problem you need extra force for */;
1727 MetaIndex
->QueueIndexes(GoodLoad
);
1729 TransactionManager
->TransactionStageCopy(MetaIndex
, MetaIndex
->DestFile
, MetaIndex
->GetFinalFilename());
1732 // FIXME: this is used often (e.g. in pkgAcqIndexTrans) so refactor
1733 if (Cnf
->LocalOnly
== true ||
1734 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1743 // AcqBaseIndex - Constructor /*{{{*/
1744 pkgAcqBaseIndex::pkgAcqBaseIndex(pkgAcquire
* const Owner
,
1745 pkgAcqMetaClearSig
* const TransactionManager
,
1746 IndexTarget
const &Target
)
1747 : pkgAcqTransactionItem(Owner
, TransactionManager
, Target
), d(NULL
)
1751 pkgAcqBaseIndex::~pkgAcqBaseIndex() {}
1753 // AcqDiffIndex::AcqDiffIndex - Constructor /*{{{*/
1754 // ---------------------------------------------------------------------
1755 /* Get the DiffIndex file first and see if there are patches available
1756 * If so, create a pkgAcqIndexDiffs fetcher that will get and apply the
1757 * patches. If anything goes wrong in that process, it will fall back to
1758 * the original packages file
1760 pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire
* const Owner
,
1761 pkgAcqMetaClearSig
* const TransactionManager
,
1762 IndexTarget
const &Target
)
1763 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
), diffs(NULL
)
1765 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
1768 Desc
.Description
= GetDiffIndexFileName(Target
.Description
);
1769 Desc
.ShortDesc
= Target
.ShortDesc
;
1770 Desc
.URI
= GetDiffIndexURI(Target
);
1772 DestFile
= GetPartialFileNameFromURI(Desc
.URI
);
1775 std::clog
<< "pkgAcqDiffIndex: " << Desc
.URI
<< std::endl
;
1780 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
1781 // ---------------------------------------------------------------------
1782 /* The only header we use is the last-modified header. */
1783 string
pkgAcqDiffIndex::Custom600Headers() const
1785 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1786 return "\nIndex-File: true";
1788 string
const Final
= GetFinalFilename();
1791 std::clog
<< "Custom600Header-IMS: " << Final
<< std::endl
;
1794 if (stat(Final
.c_str(),&Buf
) != 0)
1795 return "\nIndex-File: true";
1797 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1800 void pkgAcqDiffIndex::QueueOnIMSHit() const /*{{{*/
1802 // list cleanup needs to know that this file as well as the already
1803 // present index is ours, so we create an empty diff to save it for us
1804 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
);
1807 static bool RemoveFileForBootstrapLinking(bool const Debug
, std::string
const &For
, std::string
const &Boot
)/*{{{*/
1809 if (FileExists(Boot
) && RemoveFile("Bootstrap-linking", Boot
) == false)
1812 std::clog
<< "Bootstrap-linking for patching " << For
1813 << " by removing stale " << Boot
<< " failed!" << std::endl
;
1819 bool pkgAcqDiffIndex::ParseDiffIndex(string
const &IndexDiffFile
) /*{{{*/
1821 // failing here is fine: our caller will take care of trying to
1822 // get the complete file if patching fails
1824 std::clog
<< "pkgAcqDiffIndex::ParseIndexDiff() " << IndexDiffFile
1827 FileFd
Fd(IndexDiffFile
,FileFd::ReadOnly
);
1829 if (Fd
.IsOpen() == false || Fd
.Failed())
1833 if(unlikely(TF
.Step(Tags
) == false))
1836 HashStringList ServerHashes
;
1837 unsigned long long ServerSize
= 0;
1839 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
1841 std::string tagname
= *type
;
1842 tagname
.append("-Current");
1843 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1844 if (tmp
.empty() == true)
1848 unsigned long long size
;
1849 std::stringstream
ss(tmp
);
1851 if (unlikely(hash
.empty() == true))
1853 if (unlikely(ServerSize
!= 0 && ServerSize
!= size
))
1855 ServerHashes
.push_back(HashString(*type
, hash
));
1859 if (ServerHashes
.usable() == false)
1862 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": Did not find a good hashsum in the index" << std::endl
;
1866 std::string
const CurrentPackagesFile
= GetFinalFileNameFromURI(Target
.URI
);
1867 HashStringList
const TargetFileHashes
= GetExpectedHashesFor(Target
.MetaKey
);
1868 if (TargetFileHashes
.usable() == false || ServerHashes
!= TargetFileHashes
)
1872 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": Index has different hashes than parser, probably older, so fail pdiffing" << std::endl
;
1873 printHashSumComparison(CurrentPackagesFile
, ServerHashes
, TargetFileHashes
);
1878 HashStringList LocalHashes
;
1879 // try avoiding calculating the hash here as this is costly
1880 if (TransactionManager
->LastMetaIndexParser
!= NULL
)
1881 LocalHashes
= GetExpectedHashesFromFor(TransactionManager
->LastMetaIndexParser
, Target
.MetaKey
);
1882 if (LocalHashes
.usable() == false)
1884 FileFd
fd(CurrentPackagesFile
, FileFd::ReadOnly
, FileFd::Auto
);
1885 Hashes
LocalHashesCalc(ServerHashes
);
1886 LocalHashesCalc
.AddFD(fd
);
1887 LocalHashes
= LocalHashesCalc
.GetHashStringList();
1890 if (ServerHashes
== LocalHashes
)
1892 // we have the same sha1 as the server so we are done here
1894 std::clog
<< "pkgAcqDiffIndex: Package file " << CurrentPackagesFile
<< " is up-to-date" << std::endl
;
1900 std::clog
<< "Server-Current: " << ServerHashes
.find(NULL
)->toStr() << " and we start at "
1901 << CurrentPackagesFile
<< " " << LocalHashes
.FileSize() << " " << LocalHashes
.find(NULL
)->toStr() << std::endl
;
1903 // historically, older hashes have more info than newer ones, so start
1904 // collecting with older ones first to avoid implementing complicated
1905 // information merging techniques… a failure is after all always
1906 // recoverable with a complete file and hashes aren't changed that often.
1907 std::vector
<char const *> types
;
1908 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
1909 types
.push_back(*type
);
1911 // parse all of (provided) history
1912 vector
<DiffInfo
> available_patches
;
1913 bool firstAcceptedHashes
= true;
1914 for (auto type
= types
.crbegin(); type
!= types
.crend(); ++type
)
1916 if (LocalHashes
.find(*type
) == NULL
)
1919 std::string tagname
= *type
;
1920 tagname
.append("-History");
1921 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1922 if (tmp
.empty() == true)
1925 string hash
, filename
;
1926 unsigned long long size
;
1927 std::stringstream
ss(tmp
);
1929 while (ss
>> hash
>> size
>> filename
)
1931 if (unlikely(hash
.empty() == true || filename
.empty() == true))
1934 // see if we have a record for this file already
1935 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
1936 for (; cur
!= available_patches
.end(); ++cur
)
1938 if (cur
->file
!= filename
)
1940 cur
->result_hashes
.push_back(HashString(*type
, hash
));
1943 if (cur
!= available_patches
.end())
1945 if (firstAcceptedHashes
== true)
1948 next
.file
= filename
;
1949 next
.result_hashes
.push_back(HashString(*type
, hash
));
1950 next
.result_hashes
.FileSize(size
);
1951 available_patches
.push_back(next
);
1956 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
1957 << " wasn't in the list for the first parsed hash! (history)" << std::endl
;
1961 firstAcceptedHashes
= false;
1964 if (unlikely(available_patches
.empty() == true))
1967 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": "
1968 << "Couldn't find any patches for the patch series." << std::endl
;
1972 for (auto type
= types
.crbegin(); type
!= types
.crend(); ++type
)
1974 if (LocalHashes
.find(*type
) == NULL
)
1977 std::string tagname
= *type
;
1978 tagname
.append("-Patches");
1979 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
1980 if (tmp
.empty() == true)
1983 string hash
, filename
;
1984 unsigned long long size
;
1985 std::stringstream
ss(tmp
);
1987 while (ss
>> hash
>> size
>> filename
)
1989 if (unlikely(hash
.empty() == true || filename
.empty() == true))
1992 // see if we have a record for this file already
1993 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
1994 for (; cur
!= available_patches
.end(); ++cur
)
1996 if (cur
->file
!= filename
)
1998 if (cur
->patch_hashes
.empty())
1999 cur
->patch_hashes
.FileSize(size
);
2000 cur
->patch_hashes
.push_back(HashString(*type
, hash
));
2003 if (cur
!= available_patches
.end())
2006 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
2007 << " wasn't in the list for the first parsed hash! (patches)" << std::endl
;
2012 for (auto type
= types
.crbegin(); type
!= types
.crend(); ++type
)
2014 std::string tagname
= *type
;
2015 tagname
.append("-Download");
2016 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
2017 if (tmp
.empty() == true)
2020 string hash
, filename
;
2021 unsigned long long size
;
2022 std::stringstream
ss(tmp
);
2024 // FIXME: all of pdiff supports only .gz compressed patches
2025 while (ss
>> hash
>> size
>> filename
)
2027 if (unlikely(hash
.empty() == true || filename
.empty() == true))
2029 if (unlikely(APT::String::Endswith(filename
, ".gz") == false))
2031 filename
.erase(filename
.length() - 3);
2033 // see if we have a record for this file already
2034 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
2035 for (; cur
!= available_patches
.end(); ++cur
)
2037 if (cur
->file
!= filename
)
2039 if (cur
->download_hashes
.empty())
2040 cur
->download_hashes
.FileSize(size
);
2041 cur
->download_hashes
.push_back(HashString(*type
, hash
));
2044 if (cur
!= available_patches
.end())
2047 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
2048 << " wasn't in the list for the first parsed hash! (download)" << std::endl
;
2054 bool foundStart
= false;
2055 for (std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
2056 cur
!= available_patches
.end(); ++cur
)
2058 if (LocalHashes
!= cur
->result_hashes
)
2061 available_patches
.erase(available_patches
.begin(), cur
);
2066 if (foundStart
== false || unlikely(available_patches
.empty() == true))
2069 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": "
2070 << "Couldn't find the start of the patch series." << std::endl
;
2074 for (auto const &patch
: available_patches
)
2075 if (patch
.result_hashes
.usable() == false ||
2076 patch
.patch_hashes
.usable() == false ||
2077 patch
.download_hashes
.usable() == false)
2080 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": provides no usable hashes for " << patch
.file
2081 << " so fallback to complete download" << std::endl
;
2085 // patching with too many files is rather slow compared to a fast download
2086 unsigned long const fileLimit
= _config
->FindI("Acquire::PDiffs::FileLimit", 0);
2087 if (fileLimit
!= 0 && fileLimit
< available_patches
.size())
2090 std::clog
<< "Need " << available_patches
.size() << " diffs (Limit is " << fileLimit
2091 << ") so fallback to complete download" << std::endl
;
2095 // calculate the size of all patches we have to get
2096 unsigned short const sizeLimitPercent
= _config
->FindI("Acquire::PDiffs::SizeLimit", 100);
2097 if (sizeLimitPercent
> 0 && TransactionManager
->MetaIndexParser
!= nullptr)
2099 unsigned long long downloadSize
= std::accumulate(available_patches
.begin(),
2100 available_patches
.end(), 0llu, [](unsigned long long const T
, DiffInfo
const &I
) {
2101 return T
+ I
.download_hashes
.FileSize();
2103 if (downloadSize
!= 0)
2105 unsigned long long downloadSizeIdx
= 0;
2106 auto const types
= VectorizeString(Target
.Option(IndexTarget::COMPRESSIONTYPES
), ' ');
2107 for (auto const &t
: types
)
2109 std::string MetaKey
= Target
.MetaKey
;
2110 if (t
!= "uncompressed")
2112 HashStringList
const hsl
= GetExpectedHashesFor(MetaKey
);
2113 if (unlikely(hsl
.usable() == false))
2115 downloadSizeIdx
= hsl
.FileSize();
2118 unsigned long long const sizeLimit
= downloadSizeIdx
* sizeLimitPercent
;
2119 if ((sizeLimit
/100) < downloadSize
)
2122 std::clog
<< "Need " << downloadSize
<< " compressed bytes (Limit is " << (sizeLimit
/100) << ", "
2123 << "original is " << downloadSizeIdx
<< ") so fallback to complete download" << std::endl
;
2129 // we have something, queue the diffs
2130 string::size_type
const last_space
= Description
.rfind(" ");
2131 if(last_space
!= string::npos
)
2132 Description
.erase(last_space
, Description
.size()-last_space
);
2134 /* decide if we should download patches one by one or in one go:
2135 The first is good if the server merges patches, but many don't so client
2136 based merging can be attempt in which case the second is better.
2137 "bad things" will happen if patches are merged on the server,
2138 but client side merging is attempt as well */
2139 bool pdiff_merge
= _config
->FindB("Acquire::PDiffs::Merge", true);
2140 if (pdiff_merge
== true)
2142 // reprepro adds this flag if it has merged patches on the server
2143 std::string
const precedence
= Tags
.FindS("X-Patch-Precedence");
2144 pdiff_merge
= (precedence
!= "merged");
2149 std::string
const Final
= GetExistingFilename(CurrentPackagesFile
);
2150 if (unlikely(Final
.empty())) // because we wouldn't be called in such a case
2152 std::string
const PartialFile
= GetPartialFileNameFromURI(Target
.URI
);
2153 std::string
const PatchedFile
= GetKeepCompressedFileName(PartialFile
+ "-patched", Target
);
2154 if (RemoveFileForBootstrapLinking(Debug
, CurrentPackagesFile
, PartialFile
) == false ||
2155 RemoveFileForBootstrapLinking(Debug
, CurrentPackagesFile
, PatchedFile
) == false)
2157 for (auto const &ext
: APT::Configuration::getCompressorExtensions())
2159 if (RemoveFileForBootstrapLinking(Debug
, CurrentPackagesFile
, PartialFile
+ ext
) == false ||
2160 RemoveFileForBootstrapLinking(Debug
, CurrentPackagesFile
, PatchedFile
+ ext
) == false)
2163 std::string
const Ext
= Final
.substr(CurrentPackagesFile
.length());
2164 std::string
const Partial
= PartialFile
+ Ext
;
2165 if (symlink(Final
.c_str(), Partial
.c_str()) != 0)
2168 std::clog
<< "Bootstrap-linking for patching " << CurrentPackagesFile
2169 << " by linking " << Final
<< " to " << Partial
<< " failed!" << std::endl
;
2174 if (pdiff_merge
== false)
2175 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
, available_patches
);
2178 diffs
= new std::vector
<pkgAcqIndexMergeDiffs
*>(available_patches
.size());
2179 for(size_t i
= 0; i
< available_patches
.size(); ++i
)
2180 (*diffs
)[i
] = new pkgAcqIndexMergeDiffs(Owner
, TransactionManager
,
2182 available_patches
[i
],
2192 void pkgAcqDiffIndex::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
2194 Item::Failed(Message
,Cnf
);
2198 std::clog
<< "pkgAcqDiffIndex failed: " << Desc
.URI
<< " with " << Message
<< std::endl
2199 << "Falling back to normal index file acquire" << std::endl
;
2201 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
2204 void pkgAcqDiffIndex::Done(string
const &Message
,HashStringList
const &Hashes
, /*{{{*/
2205 pkgAcquire::MethodConfig
const * const Cnf
)
2208 std::clog
<< "pkgAcqDiffIndex::Done(): " << Desc
.URI
<< std::endl
;
2210 Item::Done(Message
, Hashes
, Cnf
);
2212 string
const FinalFile
= GetFinalFilename();
2213 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false))
2214 DestFile
= FinalFile
;
2216 if(ParseDiffIndex(DestFile
) == false)
2218 Failed("Message: Couldn't parse pdiff index", Cnf
);
2219 // queue for final move - this should happen even if we fail
2220 // while parsing (e.g. on sizelimit) and download the complete file.
2221 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
2225 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
2234 pkgAcqDiffIndex::~pkgAcqDiffIndex()
2240 // AcqIndexDiffs::AcqIndexDiffs - Constructor /*{{{*/
2241 // ---------------------------------------------------------------------
2242 /* The package diff is added to the queue. one object is constructed
2243 * for each diff and the index
2245 pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire
* const Owner
,
2246 pkgAcqMetaClearSig
* const TransactionManager
,
2247 IndexTarget
const &Target
,
2248 vector
<DiffInfo
> const &diffs
)
2249 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
),
2250 available_patches(diffs
)
2252 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
2254 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
2257 Description
= Target
.Description
;
2258 Desc
.ShortDesc
= Target
.ShortDesc
;
2260 if(available_patches
.empty() == true)
2262 // we are done (yeah!), check hashes against the final file
2263 DestFile
= GetKeepCompressedFileName(GetFinalFileNameFromURI(Target
.URI
), Target
);
2268 State
= StateFetchDiff
;
2273 void pkgAcqIndexDiffs::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
2275 Item::Failed(Message
,Cnf
);
2278 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
2280 std::clog
<< "pkgAcqIndexDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
2281 << "Falling back to normal index file acquire " << std::endl
;
2282 RenameOnError(PDiffError
);
2283 std::string
const patchname
= GetDiffsPatchFileName(DestFile
);
2284 if (RealFileExists(patchname
))
2285 Rename(patchname
, patchname
+ ".FAILED");
2286 std::string
const UnpatchedFile
= GetExistingFilename(GetPartialFileNameFromURI(Target
.URI
));
2287 if (UnpatchedFile
.empty() == false && FileExists(UnpatchedFile
))
2288 Rename(UnpatchedFile
, UnpatchedFile
+ ".FAILED");
2289 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
2293 // Finish - helper that cleans the item out of the fetcher queue /*{{{*/
2294 void pkgAcqIndexDiffs::Finish(bool allDone
)
2297 std::clog
<< "pkgAcqIndexDiffs::Finish(): "
2299 << Desc
.URI
<< std::endl
;
2301 // we restore the original name, this is required, otherwise
2302 // the file will be cleaned
2305 std::string
const Final
= GetKeepCompressedFileName(GetFinalFilename(), Target
);
2306 TransactionManager
->TransactionStageCopy(this, DestFile
, Final
);
2308 // this is for the "real" finish
2313 std::clog
<< "\n\nallDone: " << DestFile
<< "\n" << std::endl
;
2320 std::clog
<< "Finishing: " << Desc
.URI
<< std::endl
;
2327 bool pkgAcqIndexDiffs::QueueNextDiff() /*{{{*/
2329 // calc sha1 of the just patched file
2330 std::string
const PartialFile
= GetExistingFilename(GetPartialFileNameFromURI(Target
.URI
));
2331 if(unlikely(PartialFile
.empty()))
2333 Failed("Message: The file " + GetPartialFileNameFromURI(Target
.URI
) + " isn't available", NULL
);
2337 FileFd
fd(PartialFile
, FileFd::ReadOnly
, FileFd::Extension
);
2338 Hashes LocalHashesCalc
;
2339 LocalHashesCalc
.AddFD(fd
);
2340 HashStringList
const LocalHashes
= LocalHashesCalc
.GetHashStringList();
2343 std::clog
<< "QueueNextDiff: " << PartialFile
<< " (" << LocalHashes
.find(NULL
)->toStr() << ")" << std::endl
;
2345 HashStringList
const TargetFileHashes
= GetExpectedHashesFor(Target
.MetaKey
);
2346 if (unlikely(LocalHashes
.usable() == false || TargetFileHashes
.usable() == false))
2348 Failed("Local/Expected hashes are not usable for " + PartialFile
, NULL
);
2352 // final file reached before all patches are applied
2353 if(LocalHashes
== TargetFileHashes
)
2359 // remove all patches until the next matching patch is found
2360 // this requires the Index file to be ordered
2361 available_patches
.erase(available_patches
.begin(),
2362 std::find_if(available_patches
.begin(), available_patches
.end(), [&](DiffInfo
const &I
) {
2363 return I
.result_hashes
== LocalHashes
;
2366 // error checking and falling back if no patch was found
2367 if(available_patches
.empty() == true)
2369 Failed("No patches left to reach target for " + PartialFile
, NULL
);
2373 // queue the right diff
2374 Desc
.URI
= Target
.URI
+ ".diff/" + available_patches
[0].file
+ ".gz";
2375 Desc
.Description
= Description
+ " " + available_patches
[0].file
+ string(".pdiff");
2376 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
+ ".diff/" + available_patches
[0].file
), Target
);
2379 std::clog
<< "pkgAcqIndexDiffs::QueueNextDiff(): " << Desc
.URI
<< std::endl
;
2386 void pkgAcqIndexDiffs::Done(string
const &Message
, HashStringList
const &Hashes
, /*{{{*/
2387 pkgAcquire::MethodConfig
const * const Cnf
)
2390 std::clog
<< "pkgAcqIndexDiffs::Done(): " << Desc
.URI
<< std::endl
;
2392 Item::Done(Message
, Hashes
, Cnf
);
2394 std::string
const UncompressedUnpatchedFile
= GetPartialFileNameFromURI(Target
.URI
);
2395 std::string
const UnpatchedFile
= GetExistingFilename(UncompressedUnpatchedFile
);
2396 std::string
const PatchFile
= GetDiffsPatchFileName(UnpatchedFile
);
2397 std::string
const PatchedFile
= GetKeepCompressedFileName(UncompressedUnpatchedFile
, Target
);
2401 // success in downloading a diff, enter ApplyDiff state
2402 case StateFetchDiff
:
2403 Rename(DestFile
, PatchFile
);
2404 DestFile
= GetKeepCompressedFileName(UncompressedUnpatchedFile
+ "-patched", Target
);
2406 std::clog
<< "Sending to rred method: " << UnpatchedFile
<< std::endl
;
2407 State
= StateApplyDiff
;
2409 Desc
.URI
= "rred:" + UnpatchedFile
;
2411 SetActiveSubprocess("rred");
2413 // success in download/apply a diff, queue next (if needed)
2414 case StateApplyDiff
:
2415 // remove the just applied patch and base file
2416 available_patches
.erase(available_patches
.begin());
2417 RemoveFile("pkgAcqIndexDiffs::Done", PatchFile
);
2418 RemoveFile("pkgAcqIndexDiffs::Done", UnpatchedFile
);
2420 std::clog
<< "Moving patched file in place: " << std::endl
2421 << DestFile
<< " -> " << PatchedFile
<< std::endl
;
2422 Rename(DestFile
, PatchedFile
);
2424 // see if there is more to download
2425 if(available_patches
.empty() == false)
2427 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
, available_patches
);
2430 DestFile
= PatchedFile
;
2437 std::string
pkgAcqIndexDiffs::Custom600Headers() const /*{{{*/
2439 if(State
!= StateApplyDiff
)
2440 return pkgAcqBaseIndex::Custom600Headers();
2441 std::ostringstream patchhashes
;
2442 for (auto && hs
: available_patches
[0].result_hashes
)
2443 patchhashes
<< "\nStart-" << hs
.HashType() << "-Hash: " << hs
.HashValue();
2444 for (auto && hs
: available_patches
[0].patch_hashes
)
2445 patchhashes
<< "\nPatch-0-" << hs
.HashType() << "-Hash: " << hs
.HashValue();
2446 patchhashes
<< pkgAcqBaseIndex::Custom600Headers();
2447 return patchhashes
.str();
2450 pkgAcqIndexDiffs::~pkgAcqIndexDiffs() {}
2452 // AcqIndexMergeDiffs::AcqIndexMergeDiffs - Constructor /*{{{*/
2453 pkgAcqIndexMergeDiffs::pkgAcqIndexMergeDiffs(pkgAcquire
* const Owner
,
2454 pkgAcqMetaClearSig
* const TransactionManager
,
2455 IndexTarget
const &Target
,
2456 DiffInfo
const &patch
,
2457 std::vector
<pkgAcqIndexMergeDiffs
*> const * const allPatches
)
2458 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
),
2459 patch(patch
), allPatches(allPatches
), State(StateFetchDiff
)
2461 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
2464 Description
= Target
.Description
;
2465 Desc
.ShortDesc
= Target
.ShortDesc
;
2466 Desc
.URI
= Target
.URI
+ ".diff/" + patch
.file
+ ".gz";
2467 Desc
.Description
= Description
+ " " + patch
.file
+ ".pdiff";
2468 DestFile
= GetPartialFileNameFromURI(Desc
.URI
);
2471 std::clog
<< "pkgAcqIndexMergeDiffs: " << Desc
.URI
<< std::endl
;
2476 void pkgAcqIndexMergeDiffs::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)/*{{{*/
2479 std::clog
<< "pkgAcqIndexMergeDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
;
2481 Item::Failed(Message
,Cnf
);
2484 // check if we are the first to fail, otherwise we are done here
2485 State
= StateDoneDiff
;
2486 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2487 I
!= allPatches
->end(); ++I
)
2488 if ((*I
)->State
== StateErrorDiff
)
2490 State
= StateErrorDiff
;
2494 // first failure means we should fallback
2495 State
= StateErrorDiff
;
2497 std::clog
<< "Falling back to normal index file acquire" << std::endl
;
2498 RenameOnError(PDiffError
);
2499 if (RealFileExists(DestFile
))
2500 Rename(DestFile
, DestFile
+ ".FAILED");
2501 std::string
const UnpatchedFile
= GetExistingFilename(GetPartialFileNameFromURI(Target
.URI
));
2502 if (UnpatchedFile
.empty() == false && FileExists(UnpatchedFile
))
2503 Rename(UnpatchedFile
, UnpatchedFile
+ ".FAILED");
2505 new pkgAcqIndex(Owner
, TransactionManager
, Target
);
2508 void pkgAcqIndexMergeDiffs::Done(string
const &Message
, HashStringList
const &Hashes
, /*{{{*/
2509 pkgAcquire::MethodConfig
const * const Cnf
)
2512 std::clog
<< "pkgAcqIndexMergeDiffs::Done(): " << Desc
.URI
<< std::endl
;
2514 Item::Done(Message
, Hashes
, Cnf
);
2516 if (std::any_of(allPatches
->begin(), allPatches
->end(),
2517 [](pkgAcqIndexMergeDiffs
const * const P
) { return P
->State
== StateErrorDiff
; }))
2520 std::clog
<< "Another patch failed already, no point in processing this one." << std::endl
;
2521 State
= StateErrorDiff
;
2525 std::string
const UncompressedUnpatchedFile
= GetPartialFileNameFromURI(Target
.URI
);
2526 std::string
const UnpatchedFile
= GetExistingFilename(UncompressedUnpatchedFile
);
2527 if (UnpatchedFile
.empty())
2529 _error
->Fatal("Unpatched file %s doesn't exist (anymore)!", UncompressedUnpatchedFile
.c_str());
2530 State
= StateErrorDiff
;
2533 std::string
const PatchFile
= GetMergeDiffsPatchFileName(UnpatchedFile
, patch
.file
);
2534 std::string
const PatchedFile
= GetKeepCompressedFileName(UncompressedUnpatchedFile
, Target
);
2538 case StateFetchDiff
:
2539 Rename(DestFile
, PatchFile
);
2541 // check if this is the last completed diff
2542 State
= StateDoneDiff
;
2543 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2544 I
!= allPatches
->end(); ++I
)
2545 if ((*I
)->State
!= StateDoneDiff
)
2548 std::clog
<< "Not the last done diff in the batch: " << Desc
.URI
<< std::endl
;
2551 // this is the last completed diff, so we are ready to apply now
2552 DestFile
= GetKeepCompressedFileName(UncompressedUnpatchedFile
+ "-patched", Target
);
2554 std::clog
<< "Sending to rred method: " << UnpatchedFile
<< std::endl
;
2555 State
= StateApplyDiff
;
2557 Desc
.URI
= "rred:" + UnpatchedFile
;
2559 SetActiveSubprocess("rred");
2561 case StateApplyDiff
:
2562 // success in download & apply all diffs, finialize and clean up
2564 std::clog
<< "Queue patched file in place: " << std::endl
2565 << DestFile
<< " -> " << PatchedFile
<< std::endl
;
2567 // queue for copy by the transaction manager
2568 TransactionManager
->TransactionStageCopy(this, DestFile
, GetKeepCompressedFileName(GetFinalFilename(), Target
));
2570 // ensure the ed's are gone regardless of list-cleanup
2571 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2572 I
!= allPatches
->end(); ++I
)
2573 RemoveFile("pkgAcqIndexMergeDiffs::Done", GetMergeDiffsPatchFileName(UnpatchedFile
, (*I
)->patch
.file
));
2574 RemoveFile("pkgAcqIndexMergeDiffs::Done", UnpatchedFile
);
2579 std::clog
<< "allDone: " << DestFile
<< "\n" << std::endl
;
2581 case StateDoneDiff
: _error
->Fatal("Done called for %s which is in an invalid Done state", PatchFile
.c_str()); break;
2582 case StateErrorDiff
: _error
->Fatal("Done called for %s which is in an invalid Error state", PatchFile
.c_str()); break;
2586 std::string
pkgAcqIndexMergeDiffs::Custom600Headers() const /*{{{*/
2588 if(State
!= StateApplyDiff
)
2589 return pkgAcqBaseIndex::Custom600Headers();
2590 std::ostringstream patchhashes
;
2591 unsigned int seen_patches
= 0;
2592 for (auto && hs
: (*allPatches
)[0]->patch
.result_hashes
)
2593 patchhashes
<< "\nStart-" << hs
.HashType() << "-Hash: " << hs
.HashValue();
2594 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
2595 I
!= allPatches
->end(); ++I
)
2597 HashStringList
const ExpectedHashes
= (*I
)->patch
.patch_hashes
;
2598 for (HashStringList::const_iterator hs
= ExpectedHashes
.begin(); hs
!= ExpectedHashes
.end(); ++hs
)
2599 patchhashes
<< "\nPatch-" << seen_patches
<< "-" << hs
->HashType() << "-Hash: " << hs
->HashValue();
2602 patchhashes
<< pkgAcqBaseIndex::Custom600Headers();
2603 return patchhashes
.str();
2606 pkgAcqIndexMergeDiffs::~pkgAcqIndexMergeDiffs() {}
2608 // AcqIndex::AcqIndex - Constructor /*{{{*/
2609 pkgAcqIndex::pkgAcqIndex(pkgAcquire
* const Owner
,
2610 pkgAcqMetaClearSig
* const TransactionManager
,
2611 IndexTarget
const &Target
)
2612 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
), d(NULL
), Stage(STAGE_DOWNLOAD
),
2613 CompressionExtensions(Target
.Option(IndexTarget::COMPRESSIONTYPES
))
2615 Init(Target
.URI
, Target
.Description
, Target
.ShortDesc
);
2617 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
2618 std::clog
<< "New pkgIndex with TransactionManager "
2619 << TransactionManager
<< std::endl
;
2622 // AcqIndex::Init - defered Constructor /*{{{*/
2623 static void NextCompressionExtension(std::string
&CurrentCompressionExtension
, std::string
&CompressionExtensions
, bool const preview
)
2625 size_t const nextExt
= CompressionExtensions
.find(' ');
2626 if (nextExt
== std::string::npos
)
2628 CurrentCompressionExtension
= CompressionExtensions
;
2629 if (preview
== false)
2630 CompressionExtensions
.clear();
2634 CurrentCompressionExtension
= CompressionExtensions
.substr(0, nextExt
);
2635 if (preview
== false)
2636 CompressionExtensions
= CompressionExtensions
.substr(nextExt
+1);
2639 void pkgAcqIndex::Init(string
const &URI
, string
const &URIDesc
,
2640 string
const &ShortDesc
)
2642 Stage
= STAGE_DOWNLOAD
;
2644 DestFile
= GetPartialFileNameFromURI(URI
);
2645 NextCompressionExtension(CurrentCompressionExtension
, CompressionExtensions
, false);
2647 // store file size of the download to ensure the fetcher gives
2648 // accurate progress reporting
2649 FileSize
= GetExpectedHashes().FileSize();
2651 if (CurrentCompressionExtension
== "uncompressed")
2655 else if (CurrentCompressionExtension
== "by-hash")
2657 NextCompressionExtension(CurrentCompressionExtension
, CompressionExtensions
, true);
2658 if(unlikely(TransactionManager
->MetaIndexParser
== NULL
|| CurrentCompressionExtension
.empty()))
2660 if (CurrentCompressionExtension
!= "uncompressed")
2662 Desc
.URI
= URI
+ '.' + CurrentCompressionExtension
;
2663 DestFile
= DestFile
+ '.' + CurrentCompressionExtension
;
2666 HashStringList
const Hashes
= GetExpectedHashes();
2667 HashString
const * const TargetHash
= Hashes
.find(NULL
);
2668 if (unlikely(TargetHash
== nullptr))
2670 std::string
const ByHash
= "/by-hash/" + TargetHash
->HashType() + "/" + TargetHash
->HashValue();
2671 size_t const trailing_slash
= Desc
.URI
.find_last_of("/");
2672 if (unlikely(trailing_slash
== std::string::npos
))
2674 Desc
.URI
= Desc
.URI
.replace(
2676 Desc
.URI
.substr(trailing_slash
+1).size()+1,
2679 else if (unlikely(CurrentCompressionExtension
.empty()))
2683 Desc
.URI
= URI
+ '.' + CurrentCompressionExtension
;
2684 DestFile
= DestFile
+ '.' + CurrentCompressionExtension
;
2688 Desc
.Description
= URIDesc
;
2690 Desc
.ShortDesc
= ShortDesc
;
2695 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
2696 // ---------------------------------------------------------------------
2697 /* The only header we use is the last-modified header. */
2698 string
pkgAcqIndex::Custom600Headers() const
2701 string msg
= "\nIndex-File: true";
2703 if (TransactionManager
->LastMetaIndexParser
== NULL
)
2705 std::string
const Final
= GetFinalFilename();
2708 if (stat(Final
.c_str(),&Buf
) == 0)
2709 msg
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
2712 if(Target
.IsOptional
)
2713 msg
+= "\nFail-Ignore: true";
2718 // AcqIndex::Failed - getting the indexfile failed /*{{{*/
2719 void pkgAcqIndex::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)
2721 Item::Failed(Message
,Cnf
);
2723 // authorisation matches will not be fixed by other compression types
2724 if (Status
!= StatAuthError
)
2726 if (CompressionExtensions
.empty() == false)
2728 Init(Target
.URI
, Desc
.Description
, Desc
.ShortDesc
);
2734 if(Target
.IsOptional
&& GetExpectedHashes().empty() && Stage
== STAGE_DOWNLOAD
)
2737 TransactionManager
->AbortTransaction();
2740 // AcqIndex::Done - Finished a fetch /*{{{*/
2741 // ---------------------------------------------------------------------
2742 /* This goes through a number of states.. On the initial fetch the
2743 method could possibly return an alternate filename which points
2744 to the uncompressed version of the file. If this is so the file
2745 is copied into the partial directory. In all other cases the file
2746 is decompressed with a compressed uri. */
2747 void pkgAcqIndex::Done(string
const &Message
,
2748 HashStringList
const &Hashes
,
2749 pkgAcquire::MethodConfig
const * const Cfg
)
2751 Item::Done(Message
,Hashes
,Cfg
);
2755 case STAGE_DOWNLOAD
:
2756 StageDownloadDone(Message
);
2758 case STAGE_DECOMPRESS_AND_VERIFY
:
2759 StageDecompressDone();
2764 // AcqIndex::StageDownloadDone - Queue for decompress and verify /*{{{*/
2765 void pkgAcqIndex::StageDownloadDone(string
const &Message
)
2770 std::string
const AltFilename
= LookupTag(Message
,"Alt-Filename");
2771 std::string Filename
= LookupTag(Message
,"Filename");
2773 // we need to verify the file against the current Release file again
2774 // on if-modfied-since hit to avoid a stale attack against us
2775 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
2777 // copy FinalFile into partial/ so that we check the hash again
2778 string
const FinalFile
= GetExistingFilename(GetFinalFileNameFromURI(Target
.URI
));
2779 if (symlink(FinalFile
.c_str(), DestFile
.c_str()) != 0)
2780 _error
->WarningE("pkgAcqIndex::StageDownloadDone", "Symlinking final file %s back to %s failed", FinalFile
.c_str(), DestFile
.c_str());
2783 EraseFileName
= DestFile
;
2784 Filename
= DestFile
;
2786 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
2787 Desc
.URI
= "store:" + Filename
;
2789 SetActiveSubprocess(::URI(Desc
.URI
).Access
);
2792 // methods like file:// give us an alternative (uncompressed) file
2793 else if (Target
.KeepCompressed
== false && AltFilename
.empty() == false)
2795 Filename
= AltFilename
;
2796 EraseFileName
.clear();
2798 // Methods like e.g. "file:" will give us a (compressed) FileName that is
2799 // not the "DestFile" we set, in this case we uncompress from the local file
2800 else if (Filename
!= DestFile
&& RealFileExists(DestFile
) == false)
2802 // symlinking ensures that the filename can be used for compression detection
2803 // that is e.g. needed for by-hash which has no extension over file
2804 if (symlink(Filename
.c_str(),DestFile
.c_str()) != 0)
2805 _error
->WarningE("pkgAcqIndex::StageDownloadDone", "Symlinking file %s to %s failed", Filename
.c_str(), DestFile
.c_str());
2808 EraseFileName
= DestFile
;
2809 Filename
= DestFile
;
2813 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
2814 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
2815 if (Filename
!= DestFile
&& flExtension(Filename
) == flExtension(DestFile
))
2816 Desc
.URI
= "copy:" + Filename
;
2818 Desc
.URI
= "store:" + Filename
;
2819 if (DestFile
== Filename
)
2821 if (CurrentCompressionExtension
== "uncompressed")
2822 return StageDecompressDone();
2823 DestFile
= "/dev/null";
2826 if (EraseFileName
.empty() && Filename
!= AltFilename
)
2827 EraseFileName
= Filename
;
2829 // queue uri for the next stage
2831 SetActiveSubprocess(::URI(Desc
.URI
).Access
);
2834 // AcqIndex::StageDecompressDone - Final verification /*{{{*/
2835 void pkgAcqIndex::StageDecompressDone()
2837 if (DestFile
== "/dev/null")
2838 DestFile
= GetKeepCompressedFileName(GetPartialFileNameFromURI(Target
.URI
), Target
);
2840 // Done, queue for rename on transaction finished
2841 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
2844 pkgAcqIndex::~pkgAcqIndex() {}
2847 // AcqArchive::AcqArchive - Constructor /*{{{*/
2848 // ---------------------------------------------------------------------
2849 /* This just sets up the initial fetch environment and queues the first
2851 pkgAcqArchive::pkgAcqArchive(pkgAcquire
* const Owner
,pkgSourceList
* const Sources
,
2852 pkgRecords
* const Recs
,pkgCache::VerIterator
const &Version
,
2853 string
&StoreFilename
) :
2854 Item(Owner
), d(NULL
), LocalSource(false), Version(Version
), Sources(Sources
), Recs(Recs
),
2855 StoreFilename(StoreFilename
), Vf(Version
.FileList()),
2858 Retries
= _config
->FindI("Acquire::Retries",0);
2860 if (Version
.Arch() == 0)
2862 _error
->Error(_("I wasn't able to locate a file for the %s package. "
2863 "This might mean you need to manually fix this package. "
2864 "(due to missing arch)"),
2865 Version
.ParentPkg().FullName().c_str());
2869 /* We need to find a filename to determine the extension. We make the
2870 assumption here that all the available sources for this version share
2871 the same extension.. */
2872 // Skip not source sources, they do not have file fields.
2873 for (; Vf
.end() == false; ++Vf
)
2875 if (Vf
.File().Flagged(pkgCache::Flag::NotSource
))
2880 // Does not really matter here.. we are going to fail out below
2881 if (Vf
.end() != true)
2883 // If this fails to get a file name we will bomb out below.
2884 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2885 if (_error
->PendingError() == true)
2888 // Generate the final file name as: package_version_arch.foo
2889 StoreFilename
= QuoteString(Version
.ParentPkg().Name(),"_:") + '_' +
2890 QuoteString(Version
.VerStr(),"_:") + '_' +
2891 QuoteString(Version
.Arch(),"_:.") +
2892 "." + flExtension(Parse
.FileName());
2895 // check if we have one trusted source for the package. if so, switch
2896 // to "TrustedOnly" mode - but only if not in AllowUnauthenticated mode
2897 bool const allowUnauth
= _config
->FindB("APT::Get::AllowUnauthenticated", false);
2898 bool const debugAuth
= _config
->FindB("Debug::pkgAcquire::Auth", false);
2899 bool seenUntrusted
= false;
2900 for (pkgCache::VerFileIterator i
= Version
.FileList(); i
.end() == false; ++i
)
2902 pkgIndexFile
*Index
;
2903 if (Sources
->FindIndex(i
.File(),Index
) == false)
2906 if (debugAuth
== true)
2907 std::cerr
<< "Checking index: " << Index
->Describe()
2908 << "(Trusted=" << Index
->IsTrusted() << ")" << std::endl
;
2910 if (Index
->IsTrusted() == true)
2913 if (allowUnauth
== false)
2917 seenUntrusted
= true;
2920 // "allow-unauthenticated" restores apts old fetching behaviour
2921 // that means that e.g. unauthenticated file:// uris are higher
2922 // priority than authenticated http:// uris
2923 if (allowUnauth
== true && seenUntrusted
== true)
2927 if (QueueNext() == false && _error
->PendingError() == false)
2928 _error
->Error(_("Can't find a source to download version '%s' of '%s'"),
2929 Version
.VerStr(), Version
.ParentPkg().FullName(false).c_str());
2932 // AcqArchive::QueueNext - Queue the next file source /*{{{*/
2933 // ---------------------------------------------------------------------
2934 /* This queues the next available file version for download. It checks if
2935 the archive is already available in the cache and stashs the MD5 for
2937 bool pkgAcqArchive::QueueNext()
2939 for (; Vf
.end() == false; ++Vf
)
2941 pkgCache::PkgFileIterator
const PkgF
= Vf
.File();
2942 // Ignore not source sources
2943 if (PkgF
.Flagged(pkgCache::Flag::NotSource
))
2946 // Try to cross match against the source list
2947 pkgIndexFile
*Index
;
2948 if (Sources
->FindIndex(PkgF
, Index
) == false)
2950 LocalSource
= PkgF
.Flagged(pkgCache::Flag::LocalSource
);
2952 // only try to get a trusted package from another source if that source
2954 if(Trusted
&& !Index
->IsTrusted())
2957 // Grab the text package record
2958 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2959 if (_error
->PendingError() == true)
2962 string PkgFile
= Parse
.FileName();
2963 ExpectedHashes
= Parse
.Hashes();
2965 if (PkgFile
.empty() == true)
2966 return _error
->Error(_("The package index files are corrupted. No Filename: "
2967 "field for package %s."),
2968 Version
.ParentPkg().Name());
2970 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
2971 Desc
.Description
= Index
->ArchiveInfo(Version
);
2973 Desc
.ShortDesc
= Version
.ParentPkg().FullName(true);
2975 // See if we already have the file. (Legacy filenames)
2976 FileSize
= Version
->Size
;
2977 string FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile
);
2979 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2981 // Make sure the size matches
2982 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2987 StoreFilename
= DestFile
= FinalFile
;
2991 /* Hmm, we have a file and its size does not match, this means it is
2992 an old style mismatched arch */
2993 RemoveFile("pkgAcqArchive::QueueNext", FinalFile
);
2996 // Check it again using the new style output filenames
2997 FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
2998 if (stat(FinalFile
.c_str(),&Buf
) == 0)
3000 // Make sure the size matches
3001 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
3006 StoreFilename
= DestFile
= FinalFile
;
3010 /* Hmm, we have a file and its size does not match, this shouldn't
3012 RemoveFile("pkgAcqArchive::QueueNext", FinalFile
);
3015 DestFile
= _config
->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename
);
3017 // Check the destination file
3018 if (stat(DestFile
.c_str(),&Buf
) == 0)
3020 // Hmm, the partial file is too big, erase it
3021 if ((unsigned long long)Buf
.st_size
> Version
->Size
)
3022 RemoveFile("pkgAcqArchive::QueueNext", DestFile
);
3024 PartialSize
= Buf
.st_size
;
3027 // Disables download of archives - useful if no real installation follows,
3028 // e.g. if we are just interested in proposed installation order
3029 if (_config
->FindB("Debug::pkgAcqArchive::NoQueue", false) == true)
3034 StoreFilename
= DestFile
= FinalFile
;
3048 // AcqArchive::Done - Finished fetching /*{{{*/
3049 // ---------------------------------------------------------------------
3051 void pkgAcqArchive::Done(string
const &Message
, HashStringList
const &Hashes
,
3052 pkgAcquire::MethodConfig
const * const Cfg
)
3054 Item::Done(Message
, Hashes
, Cfg
);
3056 // Grab the output filename
3057 std::string
const FileName
= LookupTag(Message
,"Filename");
3058 if (DestFile
!= FileName
&& RealFileExists(DestFile
) == false)
3060 StoreFilename
= DestFile
= FileName
;
3066 // Done, move it into position
3067 string
const FinalFile
= GetFinalFilename();
3068 Rename(DestFile
,FinalFile
);
3069 StoreFilename
= DestFile
= FinalFile
;
3073 // AcqArchive::Failed - Failure handler /*{{{*/
3074 // ---------------------------------------------------------------------
3075 /* Here we try other sources */
3076 void pkgAcqArchive::Failed(string
const &Message
,pkgAcquire::MethodConfig
const * const Cnf
)
3078 Item::Failed(Message
,Cnf
);
3080 /* We don't really want to retry on failed media swaps, this prevents
3081 that. An interesting observation is that permanent failures are not
3083 if (Cnf
->Removable
== true &&
3084 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
3086 // Vf = Version.FileList();
3087 while (Vf
.end() == false) ++Vf
;
3088 StoreFilename
= string();
3093 if (QueueNext() == false)
3095 // This is the retry counter
3097 Cnf
->LocalOnly
== false &&
3098 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
3101 Vf
= Version
.FileList();
3102 if (QueueNext() == true)
3106 StoreFilename
= string();
3111 APT_PURE
bool pkgAcqArchive::IsTrusted() const /*{{{*/
3116 void pkgAcqArchive::Finished() /*{{{*/
3118 if (Status
== pkgAcquire::Item::StatDone
&&
3121 StoreFilename
= string();
3124 std::string
pkgAcqArchive::DescURI() const /*{{{*/
3129 std::string
pkgAcqArchive::ShortDesc() const /*{{{*/
3131 return Desc
.ShortDesc
;
3134 pkgAcqArchive::~pkgAcqArchive() {}
3136 // AcqChangelog::pkgAcqChangelog - Constructors /*{{{*/
3137 class pkgAcqChangelog::Private
3140 std::string FinalFile
;
3142 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire
* const Owner
, pkgCache::VerIterator
const &Ver
,
3143 std::string
const &DestDir
, std::string
const &DestFilename
) :
3144 pkgAcquire::Item(Owner
), d(new pkgAcqChangelog::Private()), SrcName(Ver
.SourcePkgName()), SrcVersion(Ver
.SourceVerStr())
3146 Desc
.URI
= URI(Ver
);
3147 Init(DestDir
, DestFilename
);
3149 // some parameters are char* here as they come likely from char* interfaces – which can also return NULL
3150 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire
* const Owner
, pkgCache::RlsFileIterator
const &RlsFile
,
3151 char const * const Component
, char const * const SrcName
, char const * const SrcVersion
,
3152 const string
&DestDir
, const string
&DestFilename
) :
3153 pkgAcquire::Item(Owner
), d(new pkgAcqChangelog::Private()), SrcName(SrcName
), SrcVersion(SrcVersion
)
3155 Desc
.URI
= URI(RlsFile
, Component
, SrcName
, SrcVersion
);
3156 Init(DestDir
, DestFilename
);
3158 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire
* const Owner
,
3159 std::string
const &URI
, char const * const SrcName
, char const * const SrcVersion
,
3160 const string
&DestDir
, const string
&DestFilename
) :
3161 pkgAcquire::Item(Owner
), d(new pkgAcqChangelog::Private()), SrcName(SrcName
), SrcVersion(SrcVersion
)
3164 Init(DestDir
, DestFilename
);
3166 void pkgAcqChangelog::Init(std::string
const &DestDir
, std::string
const &DestFilename
)
3168 if (Desc
.URI
.empty())
3171 // TRANSLATOR: %s=%s is sourcename=sourceversion, e.g. apt=1.1
3172 strprintf(ErrorText
, _("Changelog unavailable for %s=%s"), SrcName
.c_str(), SrcVersion
.c_str());
3173 // Let the error message print something sensible rather than "Failed to fetch /"
3174 if (DestFilename
.empty())
3175 DestFile
= SrcName
+ ".changelog";
3177 DestFile
= DestFilename
;
3178 Desc
.URI
= "changelog:/" + DestFile
;
3182 std::string DestFileName
;
3183 if (DestFilename
.empty())
3184 DestFileName
= flCombine(DestFile
, SrcName
+ ".changelog");
3186 DestFileName
= flCombine(DestFile
, DestFilename
);
3188 std::string
const SandboxUser
= _config
->Find("APT::Sandbox::User");
3189 std::string
const systemTemp
= GetTempDir(SandboxUser
);
3191 snprintf(tmpname
, sizeof(tmpname
), "%s/apt-changelog-XXXXXX", systemTemp
.c_str());
3192 if (NULL
== mkdtemp(tmpname
))
3194 _error
->Errno("mkdtemp", "mkdtemp failed in changelog acquire of %s %s", SrcName
.c_str(), SrcVersion
.c_str());
3198 TemporaryDirectory
= tmpname
;
3200 ChangeOwnerAndPermissionOfFile("Item::QueueURI", TemporaryDirectory
.c_str(),
3201 SandboxUser
.c_str(), "root", 0700);
3203 DestFile
= flCombine(TemporaryDirectory
, DestFileName
);
3204 if (DestDir
.empty() == false)
3206 d
->FinalFile
= flCombine(DestDir
, DestFileName
);
3207 if (RealFileExists(d
->FinalFile
))
3209 FileFd file1
, file2
;
3210 if (file1
.Open(DestFile
, FileFd::WriteOnly
| FileFd::Create
| FileFd::Exclusive
) &&
3211 file2
.Open(d
->FinalFile
, FileFd::ReadOnly
) && CopyFile(file2
, file1
))
3213 struct timeval times
[2];
3214 times
[0].tv_sec
= times
[1].tv_sec
= file2
.ModificationTime();
3215 times
[0].tv_usec
= times
[1].tv_usec
= 0;
3216 utimes(DestFile
.c_str(), times
);
3221 Desc
.ShortDesc
= "Changelog";
3222 strprintf(Desc
.Description
, "%s %s %s Changelog", URI::SiteOnly(Desc
.URI
).c_str(), SrcName
.c_str(), SrcVersion
.c_str());
3227 std::string
pkgAcqChangelog::URI(pkgCache::VerIterator
const &Ver
) /*{{{*/
3229 std::string
const confOnline
= "Acquire::Changelogs::AlwaysOnline";
3230 bool AlwaysOnline
= _config
->FindB(confOnline
, false);
3231 if (AlwaysOnline
== false)
3232 for (pkgCache::VerFileIterator VF
= Ver
.FileList(); VF
.end() == false; ++VF
)
3234 pkgCache::PkgFileIterator
const PF
= VF
.File();
3235 if (PF
.Flagged(pkgCache::Flag::NotSource
) || PF
->Release
== 0)
3237 pkgCache::RlsFileIterator
const RF
= PF
.ReleaseFile();
3238 if (RF
->Origin
!= 0 && _config
->FindB(confOnline
+ "::Origin::" + RF
.Origin(), false))
3240 AlwaysOnline
= true;
3244 if (AlwaysOnline
== false)
3246 pkgCache::PkgIterator
const Pkg
= Ver
.ParentPkg();
3247 if (Pkg
->CurrentVer
!= 0 && Pkg
.CurrentVer() == Ver
)
3249 std::string
const basename
= std::string("/usr/share/doc/") + Pkg
.Name() + "/changelog";
3250 std::string
const debianname
= basename
+ ".Debian";
3251 if (FileExists(debianname
))
3252 return "copy://" + debianname
;
3253 else if (FileExists(debianname
+ ".gz"))
3254 return "gzip://" + debianname
+ ".gz";
3255 else if (FileExists(basename
))
3256 return "copy://" + basename
;
3257 else if (FileExists(basename
+ ".gz"))
3258 return "gzip://" + basename
+ ".gz";
3262 char const * const SrcName
= Ver
.SourcePkgName();
3263 char const * const SrcVersion
= Ver
.SourceVerStr();
3264 // find the first source for this version which promises a changelog
3265 for (pkgCache::VerFileIterator VF
= Ver
.FileList(); VF
.end() == false; ++VF
)
3267 pkgCache::PkgFileIterator
const PF
= VF
.File();
3268 if (PF
.Flagged(pkgCache::Flag::NotSource
) || PF
->Release
== 0)
3270 pkgCache::RlsFileIterator
const RF
= PF
.ReleaseFile();
3271 std::string
const uri
= URI(RF
, PF
.Component(), SrcName
, SrcVersion
);
3278 std::string
pkgAcqChangelog::URITemplate(pkgCache::RlsFileIterator
const &Rls
)
3280 if (Rls
.end() == true || (Rls
->Label
== 0 && Rls
->Origin
== 0))
3282 std::string
const serverConfig
= "Acquire::Changelogs::URI";
3284 #define APT_EMPTY_SERVER \
3285 if (server.empty() == false) \
3287 if (server != "no") \
3291 #define APT_CHECK_SERVER(X, Y) \
3294 std::string const specialServerConfig = serverConfig + "::" + Y + #X + "::" + Rls.X(); \
3295 server = _config->Find(specialServerConfig); \
3298 // this way e.g. Debian-Security can fallback to Debian
3299 APT_CHECK_SERVER(Label
, "Override::")
3300 APT_CHECK_SERVER(Origin
, "Override::")
3302 if (RealFileExists(Rls
.FileName()))
3304 _error
->PushToStack();
3306 /* This can be costly. A caller wanting to get millions of URIs might
3307 want to do this on its own once and use Override settings.
3308 We don't do this here as Origin/Label are not as unique as they
3309 should be so this could produce request order-dependent anomalies */
3310 if (OpenMaybeClearSignedFile(Rls
.FileName(), rf
) == true)
3312 pkgTagFile
TagFile(&rf
, rf
.Size());
3313 pkgTagSection Section
;
3314 if (TagFile
.Step(Section
) == true)
3315 server
= Section
.FindS("Changelogs");
3317 _error
->RevertToStack();
3321 APT_CHECK_SERVER(Label
, "")
3322 APT_CHECK_SERVER(Origin
, "")
3323 #undef APT_CHECK_SERVER
3324 #undef APT_EMPTY_SERVER
3327 std::string
pkgAcqChangelog::URI(pkgCache::RlsFileIterator
const &Rls
,
3328 char const * const Component
, char const * const SrcName
,
3329 char const * const SrcVersion
)
3331 return URI(URITemplate(Rls
), Component
, SrcName
, SrcVersion
);
3333 std::string
pkgAcqChangelog::URI(std::string
const &Template
,
3334 char const * const Component
, char const * const SrcName
,
3335 char const * const SrcVersion
)
3337 if (Template
.find("@CHANGEPATH@") == std::string::npos
)
3340 // the path is: COMPONENT/SRC/SRCNAME/SRCNAME_SRCVER, e.g. main/a/apt/1.1 or contrib/liba/libapt/2.0
3341 std::string Src
= SrcName
;
3342 std::string path
= APT::String::Startswith(SrcName
, "lib") ? Src
.substr(0, 4) : Src
.substr(0,1);
3343 path
.append("/").append(Src
).append("/");
3344 path
.append(Src
).append("_").append(StripEpoch(SrcVersion
));
3345 // we omit component for releases without one (= flat-style repositories)
3346 if (Component
!= NULL
&& strlen(Component
) != 0)
3347 path
= std::string(Component
) + "/" + path
;
3349 return SubstVar(Template
, "@CHANGEPATH@", path
);
3352 // AcqChangelog::Failed - Failure handler /*{{{*/
3353 void pkgAcqChangelog::Failed(string
const &Message
, pkgAcquire::MethodConfig
const * const Cnf
)
3355 Item::Failed(Message
,Cnf
);
3357 std::string errText
;
3358 // TRANSLATOR: %s=%s is sourcename=sourceversion, e.g. apt=1.1
3359 strprintf(errText
, _("Changelog unavailable for %s=%s"), SrcName
.c_str(), SrcVersion
.c_str());
3361 // Error is probably something techy like 404 Not Found
3362 if (ErrorText
.empty())
3363 ErrorText
= errText
;
3365 ErrorText
= errText
+ " (" + ErrorText
+ ")";
3368 // AcqChangelog::Done - Item downloaded OK /*{{{*/
3369 void pkgAcqChangelog::Done(string
const &Message
,HashStringList
const &CalcHashes
,
3370 pkgAcquire::MethodConfig
const * const Cnf
)
3372 Item::Done(Message
,CalcHashes
,Cnf
);
3373 if (d
->FinalFile
.empty() == false)
3375 if (RemoveFile("pkgAcqChangelog::Done", d
->FinalFile
) == false ||
3376 Rename(DestFile
, d
->FinalFile
) == false)
3383 pkgAcqChangelog::~pkgAcqChangelog() /*{{{*/
3385 if (TemporaryDirectory
.empty() == false)
3387 RemoveFile("~pkgAcqChangelog", DestFile
);
3388 rmdir(TemporaryDirectory
.c_str());
3394 // AcqFile::pkgAcqFile - Constructor /*{{{*/
3395 pkgAcqFile::pkgAcqFile(pkgAcquire
* const Owner
,string
const &URI
, HashStringList
const &Hashes
,
3396 unsigned long long const Size
,string
const &Dsc
,string
const &ShortDesc
,
3397 const string
&DestDir
, const string
&DestFilename
,
3398 bool const IsIndexFile
) :
3399 Item(Owner
), d(NULL
), IsIndexFile(IsIndexFile
), ExpectedHashes(Hashes
)
3401 Retries
= _config
->FindI("Acquire::Retries",0);
3403 if(!DestFilename
.empty())
3404 DestFile
= DestFilename
;
3405 else if(!DestDir
.empty())
3406 DestFile
= DestDir
+ "/" + flNotDir(URI
);
3408 DestFile
= flNotDir(URI
);
3412 Desc
.Description
= Dsc
;
3415 // Set the short description to the archive component
3416 Desc
.ShortDesc
= ShortDesc
;
3418 // Get the transfer sizes
3421 if (stat(DestFile
.c_str(),&Buf
) == 0)
3423 // Hmm, the partial file is too big, erase it
3424 if ((Size
> 0) && (unsigned long long)Buf
.st_size
> Size
)
3425 RemoveFile("pkgAcqFile", DestFile
);
3427 PartialSize
= Buf
.st_size
;
3433 // AcqFile::Done - Item downloaded OK /*{{{*/
3434 void pkgAcqFile::Done(string
const &Message
,HashStringList
const &CalcHashes
,
3435 pkgAcquire::MethodConfig
const * const Cnf
)
3437 Item::Done(Message
,CalcHashes
,Cnf
);
3439 std::string
const FileName
= LookupTag(Message
,"Filename");
3442 // The files timestamp matches
3443 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
3446 // We have to copy it into place
3447 if (RealFileExists(DestFile
.c_str()) == false)
3450 if (_config
->FindB("Acquire::Source-Symlinks",true) == false ||
3451 Cnf
->Removable
== true)
3453 Desc
.URI
= "copy:" + FileName
;
3458 // Erase the file if it is a symlink so we can overwrite it
3460 if (lstat(DestFile
.c_str(),&St
) == 0)
3462 if (S_ISLNK(St
.st_mode
) != 0)
3463 RemoveFile("pkgAcqFile::Done", DestFile
);
3467 if (symlink(FileName
.c_str(),DestFile
.c_str()) != 0)
3469 _error
->PushToStack();
3470 _error
->Errno("pkgAcqFile::Done", "Symlinking file %s failed", DestFile
.c_str());
3471 std::stringstream msg
;
3472 _error
->DumpErrors(msg
, GlobalError::DEBUG
, false);
3473 _error
->RevertToStack();
3474 ErrorText
= msg
.str();
3481 // AcqFile::Failed - Failure handler /*{{{*/
3482 // ---------------------------------------------------------------------
3483 /* Here we try other sources */
3484 void pkgAcqFile::Failed(string
const &Message
, pkgAcquire::MethodConfig
const * const Cnf
)
3486 Item::Failed(Message
,Cnf
);
3488 // This is the retry counter
3490 Cnf
->LocalOnly
== false &&
3491 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
3501 string
pkgAcqFile::Custom600Headers() const /*{{{*/
3504 return "\nIndex-File: true";
3508 pkgAcqFile::~pkgAcqFile() {}