]> git.saurik.com Git - apt.git/blame - apt-pkg/acquire-item.cc
show a more descriptive error for weak Release files
[apt.git] / apt-pkg / acquire-item.cc
CommitLineData
0118833a
AL
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
b3d44315 3// $Id: acquire-item.cc,v 1.46.2.9 2004/01/16 18:51:11 mdz Exp $
0118833a
AL
4/* ######################################################################
5
6 Acquire Item - Item to acquire
7
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.
b185acc2 12
0118833a
AL
13 ##################################################################### */
14 /*}}}*/
15// Include Files /*{{{*/
ea542140
DK
16#include <config.h>
17
0118833a
AL
18#include <apt-pkg/acquire-item.h>
19#include <apt-pkg/configuration.h>
e878aedb 20#include <apt-pkg/aptconfiguration.h>
b2e465d6 21#include <apt-pkg/sourcelist.h>
03e39e59 22#include <apt-pkg/error.h>
cdcc6d34 23#include <apt-pkg/strutl.h>
36375005 24#include <apt-pkg/fileutl.h>
ac5b205a 25#include <apt-pkg/tagfile.h>
5ad0096a 26#include <apt-pkg/metaindex.h>
453b82a3
DK
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>
d56e2917 33#include <apt-pkg/gpgv.h>
453b82a3 34
d7a51997 35#include <algorithm>
453b82a3
DK
36#include <stddef.h>
37#include <stdlib.h>
38#include <string.h>
39#include <iostream>
40#include <vector>
0a8a80e5
AL
41#include <sys/stat.h>
42#include <unistd.h>
c88edf1d 43#include <errno.h>
5819a761 44#include <string>
c88edf1d 45#include <stdio.h>
1ddb8596 46#include <ctime>
ac7f8f79 47#include <sstream>
ea542140
DK
48
49#include <apti18n.h>
0118833a
AL
50 /*}}}*/
51
b3d44315 52using namespace std;
5819a761 53
b3501edb
DK
54static void printHashSumComparision(std::string const &URI, HashStringList const &Expected, HashStringList const &Actual) /*{{{*/
55{
56 if (_config->FindB("Debug::Acquire::HashSumMismatch", false) == false)
57 return;
58 std::cerr << std::endl << URI << ":" << std::endl << " Expected Hash: " << std::endl;
59 for (HashStringList::const_iterator hs = Expected.begin(); hs != Expected.end(); ++hs)
60 std::cerr << "\t- " << hs->toStr() << std::endl;
61 std::cerr << " Actual Hash: " << std::endl;
62 for (HashStringList::const_iterator hs = Actual.begin(); hs != Actual.end(); ++hs)
63 std::cerr << "\t- " << hs->toStr() << std::endl;
64}
65 /*}}}*/
70b63c57 66static std::string GetPartialFileName(std::string const &file) /*{{{*/
5684f71f
DK
67{
68 std::string DestFile = _config->FindDir("Dir::State::lists") + "partial/";
69 DestFile += file;
70 return DestFile;
71}
70b63c57
DK
72 /*}}}*/
73static std::string GetPartialFileNameFromURI(std::string const &uri) /*{{{*/
5684f71f 74{
ea7682a0 75 return GetPartialFileName(URItoFileName(uri));
5684f71f 76}
70b63c57 77 /*}}}*/
295d848b
DK
78static std::string GetFinalFileNameFromURI(std::string const &uri) /*{{{*/
79{
80 return _config->FindDir("Dir::State::lists") + URItoFileName(uri);
81}
82 /*}}}*/
d7a51997
DK
83static std::string GetKeepCompressedFileName(std::string file, IndexTarget const &Target)/*{{{*/
84{
85 if (Target.KeepCompressed == false)
86 return file;
87
88 std::string const CompressionTypes = Target.Option(IndexTarget::COMPRESSIONTYPES);
89 if (CompressionTypes.empty() == false)
90 {
91 std::string const ext = CompressionTypes.substr(0, CompressionTypes.find(' '));
92 if (ext != "uncompressed")
93 file.append(".").append(ext);
94 }
95 return file;
96}
97 /*}}}*/
653ef26c 98static std::string GetCompressedFileName(IndexTarget const &Target, std::string const &Name, std::string const &Ext) /*{{{*/
70b63c57
DK
99{
100 if (Ext.empty() || Ext == "uncompressed")
101 return Name;
102
103 // do not reverify cdrom sources as apt-cdrom may rewrite the Packages
104 // file when its doing the indexcopy
653ef26c 105 if (Target.URI.substr(0,6) == "cdrom:")
70b63c57 106 return Name;
5684f71f 107
70b63c57 108 // adjust DestFile if its compressed on disk
653ef26c 109 if (Target.KeepCompressed == true)
70b63c57
DK
110 return Name + '.' + Ext;
111 return Name;
112}
113 /*}}}*/
36795154
DK
114static std::string GetMergeDiffsPatchFileName(std::string const &Final, std::string const &Patch)/*{{{*/
115{
116 // rred expects the patch as $FinalFile.ed.$patchname.gz
117 return Final + ".ed." + Patch + ".gz";
118}
119 /*}}}*/
120static std::string GetDiffsPatchFileName(std::string const &Final) /*{{{*/
121{
122 // rred expects the patch as $FinalFile.ed
123 return Final + ".ed";
124}
125 /*}}}*/
d7a51997
DK
126static bool BootstrapPDiffWith(std::string const &PartialFile, std::string const &FinalFile, IndexTarget const &Target)/*{{{*/
127{
128 // patching needs to be bootstrapped with the 'old' version
129 std::vector<std::string> types = VectorizeString(Target.Option(IndexTarget::COMPRESSIONTYPES), ' ');
130 auto typeItr = types.cbegin();
131 for (; typeItr != types.cend(); ++typeItr)
132 {
133 std::string Final = FinalFile;
134 if (*typeItr != "uncompressed")
135 Final.append(".").append(*typeItr);
136 if (RealFileExists(Final) == false)
137 continue;
138 std::string Partial = PartialFile;
139 if (*typeItr != "uncompressed")
140 Partial.append(".").append(*typeItr);
141 if (FileExists(Partial.c_str()) == true)
142 return true;
143 if (symlink(Final.c_str(), Partial.c_str()) != 0)
144 return false;
145 break;
146 }
147 return typeItr != types.cend();
148}
149 /*}}}*/
36795154 150
f18f2338 151static bool MessageInsecureRepository(bool const isError, std::string const &msg)/*{{{*/
32532943 152{
f18f2338
DK
153 if (isError)
154 {
155 _error->Error("%s", msg.c_str());
83960341 156 _error->Notice("%s", _("Updating from such a repository can't be done securely, and is therefore disabled by default."));
f18f2338
DK
157 }
158 else
159 {
160 _error->Warning("%s", msg.c_str());
d04e44ac 161 _error->Notice("%s", _("Data from such a repository can't be authenticated and is therefore potentially dangerous to use."));
f18f2338 162 }
002b1bc4 163 _error->Notice("%s", _("See apt-secure(8) manpage for repository creation and user configuration details."));
f18f2338
DK
164 return false;
165}
166static bool MessageInsecureRepository(bool const isError, char const * const msg, std::string const &repo)
167{
168 std::string m;
169 strprintf(m, msg, repo.c_str());
170 return MessageInsecureRepository(isError, m);
171}
172 /*}}}*/
173static bool AllowInsecureRepositories(char const * const msg, std::string const &repo,/*{{{*/
174 metaIndex const * const MetaIndexParser, pkgAcqMetaClearSig * const TransactionManager, pkgAcquire::Item * const I)
175{
176 if(MetaIndexParser->GetTrusted() == metaIndex::TRI_YES)
32532943
DK
177 return true;
178
f18f2338
DK
179 if (_config->FindB("Acquire::AllowInsecureRepositories") == true)
180 {
181 MessageInsecureRepository(false, msg, repo);
182 return true;
183 }
184
185 MessageInsecureRepository(true, msg, repo);
32532943
DK
186 TransactionManager->AbortTransaction();
187 I->Status = pkgAcquire::Item::StatError;
188 return false;
189}
190 /*}}}*/
5ad0096a 191static HashStringList GetExpectedHashesFromFor(metaIndex * const Parser, std::string const &MetaKey)/*{{{*/
8d041b4f
DK
192{
193 if (Parser == NULL)
194 return HashStringList();
5ad0096a 195 metaIndex::checkSum * const R = Parser->Lookup(MetaKey);
8d041b4f
DK
196 if (R == NULL)
197 return HashStringList();
198 return R->Hashes;
199}
200 /*}}}*/
32532943 201
448c38bd
DK
202// all ::HashesRequired and ::GetExpectedHashes implementations /*{{{*/
203/* ::GetExpectedHashes is abstract and has to be implemented by all subclasses.
204 It is best to implement it as broadly as possible, while ::HashesRequired defaults
205 to true and should be as restrictive as possible for false cases. Note that if
206 a hash is returned by ::GetExpectedHashes it must match. Only if it doesn't
207 ::HashesRequired is called to evaluate if its okay to have no hashes. */
208APT_CONST bool pkgAcqTransactionItem::HashesRequired() const
209{
210 /* signed repositories obviously have a parser and good hashes.
211 unsigned repositories, too, as even if we can't trust them for security,
212 we can at least trust them for integrity of the download itself.
213 Only repositories without a Release file can (obviously) not have
214 hashes – and they are very uncommon and strongly discouraged */
5ad0096a 215 return TransactionManager->MetaIndexParser != NULL &&
f01f5d91 216 TransactionManager->MetaIndexParser->GetLoadedSuccessfully() == metaIndex::TRI_YES;
448c38bd
DK
217}
218HashStringList pkgAcqTransactionItem::GetExpectedHashes() const
219{
220 return GetExpectedHashesFor(GetMetaKey());
221}
222
223APT_CONST bool pkgAcqMetaBase::HashesRequired() const
224{
225 // Release and co have no hashes 'by design'.
226 return false;
227}
228HashStringList pkgAcqMetaBase::GetExpectedHashes() const
229{
230 return HashStringList();
231}
232
233APT_CONST bool pkgAcqIndexDiffs::HashesRequired() const
234{
4f51fd86
DK
235 /* We don't always have the diff of the downloaded pdiff file.
236 What we have for sure is hashes for the uncompressed file,
237 but rred uncompresses them on the fly while parsing, so not handled here.
238 Hashes are (also) checked while searching for (next) patch to apply. */
239 if (State == StateFetchDiff)
240 return available_patches[0].download_hashes.empty() == false;
448c38bd
DK
241 return false;
242}
243HashStringList pkgAcqIndexDiffs::GetExpectedHashes() const
244{
4f51fd86
DK
245 if (State == StateFetchDiff)
246 return available_patches[0].download_hashes;
448c38bd
DK
247 return HashStringList();
248}
249
250APT_CONST bool pkgAcqIndexMergeDiffs::HashesRequired() const
251{
252 /* @see #pkgAcqIndexDiffs::HashesRequired, with the difference that
253 we can check the rred result after all patches are applied as
254 we know the expected result rather than potentially apply more patches */
4f51fd86
DK
255 if (State == StateFetchDiff)
256 return patch.download_hashes.empty() == false;
448c38bd
DK
257 return State == StateApplyDiff;
258}
259HashStringList pkgAcqIndexMergeDiffs::GetExpectedHashes() const
260{
4f51fd86
DK
261 if (State == StateFetchDiff)
262 return patch.download_hashes;
263 else if (State == StateApplyDiff)
dcbbb14d 264 return GetExpectedHashesFor(Target.MetaKey);
448c38bd
DK
265 return HashStringList();
266}
267
268APT_CONST bool pkgAcqArchive::HashesRequired() const
269{
270 return LocalSource == false;
271}
272HashStringList pkgAcqArchive::GetExpectedHashes() const
273{
274 // figured out while parsing the records
275 return ExpectedHashes;
276}
277
278APT_CONST bool pkgAcqFile::HashesRequired() const
279{
280 // supplied as parameter at creation time, so the caller decides
281 return ExpectedHashes.usable();
282}
283HashStringList pkgAcqFile::GetExpectedHashes() const
284{
285 return ExpectedHashes;
286}
287 /*}}}*/
288// Acquire::Item::QueueURI and specialisations from child classes /*{{{*/
289bool pkgAcquire::Item::QueueURI(pkgAcquire::ItemDesc &Item)
290{
291 Owner->Enqueue(Item);
292 return true;
293}
294/* The idea here is that an item isn't queued if it exists on disk and the
295 transition manager was a hit as this means that the files it contains
296 the checksums for can't be updated either (or they are and we are asking
297 for a hashsum mismatch to happen which helps nobody) */
298bool pkgAcqTransactionItem::QueueURI(pkgAcquire::ItemDesc &Item)
299{
300 std::string const FinalFile = GetFinalFilename();
301 if (TransactionManager != NULL && TransactionManager->IMSHit == true &&
302 FileExists(FinalFile) == true)
303 {
304 PartialFile = DestFile = FinalFile;
305 Status = StatDone;
306 return false;
307 }
308 return pkgAcquire::Item::QueueURI(Item);
309}
310/* The transition manager InRelease itself (or its older sisters-in-law
311 Release & Release.gpg) is always queued as this allows us to rerun gpgv
312 on it to verify that we aren't stalled with old files */
313bool pkgAcqMetaBase::QueueURI(pkgAcquire::ItemDesc &Item)
314{
315 return pkgAcquire::Item::QueueURI(Item);
316}
317/* the Diff/Index needs to queue also the up-to-date complete index file
318 to ensure that the list cleaner isn't eating it */
319bool pkgAcqDiffIndex::QueueURI(pkgAcquire::ItemDesc &Item)
320{
321 if (pkgAcqTransactionItem::QueueURI(Item) == true)
322 return true;
323 QueueOnIMSHit();
324 return false;
325}
326 /*}}}*/
327// Acquire::Item::GetFinalFilename and specialisations for child classes /*{{{*/
328std::string pkgAcquire::Item::GetFinalFilename() const
329{
330 return GetFinalFileNameFromURI(Desc.URI);
331}
332std::string pkgAcqDiffIndex::GetFinalFilename() const
333{
334 // the logic we inherent from pkgAcqBaseIndex isn't what we need here
335 return pkgAcquire::Item::GetFinalFilename();
336}
337std::string pkgAcqIndex::GetFinalFilename() const
338{
dcbbb14d 339 std::string const FinalFile = GetFinalFileNameFromURI(Target.URI);
653ef26c 340 return GetCompressedFileName(Target, FinalFile, CurrentCompressionExtension);
448c38bd
DK
341}
342std::string pkgAcqMetaSig::GetFinalFilename() const
343{
dcbbb14d 344 return GetFinalFileNameFromURI(Target.URI);
448c38bd
DK
345}
346std::string pkgAcqBaseIndex::GetFinalFilename() const
347{
dcbbb14d 348 return GetFinalFileNameFromURI(Target.URI);
448c38bd
DK
349}
350std::string pkgAcqMetaBase::GetFinalFilename() const
351{
dcbbb14d 352 return GetFinalFileNameFromURI(Target.URI);
448c38bd
DK
353}
354std::string pkgAcqArchive::GetFinalFilename() const
355{
356 return _config->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename);
357}
358 /*}}}*/
359// pkgAcqTransactionItem::GetMetaKey and specialisations for child classes /*{{{*/
360std::string pkgAcqTransactionItem::GetMetaKey() const
361{
dcbbb14d 362 return Target.MetaKey;
448c38bd
DK
363}
364std::string pkgAcqIndex::GetMetaKey() const
365{
366 if (Stage == STAGE_DECOMPRESS_AND_VERIFY || CurrentCompressionExtension == "uncompressed")
dcbbb14d
DK
367 return Target.MetaKey;
368 return Target.MetaKey + "." + CurrentCompressionExtension;
448c38bd
DK
369}
370std::string pkgAcqDiffIndex::GetMetaKey() const
371{
dcbbb14d 372 return Target.MetaKey + ".diff/Index";
448c38bd
DK
373}
374 /*}}}*/
375//pkgAcqTransactionItem::TransactionState and specialisations for child classes /*{{{*/
376bool pkgAcqTransactionItem::TransactionState(TransactionStates const state)
377{
378 bool const Debug = _config->FindB("Debug::Acquire::Transaction", false);
379 switch(state)
380 {
381 case TransactionAbort:
382 if(Debug == true)
383 std::clog << " Cancel: " << DestFile << std::endl;
384 if (Status == pkgAcquire::Item::StatIdle)
385 {
386 Status = pkgAcquire::Item::StatDone;
387 Dequeue();
388 }
389 break;
390 case TransactionCommit:
391 if(PartialFile != "")
392 {
393 if(Debug == true)
394 std::clog << "mv " << PartialFile << " -> "<< DestFile << " # " << DescURI() << std::endl;
395
396 Rename(PartialFile, DestFile);
397 } else {
398 if(Debug == true)
399 std::clog << "rm " << DestFile << " # " << DescURI() << std::endl;
51818f26 400 RemoveFile("TransactionCommit", DestFile);
448c38bd
DK
401 }
402 break;
403 }
404 return true;
405}
406bool pkgAcqMetaBase::TransactionState(TransactionStates const state)
407{
408 // Do not remove InRelease on IMSHit of Release.gpg [yes, this is very edgecasey]
409 if (TransactionManager->IMSHit == false)
410 return pkgAcqTransactionItem::TransactionState(state);
411 return true;
412}
413bool pkgAcqIndex::TransactionState(TransactionStates const state)
414{
415 if (pkgAcqTransactionItem::TransactionState(state) == false)
416 return false;
417
418 switch (state)
419 {
420 case TransactionAbort:
421 if (Stage == STAGE_DECOMPRESS_AND_VERIFY)
422 {
423 // keep the compressed file, but drop the decompressed
424 EraseFileName.clear();
425 if (PartialFile.empty() == false && flExtension(PartialFile) == "decomp")
51818f26 426 RemoveFile("TransactionAbort", PartialFile);
448c38bd
DK
427 }
428 break;
429 case TransactionCommit:
430 if (EraseFileName.empty() == false)
51818f26 431 RemoveFile("TransactionCommit", EraseFileName);
448c38bd
DK
432 break;
433 }
434 return true;
435}
436bool pkgAcqDiffIndex::TransactionState(TransactionStates const state)
437{
438 if (pkgAcqTransactionItem::TransactionState(state) == false)
439 return false;
440
441 switch (state)
442 {
443 case TransactionCommit:
444 break;
445 case TransactionAbort:
dcbbb14d 446 std::string const Partial = GetPartialFileNameFromURI(Target.URI);
51818f26 447 RemoveFile("TransactionAbort", Partial);
448c38bd
DK
448 break;
449 }
450
451 return true;
452}
453 /*}}}*/
b3501edb 454
8d041b4f
DK
455class APT_HIDDEN NoActionItem : public pkgAcquire::Item /*{{{*/
456/* The sole purpose of this class is having an item which does nothing to
457 reach its done state to prevent cleanup deleting the mentioned file.
458 Handy in cases in which we know we have the file already, like IMS-Hits. */
459{
dcbbb14d 460 IndexTarget const Target;
8d041b4f 461 public:
3b302846
DK
462 virtual std::string DescURI() const APT_OVERRIDE {return Target.URI;};
463 virtual HashStringList GetExpectedHashes() const APT_OVERRIDE {return HashStringList();};
8d041b4f 464
e8afd168 465 NoActionItem(pkgAcquire * const Owner, IndexTarget const &Target) :
8d041b4f
DK
466 pkgAcquire::Item(Owner), Target(Target)
467 {
468 Status = StatDone;
dcbbb14d 469 DestFile = GetFinalFileNameFromURI(Target.URI);
8d041b4f 470 }
d7a51997
DK
471 NoActionItem(pkgAcquire * const Owner, IndexTarget const &Target, std::string const &FinalFile) :
472 pkgAcquire::Item(Owner), Target(Target)
473 {
474 Status = StatDone;
475 DestFile = FinalFile;
476 }
8d041b4f
DK
477};
478 /*}}}*/
479
0118833a 480// Acquire::Item::Item - Constructor /*{{{*/
586d8704 481APT_IGNORE_DEPRECATED_PUSH
e8afd168 482pkgAcquire::Item::Item(pkgAcquire * const owner) :
1eb1836f 483 FileSize(0), PartialSize(0), Mode(0), ID(0), Complete(false), Local(false),
6c55f07a 484 QueueCounter(0), ExpectedAdditionalItems(0), Owner(owner), d(NULL)
0118833a
AL
485{
486 Owner->Add(this);
c88edf1d 487 Status = StatIdle;
0118833a 488}
586d8704 489APT_IGNORE_DEPRECATED_POP
0118833a
AL
490 /*}}}*/
491// Acquire::Item::~Item - Destructor /*{{{*/
0118833a
AL
492pkgAcquire::Item::~Item()
493{
494 Owner->Remove(this);
495}
496 /*}}}*/
448c38bd
DK
497std::string pkgAcquire::Item::Custom600Headers() const /*{{{*/
498{
499 return std::string();
500}
501 /*}}}*/
502std::string pkgAcquire::Item::ShortDesc() const /*{{{*/
503{
504 return DescURI();
505}
506 /*}}}*/
507APT_CONST void pkgAcquire::Item::Finished() /*{{{*/
508{
509}
510 /*}}}*/
511APT_PURE pkgAcquire * pkgAcquire::Item::GetOwner() const /*{{{*/
512{
513 return Owner;
514}
515 /*}}}*/
c8a4ce6c 516APT_CONST pkgAcquire::ItemDesc &pkgAcquire::Item::GetItemDesc() /*{{{*/
08ea7806
DK
517{
518 return Desc;
519}
520 /*}}}*/
448c38bd
DK
521APT_CONST bool pkgAcquire::Item::IsTrusted() const /*{{{*/
522{
523 return false;
524}
525 /*}}}*/
c88edf1d
AL
526// Acquire::Item::Failed - Item failed to download /*{{{*/
527// ---------------------------------------------------------------------
93bf083d
AL
528/* We return to an idle state if there are still other queues that could
529 fetch this object */
448c38bd 530void pkgAcquire::Item::Failed(string const &Message,pkgAcquire::MethodConfig const * const Cnf)
c88edf1d 531{
03aa0847 532 if(ErrorText.empty())
2737f28a 533 ErrorText = LookupTag(Message,"Message");
c88edf1d 534 if (QueueCounter <= 1)
93bf083d 535 {
a72ace20 536 /* This indicates that the file is not available right now but might
7d8afa39 537 be sometime later. If we do a retry cycle then this should be
17caf1b1 538 retried [CDROMs] */
4dbfe436 539 if (Cnf != NULL && Cnf->LocalOnly == true &&
7d8afa39 540 StringToBool(LookupTag(Message,"Transient-Failure"),false) == true)
a72ace20
AL
541 {
542 Status = StatIdle;
681d76d0 543 Dequeue();
a72ace20
AL
544 return;
545 }
7e5f33eb 546
58702f85
DK
547 switch (Status)
548 {
549 case StatIdle:
550 case StatFetching:
551 case StatDone:
552 Status = StatError;
553 break;
554 case StatAuthError:
555 case StatError:
556 case StatTransientNetworkError:
557 break;
558 }
4dbfe436 559 Complete = false;
681d76d0 560 Dequeue();
4dbfe436 561 }
23c5897c 562
03aa0847 563 string const FailReason = LookupTag(Message, "FailReason");
448c38bd 564 if (FailReason == "MaximumSizeExceeded")
03aa0847 565 RenameOnError(MaximumSizeExceeded);
448c38bd
DK
566 else if (Status == StatAuthError)
567 RenameOnError(HashSumMismatch);
ee279506
MV
568
569 // report mirror failure back to LP if we actually use a mirror
448c38bd 570 if (FailReason.empty() == false)
f0b509cd
MV
571 ReportMirrorFailure(FailReason);
572 else
573 ReportMirrorFailure(ErrorText);
146f7715 574
448c38bd
DK
575 if (QueueCounter > 1)
576 Status = StatIdle;
146f7715
DK
577}
578 /*}}}*/
8267fe24
AL
579// Acquire::Item::Start - Item has begun to download /*{{{*/
580// ---------------------------------------------------------------------
448c38bd 581/* Stash status and the file size. Note that setting Complete means
17caf1b1 582 sub-phases of the acquire process such as decompresion are operating */
448c38bd 583void pkgAcquire::Item::Start(string const &/*Message*/, unsigned long long const Size)
8267fe24
AL
584{
585 Status = StatFetching;
03aa0847 586 ErrorText.clear();
8267fe24
AL
587 if (FileSize == 0 && Complete == false)
588 FileSize = Size;
589}
590 /*}}}*/
dd676dc7
DK
591// Acquire::Item::VerifyDone - check if Item was downloaded OK /*{{{*/
592/* Note that hash-verification is 'hardcoded' in acquire-worker and has
593 * already passed if this method is called. */
594bool pkgAcquire::Item::VerifyDone(std::string const &Message,
595 pkgAcquire::MethodConfig const * const /*Cnf*/)
596{
597 std::string const FileName = LookupTag(Message,"Filename");
598 if (FileName.empty() == true)
599 {
600 Status = StatError;
601 ErrorText = "Method gave a blank filename";
602 return false;
603 }
604
605 return true;
606}
607 /*}}}*/
c88edf1d 608// Acquire::Item::Done - Item downloaded OK /*{{{*/
a4b8112b 609void pkgAcquire::Item::Done(string const &/*Message*/, HashStringList const &Hashes,
448c38bd 610 pkgAcquire::MethodConfig const * const /*Cnf*/)
c88edf1d 611{
b98f2859 612 // We just downloaded something..
ff86d7df 613 if (FileSize == 0)
b98f2859 614 {
ff86d7df
DK
615 unsigned long long const downloadedSize = Hashes.FileSize();
616 if (downloadedSize != 0)
448c38bd 617 {
ff86d7df 618 FileSize = downloadedSize;
448c38bd 619 }
448c38bd 620 }
c88edf1d
AL
621 Status = StatDone;
622 ErrorText = string();
623 Owner->Dequeue(this);
624}
625 /*}}}*/
8b89e57f
AL
626// Acquire::Item::Rename - Rename a file /*{{{*/
627// ---------------------------------------------------------------------
1e3f4083 628/* This helper function is used by a lot of item methods as their final
8b89e57f 629 step */
448c38bd 630bool pkgAcquire::Item::Rename(string const &From,string const &To)
8b89e57f 631{
ba6b79bd 632 if (From == To || rename(From.c_str(),To.c_str()) == 0)
cecc5532
DK
633 return true;
634
635 std::string S;
636 strprintf(S, _("rename failed, %s (%s -> %s)."), strerror(errno),
637 From.c_str(),To.c_str());
638 Status = StatError;
8eafc759
DK
639 if (ErrorText.empty())
640 ErrorText = S;
641 else
642 ErrorText = ErrorText + ": " + S;
cecc5532 643 return false;
8b89e57f
AL
644}
645 /*}}}*/
448c38bd 646void pkgAcquire::Item::Dequeue() /*{{{*/
5684f71f 647{
448c38bd 648 Owner->Dequeue(this);
ba6b79bd 649}
448c38bd
DK
650 /*}}}*/
651bool pkgAcquire::Item::RenameOnError(pkgAcquire::Item::RenameOnErrorState const error)/*{{{*/
3c8030a4 652{
03aa0847 653 if (RealFileExists(DestFile))
3c8030a4
DK
654 Rename(DestFile, DestFile + ".FAILED");
655
448c38bd 656 std::string errtext;
3c8030a4
DK
657 switch (error)
658 {
659 case HashSumMismatch:
448c38bd 660 errtext = _("Hash Sum mismatch");
3c8030a4
DK
661 Status = StatAuthError;
662 ReportMirrorFailure("HashChecksumFailure");
663 break;
664 case SizeMismatch:
448c38bd 665 errtext = _("Size mismatch");
3c8030a4
DK
666 Status = StatAuthError;
667 ReportMirrorFailure("SizeFailure");
668 break;
669 case InvalidFormat:
448c38bd 670 errtext = _("Invalid file format");
3c8030a4
DK
671 Status = StatError;
672 // do not report as usually its not the mirrors fault, but Portal/Proxy
673 break;
631a7dc7 674 case SignatureError:
448c38bd 675 errtext = _("Signature error");
631a7dc7
MV
676 Status = StatError;
677 break;
678 case NotClearsigned:
dd676dc7
DK
679 strprintf(errtext, _("Clearsigned file isn't valid, got '%s' (does the network require authentication?)"), "NOSPLIT");
680 Status = StatAuthError;
03aa0847
DK
681 break;
682 case MaximumSizeExceeded:
683 // the method is expected to report a good error for this
631a7dc7
MV
684 Status = StatError;
685 break;
146f7715
DK
686 case PDiffError:
687 // no handling here, done by callers
688 break;
3c8030a4 689 }
448c38bd
DK
690 if (ErrorText.empty())
691 ErrorText = errtext;
3c8030a4
DK
692 return false;
693}
694 /*}}}*/
8267fbd9 695void pkgAcquire::Item::SetActiveSubprocess(const std::string &subprocess)/*{{{*/
eeac6897
MV
696{
697 ActiveSubprocess = subprocess;
586d8704 698 APT_IGNORE_DEPRECATED(Mode = ActiveSubprocess.c_str();)
eeac6897 699}
8267fbd9 700 /*}}}*/
c91d9a63 701// Acquire::Item::ReportMirrorFailure /*{{{*/
448c38bd 702void pkgAcquire::Item::ReportMirrorFailure(string const &FailCode)
36280399 703{
59271f62
MV
704 // we only act if a mirror was used at all
705 if(UsedMirror.empty())
706 return;
36280399
MV
707#if 0
708 std::cerr << "\nReportMirrorFailure: "
709 << UsedMirror
59271f62 710 << " Uri: " << DescURI()
36280399
MV
711 << " FailCode: "
712 << FailCode << std::endl;
713#endif
36280399 714 string report = _config->Find("Methods::Mirror::ProblemReporting",
3f599bb7 715 "/usr/lib/apt/apt-report-mirror-failure");
36280399
MV
716 if(!FileExists(report))
717 return;
cecc5532
DK
718
719 std::vector<char const*> Args;
720 Args.push_back(report.c_str());
721 Args.push_back(UsedMirror.c_str());
722 Args.push_back(DescURI().c_str());
723 Args.push_back(FailCode.c_str());
724 Args.push_back(NULL);
725
36280399 726 pid_t pid = ExecFork();
cecc5532 727 if(pid < 0)
36280399
MV
728 {
729 _error->Error("ReportMirrorFailure Fork failed");
730 return;
731 }
cecc5532 732 else if(pid == 0)
36280399 733 {
cecc5532 734 execvp(Args[0], (char**)Args.data());
361593e9
MV
735 std::cerr << "Could not exec " << Args[0] << std::endl;
736 _exit(100);
36280399 737 }
cecc5532 738 if(!ExecWait(pid, "report-mirror-failure"))
36280399
MV
739 {
740 _error->Warning("Couldn't report problem to '%s'",
361593e9 741 _config->Find("Methods::Mirror::ProblemReporting").c_str());
36280399
MV
742 }
743}
c91d9a63 744 /*}}}*/
448c38bd 745std::string pkgAcquire::Item::HashSum() const /*{{{*/
ac5b205a 746{
448c38bd
DK
747 HashStringList const hashes = GetExpectedHashes();
748 HashString const * const hs = hashes.find(NULL);
749 return hs != NULL ? hs->toStr() : "";
750}
751 /*}}}*/
2237bd01 752
448c38bd 753pkgAcqTransactionItem::pkgAcqTransactionItem(pkgAcquire * const Owner, /*{{{*/
3d8232bf 754 pkgAcqMetaClearSig * const transactionManager, IndexTarget const &target) :
6c55f07a 755 pkgAcquire::Item(Owner), d(NULL), Target(target), TransactionManager(transactionManager)
448c38bd
DK
756{
757 if (TransactionManager != this)
758 TransactionManager->Add(this);
759}
760 /*}}}*/
761pkgAcqTransactionItem::~pkgAcqTransactionItem() /*{{{*/
762{
763}
764 /*}}}*/
e8afd168 765HashStringList pkgAcqTransactionItem::GetExpectedHashesFor(std::string const &MetaKey) const /*{{{*/
448c38bd 766{
8d041b4f 767 return GetExpectedHashesFromFor(TransactionManager->MetaIndexParser, MetaKey);
448c38bd
DK
768}
769 /*}}}*/
ac5b205a 770
448c38bd
DK
771// AcqMetaBase - Constructor /*{{{*/
772pkgAcqMetaBase::pkgAcqMetaBase(pkgAcquire * const Owner,
3d8232bf 773 pkgAcqMetaClearSig * const TransactionManager,
e8afd168 774 std::vector<IndexTarget> const &IndexTargets,
3d8232bf 775 IndexTarget const &DataTarget)
6c55f07a 776: pkgAcqTransactionItem(Owner, TransactionManager, DataTarget), d(NULL),
3d8232bf 777 IndexTargets(IndexTargets),
448c38bd
DK
778 AuthPass(false), IMSHit(false)
779{
780}
781 /*}}}*/
782// AcqMetaBase::Add - Add a item to the current Transaction /*{{{*/
783void pkgAcqMetaBase::Add(pkgAcqTransactionItem * const I)
784{
785 Transaction.push_back(I);
786}
787 /*}}}*/
788// AcqMetaBase::AbortTransaction - Abort the current Transaction /*{{{*/
789void pkgAcqMetaBase::AbortTransaction()
790{
791 if(_config->FindB("Debug::Acquire::Transaction", false) == true)
792 std::clog << "AbortTransaction: " << TransactionManager << std::endl;
ac5b205a 793
448c38bd
DK
794 // ensure the toplevel is in error state too
795 for (std::vector<pkgAcqTransactionItem*>::iterator I = Transaction.begin();
796 I != Transaction.end(); ++I)
2ac3eeb6 797 {
448c38bd 798 (*I)->TransactionState(TransactionAbort);
ac5b205a 799 }
448c38bd
DK
800 Transaction.clear();
801}
802 /*}}}*/
803// AcqMetaBase::TransactionHasError - Check for errors in Transaction /*{{{*/
804APT_PURE bool pkgAcqMetaBase::TransactionHasError() const
805{
806 for (std::vector<pkgAcqTransactionItem*>::const_iterator I = Transaction.begin();
807 I != Transaction.end(); ++I)
808 {
809 switch((*I)->Status) {
810 case StatDone: break;
811 case StatIdle: break;
812 case StatAuthError: return true;
813 case StatError: return true;
814 case StatTransientNetworkError: return true;
815 case StatFetching: break;
816 }
817 }
818 return false;
819}
820 /*}}}*/
821// AcqMetaBase::CommitTransaction - Commit a transaction /*{{{*/
822void pkgAcqMetaBase::CommitTransaction()
823{
824 if(_config->FindB("Debug::Acquire::Transaction", false) == true)
825 std::clog << "CommitTransaction: " << this << std::endl;
ac5b205a 826
448c38bd
DK
827 // move new files into place *and* remove files that are not
828 // part of the transaction but are still on disk
829 for (std::vector<pkgAcqTransactionItem*>::iterator I = Transaction.begin();
830 I != Transaction.end(); ++I)
831 {
832 (*I)->TransactionState(TransactionCommit);
833 }
834 Transaction.clear();
295d848b
DK
835}
836 /*}}}*/
448c38bd
DK
837// AcqMetaBase::TransactionStageCopy - Stage a file for copying /*{{{*/
838void pkgAcqMetaBase::TransactionStageCopy(pkgAcqTransactionItem * const I,
839 const std::string &From,
840 const std::string &To)
295d848b 841{
448c38bd
DK
842 I->PartialFile = From;
843 I->DestFile = To;
ac5b205a 844}
92fcbfc1 845 /*}}}*/
448c38bd
DK
846// AcqMetaBase::TransactionStageRemoval - Stage a file for removal /*{{{*/
847void pkgAcqMetaBase::TransactionStageRemoval(pkgAcqTransactionItem * const I,
848 const std::string &FinalFile)
849{
850 I->PartialFile = "";
851 I->DestFile = FinalFile;
852}
853 /*}}}*/
854// AcqMetaBase::GenerateAuthWarning - Check gpg authentication error /*{{{*/
855bool pkgAcqMetaBase::CheckStopAuthentication(pkgAcquire::Item * const I, const std::string &Message)
856{
857 // FIXME: this entire function can do now that we disallow going to
858 // a unauthenticated state and can cleanly rollback
859
860 string const Final = I->GetFinalFilename();
861 if(FileExists(Final))
862 {
863 I->Status = StatTransientNetworkError;
864 _error->Warning(_("An error occurred during the signature "
865 "verification. The repository is not updated "
866 "and the previous index files will be used. "
0efb29eb 867 "GPG error: %s: %s"),
448c38bd
DK
868 Desc.Description.c_str(),
869 LookupTag(Message,"Message").c_str());
870 RunScripts("APT::Update::Auth-Failure");
871 return true;
872 } else if (LookupTag(Message,"Message").find("NODATA") != string::npos) {
873 /* Invalid signature file, reject (LP: #346386) (Closes: #627642) */
874 _error->Error(_("GPG error: %s: %s"),
875 Desc.Description.c_str(),
876 LookupTag(Message,"Message").c_str());
dd676dc7 877 I->Status = StatAuthError;
448c38bd
DK
878 return true;
879 } else {
880 _error->Warning(_("GPG error: %s: %s"),
881 Desc.Description.c_str(),
882 LookupTag(Message,"Message").c_str());
883 }
884 // gpgv method failed
885 ReportMirrorFailure("GPGFailure");
886 return false;
887}
888 /*}}}*/
889// AcqMetaBase::Custom600Headers - Get header for AcqMetaBase /*{{{*/
6cb30d01 890// ---------------------------------------------------------------------
448c38bd 891string pkgAcqMetaBase::Custom600Headers() const
6cb30d01 892{
448c38bd
DK
893 std::string Header = "\nIndex-File: true";
894 std::string MaximumSize;
895 strprintf(MaximumSize, "\nMaximum-Size: %i",
896 _config->FindI("Acquire::MaxReleaseFileSize", 10*1000*1000));
897 Header += MaximumSize;
4d0818cc 898
448c38bd 899 string const FinalFile = GetFinalFilename();
6cb30d01 900 struct stat Buf;
448c38bd
DK
901 if (stat(FinalFile.c_str(),&Buf) == 0)
902 Header += "\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
903
904 return Header;
6cb30d01 905}
92fcbfc1 906 /*}}}*/
448c38bd
DK
907// AcqMetaBase::QueueForSignatureVerify /*{{{*/
908void pkgAcqMetaBase::QueueForSignatureVerify(pkgAcqTransactionItem * const I, std::string const &File, std::string const &Signature)
ba6b79bd 909{
448c38bd
DK
910 AuthPass = true;
911 I->Desc.URI = "gpgv:" + Signature;
912 I->DestFile = File;
913 QueueURI(I->Desc);
914 I->SetActiveSubprocess("gpgv");
ba6b79bd
DK
915}
916 /*}}}*/
448c38bd
DK
917// AcqMetaBase::CheckDownloadDone /*{{{*/
918bool pkgAcqMetaBase::CheckDownloadDone(pkgAcqTransactionItem * const I, const std::string &Message, HashStringList const &Hashes) const
2237bd01 919{
448c38bd
DK
920 // We have just finished downloading a Release file (it is not
921 // verified yet)
f6d4ab9a 922
dd676dc7 923 std::string const FileName = LookupTag(Message,"Filename");
08ea7806 924 if (FileName != I->DestFile && RealFileExists(I->DestFile) == false)
f6d4ab9a 925 {
448c38bd
DK
926 I->Local = true;
927 I->Desc.URI = "copy:" + FileName;
928 I->QueueURI(I->Desc);
f6d4ab9a
DK
929 return false;
930 }
2237bd01 931
448c38bd
DK
932 // make sure to verify against the right file on I-M-S hit
933 bool IMSHit = StringToBool(LookupTag(Message,"IMS-Hit"), false);
934 if (IMSHit == false && Hashes.usable())
f6d4ab9a 935 {
448c38bd
DK
936 // detect IMS-Hits servers haven't detected by Hash comparison
937 std::string const FinalFile = I->GetFinalFilename();
938 if (RealFileExists(FinalFile) && Hashes.VerifyFile(FinalFile) == true)
2ac3eeb6 939 {
448c38bd 940 IMSHit = true;
51818f26 941 RemoveFile("CheckDownloadDone", I->DestFile);
5e1ed088 942 }
f6d4ab9a
DK
943 }
944
448c38bd 945 if(IMSHit == true)
f6d4ab9a 946 {
448c38bd
DK
947 // for simplicity, the transaction manager is always InRelease
948 // even if it doesn't exist.
949 if (TransactionManager != NULL)
950 TransactionManager->IMSHit = true;
951 I->PartialFile = I->DestFile = I->GetFinalFilename();
f6d4ab9a
DK
952 }
953
448c38bd
DK
954 // set Item to complete as the remaining work is all local (verify etc)
955 I->Complete = true;
f6d4ab9a 956
448c38bd
DK
957 return true;
958}
959 /*}}}*/
960bool pkgAcqMetaBase::CheckAuthDone(string const &Message) /*{{{*/
961{
962 // At this point, the gpgv method has succeeded, so there is a
963 // valid signature from a key in the trusted keyring. We
964 // perform additional verification of its contents, and use them
965 // to verify the indexes we are about to download
f6d4ab9a 966
448c38bd 967 if (TransactionManager->IMSHit == false)
f6d4ab9a 968 {
448c38bd
DK
969 // open the last (In)Release if we have it
970 std::string const FinalFile = GetFinalFilename();
971 std::string FinalRelease;
972 std::string FinalInRelease;
973 if (APT::String::Endswith(FinalFile, "InRelease"))
2ac3eeb6 974 {
448c38bd
DK
975 FinalInRelease = FinalFile;
976 FinalRelease = FinalFile.substr(0, FinalFile.length() - strlen("InRelease")) + "Release";
977 }
978 else
979 {
980 FinalInRelease = FinalFile.substr(0, FinalFile.length() - strlen("Release")) + "InRelease";
981 FinalRelease = FinalFile;
982 }
983 if (RealFileExists(FinalInRelease) || RealFileExists(FinalRelease))
984 {
5ad0096a
DK
985 TransactionManager->LastMetaIndexParser = TransactionManager->MetaIndexParser->UnloadedClone();
986 if (TransactionManager->LastMetaIndexParser != NULL)
02dceb31 987 {
5ad0096a
DK
988 _error->PushToStack();
989 if (RealFileExists(FinalInRelease))
990 TransactionManager->LastMetaIndexParser->Load(FinalInRelease, NULL);
991 else
992 TransactionManager->LastMetaIndexParser->Load(FinalRelease, NULL);
993 // its unlikely to happen, but if what we have is bad ignore it
994 if (_error->PendingError())
995 {
996 delete TransactionManager->LastMetaIndexParser;
997 TransactionManager->LastMetaIndexParser = NULL;
998 }
999 _error->RevertToStack();
2237bd01
MV
1000 }
1001 }
f6d4ab9a
DK
1002 }
1003
5ad0096a 1004 if (TransactionManager->MetaIndexParser->Load(DestFile, &ErrorText) == false)
f6d4ab9a 1005 {
448c38bd 1006 Status = StatAuthError;
f6d4ab9a
DK
1007 return false;
1008 }
1009
448c38bd 1010 if (!VerifyVendor(Message))
f6d4ab9a 1011 {
448c38bd
DK
1012 Status = StatAuthError;
1013 return false;
1014 }
f6d4ab9a 1015
448c38bd
DK
1016 if (_config->FindB("Debug::pkgAcquire::Auth", false))
1017 std::cerr << "Signature verification succeeded: "
1018 << DestFile << std::endl;
2237bd01 1019
448c38bd
DK
1020 // Download further indexes with verification
1021 QueueIndexes(true);
2237bd01 1022
448c38bd
DK
1023 return true;
1024}
1025 /*}}}*/
1026void pkgAcqMetaBase::QueueIndexes(bool const verify) /*{{{*/
1027{
1028 // at this point the real Items are loaded in the fetcher
1029 ExpectedAdditionalItems = 0;
1030
af81ab90
DK
1031 bool metaBaseSupportsByHash = false;
1032 if (TransactionManager != NULL && TransactionManager->MetaIndexParser != NULL)
1033 metaBaseSupportsByHash = TransactionManager->MetaIndexParser->GetSupportsAcquireByHash();
1034
d7a51997 1035 for (std::vector <IndexTarget>::iterator Target = IndexTargets.begin();
dcbbb14d 1036 Target != IndexTargets.end();
448c38bd
DK
1037 ++Target)
1038 {
1dd20368
DK
1039 // all is an implementation detail. Users shouldn't use this as arch
1040 // We need this support trickery here as e.g. Debian has binary-all files already,
1041 // but arch:all packages are still in the arch:any files, so we would waste precious
1042 // download time, bandwidth and diskspace for nothing, BUT Debian doesn't feature all
1043 // in the set of supported architectures, so we can filter based on this property rather
1044 // than invent an entirely new flag we would need to carry for all of eternity.
1045 if (Target->Option(IndexTarget::ARCHITECTURE) == "all" &&
1046 TransactionManager->MetaIndexParser->IsArchitectureSupported("all") == false)
1047 continue;
1048
1a3a14ac 1049 bool trypdiff = Target->OptionBool(IndexTarget::PDIFFS);
9b8c28f4 1050 if (verify == true)
2ac3eeb6 1051 {
dcbbb14d 1052 if (TransactionManager->MetaIndexParser->Exists(Target->MetaKey) == false)
9b8c28f4
DK
1053 {
1054 // optional targets that we do not have in the Release file are skipped
dcbbb14d 1055 if (Target->IsOptional)
9b8c28f4 1056 continue;
47d2bc78 1057
1dd20368
DK
1058 std::string const &arch = Target->Option(IndexTarget::ARCHITECTURE);
1059 if (arch.empty() == false)
1060 {
1061 if (TransactionManager->MetaIndexParser->IsArchitectureSupported(arch) == false)
1062 {
1063 _error->Notice(_("Skipping acquire of configured file '%s' as repository '%s' doesn't support architecture '%s'"),
1064 Target->MetaKey.c_str(), TransactionManager->Target.Description.c_str(), arch.c_str());
1065 continue;
1066 }
1067 // if the architecture is officially supported but currently no packages for it available,
1068 // ignore silently as this is pretty much the same as just shipping an empty file.
1069 // if we don't know which architectures are supported, we do NOT ignore it to notify user about this
1070 if (TransactionManager->MetaIndexParser->IsArchitectureSupported("*undefined*") == false)
1071 continue;
1072 }
1073
9b8c28f4 1074 Status = StatAuthError;
dcbbb14d 1075 strprintf(ErrorText, _("Unable to find expected entry '%s' in Release file (Wrong sources.list entry or malformed file)"), Target->MetaKey.c_str());
9b8c28f4
DK
1076 return;
1077 }
bd4a8f51
DK
1078 else
1079 {
1080 auto const hashes = GetExpectedHashesFor(Target->MetaKey);
1081 if (hashes.usable() == false && hashes.empty() == false)
1082 {
1083 _error->Warning(_("Skipping acquire of configured file '%s' as repository '%s' provides only weak security information for it"),
1084 Target->MetaKey.c_str(), TransactionManager->Target.Description.c_str());
1085 continue;
1086 }
1087 }
9b8c28f4 1088
d7a51997
DK
1089 // autoselect the compression method
1090 std::vector<std::string> types = VectorizeString(Target->Option(IndexTarget::COMPRESSIONTYPES), ' ');
1091 types.erase(std::remove_if(types.begin(), types.end(), [&](std::string const &t) {
1092 if (t == "uncompressed")
1093 return TransactionManager->MetaIndexParser->Exists(Target->MetaKey) == false;
1094 std::string const MetaKey = Target->MetaKey + "." + t;
1095 return TransactionManager->MetaIndexParser->Exists(MetaKey) == false;
1096 }), types.end());
1097 if (types.empty() == false)
8d041b4f 1098 {
d7a51997 1099 std::ostringstream os;
af81ab90
DK
1100 // add the special compressiontype byhash first if supported
1101 std::string const useByHashConf = Target->Option(IndexTarget::BY_HASH);
1102 bool useByHash = false;
1103 if(useByHashConf == "force")
1104 useByHash = true;
1105 else
1106 useByHash = StringToBool(useByHashConf) == true && metaBaseSupportsByHash;
1107 if (useByHash == true)
1108 os << "by-hash ";
d7a51997
DK
1109 std::copy(types.begin(), types.end()-1, std::ostream_iterator<std::string>(os, " "));
1110 os << *types.rbegin();
1111 Target->Options["COMPRESSIONTYPES"] = os.str();
1112 }
1113 else
1114 Target->Options["COMPRESSIONTYPES"].clear();
1115
1116 std::string filename = GetFinalFileNameFromURI(Target->URI);
1117 if (RealFileExists(filename) == false)
1118 {
1119 if (Target->KeepCompressed)
8d041b4f 1120 {
d7a51997
DK
1121 filename = GetKeepCompressedFileName(filename, *Target);
1122 if (RealFileExists(filename) == false)
1123 filename.clear();
8d041b4f 1124 }
d7a51997
DK
1125 else
1126 filename.clear();
1127 }
1128
1129 if (filename.empty() == false)
1130 {
1131 // if the Release file is a hit and we have an index it must be the current one
1132 if (TransactionManager->IMSHit == true)
1133 ;
1134 else if (TransactionManager->LastMetaIndexParser != NULL)
1196da2e 1135 {
d7a51997
DK
1136 // see if the file changed since the last Release file
1137 // we use the uncompressed files as we might compress differently compared to the server,
1138 // so the hashes might not match, even if they contain the same data.
1139 HashStringList const newFile = GetExpectedHashesFromFor(TransactionManager->MetaIndexParser, Target->MetaKey);
1140 HashStringList const oldFile = GetExpectedHashesFromFor(TransactionManager->LastMetaIndexParser, Target->MetaKey);
1141 if (newFile != oldFile)
1142 filename.clear();
1196da2e 1143 }
d7a51997
DK
1144 else
1145 filename.clear();
8d041b4f
DK
1146 }
1147 else
1148 trypdiff = false; // no file to patch
1149
d7a51997
DK
1150 if (filename.empty() == false)
1151 {
1152 new NoActionItem(Owner, *Target, filename);
3d1e34b0
DK
1153 std::string const idxfilename = GetFinalFileNameFromURI(Target->URI + ".diff/Index");
1154 if (FileExists(idxfilename))
1155 new NoActionItem(Owner, *Target, idxfilename);
d7a51997
DK
1156 continue;
1157 }
1158
9b8c28f4 1159 // check if we have patches available
dcbbb14d 1160 trypdiff &= TransactionManager->MetaIndexParser->Exists(Target->MetaKey + ".diff/Index");
2237bd01 1161 }
d7a51997
DK
1162 else
1163 {
1164 // if we have no file to patch, no point in trying
1165 std::string filename = GetFinalFileNameFromURI(Target->URI);
1166 if (RealFileExists(filename) == false)
1167 {
1168 if (Target->KeepCompressed)
1169 {
1170 filename = GetKeepCompressedFileName(filename, *Target);
1171 if (RealFileExists(filename) == false)
1172 filename.clear();
1173 }
1174 else
1175 filename.clear();
1176 }
1177 trypdiff &= (filename.empty() == false);
1178 }
448c38bd 1179
9b8c28f4
DK
1180 // no point in patching from local sources
1181 if (trypdiff)
1182 {
dcbbb14d 1183 std::string const proto = Target->URI.substr(0, strlen("file:/"));
9b8c28f4
DK
1184 if (proto == "file:/" || proto == "copy:/" || proto == "cdrom:")
1185 trypdiff = false;
1186 }
1187
1188 // Queue the Index file (Packages, Sources, Translation-$foo, …)
1189 if (trypdiff)
448c38bd
DK
1190 new pkgAcqDiffIndex(Owner, TransactionManager, *Target);
1191 else
1192 new pkgAcqIndex(Owner, TransactionManager, *Target);
2237bd01 1193 }
448c38bd
DK
1194}
1195 /*}}}*/
1196bool pkgAcqMetaBase::VerifyVendor(string const &Message) /*{{{*/
1197{
1198 string::size_type pos;
f6d4ab9a 1199
448c38bd
DK
1200 // check for missing sigs (that where not fatal because otherwise we had
1201 // bombed earlier)
1202 string missingkeys;
1203 string msg = _("There is no public key available for the "
1204 "following key IDs:\n");
1205 pos = Message.find("NO_PUBKEY ");
1206 if (pos != std::string::npos)
f6d4ab9a 1207 {
448c38bd
DK
1208 string::size_type start = pos+strlen("NO_PUBKEY ");
1209 string Fingerprint = Message.substr(start, Message.find("\n")-start);
1210 missingkeys += (Fingerprint);
f6d4ab9a 1211 }
448c38bd
DK
1212 if(!missingkeys.empty())
1213 _error->Warning("%s", (msg + missingkeys).c_str());
f6d4ab9a 1214
448c38bd
DK
1215 string Transformed = TransactionManager->MetaIndexParser->GetExpectedDist();
1216
1217 if (Transformed == "../project/experimental")
f6d4ab9a 1218 {
448c38bd 1219 Transformed = "experimental";
f6d4ab9a
DK
1220 }
1221
448c38bd
DK
1222 pos = Transformed.rfind('/');
1223 if (pos != string::npos)
f6d4ab9a 1224 {
448c38bd 1225 Transformed = Transformed.substr(0, pos);
f6d4ab9a
DK
1226 }
1227
448c38bd 1228 if (Transformed == ".")
f6d4ab9a 1229 {
448c38bd 1230 Transformed = "";
f6d4ab9a
DK
1231 }
1232
0741daeb
DK
1233 if (TransactionManager->MetaIndexParser->GetValidUntil() > 0)
1234 {
448c38bd
DK
1235 time_t const invalid_since = time(NULL) - TransactionManager->MetaIndexParser->GetValidUntil();
1236 if (invalid_since > 0)
1237 {
1238 std::string errmsg;
1239 strprintf(errmsg,
1240 // TRANSLATOR: The first %s is the URL of the bad Release file, the second is
3d8232bf 1241 // the time since then the file is invalid - formatted in the same way as in
448c38bd
DK
1242 // the download progress display (e.g. 7d 3h 42min 1s)
1243 _("Release file for %s is expired (invalid since %s). "
1244 "Updates for this repository will not be applied."),
dcbbb14d 1245 Target.URI.c_str(), TimeToStr(invalid_since).c_str());
448c38bd
DK
1246 if (ErrorText.empty())
1247 ErrorText = errmsg;
1248 return _error->Error("%s", errmsg.c_str());
1249 }
1250 }
f6d4ab9a 1251
448c38bd
DK
1252 /* Did we get a file older than what we have? This is a last minute IMS hit and doubles
1253 as a prevention of downgrading us to older (still valid) files */
1254 if (TransactionManager->IMSHit == false && TransactionManager->LastMetaIndexParser != NULL &&
1255 TransactionManager->LastMetaIndexParser->GetDate() > TransactionManager->MetaIndexParser->GetDate())
f6d4ab9a 1256 {
448c38bd 1257 TransactionManager->IMSHit = true;
51818f26 1258 RemoveFile("VerifyVendor", DestFile);
448c38bd 1259 PartialFile = DestFile = GetFinalFilename();
5ad0096a
DK
1260 // load the 'old' file in the 'new' one instead of flipping pointers as
1261 // the new one isn't owned by us, while the old one is so cleanup would be confused.
1262 TransactionManager->MetaIndexParser->swapLoad(TransactionManager->LastMetaIndexParser);
1263 delete TransactionManager->LastMetaIndexParser;
448c38bd 1264 TransactionManager->LastMetaIndexParser = NULL;
f6d4ab9a
DK
1265 }
1266
448c38bd 1267 if (_config->FindB("Debug::pkgAcquire::Auth", false))
f6d4ab9a 1268 {
5ad0096a 1269 std::cerr << "Got Codename: " << TransactionManager->MetaIndexParser->GetCodename() << std::endl;
448c38bd
DK
1270 std::cerr << "Expecting Dist: " << TransactionManager->MetaIndexParser->GetExpectedDist() << std::endl;
1271 std::cerr << "Transformed Dist: " << Transformed << std::endl;
f6d4ab9a 1272 }
448c38bd
DK
1273
1274 if (TransactionManager->MetaIndexParser->CheckDist(Transformed) == false)
f6d4ab9a 1275 {
448c38bd
DK
1276 // This might become fatal one day
1277// Status = StatAuthError;
1278// ErrorText = "Conflicting distribution; expected "
1279// + MetaIndexParser->GetExpectedDist() + " but got "
5ad0096a 1280// + MetaIndexParser->GetCodename();
448c38bd
DK
1281// return false;
1282 if (!Transformed.empty())
1283 {
1284 _error->Warning(_("Conflicting distribution: %s (expected %s but got %s)"),
1285 Desc.Description.c_str(),
1286 Transformed.c_str(),
5ad0096a 1287 TransactionManager->MetaIndexParser->GetCodename().c_str());
448c38bd 1288 }
f6d4ab9a
DK
1289 }
1290
f6d4ab9a 1291 return true;
2237bd01 1292}
92fcbfc1 1293 /*}}}*/
3d8232bf
DK
1294pkgAcqMetaBase::~pkgAcqMetaBase()
1295{
1296}
2237bd01 1297
448c38bd
DK
1298pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire * const Owner, /*{{{*/
1299 IndexTarget const &ClearsignedTarget,
1300 IndexTarget const &DetachedDataTarget, IndexTarget const &DetachedSigTarget,
e8afd168 1301 std::vector<IndexTarget> const &IndexTargets,
5ad0096a 1302 metaIndex * const MetaIndexParser) :
3d8232bf 1303 pkgAcqMetaIndex(Owner, this, ClearsignedTarget, DetachedSigTarget, IndexTargets),
6c55f07a 1304 d(NULL), ClearsignedTarget(ClearsignedTarget),
3d8232bf
DK
1305 DetachedDataTarget(DetachedDataTarget),
1306 MetaIndexParser(MetaIndexParser), LastMetaIndexParser(NULL)
448c38bd
DK
1307{
1308 // index targets + (worst case:) Release/Release.gpg
dcbbb14d 1309 ExpectedAdditionalItems = IndexTargets.size() + 2;
448c38bd 1310 TransactionManager->Add(this);
2237bd01 1311}
92fcbfc1 1312 /*}}}*/
448c38bd 1313pkgAcqMetaClearSig::~pkgAcqMetaClearSig() /*{{{*/
146f7715 1314{
3d8232bf
DK
1315 if (LastMetaIndexParser != NULL)
1316 delete LastMetaIndexParser;
146f7715
DK
1317}
1318 /*}}}*/
448c38bd
DK
1319// pkgAcqMetaClearSig::Custom600Headers - Insert custom request headers /*{{{*/
1320string pkgAcqMetaClearSig::Custom600Headers() const
2237bd01 1321{
448c38bd
DK
1322 string Header = pkgAcqMetaBase::Custom600Headers();
1323 Header += "\nFail-Ignore: true";
b0d40854
DK
1324 std::string const key = TransactionManager->MetaIndexParser->GetSignedBy();
1325 if (key.empty() == false)
1326 Header += "\nSigned-By: " + key;
1327
448c38bd
DK
1328 return Header;
1329}
1330 /*}}}*/
24e8f24e 1331bool pkgAcqMetaClearSig::VerifyDone(std::string const &Message, /*{{{*/
dd676dc7
DK
1332 pkgAcquire::MethodConfig const * const Cnf)
1333{
1334 Item::VerifyDone(Message, Cnf);
1335
1336 if (FileExists(DestFile) && !StartsWithGPGClearTextSignature(DestFile))
1337 return RenameOnError(NotClearsigned);
1338
1339 return true;
1340}
24e8f24e 1341 /*}}}*/
448c38bd 1342// pkgAcqMetaClearSig::Done - We got a file /*{{{*/
448c38bd
DK
1343void pkgAcqMetaClearSig::Done(std::string const &Message,
1344 HashStringList const &Hashes,
1345 pkgAcquire::MethodConfig const * const Cnf)
1346{
1347 Item::Done(Message, Hashes, Cnf);
8d266656 1348
448c38bd
DK
1349 if(AuthPass == false)
1350 {
1351 if(CheckDownloadDone(this, Message, Hashes) == true)
1352 QueueForSignatureVerify(this, DestFile, DestFile);
1353 return;
1354 }
1355 else if(CheckAuthDone(Message) == true)
1356 {
1357 if (TransactionManager->IMSHit == false)
1358 TransactionManager->TransactionStageCopy(this, DestFile, GetFinalFilename());
1359 else if (RealFileExists(GetFinalFilename()) == false)
1360 {
1361 // We got an InRelease file IMSHit, but we haven't one, which means
1362 // we had a valid Release/Release.gpg combo stepping in, which we have
1363 // to 'acquire' now to ensure list cleanup isn't removing them
dcbbb14d
DK
1364 new NoActionItem(Owner, DetachedDataTarget);
1365 new NoActionItem(Owner, DetachedSigTarget);
448c38bd
DK
1366 }
1367 }
2237bd01 1368}
92fcbfc1 1369 /*}}}*/
448c38bd 1370void pkgAcqMetaClearSig::Failed(string const &Message,pkgAcquire::MethodConfig const * const Cnf) /*{{{*/
2237bd01 1371{
448c38bd 1372 Item::Failed(Message, Cnf);
2237bd01 1373
448c38bd
DK
1374 // we failed, we will not get additional items from this method
1375 ExpectedAdditionalItems = 0;
2237bd01 1376
448c38bd 1377 if (AuthPass == false)
2ac3eeb6 1378 {
f18f2338 1379 if (Status == StatAuthError || Status == StatTransientNetworkError)
dd676dc7 1380 {
f18f2338
DK
1381 // if we expected a ClearTextSignature (InRelease) but got a network
1382 // error or got a file, but it wasn't valid, we end up here (see VerifyDone).
dd676dc7
DK
1383 // As these is usually called by web-portals we do not try Release/Release.gpg
1384 // as this is gonna fail anyway and instead abort our try (LP#346386)
1385 TransactionManager->AbortTransaction();
1386 return;
1387 }
1388
448c38bd
DK
1389 // Queue the 'old' InRelease file for removal if we try Release.gpg
1390 // as otherwise the file will stay around and gives a false-auth
1391 // impression (CVE-2012-0214)
1392 TransactionManager->TransactionStageRemoval(this, GetFinalFilename());
1393 Status = StatDone;
1394
3d8232bf 1395 new pkgAcqMetaIndex(Owner, TransactionManager, DetachedDataTarget, DetachedSigTarget, IndexTargets);
2ac3eeb6
MV
1396 }
1397 else
1398 {
448c38bd
DK
1399 if(CheckStopAuthentication(this, Message))
1400 return;
1401
448c38bd
DK
1402 // No Release file was present, or verification failed, so fall
1403 // back to queueing Packages files without verification
d04e44ac 1404 // only allow going further if the user explicitly wants it
f18f2338 1405 if(AllowInsecureRepositories(_("The repository '%s' is not signed."), ClearsignedTarget.Description, TransactionManager->MetaIndexParser, TransactionManager, this) == true)
146f7715 1406 {
448c38bd
DK
1407 Status = StatDone;
1408
1409 /* InRelease files become Release files, otherwise
1410 * they would be considered as trusted later on */
1411 string const FinalRelease = GetFinalFileNameFromURI(DetachedDataTarget.URI);
1412 string const PartialRelease = GetPartialFileNameFromURI(DetachedDataTarget.URI);
1413 string const FinalReleasegpg = GetFinalFileNameFromURI(DetachedSigTarget.URI);
1414 string const FinalInRelease = GetFinalFilename();
1415 Rename(DestFile, PartialRelease);
1416 TransactionManager->TransactionStageCopy(this, PartialRelease, FinalRelease);
1417
1418 if (RealFileExists(FinalReleasegpg) || RealFileExists(FinalInRelease))
146f7715 1419 {
448c38bd
DK
1420 // open the last Release if we have it
1421 if (TransactionManager->IMSHit == false)
1422 {
5ad0096a
DK
1423 TransactionManager->LastMetaIndexParser = TransactionManager->MetaIndexParser->UnloadedClone();
1424 if (TransactionManager->LastMetaIndexParser != NULL)
448c38bd 1425 {
5ad0096a
DK
1426 _error->PushToStack();
1427 if (RealFileExists(FinalInRelease))
1428 TransactionManager->LastMetaIndexParser->Load(FinalInRelease, NULL);
1429 else
1430 TransactionManager->LastMetaIndexParser->Load(FinalRelease, NULL);
1431 // its unlikely to happen, but if what we have is bad ignore it
1432 if (_error->PendingError())
1433 {
1434 delete TransactionManager->LastMetaIndexParser;
1435 TransactionManager->LastMetaIndexParser = NULL;
1436 }
1437 _error->RevertToStack();
448c38bd 1438 }
448c38bd 1439 }
146f7715 1440 }
146f7715 1441
448c38bd
DK
1442 // we parse the indexes here because at this point the user wanted
1443 // a repository that may potentially harm him
5ad0096a 1444 if (TransactionManager->MetaIndexParser->Load(PartialRelease, &ErrorText) == false || VerifyVendor(Message) == false)
448c38bd
DK
1445 /* expired Release files are still a problem you need extra force for */;
1446 else
1447 QueueIndexes(true);
1448 }
2237bd01
MV
1449 }
1450}
92fcbfc1 1451 /*}}}*/
03aa0847 1452
448c38bd 1453pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire * const Owner, /*{{{*/
3d8232bf 1454 pkgAcqMetaClearSig * const TransactionManager,
448c38bd
DK
1455 IndexTarget const &DataTarget,
1456 IndexTarget const &DetachedSigTarget,
3d8232bf
DK
1457 vector<IndexTarget> const &IndexTargets) :
1458 pkgAcqMetaBase(Owner, TransactionManager, IndexTargets, DataTarget), d(NULL),
448c38bd 1459 DetachedSigTarget(DetachedSigTarget)
ac5b205a 1460{
448c38bd
DK
1461 if(_config->FindB("Debug::Acquire::Transaction", false) == true)
1462 std::clog << "New pkgAcqMetaIndex with TransactionManager "
1463 << this->TransactionManager << std::endl;
2d4722e2 1464
448c38bd 1465 DestFile = GetPartialFileNameFromURI(DataTarget.URI);
fa3a96a1 1466
448c38bd
DK
1467 // Create the item
1468 Desc.Description = DataTarget.Description;
1469 Desc.Owner = this;
1470 Desc.ShortDesc = DataTarget.ShortDesc;
1471 Desc.URI = DataTarget.URI;
ac5b205a 1472
448c38bd 1473 // we expect more item
dcbbb14d 1474 ExpectedAdditionalItems = IndexTargets.size();
448c38bd 1475 QueueURI(Desc);
ac5b205a 1476}
92fcbfc1 1477 /*}}}*/
448c38bd
DK
1478void pkgAcqMetaIndex::Done(string const &Message, /*{{{*/
1479 HashStringList const &Hashes,
1480 pkgAcquire::MethodConfig const * const Cfg)
ac5b205a 1481{
448c38bd 1482 Item::Done(Message,Hashes,Cfg);
03bfbc96 1483
448c38bd 1484 if(CheckDownloadDone(this, Message, Hashes))
03bfbc96 1485 {
448c38bd
DK
1486 // we have a Release file, now download the Signature, all further
1487 // verify/queue for additional downloads will be done in the
1488 // pkgAcqMetaSig::Done() code
dcbbb14d 1489 new pkgAcqMetaSig(Owner, TransactionManager, DetachedSigTarget, this);
03bfbc96 1490 }
448c38bd
DK
1491}
1492 /*}}}*/
1493// pkgAcqMetaIndex::Failed - no Release file present /*{{{*/
1494void pkgAcqMetaIndex::Failed(string const &Message,
1495 pkgAcquire::MethodConfig const * const Cnf)
1496{
1497 pkgAcquire::Item::Failed(Message, Cnf);
1498 Status = StatDone;
94dc9d7d 1499
448c38bd
DK
1500 // No Release file was present so fall
1501 // back to queueing Packages files without verification
d04e44ac 1502 // only allow going further if the user explicitly wants it
f18f2338 1503 if(AllowInsecureRepositories(_("The repository '%s' does not have a Release file."), Target.Description, TransactionManager->MetaIndexParser, TransactionManager, this) == true)
f6d4ab9a 1504 {
448c38bd
DK
1505 // ensure old Release files are removed
1506 TransactionManager->TransactionStageRemoval(this, GetFinalFilename());
03bfbc96 1507
448c38bd
DK
1508 // queue without any kind of hashsum support
1509 QueueIndexes(false);
59a704f0 1510 }
448c38bd
DK
1511}
1512 /*}}}*/
1513void pkgAcqMetaIndex::Finished() /*{{{*/
1514{
1515 if(_config->FindB("Debug::Acquire::Transaction", false) == true)
1516 std::clog << "Finished: " << DestFile <<std::endl;
1517 if(TransactionManager != NULL &&
1518 TransactionManager->TransactionHasError() == false)
1519 TransactionManager->CommitTransaction();
1520}
1521 /*}}}*/
1522std::string pkgAcqMetaIndex::DescURI() const /*{{{*/
1523{
dcbbb14d 1524 return Target.URI;
448c38bd
DK
1525}
1526 /*}}}*/
c8a4ce6c 1527pkgAcqMetaIndex::~pkgAcqMetaIndex() {}
94dc9d7d 1528
448c38bd
DK
1529// AcqMetaSig::AcqMetaSig - Constructor /*{{{*/
1530pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire * const Owner,
3d8232bf 1531 pkgAcqMetaClearSig * const TransactionManager,
e8afd168 1532 IndexTarget const &Target,
448c38bd 1533 pkgAcqMetaIndex * const MetaIndex) :
6c55f07a 1534 pkgAcqTransactionItem(Owner, TransactionManager, Target), d(NULL), MetaIndex(MetaIndex)
448c38bd 1535{
dcbbb14d 1536 DestFile = GetPartialFileNameFromURI(Target.URI);
6cb30d01 1537
448c38bd
DK
1538 // remove any partial downloaded sig-file in partial/.
1539 // it may confuse proxies and is too small to warrant a
1540 // partial download anyway
51818f26 1541 RemoveFile("pkgAcqMetaSig", DestFile);
ac5b205a 1542
448c38bd
DK
1543 // set the TransactionManager
1544 if(_config->FindB("Debug::Acquire::Transaction", false) == true)
1545 std::clog << "New pkgAcqMetaSig with TransactionManager "
1546 << TransactionManager << std::endl;
f6d4ab9a 1547
448c38bd 1548 // Create the item
dcbbb14d 1549 Desc.Description = Target.Description;
448c38bd 1550 Desc.Owner = this;
dcbbb14d
DK
1551 Desc.ShortDesc = Target.ShortDesc;
1552 Desc.URI = Target.URI;
ac5b205a 1553
448c38bd
DK
1554 // If we got a hit for Release, we will get one for Release.gpg too (or obscure errors),
1555 // so we skip the download step and go instantly to verification
1556 if (TransactionManager->IMSHit == true && RealFileExists(GetFinalFilename()))
1557 {
1558 Complete = true;
1559 Status = StatDone;
1560 PartialFile = DestFile = GetFinalFilename();
1561 MetaIndexFileSignature = DestFile;
1562 MetaIndex->QueueForSignatureVerify(this, MetaIndex->DestFile, DestFile);
1563 }
1564 else
1565 QueueURI(Desc);
ac5b205a 1566}
92fcbfc1 1567 /*}}}*/
448c38bd 1568pkgAcqMetaSig::~pkgAcqMetaSig() /*{{{*/
ac5b205a 1569{
b0d40854
DK
1570}
1571 /*}}}*/
1572// pkgAcqMetaSig::Custom600Headers - Insert custom request headers /*{{{*/
1573std::string pkgAcqMetaSig::Custom600Headers() const
1574{
1575 std::string Header = pkgAcqTransactionItem::Custom600Headers();
1576 std::string const key = TransactionManager->MetaIndexParser->GetSignedBy();
1577 if (key.empty() == false)
1578 Header += "\nSigned-By: " + key;
1579 return Header;
448c38bd
DK
1580}
1581 /*}}}*/
1582// AcqMetaSig::Done - The signature was downloaded/verified /*{{{*/
1583void pkgAcqMetaSig::Done(string const &Message, HashStringList const &Hashes,
1584 pkgAcquire::MethodConfig const * const Cfg)
1585{
1586 if (MetaIndexFileSignature.empty() == false)
4a0a786f 1587 {
448c38bd
DK
1588 DestFile = MetaIndexFileSignature;
1589 MetaIndexFileSignature.clear();
1590 }
1591 Item::Done(Message, Hashes, Cfg);
f6d4ab9a 1592
448c38bd
DK
1593 if(MetaIndex->AuthPass == false)
1594 {
1595 if(MetaIndex->CheckDownloadDone(this, Message, Hashes) == true)
f6d4ab9a 1596 {
448c38bd
DK
1597 // destfile will be modified to point to MetaIndexFile for the
1598 // gpgv method, so we need to save it here
1599 MetaIndexFileSignature = DestFile;
1600 MetaIndex->QueueForSignatureVerify(this, MetaIndex->DestFile, DestFile);
1601 }
1602 return;
1603 }
1604 else if(MetaIndex->CheckAuthDone(Message) == true)
1605 {
1606 if (TransactionManager->IMSHit == false)
1607 {
1608 TransactionManager->TransactionStageCopy(this, DestFile, GetFinalFilename());
1609 TransactionManager->TransactionStageCopy(MetaIndex, MetaIndex->DestFile, MetaIndex->GetFinalFilename());
f6d4ab9a 1610 }
448c38bd
DK
1611 }
1612}
1613 /*}}}*/
1614void pkgAcqMetaSig::Failed(string const &Message,pkgAcquire::MethodConfig const * const Cnf)/*{{{*/
1615{
1616 Item::Failed(Message,Cnf);
4a0a786f 1617
448c38bd
DK
1618 // check if we need to fail at this point
1619 if (MetaIndex->AuthPass == true && MetaIndex->CheckStopAuthentication(this, Message))
1620 return;
4a0a786f 1621
448c38bd
DK
1622 string const FinalRelease = MetaIndex->GetFinalFilename();
1623 string const FinalReleasegpg = GetFinalFilename();
1624 string const FinalInRelease = TransactionManager->GetFinalFilename();
4a0a786f 1625
448c38bd
DK
1626 if (RealFileExists(FinalReleasegpg) || RealFileExists(FinalInRelease))
1627 {
1628 std::string downgrade_msg;
1629 strprintf(downgrade_msg, _("The repository '%s' is no longer signed."),
dcbbb14d 1630 MetaIndex->Target.Description.c_str());
448c38bd
DK
1631 if(_config->FindB("Acquire::AllowDowngradeToInsecureRepositories"))
1632 {
1633 // meh, the users wants to take risks (we still mark the packages
1634 // from this repository as unauthenticated)
1635 _error->Warning("%s", downgrade_msg.c_str());
1636 _error->Warning(_("This is normally not allowed, but the option "
1637 "Acquire::AllowDowngradeToInsecureRepositories was "
1638 "given to override it."));
1639 Status = StatDone;
1640 } else {
f18f2338 1641 MessageInsecureRepository(true, downgrade_msg);
448c38bd
DK
1642 if (TransactionManager->IMSHit == false)
1643 Rename(MetaIndex->DestFile, MetaIndex->DestFile + ".FAILED");
1644 Item::Failed("Message: " + downgrade_msg, Cnf);
1645 TransactionManager->AbortTransaction();
1646 return;
1647 }
1648 }
4a0a786f 1649
448c38bd
DK
1650 // ensures that a Release.gpg file in the lists/ is removed by the transaction
1651 TransactionManager->TransactionStageRemoval(this, DestFile);
4a0a786f 1652
d04e44ac 1653 // only allow going further if the user explicitly wants it
f18f2338 1654 if (AllowInsecureRepositories(_("The repository '%s' is not signed."), MetaIndex->Target.Description, TransactionManager->MetaIndexParser, TransactionManager, this) == true)
4a0a786f 1655 {
448c38bd 1656 if (RealFileExists(FinalReleasegpg) || RealFileExists(FinalInRelease))
59a704f0 1657 {
448c38bd
DK
1658 // open the last Release if we have it
1659 if (TransactionManager->IMSHit == false)
1660 {
5ad0096a
DK
1661 TransactionManager->LastMetaIndexParser = TransactionManager->MetaIndexParser->UnloadedClone();
1662 if (TransactionManager->LastMetaIndexParser != NULL)
448c38bd 1663 {
5ad0096a
DK
1664 _error->PushToStack();
1665 if (RealFileExists(FinalInRelease))
1666 TransactionManager->LastMetaIndexParser->Load(FinalInRelease, NULL);
1667 else
1668 TransactionManager->LastMetaIndexParser->Load(FinalRelease, NULL);
1669 // its unlikely to happen, but if what we have is bad ignore it
1670 if (_error->PendingError())
1671 {
1672 delete TransactionManager->LastMetaIndexParser;
1673 TransactionManager->LastMetaIndexParser = NULL;
1674 }
1675 _error->RevertToStack();
448c38bd 1676 }
448c38bd 1677 }
59a704f0 1678 }
4a0a786f 1679
448c38bd
DK
1680 // we parse the indexes here because at this point the user wanted
1681 // a repository that may potentially harm him
f01f5d91
DK
1682 bool const GoodLoad = TransactionManager->MetaIndexParser->Load(MetaIndex->DestFile, &ErrorText);
1683 if (MetaIndex->VerifyVendor(Message) == false)
448c38bd
DK
1684 /* expired Release files are still a problem you need extra force for */;
1685 else
f01f5d91 1686 MetaIndex->QueueIndexes(GoodLoad);
448c38bd
DK
1687
1688 TransactionManager->TransactionStageCopy(MetaIndex, MetaIndex->DestFile, MetaIndex->GetFinalFilename());
1689 }
1690
1691 // FIXME: this is used often (e.g. in pkgAcqIndexTrans) so refactor
1692 if (Cnf->LocalOnly == true ||
1693 StringToBool(LookupTag(Message,"Transient-Failure"),false) == false)
1694 {
1695 // Ignore this
1696 Status = StatDone;
ac5b205a 1697 }
ac5b205a 1698}
92fcbfc1 1699 /*}}}*/
448c38bd
DK
1700
1701
1702// AcqBaseIndex - Constructor /*{{{*/
1703pkgAcqBaseIndex::pkgAcqBaseIndex(pkgAcquire * const Owner,
3d8232bf 1704 pkgAcqMetaClearSig * const TransactionManager,
e8afd168 1705 IndexTarget const &Target)
6c55f07a 1706: pkgAcqTransactionItem(Owner, TransactionManager, Target), d(NULL)
448c38bd
DK
1707{
1708}
1709 /*}}}*/
c8a4ce6c 1710pkgAcqBaseIndex::~pkgAcqBaseIndex() {}
448c38bd
DK
1711
1712// AcqDiffIndex::AcqDiffIndex - Constructor /*{{{*/
1713// ---------------------------------------------------------------------
1714/* Get the DiffIndex file first and see if there are patches available
1715 * If so, create a pkgAcqIndexDiffs fetcher that will get and apply the
1716 * patches. If anything goes wrong in that process, it will fall back to
1717 * the original packages file
1718 */
1719pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire * const Owner,
3d8232bf 1720 pkgAcqMetaClearSig * const TransactionManager,
e8afd168 1721 IndexTarget const &Target)
3d8232bf 1722 : pkgAcqBaseIndex(Owner, TransactionManager, Target), d(NULL), diffs(NULL)
47d2bc78 1723{
47d2bc78
DK
1724 Debug = _config->FindB("Debug::pkgAcquire::Diffs",false);
1725
47d2bc78 1726 Desc.Owner = this;
dcbbb14d
DK
1727 Desc.Description = Target.Description + ".diff/Index";
1728 Desc.ShortDesc = Target.ShortDesc;
1729 Desc.URI = Target.URI + ".diff/Index";
47d2bc78 1730
448c38bd
DK
1731 DestFile = GetPartialFileNameFromURI(Desc.URI);
1732
1733 if(Debug)
1734 std::clog << "pkgAcqDiffIndex: " << Desc.URI << std::endl;
5684f71f 1735
47d2bc78
DK
1736 QueueURI(Desc);
1737}
1738 /*}}}*/
448c38bd
DK
1739// AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
1740// ---------------------------------------------------------------------
1741/* The only header we use is the last-modified header. */
1742string pkgAcqDiffIndex::Custom600Headers() const
47d2bc78 1743{
abd6af5a
DK
1744 if (TransactionManager->LastMetaIndexParser != NULL)
1745 return "\nIndex-File: true";
1746
448c38bd 1747 string const Final = GetFinalFilename();
47d2bc78 1748
448c38bd
DK
1749 if(Debug)
1750 std::clog << "Custom600Header-IMS: " << Final << std::endl;
47d2bc78 1751
448c38bd
DK
1752 struct stat Buf;
1753 if (stat(Final.c_str(),&Buf) != 0)
1754 return "\nIndex-File: true";
1755
1756 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
1757}
1758 /*}}}*/
1759void pkgAcqDiffIndex::QueueOnIMSHit() const /*{{{*/
1760{
1761 // list cleanup needs to know that this file as well as the already
1762 // present index is ours, so we create an empty diff to save it for us
1763 new pkgAcqIndexDiffs(Owner, TransactionManager, Target);
47d2bc78
DK
1764}
1765 /*}}}*/
448c38bd 1766bool pkgAcqDiffIndex::ParseDiffIndex(string const &IndexDiffFile) /*{{{*/
47d2bc78 1767{
448c38bd
DK
1768 // failing here is fine: our caller will take care of trying to
1769 // get the complete file if patching fails
47d2bc78 1770 if(Debug)
448c38bd
DK
1771 std::clog << "pkgAcqDiffIndex::ParseIndexDiff() " << IndexDiffFile
1772 << std::endl;
f6d4ab9a 1773
448c38bd
DK
1774 FileFd Fd(IndexDiffFile,FileFd::ReadOnly);
1775 pkgTagFile TF(&Fd);
95278287 1776 if (Fd.IsOpen() == false || Fd.Failed())
448c38bd 1777 return false;
47d2bc78 1778
448c38bd
DK
1779 pkgTagSection Tags;
1780 if(unlikely(TF.Step(Tags) == false))
1781 return false;
47d2bc78 1782
448c38bd
DK
1783 HashStringList ServerHashes;
1784 unsigned long long ServerSize = 0;
47d2bc78 1785
448c38bd
DK
1786 for (char const * const * type = HashString::SupportedHashes(); *type != NULL; ++type)
1787 {
1788 std::string tagname = *type;
1789 tagname.append("-Current");
1790 std::string const tmp = Tags.FindS(tagname.c_str());
1791 if (tmp.empty() == true)
1792 continue;
146f7715 1793
448c38bd
DK
1794 string hash;
1795 unsigned long long size;
1796 std::stringstream ss(tmp);
1797 ss >> hash >> size;
1798 if (unlikely(hash.empty() == true))
1799 continue;
1800 if (unlikely(ServerSize != 0 && ServerSize != size))
1801 continue;
1802 ServerHashes.push_back(HashString(*type, hash));
1803 ServerSize = size;
1804 }
47d2bc78 1805
448c38bd
DK
1806 if (ServerHashes.usable() == false)
1807 {
1808 if (Debug == true)
1809 std::clog << "pkgAcqDiffIndex: " << IndexDiffFile << ": Did not find a good hashsum in the index" << std::endl;
1810 return false;
47d2bc78 1811 }
448c38bd 1812
dcbbb14d
DK
1813 std::string const CurrentPackagesFile = GetFinalFileNameFromURI(Target.URI);
1814 HashStringList const TargetFileHashes = GetExpectedHashesFor(Target.MetaKey);
448c38bd 1815 if (TargetFileHashes.usable() == false || ServerHashes != TargetFileHashes)
47d2bc78 1816 {
448c38bd 1817 if (Debug == true)
47d2bc78 1818 {
448c38bd
DK
1819 std::clog << "pkgAcqDiffIndex: " << IndexDiffFile << ": Index has different hashes than parser, probably older, so fail pdiffing" << std::endl;
1820 printHashSumComparision(CurrentPackagesFile, ServerHashes, TargetFileHashes);
47d2bc78 1821 }
448c38bd
DK
1822 return false;
1823 }
47d2bc78 1824
9b8c28f4
DK
1825 HashStringList LocalHashes;
1826 // try avoiding calculating the hash here as this is costly
1827 if (TransactionManager->LastMetaIndexParser != NULL)
dcbbb14d 1828 LocalHashes = GetExpectedHashesFromFor(TransactionManager->LastMetaIndexParser, Target.MetaKey);
9b8c28f4
DK
1829 if (LocalHashes.usable() == false)
1830 {
d7a51997 1831 FileFd fd(CurrentPackagesFile, FileFd::ReadOnly, FileFd::Auto);
9b8c28f4
DK
1832 Hashes LocalHashesCalc(ServerHashes);
1833 LocalHashesCalc.AddFD(fd);
1834 LocalHashes = LocalHashesCalc.GetHashStringList();
1835 }
1836
1837 if (ServerHashes == LocalHashes)
448c38bd
DK
1838 {
1839 // we have the same sha1 as the server so we are done here
47d2bc78 1840 if(Debug)
448c38bd
DK
1841 std::clog << "pkgAcqDiffIndex: Package file " << CurrentPackagesFile << " is up-to-date" << std::endl;
1842 QueueOnIMSHit();
1843 return true;
1844 }
47d2bc78 1845
448c38bd
DK
1846 if(Debug)
1847 std::clog << "Server-Current: " << ServerHashes.find(NULL)->toStr() << " and we start at "
9b8c28f4 1848 << CurrentPackagesFile << " " << LocalHashes.FileSize() << " " << LocalHashes.find(NULL)->toStr() << std::endl;
34d6ece7 1849
37141fe4
DK
1850 // historically, older hashes have more info than newer ones, so start
1851 // collecting with older ones first to avoid implementing complicated
1852 // information merging techniques… a failure is after all always
1853 // recoverable with a complete file and hashes aren't changed that often.
1854 std::vector<char const *> types;
1855 for (char const * const * type = HashString::SupportedHashes(); *type != NULL; ++type)
1856 types.push_back(*type);
1857
448c38bd
DK
1858 // parse all of (provided) history
1859 vector<DiffInfo> available_patches;
1860 bool firstAcceptedHashes = true;
37141fe4 1861 for (auto type = types.crbegin(); type != types.crend(); ++type)
651bddad 1862 {
448c38bd
DK
1863 if (LocalHashes.find(*type) == NULL)
1864 continue;
21638c3a 1865
448c38bd
DK
1866 std::string tagname = *type;
1867 tagname.append("-History");
1868 std::string const tmp = Tags.FindS(tagname.c_str());
1869 if (tmp.empty() == true)
1870 continue;
a64bf0eb 1871
448c38bd
DK
1872 string hash, filename;
1873 unsigned long long size;
1874 std::stringstream ss(tmp);
56472095 1875
448c38bd 1876 while (ss >> hash >> size >> filename)
651bddad 1877 {
448c38bd
DK
1878 if (unlikely(hash.empty() == true || filename.empty() == true))
1879 continue;
1880
1881 // see if we have a record for this file already
1882 std::vector<DiffInfo>::iterator cur = available_patches.begin();
1883 for (; cur != available_patches.end(); ++cur)
1884 {
4f51fd86 1885 if (cur->file != filename)
448c38bd
DK
1886 continue;
1887 cur->result_hashes.push_back(HashString(*type, hash));
1888 break;
1889 }
1890 if (cur != available_patches.end())
1891 continue;
1892 if (firstAcceptedHashes == true)
1893 {
1894 DiffInfo next;
1895 next.file = filename;
1896 next.result_hashes.push_back(HashString(*type, hash));
4f51fd86 1897 next.result_hashes.FileSize(size);
448c38bd
DK
1898 available_patches.push_back(next);
1899 }
1900 else
1901 {
1902 if (Debug == true)
1903 std::clog << "pkgAcqDiffIndex: " << IndexDiffFile << ": File " << filename
1904 << " wasn't in the list for the first parsed hash! (history)" << std::endl;
1905 break;
1906 }
651bddad 1907 }
448c38bd 1908 firstAcceptedHashes = false;
5d885723 1909 }
448c38bd
DK
1910
1911 if (unlikely(available_patches.empty() == true))
5d885723 1912 {
448c38bd
DK
1913 if (Debug)
1914 std::clog << "pkgAcqDiffIndex: " << IndexDiffFile << ": "
1915 << "Couldn't find any patches for the patch series." << std::endl;
1916 return false;
5d885723 1917 }
8267fe24 1918
37141fe4 1919 for (auto type = types.crbegin(); type != types.crend(); ++type)
b11f9599 1920 {
448c38bd
DK
1921 if (LocalHashes.find(*type) == NULL)
1922 continue;
97b65b10 1923
448c38bd
DK
1924 std::string tagname = *type;
1925 tagname.append("-Patches");
1926 std::string const tmp = Tags.FindS(tagname.c_str());
1927 if (tmp.empty() == true)
1928 continue;
18593cf7 1929
448c38bd
DK
1930 string hash, filename;
1931 unsigned long long size;
1932 std::stringstream ss(tmp);
03aa0847 1933
448c38bd 1934 while (ss >> hash >> size >> filename)
58702f85 1935 {
448c38bd
DK
1936 if (unlikely(hash.empty() == true || filename.empty() == true))
1937 continue;
146f7715 1938
448c38bd
DK
1939 // see if we have a record for this file already
1940 std::vector<DiffInfo>::iterator cur = available_patches.begin();
1941 for (; cur != available_patches.end(); ++cur)
146f7715 1942 {
448c38bd
DK
1943 if (cur->file != filename)
1944 continue;
4f51fd86
DK
1945 if (cur->patch_hashes.empty())
1946 cur->patch_hashes.FileSize(size);
448c38bd 1947 cur->patch_hashes.push_back(HashString(*type, hash));
448c38bd 1948 break;
146f7715 1949 }
448c38bd
DK
1950 if (cur != available_patches.end())
1951 continue;
1952 if (Debug == true)
1953 std::clog << "pkgAcqDiffIndex: " << IndexDiffFile << ": File " << filename
1954 << " wasn't in the list for the first parsed hash! (patches)" << std::endl;
146f7715 1955 break;
146f7715
DK
1956 }
1957 }
2d0a7bb4 1958
37141fe4 1959 for (auto type = types.crbegin(); type != types.crend(); ++type)
4f51fd86
DK
1960 {
1961 std::string tagname = *type;
1962 tagname.append("-Download");
1963 std::string const tmp = Tags.FindS(tagname.c_str());
1964 if (tmp.empty() == true)
1965 continue;
1966
1967 string hash, filename;
1968 unsigned long long size;
1969 std::stringstream ss(tmp);
1970
1971 // FIXME: all of pdiff supports only .gz compressed patches
1972 while (ss >> hash >> size >> filename)
1973 {
1974 if (unlikely(hash.empty() == true || filename.empty() == true))
1975 continue;
1976 if (unlikely(APT::String::Endswith(filename, ".gz") == false))
1977 continue;
1978 filename.erase(filename.length() - 3);
1979
1980 // see if we have a record for this file already
1981 std::vector<DiffInfo>::iterator cur = available_patches.begin();
1982 for (; cur != available_patches.end(); ++cur)
1983 {
1984 if (cur->file != filename)
1985 continue;
1986 if (cur->download_hashes.empty())
1987 cur->download_hashes.FileSize(size);
1988 cur->download_hashes.push_back(HashString(*type, hash));
1989 break;
1990 }
1991 if (cur != available_patches.end())
1992 continue;
1993 if (Debug == true)
1994 std::clog << "pkgAcqDiffIndex: " << IndexDiffFile << ": File " << filename
1995 << " wasn't in the list for the first parsed hash! (download)" << std::endl;
1996 break;
1997 }
1998 }
1999
2000
448c38bd
DK
2001 bool foundStart = false;
2002 for (std::vector<DiffInfo>::iterator cur = available_patches.begin();
2003 cur != available_patches.end(); ++cur)
2004 {
2005 if (LocalHashes != cur->result_hashes)
2006 continue;
2007
2008 available_patches.erase(available_patches.begin(), cur);
2009 foundStart = true;
2010 break;
e6e89390 2011 }
b3d44315 2012
448c38bd
DK
2013 if (foundStart == false || unlikely(available_patches.empty() == true))
2014 {
2015 if (Debug)
2016 std::clog << "pkgAcqDiffIndex: " << IndexDiffFile << ": "
2017 << "Couldn't find the start of the patch series." << std::endl;
2018 return false;
2019 }
f6237efd 2020
448c38bd
DK
2021 // patching with too many files is rather slow compared to a fast download
2022 unsigned long const fileLimit = _config->FindI("Acquire::PDiffs::FileLimit", 0);
2023 if (fileLimit != 0 && fileLimit < available_patches.size())
2024 {
2025 if (Debug)
2026 std::clog << "Need " << available_patches.size() << " diffs (Limit is " << fileLimit
2027 << ") so fallback to complete download" << std::endl;
2028 return false;
2029 }
1f4dd8fd 2030
448c38bd
DK
2031 // calculate the size of all patches we have to get
2032 // note that all sizes are uncompressed, while we download compressed files
2033 unsigned long long patchesSize = 0;
2034 for (std::vector<DiffInfo>::const_iterator cur = available_patches.begin();
2035 cur != available_patches.end(); ++cur)
4f51fd86 2036 patchesSize += cur->patch_hashes.FileSize();
448c38bd
DK
2037 unsigned long long const sizeLimit = ServerSize * _config->FindI("Acquire::PDiffs::SizeLimit", 100);
2038 if (sizeLimit > 0 && (sizeLimit/100) < patchesSize)
2039 {
2040 if (Debug)
2041 std::clog << "Need " << patchesSize << " bytes (Limit is " << sizeLimit/100
2042 << ") so fallback to complete download" << std::endl;
2043 return false;
2044 }
2737f28a 2045
448c38bd
DK
2046 // we have something, queue the diffs
2047 string::size_type const last_space = Description.rfind(" ");
2048 if(last_space != string::npos)
2049 Description.erase(last_space, Description.size()-last_space);
2050
2051 /* decide if we should download patches one by one or in one go:
2052 The first is good if the server merges patches, but many don't so client
2053 based merging can be attempt in which case the second is better.
2054 "bad things" will happen if patches are merged on the server,
2055 but client side merging is attempt as well */
2056 bool pdiff_merge = _config->FindB("Acquire::PDiffs::Merge", true);
2057 if (pdiff_merge == true)
6bf93605 2058 {
448c38bd
DK
2059 // reprepro adds this flag if it has merged patches on the server
2060 std::string const precedence = Tags.FindS("X-Patch-Precedence");
2061 pdiff_merge = (precedence != "merged");
6bf93605 2062 }
448c38bd
DK
2063
2064 if (pdiff_merge == false)
2065 new pkgAcqIndexDiffs(Owner, TransactionManager, Target, available_patches);
6bf93605 2066 else
448c38bd 2067 {
3d8232bf 2068 diffs = new std::vector<pkgAcqIndexMergeDiffs*>(available_patches.size());
448c38bd
DK
2069 for(size_t i = 0; i < available_patches.size(); ++i)
2070 (*diffs)[i] = new pkgAcqIndexMergeDiffs(Owner, TransactionManager,
2071 Target,
2072 available_patches[i],
2073 diffs);
2074 }
2075
2076 Complete = false;
2077 Status = StatDone;
2078 Dequeue();
2079 return true;
6bf93605
DK
2080}
2081 /*}}}*/
448c38bd 2082void pkgAcqDiffIndex::Failed(string const &Message,pkgAcquire::MethodConfig const * const Cnf)/*{{{*/
6bf93605 2083{
448c38bd
DK
2084 Item::Failed(Message,Cnf);
2085 Status = StatDone;
2086
2087 if(Debug)
2088 std::clog << "pkgAcqDiffIndex failed: " << Desc.URI << " with " << Message << std::endl
2089 << "Falling back to normal index file acquire" << std::endl;
2090
2091 new pkgAcqIndex(Owner, TransactionManager, Target);
0118833a 2092}
61aea84d 2093 /*}}}*/
448c38bd
DK
2094void pkgAcqDiffIndex::Done(string const &Message,HashStringList const &Hashes, /*{{{*/
2095 pkgAcquire::MethodConfig const * const Cnf)
c88edf1d 2096{
448c38bd
DK
2097 if(Debug)
2098 std::clog << "pkgAcqDiffIndex::Done(): " << Desc.URI << std::endl;
c88edf1d 2099
448c38bd
DK
2100 Item::Done(Message, Hashes, Cnf);
2101
2102 string const FinalFile = GetFinalFilename();
2103 if(StringToBool(LookupTag(Message,"IMS-Hit"),false))
2104 DestFile = FinalFile;
2105
2106 if(ParseDiffIndex(DestFile) == false)
c88edf1d 2107 {
448c38bd
DK
2108 Failed("Message: Couldn't parse pdiff index", Cnf);
2109 // queue for final move - this should happen even if we fail
2110 // while parsing (e.g. on sizelimit) and download the complete file.
2111 TransactionManager->TransactionStageCopy(this, DestFile, FinalFile);
2737f28a
MV
2112 return;
2113 }
448c38bd
DK
2114
2115 TransactionManager->TransactionStageCopy(this, DestFile, FinalFile);
2116
2117 Complete = true;
2118 Status = StatDone;
2119 Dequeue();
2120
2121 return;
c88edf1d
AL
2122}
2123 /*}}}*/
3d8232bf
DK
2124pkgAcqDiffIndex::~pkgAcqDiffIndex()
2125{
2126 if (diffs != NULL)
2127 delete diffs;
2128}
448c38bd
DK
2129
2130// AcqIndexDiffs::AcqIndexDiffs - Constructor /*{{{*/
2131// ---------------------------------------------------------------------
2132/* The package diff is added to the queue. one object is constructed
2133 * for each diff and the index
2134 */
2135pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire * const Owner,
3d8232bf 2136 pkgAcqMetaClearSig * const TransactionManager,
e8afd168 2137 IndexTarget const &Target,
448c38bd 2138 vector<DiffInfo> const &diffs)
6c55f07a 2139 : pkgAcqBaseIndex(Owner, TransactionManager, Target), d(NULL),
448c38bd 2140 available_patches(diffs)
681d76d0 2141{
d7a51997 2142 DestFile = GetKeepCompressedFileName(GetPartialFileNameFromURI(Target.URI), Target);
e8b1db38 2143
448c38bd 2144 Debug = _config->FindB("Debug::pkgAcquire::Diffs",false);
e8b1db38 2145
448c38bd 2146 Desc.Owner = this;
dcbbb14d
DK
2147 Description = Target.Description;
2148 Desc.ShortDesc = Target.ShortDesc;
631a7dc7 2149
448c38bd 2150 if(available_patches.empty() == true)
631a7dc7 2151 {
448c38bd 2152 // we are done (yeah!), check hashes against the final file
d7a51997 2153 DestFile = GetKeepCompressedFileName(GetFinalFileNameFromURI(Target.URI), Target);
448c38bd 2154 Finish(true);
631a7dc7 2155 }
9d653a6d 2156 else
631a7dc7 2157 {
d7a51997 2158 if (BootstrapPDiffWith(GetPartialFileNameFromURI(Target.URI), GetFinalFilename(), Target) == false)
6bf93605 2159 {
d7a51997
DK
2160 Failed("Bootstrapping of " + DestFile + " failed", NULL);
2161 return;
6bf93605
DK
2162 }
2163
448c38bd
DK
2164 // get the next diff
2165 State = StateFetchDiff;
2166 QueueNextDiff();
631a7dc7 2167 }
448c38bd
DK
2168}
2169 /*}}}*/
2170void pkgAcqIndexDiffs::Failed(string const &Message,pkgAcquire::MethodConfig const * const Cnf)/*{{{*/
2171{
2172 Item::Failed(Message,Cnf);
2173 Status = StatDone;
631a7dc7 2174
d7a51997 2175 DestFile = GetKeepCompressedFileName(GetPartialFileNameFromURI(Target.URI), Target);
448c38bd
DK
2176 if(Debug)
2177 std::clog << "pkgAcqIndexDiffs failed: " << Desc.URI << " with " << Message << std::endl
d7a51997 2178 << "Falling back to normal index file acquire " << std::endl;
448c38bd 2179 RenameOnError(PDiffError);
36795154
DK
2180 std::string const patchname = GetDiffsPatchFileName(DestFile);
2181 if (RealFileExists(patchname))
2182 rename(patchname.c_str(), std::string(patchname + ".FAILED").c_str());
448c38bd
DK
2183 new pkgAcqIndex(Owner, TransactionManager, Target);
2184 Finish();
2185}
2186 /*}}}*/
2187// Finish - helper that cleans the item out of the fetcher queue /*{{{*/
2188void pkgAcqIndexDiffs::Finish(bool allDone)
2189{
2190 if(Debug)
2191 std::clog << "pkgAcqIndexDiffs::Finish(): "
2192 << allDone << " "
2193 << Desc.URI << std::endl;
2194
2195 // we restore the original name, this is required, otherwise
2196 // the file will be cleaned
2197 if(allDone)
4dbfe436 2198 {
d7a51997
DK
2199 std::string Final = GetFinalFilename();
2200 if (Target.KeepCompressed)
2201 {
2202 std::string const ext = flExtension(DestFile);
2203 if (ext.empty() == false)
2204 Final.append(".").append(ext);
2205 }
2206 TransactionManager->TransactionStageCopy(this, DestFile, Final);
448c38bd
DK
2207
2208 // this is for the "real" finish
2209 Complete = true;
e05672e8 2210 Status = StatDone;
448c38bd
DK
2211 Dequeue();
2212 if(Debug)
2213 std::clog << "\n\nallDone: " << DestFile << "\n" << std::endl;
2214 return;
e05672e8 2215 }
d7a51997
DK
2216 else
2217 DestFile.clear();
448c38bd
DK
2218
2219 if(Debug)
2220 std::clog << "Finishing: " << Desc.URI << std::endl;
2221 Complete = false;
2222 Status = StatDone;
2223 Dequeue();
2224 return;
681d76d0 2225}
92fcbfc1 2226 /*}}}*/
448c38bd 2227bool pkgAcqIndexDiffs::QueueNextDiff() /*{{{*/
b3d44315 2228{
448c38bd 2229 // calc sha1 of the just patched file
d7a51997 2230 std::string const FinalFile = GetKeepCompressedFileName(GetPartialFileNameFromURI(Target.URI), Target);
448c38bd 2231 if(!FileExists(FinalFile))
715c65de 2232 {
448c38bd
DK
2233 Failed("Message: No FinalFile " + FinalFile + " available", NULL);
2234 return false;
715c65de 2235 }
e05672e8 2236
d7a51997 2237 FileFd fd(FinalFile, FileFd::ReadOnly, FileFd::Extension);
448c38bd
DK
2238 Hashes LocalHashesCalc;
2239 LocalHashesCalc.AddFD(fd);
2240 HashStringList const LocalHashes = LocalHashesCalc.GetHashStringList();
b3d44315 2241
448c38bd
DK
2242 if(Debug)
2243 std::clog << "QueueNextDiff: " << FinalFile << " (" << LocalHashes.find(NULL)->toStr() << ")" << std::endl;
b3d44315 2244
dcbbb14d 2245 HashStringList const TargetFileHashes = GetExpectedHashesFor(Target.MetaKey);
448c38bd 2246 if (unlikely(LocalHashes.usable() == false || TargetFileHashes.usable() == false))
b3d44315 2247 {
448c38bd
DK
2248 Failed("Local/Expected hashes are not usable", NULL);
2249 return false;
b3d44315 2250 }
b3d44315 2251
448c38bd
DK
2252
2253 // final file reached before all patches are applied
2254 if(LocalHashes == TargetFileHashes)
6bf93605 2255 {
448c38bd
DK
2256 Finish(true);
2257 return true;
6bf93605
DK
2258 }
2259
448c38bd
DK
2260 // remove all patches until the next matching patch is found
2261 // this requires the Index file to be ordered
258b9e51
DK
2262 available_patches.erase(available_patches.begin(),
2263 std::find_if(available_patches.begin(), available_patches.end(), [&](DiffInfo const &I) {
2264 return I.result_hashes == LocalHashes;
2265 }));
56bc3358 2266
448c38bd
DK
2267 // error checking and falling back if no patch was found
2268 if(available_patches.empty() == true)
56bc3358 2269 {
448c38bd 2270 Failed("No patches left to reach target", NULL);
f3097647 2271 return false;
56bc3358 2272 }
f3097647 2273
448c38bd 2274 // queue the right diff
dcbbb14d 2275 Desc.URI = Target.URI + ".diff/" + available_patches[0].file + ".gz";
448c38bd 2276 Desc.Description = Description + " " + available_patches[0].file + string(".pdiff");
d7a51997 2277 DestFile = GetKeepCompressedFileName(GetPartialFileNameFromURI(Target.URI + ".diff/" + available_patches[0].file), Target);
f3097647 2278
448c38bd
DK
2279 if(Debug)
2280 std::clog << "pkgAcqIndexDiffs::QueueNextDiff(): " << Desc.URI << std::endl;
2281
2282 QueueURI(Desc);
f3097647
MV
2283
2284 return true;
2285}
2286 /*}}}*/
448c38bd
DK
2287void pkgAcqIndexDiffs::Done(string const &Message, HashStringList const &Hashes, /*{{{*/
2288 pkgAcquire::MethodConfig const * const Cnf)
27e6c17a 2289{
448c38bd
DK
2290 if(Debug)
2291 std::clog << "pkgAcqIndexDiffs::Done(): " << Desc.URI << std::endl;
27e6c17a 2292
448c38bd 2293 Item::Done(Message, Hashes, Cnf);
27e6c17a 2294
d7a51997 2295 std::string const FinalFile = GetKeepCompressedFileName(GetPartialFileNameFromURI(Target.URI), Target);
36795154 2296 std::string const PatchFile = GetDiffsPatchFileName(FinalFile);
b3d44315 2297
448c38bd
DK
2298 // success in downloading a diff, enter ApplyDiff state
2299 if(State == StateFetchDiff)
b3d44315 2300 {
36795154 2301 Rename(DestFile, PatchFile);
448c38bd
DK
2302
2303 if(Debug)
2304 std::clog << "Sending to rred method: " << FinalFile << std::endl;
2305
2306 State = StateApplyDiff;
2307 Local = true;
2308 Desc.URI = "rred:" + FinalFile;
2309 QueueURI(Desc);
2310 SetActiveSubprocess("rred");
2311 return;
36795154 2312 }
448c38bd
DK
2313
2314 // success in download/apply a diff, queue next (if needed)
2315 if(State == StateApplyDiff)
8eafc759 2316 {
448c38bd
DK
2317 // remove the just applied patch
2318 available_patches.erase(available_patches.begin());
51818f26 2319 RemoveFile("pkgAcqIndexDiffs::Done", PatchFile);
448c38bd
DK
2320
2321 // move into place
36795154 2322 if(Debug)
8eafc759 2323 {
448c38bd
DK
2324 std::clog << "Moving patched file in place: " << std::endl
2325 << DestFile << " -> " << FinalFile << std::endl;
8eafc759 2326 }
448c38bd
DK
2327 Rename(DestFile,FinalFile);
2328 chmod(FinalFile.c_str(),0644);
8eafc759 2329
448c38bd
DK
2330 // see if there is more to download
2331 if(available_patches.empty() == false) {
2332 new pkgAcqIndexDiffs(Owner, TransactionManager, Target,
2333 available_patches);
2334 return Finish();
2335 } else
2336 // update
2337 DestFile = FinalFile;
2338 return Finish(true);
ba6b79bd 2339 }
448c38bd
DK
2340}
2341 /*}}}*/
36795154
DK
2342std::string pkgAcqIndexDiffs::Custom600Headers() const /*{{{*/
2343{
2344 if(State != StateApplyDiff)
2345 return pkgAcqBaseIndex::Custom600Headers();
2346 std::ostringstream patchhashes;
2347 HashStringList const ExpectedHashes = available_patches[0].patch_hashes;
2348 for (HashStringList::const_iterator hs = ExpectedHashes.begin(); hs != ExpectedHashes.end(); ++hs)
2349 patchhashes << "\nPatch-0-" << hs->HashType() << "-Hash: " << hs->HashValue();
2350 patchhashes << pkgAcqBaseIndex::Custom600Headers();
2351 return patchhashes.str();
2352}
2353 /*}}}*/
c8a4ce6c 2354pkgAcqIndexDiffs::~pkgAcqIndexDiffs() {}
448c38bd
DK
2355
2356// AcqIndexMergeDiffs::AcqIndexMergeDiffs - Constructor /*{{{*/
2357pkgAcqIndexMergeDiffs::pkgAcqIndexMergeDiffs(pkgAcquire * const Owner,
3d8232bf 2358 pkgAcqMetaClearSig * const TransactionManager,
e8afd168 2359 IndexTarget const &Target,
448c38bd
DK
2360 DiffInfo const &patch,
2361 std::vector<pkgAcqIndexMergeDiffs*> const * const allPatches)
6c55f07a 2362 : pkgAcqBaseIndex(Owner, TransactionManager, Target), d(NULL),
448c38bd
DK
2363 patch(patch), allPatches(allPatches), State(StateFetchDiff)
2364{
2365 Debug = _config->FindB("Debug::pkgAcquire::Diffs",false);
2366
2367 Desc.Owner = this;
dcbbb14d
DK
2368 Description = Target.Description;
2369 Desc.ShortDesc = Target.ShortDesc;
448c38bd 2370
dcbbb14d 2371 Desc.URI = Target.URI + ".diff/" + patch.file + ".gz";
448c38bd
DK
2372 Desc.Description = Description + " " + patch.file + string(".pdiff");
2373
d7a51997 2374 DestFile = GetKeepCompressedFileName(GetPartialFileNameFromURI(Target.URI + ".diff/" + patch.file), Target);
448c38bd
DK
2375
2376 if(Debug)
2377 std::clog << "pkgAcqIndexMergeDiffs: " << Desc.URI << std::endl;
2378
2379 QueueURI(Desc);
2380}
2381 /*}}}*/
2382void pkgAcqIndexMergeDiffs::Failed(string const &Message,pkgAcquire::MethodConfig const * const Cnf)/*{{{*/
2383{
2384 if(Debug)
2385 std::clog << "pkgAcqIndexMergeDiffs failed: " << Desc.URI << " with " << Message << std::endl;
2737f28a 2386
448c38bd
DK
2387 Item::Failed(Message,Cnf);
2388 Status = StatDone;
b3d44315 2389
448c38bd
DK
2390 // check if we are the first to fail, otherwise we are done here
2391 State = StateDoneDiff;
2392 for (std::vector<pkgAcqIndexMergeDiffs *>::const_iterator I = allPatches->begin();
2393 I != allPatches->end(); ++I)
2394 if ((*I)->State == StateErrorDiff)
2395 return;
2396
2397 // first failure means we should fallback
2398 State = StateErrorDiff;
2399 if (Debug)
2400 std::clog << "Falling back to normal index file acquire" << std::endl;
d7a51997 2401 DestFile = GetKeepCompressedFileName(GetPartialFileNameFromURI(Target.URI), Target);
448c38bd 2402 RenameOnError(PDiffError);
36795154
DK
2403 std::string const patchname = GetMergeDiffsPatchFileName(DestFile, patch.file);
2404 if (RealFileExists(patchname))
2405 rename(patchname.c_str(), std::string(patchname + ".FAILED").c_str());
448c38bd 2406 new pkgAcqIndex(Owner, TransactionManager, Target);
d7a51997 2407 DestFile.clear();
b3d44315 2408}
92fcbfc1 2409 /*}}}*/
448c38bd
DK
2410void pkgAcqIndexMergeDiffs::Done(string const &Message, HashStringList const &Hashes, /*{{{*/
2411 pkgAcquire::MethodConfig const * const Cnf)
b3d44315 2412{
448c38bd
DK
2413 if(Debug)
2414 std::clog << "pkgAcqIndexMergeDiffs::Done(): " << Desc.URI << std::endl;
18593cf7 2415
448c38bd 2416 Item::Done(Message, Hashes, Cnf);
18593cf7 2417
d7a51997
DK
2418 std::string const UncompressedFinalFile = GetPartialFileNameFromURI(Target.URI);
2419 std::string const FinalFile = GetKeepCompressedFileName(GetPartialFileNameFromURI(Target.URI), Target);
448c38bd
DK
2420 if (State == StateFetchDiff)
2421 {
36795154 2422 Rename(DestFile, GetMergeDiffsPatchFileName(FinalFile, patch.file));
448c38bd
DK
2423
2424 // check if this is the last completed diff
2425 State = StateDoneDiff;
2426 for (std::vector<pkgAcqIndexMergeDiffs *>::const_iterator I = allPatches->begin();
2427 I != allPatches->end(); ++I)
2428 if ((*I)->State != StateDoneDiff)
2429 {
2430 if(Debug)
2431 std::clog << "Not the last done diff in the batch: " << Desc.URI << std::endl;
2432 return;
2433 }
2434
2435 // this is the last completed diff, so we are ready to apply now
2436 State = StateApplyDiff;
ab53c018 2437
d7a51997 2438 if (BootstrapPDiffWith(UncompressedFinalFile, GetFinalFilename(), Target) == false)
448c38bd 2439 {
d7a51997 2440 Failed("Bootstrapping of " + DestFile + " failed", NULL);
448c38bd 2441 return;
18593cf7 2442 }
448c38bd
DK
2443
2444 if(Debug)
2445 std::clog << "Sending to rred method: " << FinalFile << std::endl;
2446
2447 Local = true;
2448 Desc.URI = "rred:" + FinalFile;
2449 QueueURI(Desc);
2450 SetActiveSubprocess("rred");
2451 return;
2452 }
2453 // success in download/apply all diffs, clean up
2454 else if (State == StateApplyDiff)
2455 {
2456 // move the result into place
d7a51997 2457 std::string const Final = GetKeepCompressedFileName(GetFinalFilename(), Target);
448c38bd
DK
2458 if(Debug)
2459 std::clog << "Queue patched file in place: " << std::endl
2460 << DestFile << " -> " << Final << std::endl;
2461
2462 // queue for copy by the transaction manager
2463 TransactionManager->TransactionStageCopy(this, DestFile, Final);
2464
2465 // ensure the ed's are gone regardless of list-cleanup
2466 for (std::vector<pkgAcqIndexMergeDiffs *>::const_iterator I = allPatches->begin();
2467 I != allPatches->end(); ++I)
ab53c018 2468 {
d7a51997 2469 std::string const PartialFile = GetKeepCompressedFileName(GetPartialFileNameFromURI(Target.URI), Target);
36795154 2470 std::string const patch = GetMergeDiffsPatchFileName(PartialFile, (*I)->patch.file);
51818f26 2471 RemoveFile("pkgAcqIndexMergeDiffs::Done", patch);
b3d44315 2472 }
51818f26 2473 RemoveFile("pkgAcqIndexMergeDiffs::Done", FinalFile);
e1430400 2474
448c38bd
DK
2475 // all set and done
2476 Complete = true;
2477 if(Debug)
2478 std::clog << "allDone: " << DestFile << "\n" << std::endl;
b3d44315
MV
2479 }
2480}
92fcbfc1 2481 /*}}}*/
36795154
DK
2482std::string pkgAcqIndexMergeDiffs::Custom600Headers() const /*{{{*/
2483{
2484 if(State != StateApplyDiff)
2485 return pkgAcqBaseIndex::Custom600Headers();
2486 std::ostringstream patchhashes;
2487 unsigned int seen_patches = 0;
2488 for (std::vector<pkgAcqIndexMergeDiffs *>::const_iterator I = allPatches->begin();
2489 I != allPatches->end(); ++I)
2490 {
2491 HashStringList const ExpectedHashes = (*I)->patch.patch_hashes;
2492 for (HashStringList::const_iterator hs = ExpectedHashes.begin(); hs != ExpectedHashes.end(); ++hs)
2493 patchhashes << "\nPatch-" << seen_patches << "-" << hs->HashType() << "-Hash: " << hs->HashValue();
2494 ++seen_patches;
2495 }
2496 patchhashes << pkgAcqBaseIndex::Custom600Headers();
2497 return patchhashes.str();
2498}
2499 /*}}}*/
c8a4ce6c 2500pkgAcqIndexMergeDiffs::~pkgAcqIndexMergeDiffs() {}
448c38bd
DK
2501
2502// AcqIndex::AcqIndex - Constructor /*{{{*/
2503pkgAcqIndex::pkgAcqIndex(pkgAcquire * const Owner,
3d8232bf 2504 pkgAcqMetaClearSig * const TransactionManager,
e8afd168 2505 IndexTarget const &Target)
d7a51997
DK
2506 : pkgAcqBaseIndex(Owner, TransactionManager, Target), d(NULL), Stage(STAGE_DOWNLOAD),
2507 CompressionExtensions(Target.Option(IndexTarget::COMPRESSIONTYPES))
b3d44315 2508{
dcbbb14d 2509 Init(Target.URI, Target.Description, Target.ShortDesc);
ce424cd4 2510
448c38bd
DK
2511 if(_config->FindB("Debug::Acquire::Transaction", false) == true)
2512 std::clog << "New pkgIndex with TransactionManager "
2513 << TransactionManager << std::endl;
2514}
2515 /*}}}*/
448c38bd 2516// AcqIndex::Init - defered Constructor /*{{{*/
af81ab90 2517static void NextCompressionExtension(std::string &CurrentCompressionExtension, std::string &CompressionExtensions, bool const preview)
448c38bd 2518{
448c38bd
DK
2519 size_t const nextExt = CompressionExtensions.find(' ');
2520 if (nextExt == std::string::npos)
b3d44315 2521 {
448c38bd 2522 CurrentCompressionExtension = CompressionExtensions;
af81ab90
DK
2523 if (preview == false)
2524 CompressionExtensions.clear();
b3d44315 2525 }
448c38bd
DK
2526 else
2527 {
2528 CurrentCompressionExtension = CompressionExtensions.substr(0, nextExt);
af81ab90
DK
2529 if (preview == false)
2530 CompressionExtensions = CompressionExtensions.substr(nextExt+1);
1ddb8596 2531 }
af81ab90
DK
2532}
2533void pkgAcqIndex::Init(string const &URI, string const &URIDesc,
2534 string const &ShortDesc)
2535{
2536 Stage = STAGE_DOWNLOAD;
2537
2538 DestFile = GetPartialFileNameFromURI(URI);
2539 NextCompressionExtension(CurrentCompressionExtension, CompressionExtensions, false);
1ddb8596 2540
448c38bd 2541 if (CurrentCompressionExtension == "uncompressed")
6bf93605 2542 {
448c38bd 2543 Desc.URI = URI;
6bf93605 2544 }
af81ab90
DK
2545 else if (CurrentCompressionExtension == "by-hash")
2546 {
2547 NextCompressionExtension(CurrentCompressionExtension, CompressionExtensions, true);
2548 if(unlikely(TransactionManager->MetaIndexParser == NULL || CurrentCompressionExtension.empty()))
2549 return;
2550 if (CurrentCompressionExtension != "uncompressed")
2551 {
2552 Desc.URI = URI + '.' + CurrentCompressionExtension;
2553 DestFile = DestFile + '.' + CurrentCompressionExtension;
2554 }
2555
2556 HashStringList const Hashes = GetExpectedHashes();
2557 HashString const * const TargetHash = Hashes.find(NULL);
2558 if (unlikely(TargetHash == nullptr))
2559 return;
2560 std::string const ByHash = "/by-hash/" + TargetHash->HashType() + "/" + TargetHash->HashValue();
2561 size_t const trailing_slash = Desc.URI.find_last_of("/");
2562 if (unlikely(trailing_slash == std::string::npos))
2563 return;
2564 Desc.URI = Desc.URI.replace(
2565 trailing_slash,
2566 Desc.URI.substr(trailing_slash+1).size()+1,
2567 ByHash);
2568 }
448c38bd
DK
2569 else if (unlikely(CurrentCompressionExtension.empty()))
2570 return;
2571 else
b3d44315 2572 {
448c38bd
DK
2573 Desc.URI = URI + '.' + CurrentCompressionExtension;
2574 DestFile = DestFile + '.' + CurrentCompressionExtension;
b3d44315
MV
2575 }
2576
448c38bd
DK
2577
2578 Desc.Description = URIDesc;
2579 Desc.Owner = this;
2580 Desc.ShortDesc = ShortDesc;
2581
2582 QueueURI(Desc);
2583}
2584 /*}}}*/
448c38bd
DK
2585// AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
2586// ---------------------------------------------------------------------
2587/* The only header we use is the last-modified header. */
2588string pkgAcqIndex::Custom600Headers() const
b3d44315 2589{
c5fced38 2590
448c38bd 2591 string msg = "\nIndex-File: true";
abd6af5a
DK
2592
2593 if (TransactionManager->LastMetaIndexParser == NULL)
2594 {
2595 std::string const Final = GetFinalFilename();
2596
2597 struct stat Buf;
2598 if (stat(Final.c_str(),&Buf) == 0)
2599 msg += "\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
2600 }
1d970e6c 2601
dcbbb14d 2602 if(Target.IsOptional)
448c38bd
DK
2603 msg += "\nFail-Ignore: true";
2604
2605 return msg;
b3d44315 2606}
681d76d0 2607 /*}}}*/
448c38bd
DK
2608// AcqIndex::Failed - getting the indexfile failed /*{{{*/
2609void pkgAcqIndex::Failed(string const &Message,pkgAcquire::MethodConfig const * const Cnf)
56472095 2610{
448c38bd
DK
2611 Item::Failed(Message,Cnf);
2612
2613 // authorisation matches will not be fixed by other compression types
2614 if (Status != StatAuthError)
2615 {
2616 if (CompressionExtensions.empty() == false)
2617 {
dcbbb14d 2618 Init(Target.URI, Desc.Description, Desc.ShortDesc);
448c38bd
DK
2619 Status = StatIdle;
2620 return;
2621 }
2622 }
2623
dcbbb14d 2624 if(Target.IsOptional && GetExpectedHashes().empty() && Stage == STAGE_DOWNLOAD)
448c38bd
DK
2625 Status = StatDone;
2626 else
2627 TransactionManager->AbortTransaction();
56472095 2628}
8267fbd9 2629 /*}}}*/
448c38bd
DK
2630// AcqIndex::ReverifyAfterIMS - Reverify index after an ims-hit /*{{{*/
2631void pkgAcqIndex::ReverifyAfterIMS()
fe0f7911 2632{
448c38bd
DK
2633 // update destfile to *not* include the compression extension when doing
2634 // a reverify (as its uncompressed on disk already)
653ef26c 2635 DestFile = GetCompressedFileName(Target, GetPartialFileNameFromURI(Target.URI), CurrentCompressionExtension);
448c38bd
DK
2636
2637 // copy FinalFile into partial/ so that we check the hash again
2638 string FinalFile = GetFinalFilename();
2639 Stage = STAGE_DECOMPRESS_AND_VERIFY;
2640 Desc.URI = "copy:" + FinalFile;
2641 QueueURI(Desc);
fe0f7911
DK
2642}
2643 /*}}}*/
448c38bd
DK
2644// AcqIndex::Done - Finished a fetch /*{{{*/
2645// ---------------------------------------------------------------------
2646/* This goes through a number of states.. On the initial fetch the
2647 method could possibly return an alternate filename which points
2648 to the uncompressed version of the file. If this is so the file
2649 is copied into the partial directory. In all other cases the file
2650 is decompressed with a compressed uri. */
2651void pkgAcqIndex::Done(string const &Message,
2652 HashStringList const &Hashes,
2653 pkgAcquire::MethodConfig const * const Cfg)
8d6c5839 2654{
448c38bd
DK
2655 Item::Done(Message,Hashes,Cfg);
2656
2657 switch(Stage)
2658 {
2659 case STAGE_DOWNLOAD:
2660 StageDownloadDone(Message, Hashes, Cfg);
2661 break;
2662 case STAGE_DECOMPRESS_AND_VERIFY:
2663 StageDecompressDone(Message, Hashes, Cfg);
2664 break;
2665 }
8d6c5839
MV
2666}
2667 /*}}}*/
448c38bd
DK
2668// AcqIndex::StageDownloadDone - Queue for decompress and verify /*{{{*/
2669void pkgAcqIndex::StageDownloadDone(string const &Message, HashStringList const &,
2670 pkgAcquire::MethodConfig const * const)
6bf93605 2671{
448c38bd 2672 Complete = true;
6bf93605 2673
448c38bd 2674 // Handle the unzipd case
dd676dc7 2675 std::string FileName = LookupTag(Message,"Alt-Filename");
448c38bd 2676 if (FileName.empty() == false)
6bf93605 2677 {
448c38bd
DK
2678 Stage = STAGE_DECOMPRESS_AND_VERIFY;
2679 Local = true;
2680 DestFile += ".decomp";
2681 Desc.URI = "copy:" + FileName;
2682 QueueURI(Desc);
2683 SetActiveSubprocess("copy");
2684 return;
6bf93605 2685 }
448c38bd 2686 FileName = LookupTag(Message,"Filename");
f3097647 2687
448c38bd
DK
2688 // Methods like e.g. "file:" will give us a (compressed) FileName that is
2689 // not the "DestFile" we set, in this case we uncompress from the local file
08ea7806 2690 if (FileName != DestFile && RealFileExists(DestFile) == false)
af9e40c9 2691 {
448c38bd 2692 Local = true;
af9e40c9
DK
2693 if (Target.KeepCompressed == true)
2694 {
2695 // but if we don't keep the uncompress we copy the compressed file first
2696 Stage = STAGE_DOWNLOAD;
2697 Desc.URI = "copy:" + FileName;
2698 QueueURI(Desc);
2699 SetActiveSubprocess("copy");
2700 return;
2701 }
2702 }
448c38bd
DK
2703 else
2704 EraseFileName = FileName;
2705
2706 // we need to verify the file against the current Release file again
2707 // on if-modfied-since hit to avoid a stale attack against us
2708 if(StringToBool(LookupTag(Message,"IMS-Hit"),false) == true)
f3097647 2709 {
448c38bd
DK
2710 // The files timestamp matches, reverify by copy into partial/
2711 EraseFileName = "";
2712 ReverifyAfterIMS();
f3097647
MV
2713 return;
2714 }
448c38bd 2715
448c38bd
DK
2716 // get the binary name for your used compression type
2717 string decompProg;
2718 if(CurrentCompressionExtension == "uncompressed")
2719 decompProg = "copy";
2720 else
2721 decompProg = _config->Find(string("Acquire::CompressionTypes::").append(CurrentCompressionExtension),"");
2722 if(decompProg.empty() == true)
2723 {
2724 _error->Error("Unsupported extension: %s", CurrentCompressionExtension.c_str());
2725 return;
6bf93605 2726 }
448c38bd 2727
af9e40c9
DK
2728 if (Target.KeepCompressed == true)
2729 {
2730 DestFile = "/dev/null";
2731 EraseFileName.clear();
2732 }
2733 else
2734 DestFile += ".decomp";
2735
448c38bd
DK
2736 // queue uri for the next stage
2737 Stage = STAGE_DECOMPRESS_AND_VERIFY;
448c38bd
DK
2738 Desc.URI = decompProg + ":" + FileName;
2739 QueueURI(Desc);
2740 SetActiveSubprocess(decompProg);
a9bb651a
MV
2741}
2742 /*}}}*/
448c38bd 2743// AcqIndex::StageDecompressDone - Final verification /*{{{*/
4cd86fc6 2744void pkgAcqIndex::StageDecompressDone(string const &,
448c38bd 2745 HashStringList const &,
4cd86fc6 2746 pkgAcquire::MethodConfig const * const)
a9bb651a 2747{
af9e40c9
DK
2748 if (Target.KeepCompressed == true && DestFile == "/dev/null")
2749 DestFile = GetPartialFileNameFromURI(Target.URI + '.' + CurrentCompressionExtension);
2750
448c38bd
DK
2751 // Done, queue for rename on transaction finished
2752 TransactionManager->TransactionStageCopy(this, DestFile, GetFinalFilename());
448c38bd 2753 return;
fe0f7911
DK
2754}
2755 /*}}}*/
c8a4ce6c 2756pkgAcqIndex::~pkgAcqIndex() {}
448c38bd
DK
2757
2758
03e39e59
AL
2759// AcqArchive::AcqArchive - Constructor /*{{{*/
2760// ---------------------------------------------------------------------
17caf1b1
AL
2761/* This just sets up the initial fetch environment and queues the first
2762 possibilitiy */
448c38bd
DK
2763pkgAcqArchive::pkgAcqArchive(pkgAcquire * const Owner,pkgSourceList * const Sources,
2764 pkgRecords * const Recs,pkgCache::VerIterator const &Version,
30e1eab5 2765 string &StoreFilename) :
6c55f07a 2766 Item(Owner), d(NULL), LocalSource(false), Version(Version), Sources(Sources), Recs(Recs),
448c38bd 2767 StoreFilename(StoreFilename), Vf(Version.FileList()),
b3d44315 2768 Trusted(false)
03e39e59 2769{
7d8afa39 2770 Retries = _config->FindI("Acquire::Retries",0);
813c8eea
AL
2771
2772 if (Version.Arch() == 0)
bdae53f1 2773 {
d1f1f6a8 2774 _error->Error(_("I wasn't able to locate a file for the %s package. "
7a3c2ab0
AL
2775 "This might mean you need to manually fix this package. "
2776 "(due to missing arch)"),
40f8a8ba 2777 Version.ParentPkg().FullName().c_str());
bdae53f1
AL
2778 return;
2779 }
813c8eea 2780
b2e465d6
AL
2781 /* We need to find a filename to determine the extension. We make the
2782 assumption here that all the available sources for this version share
2783 the same extension.. */
2784 // Skip not source sources, they do not have file fields.
69c2ecbd 2785 for (; Vf.end() == false; ++Vf)
b2e465d6 2786 {
b07aeb1a 2787 if (Vf.File().Flagged(pkgCache::Flag::NotSource))
b2e465d6
AL
2788 continue;
2789 break;
2790 }
2791
2792 // Does not really matter here.. we are going to fail out below
2793 if (Vf.end() != true)
2794 {
2795 // If this fails to get a file name we will bomb out below.
2796 pkgRecords::Parser &Parse = Recs->Lookup(Vf);
2797 if (_error->PendingError() == true)
2798 return;
2799
2800 // Generate the final file name as: package_version_arch.foo
2801 StoreFilename = QuoteString(Version.ParentPkg().Name(),"_:") + '_' +
2802 QuoteString(Version.VerStr(),"_:") + '_' +
2803 QuoteString(Version.Arch(),"_:.") +
2804 "." + flExtension(Parse.FileName());
2805 }
b3d44315
MV
2806
2807 // check if we have one trusted source for the package. if so, switch
6c34ccca
DK
2808 // to "TrustedOnly" mode - but only if not in AllowUnauthenticated mode
2809 bool const allowUnauth = _config->FindB("APT::Get::AllowUnauthenticated", false);
2810 bool const debugAuth = _config->FindB("Debug::pkgAcquire::Auth", false);
2811 bool seenUntrusted = false;
f7f0d6c7 2812 for (pkgCache::VerFileIterator i = Version.FileList(); i.end() == false; ++i)
b3d44315
MV
2813 {
2814 pkgIndexFile *Index;
2815 if (Sources->FindIndex(i.File(),Index) == false)
2816 continue;
6c34ccca
DK
2817
2818 if (debugAuth == true)
b3d44315 2819 std::cerr << "Checking index: " << Index->Describe()
6c34ccca
DK
2820 << "(Trusted=" << Index->IsTrusted() << ")" << std::endl;
2821
2822 if (Index->IsTrusted() == true)
2823 {
b3d44315 2824 Trusted = true;
6c34ccca
DK
2825 if (allowUnauth == false)
2826 break;
b3d44315 2827 }
6c34ccca
DK
2828 else
2829 seenUntrusted = true;
b3d44315
MV
2830 }
2831
a3371852
MV
2832 // "allow-unauthenticated" restores apts old fetching behaviour
2833 // that means that e.g. unauthenticated file:// uris are higher
2834 // priority than authenticated http:// uris
6c34ccca 2835 if (allowUnauth == true && seenUntrusted == true)
a3371852
MV
2836 Trusted = false;
2837
03e39e59 2838 // Select a source
b185acc2 2839 if (QueueNext() == false && _error->PendingError() == false)
d57f6084
DK
2840 _error->Error(_("Can't find a source to download version '%s' of '%s'"),
2841 Version.VerStr(), Version.ParentPkg().FullName(false).c_str());
b185acc2
AL
2842}
2843 /*}}}*/
2844// AcqArchive::QueueNext - Queue the next file source /*{{{*/
2845// ---------------------------------------------------------------------
17caf1b1
AL
2846/* This queues the next available file version for download. It checks if
2847 the archive is already available in the cache and stashs the MD5 for
2848 checking later. */
b185acc2 2849bool pkgAcqArchive::QueueNext()
a722b2c5 2850{
f7f0d6c7 2851 for (; Vf.end() == false; ++Vf)
03e39e59 2852 {
448c38bd 2853 pkgCache::PkgFileIterator const PkgF = Vf.File();
03e39e59 2854 // Ignore not source sources
b07aeb1a 2855 if (PkgF.Flagged(pkgCache::Flag::NotSource))
03e39e59
AL
2856 continue;
2857
2858 // Try to cross match against the source list
b2e465d6 2859 pkgIndexFile *Index;
448c38bd 2860 if (Sources->FindIndex(PkgF, Index) == false)
b2e465d6 2861 continue;
b07aeb1a 2862 LocalSource = PkgF.Flagged(pkgCache::Flag::LocalSource);
448c38bd 2863
b3d44315
MV
2864 // only try to get a trusted package from another source if that source
2865 // is also trusted
2866 if(Trusted && !Index->IsTrusted())
2867 continue;
2868
03e39e59
AL
2869 // Grab the text package record
2870 pkgRecords::Parser &Parse = Recs->Lookup(Vf);
2871 if (_error->PendingError() == true)
b185acc2 2872 return false;
b3501edb 2873
b2e465d6 2874 string PkgFile = Parse.FileName();
b3501edb
DK
2875 ExpectedHashes = Parse.Hashes();
2876
03e39e59 2877 if (PkgFile.empty() == true)
b2e465d6
AL
2878 return _error->Error(_("The package index files are corrupted. No Filename: "
2879 "field for package %s."),
2880 Version.ParentPkg().Name());
a6568219 2881
b3d44315
MV
2882 Desc.URI = Index->ArchiveURI(PkgFile);
2883 Desc.Description = Index->ArchiveInfo(Version);
2884 Desc.Owner = this;
40f8a8ba 2885 Desc.ShortDesc = Version.ParentPkg().FullName(true);
b3d44315 2886
17caf1b1 2887 // See if we already have the file. (Legacy filenames)
a6568219
AL
2888 FileSize = Version->Size;
2889 string FinalFile = _config->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile);
2890 struct stat Buf;
2891 if (stat(FinalFile.c_str(),&Buf) == 0)
2892 {
2893 // Make sure the size matches
73da43e9 2894 if ((unsigned long long)Buf.st_size == Version->Size)
a6568219
AL
2895 {
2896 Complete = true;
2897 Local = true;
2898 Status = StatDone;
30e1eab5 2899 StoreFilename = DestFile = FinalFile;
b185acc2 2900 return true;
a6568219
AL
2901 }
2902
6b1ff003
AL
2903 /* Hmm, we have a file and its size does not match, this means it is
2904 an old style mismatched arch */
51818f26 2905 RemoveFile("pkgAcqArchive::QueueNext", FinalFile);
a6568219 2906 }
17caf1b1
AL
2907
2908 // Check it again using the new style output filenames
2909 FinalFile = _config->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename);
2910 if (stat(FinalFile.c_str(),&Buf) == 0)
2911 {
2912 // Make sure the size matches
73da43e9 2913 if ((unsigned long long)Buf.st_size == Version->Size)
17caf1b1
AL
2914 {
2915 Complete = true;
2916 Local = true;
2917 Status = StatDone;
2918 StoreFilename = DestFile = FinalFile;
2919 return true;
2920 }
2921
1e3f4083 2922 /* Hmm, we have a file and its size does not match, this shouldn't
17caf1b1 2923 happen.. */
51818f26 2924 RemoveFile("pkgAcqArchive::QueueNext", FinalFile);
17caf1b1
AL
2925 }
2926
2927 DestFile = _config->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename);
6b1ff003
AL
2928
2929 // Check the destination file
2930 if (stat(DestFile.c_str(),&Buf) == 0)
2931 {
2932 // Hmm, the partial file is too big, erase it
73da43e9 2933 if ((unsigned long long)Buf.st_size > Version->Size)
51818f26 2934 RemoveFile("pkgAcqArchive::QueueNext", DestFile);
6b1ff003
AL
2935 else
2936 PartialSize = Buf.st_size;
2937 }
de31189f
DK
2938
2939 // Disables download of archives - useful if no real installation follows,
2940 // e.g. if we are just interested in proposed installation order
2941 if (_config->FindB("Debug::pkgAcqArchive::NoQueue", false) == true)
2942 {
2943 Complete = true;
2944 Local = true;
2945 Status = StatDone;
2946 StoreFilename = DestFile = FinalFile;
2947 return true;
2948 }
2949
03e39e59 2950 // Create the item
b2e465d6 2951 Local = false;
03e39e59 2952 QueueURI(Desc);
b185acc2 2953
f7f0d6c7 2954 ++Vf;
b185acc2 2955 return true;
03e39e59 2956 }
b185acc2
AL
2957 return false;
2958}
03e39e59
AL
2959 /*}}}*/
2960// AcqArchive::Done - Finished fetching /*{{{*/
2961// ---------------------------------------------------------------------
2962/* */
448c38bd
DK
2963void pkgAcqArchive::Done(string const &Message, HashStringList const &Hashes,
2964 pkgAcquire::MethodConfig const * const Cfg)
03e39e59 2965{
448c38bd 2966 Item::Done(Message, Hashes, Cfg);
a6568219
AL
2967
2968 // Grab the output filename
dd676dc7 2969 std::string const FileName = LookupTag(Message,"Filename");
08ea7806 2970 if (DestFile != FileName && RealFileExists(DestFile) == false)
a6568219 2971 {
30e1eab5 2972 StoreFilename = DestFile = FileName;
a6568219 2973 Local = true;
5684f71f 2974 Complete = true;
a6568219
AL
2975 return;
2976 }
5684f71f 2977
a6568219 2978 // Done, move it into position
295d848b 2979 string const FinalFile = GetFinalFilename();
a6568219 2980 Rename(DestFile,FinalFile);
30e1eab5 2981 StoreFilename = DestFile = FinalFile;
03e39e59
AL
2982 Complete = true;
2983}
2984 /*}}}*/
db890fdb
AL
2985// AcqArchive::Failed - Failure handler /*{{{*/
2986// ---------------------------------------------------------------------
2987/* Here we try other sources */
448c38bd 2988void pkgAcqArchive::Failed(string const &Message,pkgAcquire::MethodConfig const * const Cnf)
db890fdb 2989{
03aa0847
DK
2990 Item::Failed(Message,Cnf);
2991
448c38bd 2992 /* We don't really want to retry on failed media swaps, this prevents
b2e465d6
AL
2993 that. An interesting observation is that permanent failures are not
2994 recorded. */
448c38bd 2995 if (Cnf->Removable == true &&
b2e465d6
AL
2996 StringToBool(LookupTag(Message,"Transient-Failure"),false) == true)
2997 {
2998 // Vf = Version.FileList();
f7f0d6c7 2999 while (Vf.end() == false) ++Vf;
b2e465d6 3000 StoreFilename = string();
b2e465d6
AL
3001 return;
3002 }
03aa0847
DK
3003
3004 Status = StatIdle;
db890fdb 3005 if (QueueNext() == false)
7d8afa39
AL
3006 {
3007 // This is the retry counter
3008 if (Retries != 0 &&
3009 Cnf->LocalOnly == false &&
3010 StringToBool(LookupTag(Message,"Transient-Failure"),false) == true)
3011 {
3012 Retries--;
3013 Vf = Version.FileList();
3014 if (QueueNext() == true)
3015 return;
3016 }
03aa0847 3017
9dbb421f 3018 StoreFilename = string();
03aa0847 3019 Status = StatError;
7d8afa39 3020 }
db890fdb
AL
3021}
3022 /*}}}*/
448c38bd 3023APT_PURE bool pkgAcqArchive::IsTrusted() const /*{{{*/
b3d44315
MV
3024{
3025 return Trusted;
3026}
92fcbfc1 3027 /*}}}*/
448c38bd 3028void pkgAcqArchive::Finished() /*{{{*/
ab559b35
AL
3029{
3030 if (Status == pkgAcquire::Item::StatDone &&
3031 Complete == true)
3032 return;
3033 StoreFilename = string();
3034}
3035 /*}}}*/
448c38bd
DK
3036std::string pkgAcqArchive::DescURI() const /*{{{*/
3037{
3038 return Desc.URI;
3039}
3040 /*}}}*/
3041std::string pkgAcqArchive::ShortDesc() const /*{{{*/
3042{
3043 return Desc.ShortDesc;
3044}
3045 /*}}}*/
c8a4ce6c 3046pkgAcqArchive::~pkgAcqArchive() {}
448c38bd 3047
d56e2917
DK
3048// AcqChangelog::pkgAcqChangelog - Constructors /*{{{*/
3049pkgAcqChangelog::pkgAcqChangelog(pkgAcquire * const Owner, pkgCache::VerIterator const &Ver,
3050 std::string const &DestDir, std::string const &DestFilename) :
3051 pkgAcquire::Item(Owner), d(NULL), SrcName(Ver.SourcePkgName()), SrcVersion(Ver.SourceVerStr())
3052{
3053 Desc.URI = URI(Ver);
3054 Init(DestDir, DestFilename);
3055}
3056// some parameters are char* here as they come likely from char* interfaces – which can also return NULL
3057pkgAcqChangelog::pkgAcqChangelog(pkgAcquire * const Owner, pkgCache::RlsFileIterator const &RlsFile,
3058 char const * const Component, char const * const SrcName, char const * const SrcVersion,
3059 const string &DestDir, const string &DestFilename) :
3060 pkgAcquire::Item(Owner), d(NULL), SrcName(SrcName), SrcVersion(SrcVersion)
3061{
3062 Desc.URI = URI(RlsFile, Component, SrcName, SrcVersion);
3063 Init(DestDir, DestFilename);
3064}
3065pkgAcqChangelog::pkgAcqChangelog(pkgAcquire * const Owner,
3066 std::string const &URI, char const * const SrcName, char const * const SrcVersion,
3067 const string &DestDir, const string &DestFilename) :
3068 pkgAcquire::Item(Owner), d(NULL), SrcName(SrcName), SrcVersion(SrcVersion)
3069{
3070 Desc.URI = URI;
3071 Init(DestDir, DestFilename);
3072}
3073void pkgAcqChangelog::Init(std::string const &DestDir, std::string const &DestFilename)
3074{
3075 if (Desc.URI.empty())
3076 {
3077 Status = StatError;
3078 // TRANSLATOR: %s=%s is sourcename=sourceversion, e.g. apt=1.1
3079 strprintf(ErrorText, _("Changelog unavailable for %s=%s"), SrcName.c_str(), SrcVersion.c_str());
3080 // Let the error message print something sensible rather than "Failed to fetch /"
3081 if (DestFilename.empty())
3082 DestFile = SrcName + ".changelog";
3083 else
3084 DestFile = DestFilename;
3085 Desc.URI = "changelog:/" + DestFile;
3086 return;
3087 }
3088
3089 if (DestDir.empty())
3090 {
dd6da7d2
DK
3091 std::string const SandboxUser = _config->Find("APT::Sandbox::User");
3092 std::string const systemTemp = GetTempDir(SandboxUser);
d56e2917
DK
3093 char tmpname[100];
3094 snprintf(tmpname, sizeof(tmpname), "%s/apt-changelog-XXXXXX", systemTemp.c_str());
3095 if (NULL == mkdtemp(tmpname))
3096 {
3097 _error->Errno("mkdtemp", "mkdtemp failed in changelog acquire of %s %s", SrcName.c_str(), SrcVersion.c_str());
3098 Status = StatError;
3099 return;
3100 }
3101 DestFile = TemporaryDirectory = tmpname;
d1256170 3102
d1256170
DK
3103 ChangeOwnerAndPermissionOfFile("Item::QueueURI", DestFile.c_str(),
3104 SandboxUser.c_str(), "root", 0700);
d56e2917
DK
3105 }
3106 else
3107 DestFile = DestDir;
3108
3109 if (DestFilename.empty())
3110 DestFile = flCombine(DestFile, SrcName + ".changelog");
3111 else
3112 DestFile = flCombine(DestFile, DestFilename);
3113
3114 Desc.ShortDesc = "Changelog";
3115 strprintf(Desc.Description, "%s %s %s Changelog", URI::SiteOnly(Desc.URI).c_str(), SrcName.c_str(), SrcVersion.c_str());
3116 Desc.Owner = this;
3117 QueueURI(Desc);
d56e2917
DK
3118}
3119 /*}}}*/
3120std::string pkgAcqChangelog::URI(pkgCache::VerIterator const &Ver) /*{{{*/
3121{
3122 char const * const SrcName = Ver.SourcePkgName();
3123 char const * const SrcVersion = Ver.SourceVerStr();
3124 pkgCache::PkgFileIterator PkgFile;
3125 // find the first source for this version which promises a changelog
3126 for (pkgCache::VerFileIterator VF = Ver.FileList(); VF.end() == false; ++VF)
3127 {
3128 pkgCache::PkgFileIterator const PF = VF.File();
3129 if (PF.Flagged(pkgCache::Flag::NotSource) || PF->Release == 0)
3130 continue;
3131 PkgFile = PF;
3132 pkgCache::RlsFileIterator const RF = PF.ReleaseFile();
3133 std::string const uri = URI(RF, PF.Component(), SrcName, SrcVersion);
3134 if (uri.empty())
3135 continue;
3136 return uri;
3137 }
3138 return "";
3139}
3140std::string pkgAcqChangelog::URITemplate(pkgCache::RlsFileIterator const &Rls)
3141{
3142 if (Rls.end() == true || (Rls->Label == 0 && Rls->Origin == 0))
3143 return "";
3144 std::string const serverConfig = "Acquire::Changelogs::URI";
3145 std::string server;
3146#define APT_EMPTY_SERVER \
3147 if (server.empty() == false) \
3148 { \
3149 if (server != "no") \
3150 return server; \
3151 return ""; \
3152 }
3153#define APT_CHECK_SERVER(X, Y) \
3154 if (Rls->X != 0) \
3155 { \
3156 std::string const specialServerConfig = serverConfig + "::" + Y + #X + "::" + Rls.X(); \
3157 server = _config->Find(specialServerConfig); \
3158 APT_EMPTY_SERVER \
3159 }
3160 // this way e.g. Debian-Security can fallback to Debian
3161 APT_CHECK_SERVER(Label, "Override::")
3162 APT_CHECK_SERVER(Origin, "Override::")
3163
3164 if (RealFileExists(Rls.FileName()))
3165 {
3166 _error->PushToStack();
3167 FileFd rf;
3168 /* This can be costly. A caller wanting to get millions of URIs might
3169 want to do this on its own once and use Override settings.
3170 We don't do this here as Origin/Label are not as unique as they
3171 should be so this could produce request order-dependent anomalies */
3172 if (OpenMaybeClearSignedFile(Rls.FileName(), rf) == true)
3173 {
3174 pkgTagFile TagFile(&rf, rf.Size());
3175 pkgTagSection Section;
3176 if (TagFile.Step(Section) == true)
3177 server = Section.FindS("Changelogs");
3178 }
3179 _error->RevertToStack();
3180 APT_EMPTY_SERVER
3181 }
3182
3183 APT_CHECK_SERVER(Label, "")
3184 APT_CHECK_SERVER(Origin, "")
3185#undef APT_CHECK_SERVER
3186#undef APT_EMPTY_SERVER
3187 return "";
3188}
3189std::string pkgAcqChangelog::URI(pkgCache::RlsFileIterator const &Rls,
3190 char const * const Component, char const * const SrcName,
3191 char const * const SrcVersion)
3192{
3193 return URI(URITemplate(Rls), Component, SrcName, SrcVersion);
3194}
3195std::string pkgAcqChangelog::URI(std::string const &Template,
3196 char const * const Component, char const * const SrcName,
3197 char const * const SrcVersion)
3198{
430481e7 3199 if (Template.find("@CHANGEPATH@") == std::string::npos)
d56e2917
DK
3200 return "";
3201
3202 // the path is: COMPONENT/SRC/SRCNAME/SRCNAME_SRCVER, e.g. main/a/apt/1.1 or contrib/liba/libapt/2.0
3203 std::string Src = SrcName;
3204 std::string path = APT::String::Startswith(SrcName, "lib") ? Src.substr(0, 4) : Src.substr(0,1);
3205 path.append("/").append(Src).append("/");
3206 path.append(Src).append("_").append(StripEpoch(SrcVersion));
3207 // we omit component for releases without one (= flat-style repositories)
3208 if (Component != NULL && strlen(Component) != 0)
3209 path = std::string(Component) + "/" + path;
3210
430481e7 3211 return SubstVar(Template, "@CHANGEPATH@", path);
d56e2917
DK
3212}
3213 /*}}}*/
3214// AcqChangelog::Failed - Failure handler /*{{{*/
3215void pkgAcqChangelog::Failed(string const &Message, pkgAcquire::MethodConfig const * const Cnf)
3216{
3217 Item::Failed(Message,Cnf);
3218
3219 std::string errText;
3220 // TRANSLATOR: %s=%s is sourcename=sourceversion, e.g. apt=1.1
3221 strprintf(errText, _("Changelog unavailable for %s=%s"), SrcName.c_str(), SrcVersion.c_str());
3222
3223 // Error is probably something techy like 404 Not Found
3224 if (ErrorText.empty())
3225 ErrorText = errText;
3226 else
3227 ErrorText = errText + " (" + ErrorText + ")";
3228 return;
3229}
3230 /*}}}*/
3231// AcqChangelog::Done - Item downloaded OK /*{{{*/
3232void pkgAcqChangelog::Done(string const &Message,HashStringList const &CalcHashes,
3233 pkgAcquire::MethodConfig const * const Cnf)
3234{
3235 Item::Done(Message,CalcHashes,Cnf);
3236
3237 Complete = true;
3238}
3239 /*}}}*/
3240pkgAcqChangelog::~pkgAcqChangelog() /*{{{*/
3241{
3242 if (TemporaryDirectory.empty() == false)
3243 {
51818f26 3244 RemoveFile("~pkgAcqChangelog", DestFile);
d56e2917
DK
3245 rmdir(TemporaryDirectory.c_str());
3246 }
3247}
3248 /*}}}*/
3249
36375005 3250// AcqFile::pkgAcqFile - Constructor /*{{{*/
448c38bd
DK
3251pkgAcqFile::pkgAcqFile(pkgAcquire * const Owner,string const &URI, HashStringList const &Hashes,
3252 unsigned long long const Size,string const &Dsc,string const &ShortDesc,
77278c2b 3253 const string &DestDir, const string &DestFilename,
448c38bd 3254 bool const IsIndexFile) :
6c55f07a 3255 Item(Owner), d(NULL), IsIndexFile(IsIndexFile), ExpectedHashes(Hashes)
36375005 3256{
08cfc005 3257 Retries = _config->FindI("Acquire::Retries",0);
448c38bd 3258
46e00f9d
MV
3259 if(!DestFilename.empty())
3260 DestFile = DestFilename;
3261 else if(!DestDir.empty())
3262 DestFile = DestDir + "/" + flNotDir(URI);
3263 else
3264 DestFile = flNotDir(URI);
3265
36375005
AL
3266 // Create the item
3267 Desc.URI = URI;
3268 Desc.Description = Dsc;
3269 Desc.Owner = this;
3270
3271 // Set the short description to the archive component
3272 Desc.ShortDesc = ShortDesc;
448c38bd 3273
36375005
AL
3274 // Get the transfer sizes
3275 FileSize = Size;
3276 struct stat Buf;
3277 if (stat(DestFile.c_str(),&Buf) == 0)
3278 {
3279 // Hmm, the partial file is too big, erase it
ed9665ae 3280 if ((Size > 0) && (unsigned long long)Buf.st_size > Size)
51818f26 3281 RemoveFile("pkgAcqFile", DestFile);
36375005
AL
3282 else
3283 PartialSize = Buf.st_size;
3284 }
092ae175 3285
36375005
AL
3286 QueueURI(Desc);
3287}
3288 /*}}}*/
3289// AcqFile::Done - Item downloaded OK /*{{{*/
448c38bd
DK
3290void pkgAcqFile::Done(string const &Message,HashStringList const &CalcHashes,
3291 pkgAcquire::MethodConfig const * const Cnf)
36375005 3292{
448c38bd 3293 Item::Done(Message,CalcHashes,Cnf);
495e5cb2 3294
dd676dc7 3295 std::string const FileName = LookupTag(Message,"Filename");
36375005 3296 Complete = true;
448c38bd 3297
36375005
AL
3298 // The files timestamp matches
3299 if (StringToBool(LookupTag(Message,"IMS-Hit"),false) == true)
3300 return;
448c38bd 3301
36375005 3302 // We have to copy it into place
08ea7806 3303 if (RealFileExists(DestFile.c_str()) == false)
36375005
AL
3304 {
3305 Local = true;
459681d3
AL
3306 if (_config->FindB("Acquire::Source-Symlinks",true) == false ||
3307 Cnf->Removable == true)
917ae805
AL
3308 {
3309 Desc.URI = "copy:" + FileName;
3310 QueueURI(Desc);
3311 return;
3312 }
448c38bd 3313
83ab33fc
AL
3314 // Erase the file if it is a symlink so we can overwrite it
3315 struct stat St;
3316 if (lstat(DestFile.c_str(),&St) == 0)
3317 {
3318 if (S_ISLNK(St.st_mode) != 0)
51818f26 3319 RemoveFile("pkgAcqFile::Done", DestFile);
83ab33fc 3320 }
448c38bd 3321
83ab33fc 3322 // Symlink the file
917ae805
AL
3323 if (symlink(FileName.c_str(),DestFile.c_str()) != 0)
3324 {
03aa0847
DK
3325 _error->PushToStack();
3326 _error->Errno("pkgAcqFile::Done", "Symlinking file %s failed", DestFile.c_str());
3327 std::stringstream msg;
95278287 3328 _error->DumpErrors(msg, GlobalError::DEBUG, false);
03aa0847
DK
3329 _error->RevertToStack();
3330 ErrorText = msg.str();
917ae805
AL
3331 Status = StatError;
3332 Complete = false;
448c38bd 3333 }
36375005
AL
3334 }
3335}
3336 /*}}}*/
08cfc005
AL
3337// AcqFile::Failed - Failure handler /*{{{*/
3338// ---------------------------------------------------------------------
3339/* Here we try other sources */
448c38bd 3340void pkgAcqFile::Failed(string const &Message, pkgAcquire::MethodConfig const * const Cnf)
08cfc005 3341{
03aa0847
DK
3342 Item::Failed(Message,Cnf);
3343
08cfc005
AL
3344 // This is the retry counter
3345 if (Retries != 0 &&
3346 Cnf->LocalOnly == false &&
3347 StringToBool(LookupTag(Message,"Transient-Failure"),false) == true)
3348 {
03aa0847 3349 --Retries;
08cfc005 3350 QueueURI(Desc);
03aa0847 3351 Status = StatIdle;
08cfc005
AL
3352 return;
3353 }
03aa0847 3354
08cfc005
AL
3355}
3356 /*}}}*/
448c38bd 3357string pkgAcqFile::Custom600Headers() const /*{{{*/
77278c2b
MV
3358{
3359 if (IsIndexFile)
3360 return "\nIndex-File: true";
61a07c57 3361 return "";
77278c2b
MV
3362}
3363 /*}}}*/
c8a4ce6c 3364pkgAcqFile::~pkgAcqFile() {}