]> git.saurik.com Git - apt.git/blame - apt-pkg/acquire-item.cc
debian/gbp.conf: point debian-branch to master
[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 }
1078
d7a51997
DK
1079 // autoselect the compression method
1080 std::vector<std::string> types = VectorizeString(Target->Option(IndexTarget::COMPRESSIONTYPES), ' ');
1081 types.erase(std::remove_if(types.begin(), types.end(), [&](std::string const &t) {
1082 if (t == "uncompressed")
1083 return TransactionManager->MetaIndexParser->Exists(Target->MetaKey) == false;
1084 std::string const MetaKey = Target->MetaKey + "." + t;
1085 return TransactionManager->MetaIndexParser->Exists(MetaKey) == false;
1086 }), types.end());
1087 if (types.empty() == false)
8d041b4f 1088 {
d7a51997 1089 std::ostringstream os;
af81ab90
DK
1090 // add the special compressiontype byhash first if supported
1091 std::string const useByHashConf = Target->Option(IndexTarget::BY_HASH);
1092 bool useByHash = false;
1093 if(useByHashConf == "force")
1094 useByHash = true;
1095 else
1096 useByHash = StringToBool(useByHashConf) == true && metaBaseSupportsByHash;
1097 if (useByHash == true)
1098 os << "by-hash ";
d7a51997
DK
1099 std::copy(types.begin(), types.end()-1, std::ostream_iterator<std::string>(os, " "));
1100 os << *types.rbegin();
1101 Target->Options["COMPRESSIONTYPES"] = os.str();
1102 }
1103 else
1104 Target->Options["COMPRESSIONTYPES"].clear();
1105
1106 std::string filename = GetFinalFileNameFromURI(Target->URI);
1107 if (RealFileExists(filename) == false)
1108 {
1109 if (Target->KeepCompressed)
8d041b4f 1110 {
d7a51997
DK
1111 filename = GetKeepCompressedFileName(filename, *Target);
1112 if (RealFileExists(filename) == false)
1113 filename.clear();
8d041b4f 1114 }
d7a51997
DK
1115 else
1116 filename.clear();
1117 }
1118
1119 if (filename.empty() == false)
1120 {
1121 // if the Release file is a hit and we have an index it must be the current one
1122 if (TransactionManager->IMSHit == true)
1123 ;
1124 else if (TransactionManager->LastMetaIndexParser != NULL)
1196da2e 1125 {
d7a51997
DK
1126 // see if the file changed since the last Release file
1127 // we use the uncompressed files as we might compress differently compared to the server,
1128 // so the hashes might not match, even if they contain the same data.
1129 HashStringList const newFile = GetExpectedHashesFromFor(TransactionManager->MetaIndexParser, Target->MetaKey);
1130 HashStringList const oldFile = GetExpectedHashesFromFor(TransactionManager->LastMetaIndexParser, Target->MetaKey);
1131 if (newFile != oldFile)
1132 filename.clear();
1196da2e 1133 }
d7a51997
DK
1134 else
1135 filename.clear();
8d041b4f
DK
1136 }
1137 else
1138 trypdiff = false; // no file to patch
1139
d7a51997
DK
1140 if (filename.empty() == false)
1141 {
1142 new NoActionItem(Owner, *Target, filename);
3d1e34b0
DK
1143 std::string const idxfilename = GetFinalFileNameFromURI(Target->URI + ".diff/Index");
1144 if (FileExists(idxfilename))
1145 new NoActionItem(Owner, *Target, idxfilename);
d7a51997
DK
1146 continue;
1147 }
1148
9b8c28f4 1149 // check if we have patches available
dcbbb14d 1150 trypdiff &= TransactionManager->MetaIndexParser->Exists(Target->MetaKey + ".diff/Index");
2237bd01 1151 }
d7a51997
DK
1152 else
1153 {
1154 // if we have no file to patch, no point in trying
1155 std::string filename = GetFinalFileNameFromURI(Target->URI);
1156 if (RealFileExists(filename) == false)
1157 {
1158 if (Target->KeepCompressed)
1159 {
1160 filename = GetKeepCompressedFileName(filename, *Target);
1161 if (RealFileExists(filename) == false)
1162 filename.clear();
1163 }
1164 else
1165 filename.clear();
1166 }
1167 trypdiff &= (filename.empty() == false);
1168 }
448c38bd 1169
9b8c28f4
DK
1170 // no point in patching from local sources
1171 if (trypdiff)
1172 {
dcbbb14d 1173 std::string const proto = Target->URI.substr(0, strlen("file:/"));
9b8c28f4
DK
1174 if (proto == "file:/" || proto == "copy:/" || proto == "cdrom:")
1175 trypdiff = false;
1176 }
1177
1178 // Queue the Index file (Packages, Sources, Translation-$foo, …)
1179 if (trypdiff)
448c38bd
DK
1180 new pkgAcqDiffIndex(Owner, TransactionManager, *Target);
1181 else
1182 new pkgAcqIndex(Owner, TransactionManager, *Target);
2237bd01 1183 }
448c38bd
DK
1184}
1185 /*}}}*/
1186bool pkgAcqMetaBase::VerifyVendor(string const &Message) /*{{{*/
1187{
1188 string::size_type pos;
f6d4ab9a 1189
448c38bd
DK
1190 // check for missing sigs (that where not fatal because otherwise we had
1191 // bombed earlier)
1192 string missingkeys;
1193 string msg = _("There is no public key available for the "
1194 "following key IDs:\n");
1195 pos = Message.find("NO_PUBKEY ");
1196 if (pos != std::string::npos)
f6d4ab9a 1197 {
448c38bd
DK
1198 string::size_type start = pos+strlen("NO_PUBKEY ");
1199 string Fingerprint = Message.substr(start, Message.find("\n")-start);
1200 missingkeys += (Fingerprint);
f6d4ab9a 1201 }
448c38bd
DK
1202 if(!missingkeys.empty())
1203 _error->Warning("%s", (msg + missingkeys).c_str());
f6d4ab9a 1204
448c38bd
DK
1205 string Transformed = TransactionManager->MetaIndexParser->GetExpectedDist();
1206
1207 if (Transformed == "../project/experimental")
f6d4ab9a 1208 {
448c38bd 1209 Transformed = "experimental";
f6d4ab9a
DK
1210 }
1211
448c38bd
DK
1212 pos = Transformed.rfind('/');
1213 if (pos != string::npos)
f6d4ab9a 1214 {
448c38bd 1215 Transformed = Transformed.substr(0, pos);
f6d4ab9a
DK
1216 }
1217
448c38bd 1218 if (Transformed == ".")
f6d4ab9a 1219 {
448c38bd 1220 Transformed = "";
f6d4ab9a
DK
1221 }
1222
0741daeb
DK
1223 if (TransactionManager->MetaIndexParser->GetValidUntil() > 0)
1224 {
448c38bd
DK
1225 time_t const invalid_since = time(NULL) - TransactionManager->MetaIndexParser->GetValidUntil();
1226 if (invalid_since > 0)
1227 {
1228 std::string errmsg;
1229 strprintf(errmsg,
1230 // TRANSLATOR: The first %s is the URL of the bad Release file, the second is
3d8232bf 1231 // the time since then the file is invalid - formatted in the same way as in
448c38bd
DK
1232 // the download progress display (e.g. 7d 3h 42min 1s)
1233 _("Release file for %s is expired (invalid since %s). "
1234 "Updates for this repository will not be applied."),
dcbbb14d 1235 Target.URI.c_str(), TimeToStr(invalid_since).c_str());
448c38bd
DK
1236 if (ErrorText.empty())
1237 ErrorText = errmsg;
1238 return _error->Error("%s", errmsg.c_str());
1239 }
1240 }
f6d4ab9a 1241
448c38bd
DK
1242 /* Did we get a file older than what we have? This is a last minute IMS hit and doubles
1243 as a prevention of downgrading us to older (still valid) files */
1244 if (TransactionManager->IMSHit == false && TransactionManager->LastMetaIndexParser != NULL &&
1245 TransactionManager->LastMetaIndexParser->GetDate() > TransactionManager->MetaIndexParser->GetDate())
f6d4ab9a 1246 {
448c38bd 1247 TransactionManager->IMSHit = true;
51818f26 1248 RemoveFile("VerifyVendor", DestFile);
448c38bd 1249 PartialFile = DestFile = GetFinalFilename();
5ad0096a
DK
1250 // load the 'old' file in the 'new' one instead of flipping pointers as
1251 // the new one isn't owned by us, while the old one is so cleanup would be confused.
1252 TransactionManager->MetaIndexParser->swapLoad(TransactionManager->LastMetaIndexParser);
1253 delete TransactionManager->LastMetaIndexParser;
448c38bd 1254 TransactionManager->LastMetaIndexParser = NULL;
f6d4ab9a
DK
1255 }
1256
448c38bd 1257 if (_config->FindB("Debug::pkgAcquire::Auth", false))
f6d4ab9a 1258 {
5ad0096a 1259 std::cerr << "Got Codename: " << TransactionManager->MetaIndexParser->GetCodename() << std::endl;
448c38bd
DK
1260 std::cerr << "Expecting Dist: " << TransactionManager->MetaIndexParser->GetExpectedDist() << std::endl;
1261 std::cerr << "Transformed Dist: " << Transformed << std::endl;
f6d4ab9a 1262 }
448c38bd
DK
1263
1264 if (TransactionManager->MetaIndexParser->CheckDist(Transformed) == false)
f6d4ab9a 1265 {
448c38bd
DK
1266 // This might become fatal one day
1267// Status = StatAuthError;
1268// ErrorText = "Conflicting distribution; expected "
1269// + MetaIndexParser->GetExpectedDist() + " but got "
5ad0096a 1270// + MetaIndexParser->GetCodename();
448c38bd
DK
1271// return false;
1272 if (!Transformed.empty())
1273 {
1274 _error->Warning(_("Conflicting distribution: %s (expected %s but got %s)"),
1275 Desc.Description.c_str(),
1276 Transformed.c_str(),
5ad0096a 1277 TransactionManager->MetaIndexParser->GetCodename().c_str());
448c38bd 1278 }
f6d4ab9a
DK
1279 }
1280
f6d4ab9a 1281 return true;
2237bd01 1282}
92fcbfc1 1283 /*}}}*/
3d8232bf
DK
1284pkgAcqMetaBase::~pkgAcqMetaBase()
1285{
1286}
2237bd01 1287
448c38bd
DK
1288pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire * const Owner, /*{{{*/
1289 IndexTarget const &ClearsignedTarget,
1290 IndexTarget const &DetachedDataTarget, IndexTarget const &DetachedSigTarget,
e8afd168 1291 std::vector<IndexTarget> const &IndexTargets,
5ad0096a 1292 metaIndex * const MetaIndexParser) :
3d8232bf 1293 pkgAcqMetaIndex(Owner, this, ClearsignedTarget, DetachedSigTarget, IndexTargets),
6c55f07a 1294 d(NULL), ClearsignedTarget(ClearsignedTarget),
3d8232bf
DK
1295 DetachedDataTarget(DetachedDataTarget),
1296 MetaIndexParser(MetaIndexParser), LastMetaIndexParser(NULL)
448c38bd
DK
1297{
1298 // index targets + (worst case:) Release/Release.gpg
dcbbb14d 1299 ExpectedAdditionalItems = IndexTargets.size() + 2;
448c38bd 1300 TransactionManager->Add(this);
2237bd01 1301}
92fcbfc1 1302 /*}}}*/
448c38bd 1303pkgAcqMetaClearSig::~pkgAcqMetaClearSig() /*{{{*/
146f7715 1304{
3d8232bf
DK
1305 if (LastMetaIndexParser != NULL)
1306 delete LastMetaIndexParser;
146f7715
DK
1307}
1308 /*}}}*/
448c38bd
DK
1309// pkgAcqMetaClearSig::Custom600Headers - Insert custom request headers /*{{{*/
1310string pkgAcqMetaClearSig::Custom600Headers() const
2237bd01 1311{
448c38bd
DK
1312 string Header = pkgAcqMetaBase::Custom600Headers();
1313 Header += "\nFail-Ignore: true";
b0d40854
DK
1314 std::string const key = TransactionManager->MetaIndexParser->GetSignedBy();
1315 if (key.empty() == false)
1316 Header += "\nSigned-By: " + key;
1317
448c38bd
DK
1318 return Header;
1319}
1320 /*}}}*/
24e8f24e 1321bool pkgAcqMetaClearSig::VerifyDone(std::string const &Message, /*{{{*/
dd676dc7
DK
1322 pkgAcquire::MethodConfig const * const Cnf)
1323{
1324 Item::VerifyDone(Message, Cnf);
1325
1326 if (FileExists(DestFile) && !StartsWithGPGClearTextSignature(DestFile))
1327 return RenameOnError(NotClearsigned);
1328
1329 return true;
1330}
24e8f24e 1331 /*}}}*/
448c38bd 1332// pkgAcqMetaClearSig::Done - We got a file /*{{{*/
448c38bd
DK
1333void pkgAcqMetaClearSig::Done(std::string const &Message,
1334 HashStringList const &Hashes,
1335 pkgAcquire::MethodConfig const * const Cnf)
1336{
1337 Item::Done(Message, Hashes, Cnf);
8d266656 1338
448c38bd
DK
1339 if(AuthPass == false)
1340 {
1341 if(CheckDownloadDone(this, Message, Hashes) == true)
1342 QueueForSignatureVerify(this, DestFile, DestFile);
1343 return;
1344 }
1345 else if(CheckAuthDone(Message) == true)
1346 {
1347 if (TransactionManager->IMSHit == false)
1348 TransactionManager->TransactionStageCopy(this, DestFile, GetFinalFilename());
1349 else if (RealFileExists(GetFinalFilename()) == false)
1350 {
1351 // We got an InRelease file IMSHit, but we haven't one, which means
1352 // we had a valid Release/Release.gpg combo stepping in, which we have
1353 // to 'acquire' now to ensure list cleanup isn't removing them
dcbbb14d
DK
1354 new NoActionItem(Owner, DetachedDataTarget);
1355 new NoActionItem(Owner, DetachedSigTarget);
448c38bd
DK
1356 }
1357 }
2237bd01 1358}
92fcbfc1 1359 /*}}}*/
448c38bd 1360void pkgAcqMetaClearSig::Failed(string const &Message,pkgAcquire::MethodConfig const * const Cnf) /*{{{*/
2237bd01 1361{
448c38bd 1362 Item::Failed(Message, Cnf);
2237bd01 1363
448c38bd
DK
1364 // we failed, we will not get additional items from this method
1365 ExpectedAdditionalItems = 0;
2237bd01 1366
448c38bd 1367 if (AuthPass == false)
2ac3eeb6 1368 {
f18f2338 1369 if (Status == StatAuthError || Status == StatTransientNetworkError)
dd676dc7 1370 {
f18f2338
DK
1371 // if we expected a ClearTextSignature (InRelease) but got a network
1372 // error or got a file, but it wasn't valid, we end up here (see VerifyDone).
dd676dc7
DK
1373 // As these is usually called by web-portals we do not try Release/Release.gpg
1374 // as this is gonna fail anyway and instead abort our try (LP#346386)
1375 TransactionManager->AbortTransaction();
1376 return;
1377 }
1378
448c38bd
DK
1379 // Queue the 'old' InRelease file for removal if we try Release.gpg
1380 // as otherwise the file will stay around and gives a false-auth
1381 // impression (CVE-2012-0214)
1382 TransactionManager->TransactionStageRemoval(this, GetFinalFilename());
1383 Status = StatDone;
1384
3d8232bf 1385 new pkgAcqMetaIndex(Owner, TransactionManager, DetachedDataTarget, DetachedSigTarget, IndexTargets);
2ac3eeb6
MV
1386 }
1387 else
1388 {
448c38bd
DK
1389 if(CheckStopAuthentication(this, Message))
1390 return;
1391
448c38bd
DK
1392 // No Release file was present, or verification failed, so fall
1393 // back to queueing Packages files without verification
d04e44ac 1394 // only allow going further if the user explicitly wants it
f18f2338 1395 if(AllowInsecureRepositories(_("The repository '%s' is not signed."), ClearsignedTarget.Description, TransactionManager->MetaIndexParser, TransactionManager, this) == true)
146f7715 1396 {
448c38bd
DK
1397 Status = StatDone;
1398
1399 /* InRelease files become Release files, otherwise
1400 * they would be considered as trusted later on */
1401 string const FinalRelease = GetFinalFileNameFromURI(DetachedDataTarget.URI);
1402 string const PartialRelease = GetPartialFileNameFromURI(DetachedDataTarget.URI);
1403 string const FinalReleasegpg = GetFinalFileNameFromURI(DetachedSigTarget.URI);
1404 string const FinalInRelease = GetFinalFilename();
1405 Rename(DestFile, PartialRelease);
1406 TransactionManager->TransactionStageCopy(this, PartialRelease, FinalRelease);
1407
1408 if (RealFileExists(FinalReleasegpg) || RealFileExists(FinalInRelease))
146f7715 1409 {
448c38bd
DK
1410 // open the last Release if we have it
1411 if (TransactionManager->IMSHit == false)
1412 {
5ad0096a
DK
1413 TransactionManager->LastMetaIndexParser = TransactionManager->MetaIndexParser->UnloadedClone();
1414 if (TransactionManager->LastMetaIndexParser != NULL)
448c38bd 1415 {
5ad0096a
DK
1416 _error->PushToStack();
1417 if (RealFileExists(FinalInRelease))
1418 TransactionManager->LastMetaIndexParser->Load(FinalInRelease, NULL);
1419 else
1420 TransactionManager->LastMetaIndexParser->Load(FinalRelease, NULL);
1421 // its unlikely to happen, but if what we have is bad ignore it
1422 if (_error->PendingError())
1423 {
1424 delete TransactionManager->LastMetaIndexParser;
1425 TransactionManager->LastMetaIndexParser = NULL;
1426 }
1427 _error->RevertToStack();
448c38bd 1428 }
448c38bd 1429 }
146f7715 1430 }
146f7715 1431
448c38bd
DK
1432 // we parse the indexes here because at this point the user wanted
1433 // a repository that may potentially harm him
5ad0096a 1434 if (TransactionManager->MetaIndexParser->Load(PartialRelease, &ErrorText) == false || VerifyVendor(Message) == false)
448c38bd
DK
1435 /* expired Release files are still a problem you need extra force for */;
1436 else
1437 QueueIndexes(true);
1438 }
2237bd01
MV
1439 }
1440}
92fcbfc1 1441 /*}}}*/
03aa0847 1442
448c38bd 1443pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire * const Owner, /*{{{*/
3d8232bf 1444 pkgAcqMetaClearSig * const TransactionManager,
448c38bd
DK
1445 IndexTarget const &DataTarget,
1446 IndexTarget const &DetachedSigTarget,
3d8232bf
DK
1447 vector<IndexTarget> const &IndexTargets) :
1448 pkgAcqMetaBase(Owner, TransactionManager, IndexTargets, DataTarget), d(NULL),
448c38bd 1449 DetachedSigTarget(DetachedSigTarget)
ac5b205a 1450{
448c38bd
DK
1451 if(_config->FindB("Debug::Acquire::Transaction", false) == true)
1452 std::clog << "New pkgAcqMetaIndex with TransactionManager "
1453 << this->TransactionManager << std::endl;
2d4722e2 1454
448c38bd 1455 DestFile = GetPartialFileNameFromURI(DataTarget.URI);
fa3a96a1 1456
448c38bd
DK
1457 // Create the item
1458 Desc.Description = DataTarget.Description;
1459 Desc.Owner = this;
1460 Desc.ShortDesc = DataTarget.ShortDesc;
1461 Desc.URI = DataTarget.URI;
ac5b205a 1462
448c38bd 1463 // we expect more item
dcbbb14d 1464 ExpectedAdditionalItems = IndexTargets.size();
448c38bd 1465 QueueURI(Desc);
ac5b205a 1466}
92fcbfc1 1467 /*}}}*/
448c38bd
DK
1468void pkgAcqMetaIndex::Done(string const &Message, /*{{{*/
1469 HashStringList const &Hashes,
1470 pkgAcquire::MethodConfig const * const Cfg)
ac5b205a 1471{
448c38bd 1472 Item::Done(Message,Hashes,Cfg);
03bfbc96 1473
448c38bd 1474 if(CheckDownloadDone(this, Message, Hashes))
03bfbc96 1475 {
448c38bd
DK
1476 // we have a Release file, now download the Signature, all further
1477 // verify/queue for additional downloads will be done in the
1478 // pkgAcqMetaSig::Done() code
dcbbb14d 1479 new pkgAcqMetaSig(Owner, TransactionManager, DetachedSigTarget, this);
03bfbc96 1480 }
448c38bd
DK
1481}
1482 /*}}}*/
1483// pkgAcqMetaIndex::Failed - no Release file present /*{{{*/
1484void pkgAcqMetaIndex::Failed(string const &Message,
1485 pkgAcquire::MethodConfig const * const Cnf)
1486{
1487 pkgAcquire::Item::Failed(Message, Cnf);
1488 Status = StatDone;
94dc9d7d 1489
448c38bd
DK
1490 // No Release file was present so fall
1491 // back to queueing Packages files without verification
d04e44ac 1492 // only allow going further if the user explicitly wants it
f18f2338 1493 if(AllowInsecureRepositories(_("The repository '%s' does not have a Release file."), Target.Description, TransactionManager->MetaIndexParser, TransactionManager, this) == true)
f6d4ab9a 1494 {
448c38bd
DK
1495 // ensure old Release files are removed
1496 TransactionManager->TransactionStageRemoval(this, GetFinalFilename());
03bfbc96 1497
448c38bd
DK
1498 // queue without any kind of hashsum support
1499 QueueIndexes(false);
59a704f0 1500 }
448c38bd
DK
1501}
1502 /*}}}*/
1503void pkgAcqMetaIndex::Finished() /*{{{*/
1504{
1505 if(_config->FindB("Debug::Acquire::Transaction", false) == true)
1506 std::clog << "Finished: " << DestFile <<std::endl;
1507 if(TransactionManager != NULL &&
1508 TransactionManager->TransactionHasError() == false)
1509 TransactionManager->CommitTransaction();
1510}
1511 /*}}}*/
1512std::string pkgAcqMetaIndex::DescURI() const /*{{{*/
1513{
dcbbb14d 1514 return Target.URI;
448c38bd
DK
1515}
1516 /*}}}*/
c8a4ce6c 1517pkgAcqMetaIndex::~pkgAcqMetaIndex() {}
94dc9d7d 1518
448c38bd
DK
1519// AcqMetaSig::AcqMetaSig - Constructor /*{{{*/
1520pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire * const Owner,
3d8232bf 1521 pkgAcqMetaClearSig * const TransactionManager,
e8afd168 1522 IndexTarget const &Target,
448c38bd 1523 pkgAcqMetaIndex * const MetaIndex) :
6c55f07a 1524 pkgAcqTransactionItem(Owner, TransactionManager, Target), d(NULL), MetaIndex(MetaIndex)
448c38bd 1525{
dcbbb14d 1526 DestFile = GetPartialFileNameFromURI(Target.URI);
6cb30d01 1527
448c38bd
DK
1528 // remove any partial downloaded sig-file in partial/.
1529 // it may confuse proxies and is too small to warrant a
1530 // partial download anyway
51818f26 1531 RemoveFile("pkgAcqMetaSig", DestFile);
ac5b205a 1532
448c38bd
DK
1533 // set the TransactionManager
1534 if(_config->FindB("Debug::Acquire::Transaction", false) == true)
1535 std::clog << "New pkgAcqMetaSig with TransactionManager "
1536 << TransactionManager << std::endl;
f6d4ab9a 1537
448c38bd 1538 // Create the item
dcbbb14d 1539 Desc.Description = Target.Description;
448c38bd 1540 Desc.Owner = this;
dcbbb14d
DK
1541 Desc.ShortDesc = Target.ShortDesc;
1542 Desc.URI = Target.URI;
ac5b205a 1543
448c38bd
DK
1544 // If we got a hit for Release, we will get one for Release.gpg too (or obscure errors),
1545 // so we skip the download step and go instantly to verification
1546 if (TransactionManager->IMSHit == true && RealFileExists(GetFinalFilename()))
1547 {
1548 Complete = true;
1549 Status = StatDone;
1550 PartialFile = DestFile = GetFinalFilename();
1551 MetaIndexFileSignature = DestFile;
1552 MetaIndex->QueueForSignatureVerify(this, MetaIndex->DestFile, DestFile);
1553 }
1554 else
1555 QueueURI(Desc);
ac5b205a 1556}
92fcbfc1 1557 /*}}}*/
448c38bd 1558pkgAcqMetaSig::~pkgAcqMetaSig() /*{{{*/
ac5b205a 1559{
b0d40854
DK
1560}
1561 /*}}}*/
1562// pkgAcqMetaSig::Custom600Headers - Insert custom request headers /*{{{*/
1563std::string pkgAcqMetaSig::Custom600Headers() const
1564{
1565 std::string Header = pkgAcqTransactionItem::Custom600Headers();
1566 std::string const key = TransactionManager->MetaIndexParser->GetSignedBy();
1567 if (key.empty() == false)
1568 Header += "\nSigned-By: " + key;
1569 return Header;
448c38bd
DK
1570}
1571 /*}}}*/
1572// AcqMetaSig::Done - The signature was downloaded/verified /*{{{*/
1573void pkgAcqMetaSig::Done(string const &Message, HashStringList const &Hashes,
1574 pkgAcquire::MethodConfig const * const Cfg)
1575{
1576 if (MetaIndexFileSignature.empty() == false)
4a0a786f 1577 {
448c38bd
DK
1578 DestFile = MetaIndexFileSignature;
1579 MetaIndexFileSignature.clear();
1580 }
1581 Item::Done(Message, Hashes, Cfg);
f6d4ab9a 1582
448c38bd
DK
1583 if(MetaIndex->AuthPass == false)
1584 {
1585 if(MetaIndex->CheckDownloadDone(this, Message, Hashes) == true)
f6d4ab9a 1586 {
448c38bd
DK
1587 // destfile will be modified to point to MetaIndexFile for the
1588 // gpgv method, so we need to save it here
1589 MetaIndexFileSignature = DestFile;
1590 MetaIndex->QueueForSignatureVerify(this, MetaIndex->DestFile, DestFile);
1591 }
1592 return;
1593 }
1594 else if(MetaIndex->CheckAuthDone(Message) == true)
1595 {
1596 if (TransactionManager->IMSHit == false)
1597 {
1598 TransactionManager->TransactionStageCopy(this, DestFile, GetFinalFilename());
1599 TransactionManager->TransactionStageCopy(MetaIndex, MetaIndex->DestFile, MetaIndex->GetFinalFilename());
f6d4ab9a 1600 }
448c38bd
DK
1601 }
1602}
1603 /*}}}*/
1604void pkgAcqMetaSig::Failed(string const &Message,pkgAcquire::MethodConfig const * const Cnf)/*{{{*/
1605{
1606 Item::Failed(Message,Cnf);
4a0a786f 1607
448c38bd
DK
1608 // check if we need to fail at this point
1609 if (MetaIndex->AuthPass == true && MetaIndex->CheckStopAuthentication(this, Message))
1610 return;
4a0a786f 1611
448c38bd
DK
1612 string const FinalRelease = MetaIndex->GetFinalFilename();
1613 string const FinalReleasegpg = GetFinalFilename();
1614 string const FinalInRelease = TransactionManager->GetFinalFilename();
4a0a786f 1615
448c38bd
DK
1616 if (RealFileExists(FinalReleasegpg) || RealFileExists(FinalInRelease))
1617 {
1618 std::string downgrade_msg;
1619 strprintf(downgrade_msg, _("The repository '%s' is no longer signed."),
dcbbb14d 1620 MetaIndex->Target.Description.c_str());
448c38bd
DK
1621 if(_config->FindB("Acquire::AllowDowngradeToInsecureRepositories"))
1622 {
1623 // meh, the users wants to take risks (we still mark the packages
1624 // from this repository as unauthenticated)
1625 _error->Warning("%s", downgrade_msg.c_str());
1626 _error->Warning(_("This is normally not allowed, but the option "
1627 "Acquire::AllowDowngradeToInsecureRepositories was "
1628 "given to override it."));
1629 Status = StatDone;
1630 } else {
f18f2338 1631 MessageInsecureRepository(true, downgrade_msg);
448c38bd
DK
1632 if (TransactionManager->IMSHit == false)
1633 Rename(MetaIndex->DestFile, MetaIndex->DestFile + ".FAILED");
1634 Item::Failed("Message: " + downgrade_msg, Cnf);
1635 TransactionManager->AbortTransaction();
1636 return;
1637 }
1638 }
4a0a786f 1639
448c38bd
DK
1640 // ensures that a Release.gpg file in the lists/ is removed by the transaction
1641 TransactionManager->TransactionStageRemoval(this, DestFile);
4a0a786f 1642
d04e44ac 1643 // only allow going further if the user explicitly wants it
f18f2338 1644 if (AllowInsecureRepositories(_("The repository '%s' is not signed."), MetaIndex->Target.Description, TransactionManager->MetaIndexParser, TransactionManager, this) == true)
4a0a786f 1645 {
448c38bd 1646 if (RealFileExists(FinalReleasegpg) || RealFileExists(FinalInRelease))
59a704f0 1647 {
448c38bd
DK
1648 // open the last Release if we have it
1649 if (TransactionManager->IMSHit == false)
1650 {
5ad0096a
DK
1651 TransactionManager->LastMetaIndexParser = TransactionManager->MetaIndexParser->UnloadedClone();
1652 if (TransactionManager->LastMetaIndexParser != NULL)
448c38bd 1653 {
5ad0096a
DK
1654 _error->PushToStack();
1655 if (RealFileExists(FinalInRelease))
1656 TransactionManager->LastMetaIndexParser->Load(FinalInRelease, NULL);
1657 else
1658 TransactionManager->LastMetaIndexParser->Load(FinalRelease, NULL);
1659 // its unlikely to happen, but if what we have is bad ignore it
1660 if (_error->PendingError())
1661 {
1662 delete TransactionManager->LastMetaIndexParser;
1663 TransactionManager->LastMetaIndexParser = NULL;
1664 }
1665 _error->RevertToStack();
448c38bd 1666 }
448c38bd 1667 }
59a704f0 1668 }
4a0a786f 1669
448c38bd
DK
1670 // we parse the indexes here because at this point the user wanted
1671 // a repository that may potentially harm him
f01f5d91
DK
1672 bool const GoodLoad = TransactionManager->MetaIndexParser->Load(MetaIndex->DestFile, &ErrorText);
1673 if (MetaIndex->VerifyVendor(Message) == false)
448c38bd
DK
1674 /* expired Release files are still a problem you need extra force for */;
1675 else
f01f5d91 1676 MetaIndex->QueueIndexes(GoodLoad);
448c38bd
DK
1677
1678 TransactionManager->TransactionStageCopy(MetaIndex, MetaIndex->DestFile, MetaIndex->GetFinalFilename());
1679 }
1680
1681 // FIXME: this is used often (e.g. in pkgAcqIndexTrans) so refactor
1682 if (Cnf->LocalOnly == true ||
1683 StringToBool(LookupTag(Message,"Transient-Failure"),false) == false)
1684 {
1685 // Ignore this
1686 Status = StatDone;
ac5b205a 1687 }
ac5b205a 1688}
92fcbfc1 1689 /*}}}*/
448c38bd
DK
1690
1691
1692// AcqBaseIndex - Constructor /*{{{*/
1693pkgAcqBaseIndex::pkgAcqBaseIndex(pkgAcquire * const Owner,
3d8232bf 1694 pkgAcqMetaClearSig * const TransactionManager,
e8afd168 1695 IndexTarget const &Target)
6c55f07a 1696: pkgAcqTransactionItem(Owner, TransactionManager, Target), d(NULL)
448c38bd
DK
1697{
1698}
1699 /*}}}*/
c8a4ce6c 1700pkgAcqBaseIndex::~pkgAcqBaseIndex() {}
448c38bd
DK
1701
1702// AcqDiffIndex::AcqDiffIndex - Constructor /*{{{*/
1703// ---------------------------------------------------------------------
1704/* Get the DiffIndex file first and see if there are patches available
1705 * If so, create a pkgAcqIndexDiffs fetcher that will get and apply the
1706 * patches. If anything goes wrong in that process, it will fall back to
1707 * the original packages file
1708 */
1709pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire * const Owner,
3d8232bf 1710 pkgAcqMetaClearSig * const TransactionManager,
e8afd168 1711 IndexTarget const &Target)
3d8232bf 1712 : pkgAcqBaseIndex(Owner, TransactionManager, Target), d(NULL), diffs(NULL)
47d2bc78 1713{
47d2bc78
DK
1714 Debug = _config->FindB("Debug::pkgAcquire::Diffs",false);
1715
47d2bc78 1716 Desc.Owner = this;
dcbbb14d
DK
1717 Desc.Description = Target.Description + ".diff/Index";
1718 Desc.ShortDesc = Target.ShortDesc;
1719 Desc.URI = Target.URI + ".diff/Index";
47d2bc78 1720
448c38bd
DK
1721 DestFile = GetPartialFileNameFromURI(Desc.URI);
1722
1723 if(Debug)
1724 std::clog << "pkgAcqDiffIndex: " << Desc.URI << std::endl;
5684f71f 1725
47d2bc78
DK
1726 QueueURI(Desc);
1727}
1728 /*}}}*/
448c38bd
DK
1729// AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
1730// ---------------------------------------------------------------------
1731/* The only header we use is the last-modified header. */
1732string pkgAcqDiffIndex::Custom600Headers() const
47d2bc78 1733{
abd6af5a
DK
1734 if (TransactionManager->LastMetaIndexParser != NULL)
1735 return "\nIndex-File: true";
1736
448c38bd 1737 string const Final = GetFinalFilename();
47d2bc78 1738
448c38bd
DK
1739 if(Debug)
1740 std::clog << "Custom600Header-IMS: " << Final << std::endl;
47d2bc78 1741
448c38bd
DK
1742 struct stat Buf;
1743 if (stat(Final.c_str(),&Buf) != 0)
1744 return "\nIndex-File: true";
1745
1746 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
1747}
1748 /*}}}*/
1749void pkgAcqDiffIndex::QueueOnIMSHit() const /*{{{*/
1750{
1751 // list cleanup needs to know that this file as well as the already
1752 // present index is ours, so we create an empty diff to save it for us
1753 new pkgAcqIndexDiffs(Owner, TransactionManager, Target);
47d2bc78
DK
1754}
1755 /*}}}*/
448c38bd 1756bool pkgAcqDiffIndex::ParseDiffIndex(string const &IndexDiffFile) /*{{{*/
47d2bc78 1757{
448c38bd
DK
1758 // failing here is fine: our caller will take care of trying to
1759 // get the complete file if patching fails
47d2bc78 1760 if(Debug)
448c38bd
DK
1761 std::clog << "pkgAcqDiffIndex::ParseIndexDiff() " << IndexDiffFile
1762 << std::endl;
f6d4ab9a 1763
448c38bd
DK
1764 FileFd Fd(IndexDiffFile,FileFd::ReadOnly);
1765 pkgTagFile TF(&Fd);
95278287 1766 if (Fd.IsOpen() == false || Fd.Failed())
448c38bd 1767 return false;
47d2bc78 1768
448c38bd
DK
1769 pkgTagSection Tags;
1770 if(unlikely(TF.Step(Tags) == false))
1771 return false;
47d2bc78 1772
448c38bd
DK
1773 HashStringList ServerHashes;
1774 unsigned long long ServerSize = 0;
47d2bc78 1775
448c38bd
DK
1776 for (char const * const * type = HashString::SupportedHashes(); *type != NULL; ++type)
1777 {
1778 std::string tagname = *type;
1779 tagname.append("-Current");
1780 std::string const tmp = Tags.FindS(tagname.c_str());
1781 if (tmp.empty() == true)
1782 continue;
146f7715 1783
448c38bd
DK
1784 string hash;
1785 unsigned long long size;
1786 std::stringstream ss(tmp);
1787 ss >> hash >> size;
1788 if (unlikely(hash.empty() == true))
1789 continue;
1790 if (unlikely(ServerSize != 0 && ServerSize != size))
1791 continue;
1792 ServerHashes.push_back(HashString(*type, hash));
1793 ServerSize = size;
1794 }
47d2bc78 1795
448c38bd
DK
1796 if (ServerHashes.usable() == false)
1797 {
1798 if (Debug == true)
1799 std::clog << "pkgAcqDiffIndex: " << IndexDiffFile << ": Did not find a good hashsum in the index" << std::endl;
1800 return false;
47d2bc78 1801 }
448c38bd 1802
dcbbb14d
DK
1803 std::string const CurrentPackagesFile = GetFinalFileNameFromURI(Target.URI);
1804 HashStringList const TargetFileHashes = GetExpectedHashesFor(Target.MetaKey);
448c38bd 1805 if (TargetFileHashes.usable() == false || ServerHashes != TargetFileHashes)
47d2bc78 1806 {
448c38bd 1807 if (Debug == true)
47d2bc78 1808 {
448c38bd
DK
1809 std::clog << "pkgAcqDiffIndex: " << IndexDiffFile << ": Index has different hashes than parser, probably older, so fail pdiffing" << std::endl;
1810 printHashSumComparision(CurrentPackagesFile, ServerHashes, TargetFileHashes);
47d2bc78 1811 }
448c38bd
DK
1812 return false;
1813 }
47d2bc78 1814
9b8c28f4
DK
1815 HashStringList LocalHashes;
1816 // try avoiding calculating the hash here as this is costly
1817 if (TransactionManager->LastMetaIndexParser != NULL)
dcbbb14d 1818 LocalHashes = GetExpectedHashesFromFor(TransactionManager->LastMetaIndexParser, Target.MetaKey);
9b8c28f4
DK
1819 if (LocalHashes.usable() == false)
1820 {
d7a51997 1821 FileFd fd(CurrentPackagesFile, FileFd::ReadOnly, FileFd::Auto);
9b8c28f4
DK
1822 Hashes LocalHashesCalc(ServerHashes);
1823 LocalHashesCalc.AddFD(fd);
1824 LocalHashes = LocalHashesCalc.GetHashStringList();
1825 }
1826
1827 if (ServerHashes == LocalHashes)
448c38bd
DK
1828 {
1829 // we have the same sha1 as the server so we are done here
47d2bc78 1830 if(Debug)
448c38bd
DK
1831 std::clog << "pkgAcqDiffIndex: Package file " << CurrentPackagesFile << " is up-to-date" << std::endl;
1832 QueueOnIMSHit();
1833 return true;
1834 }
47d2bc78 1835
448c38bd
DK
1836 if(Debug)
1837 std::clog << "Server-Current: " << ServerHashes.find(NULL)->toStr() << " and we start at "
9b8c28f4 1838 << CurrentPackagesFile << " " << LocalHashes.FileSize() << " " << LocalHashes.find(NULL)->toStr() << std::endl;
34d6ece7 1839
448c38bd
DK
1840 // parse all of (provided) history
1841 vector<DiffInfo> available_patches;
1842 bool firstAcceptedHashes = true;
1843 for (char const * const * type = HashString::SupportedHashes(); *type != NULL; ++type)
651bddad 1844 {
448c38bd
DK
1845 if (LocalHashes.find(*type) == NULL)
1846 continue;
21638c3a 1847
448c38bd
DK
1848 std::string tagname = *type;
1849 tagname.append("-History");
1850 std::string const tmp = Tags.FindS(tagname.c_str());
1851 if (tmp.empty() == true)
1852 continue;
a64bf0eb 1853
448c38bd
DK
1854 string hash, filename;
1855 unsigned long long size;
1856 std::stringstream ss(tmp);
56472095 1857
448c38bd 1858 while (ss >> hash >> size >> filename)
651bddad 1859 {
448c38bd
DK
1860 if (unlikely(hash.empty() == true || filename.empty() == true))
1861 continue;
1862
1863 // see if we have a record for this file already
1864 std::vector<DiffInfo>::iterator cur = available_patches.begin();
1865 for (; cur != available_patches.end(); ++cur)
1866 {
4f51fd86 1867 if (cur->file != filename)
448c38bd
DK
1868 continue;
1869 cur->result_hashes.push_back(HashString(*type, hash));
1870 break;
1871 }
1872 if (cur != available_patches.end())
1873 continue;
1874 if (firstAcceptedHashes == true)
1875 {
1876 DiffInfo next;
1877 next.file = filename;
1878 next.result_hashes.push_back(HashString(*type, hash));
4f51fd86 1879 next.result_hashes.FileSize(size);
448c38bd
DK
1880 available_patches.push_back(next);
1881 }
1882 else
1883 {
1884 if (Debug == true)
1885 std::clog << "pkgAcqDiffIndex: " << IndexDiffFile << ": File " << filename
1886 << " wasn't in the list for the first parsed hash! (history)" << std::endl;
1887 break;
1888 }
651bddad 1889 }
448c38bd 1890 firstAcceptedHashes = false;
5d885723 1891 }
448c38bd
DK
1892
1893 if (unlikely(available_patches.empty() == true))
5d885723 1894 {
448c38bd
DK
1895 if (Debug)
1896 std::clog << "pkgAcqDiffIndex: " << IndexDiffFile << ": "
1897 << "Couldn't find any patches for the patch series." << std::endl;
1898 return false;
5d885723 1899 }
8267fe24 1900
448c38bd 1901 for (char const * const * type = HashString::SupportedHashes(); *type != NULL; ++type)
b11f9599 1902 {
448c38bd
DK
1903 if (LocalHashes.find(*type) == NULL)
1904 continue;
97b65b10 1905
448c38bd
DK
1906 std::string tagname = *type;
1907 tagname.append("-Patches");
1908 std::string const tmp = Tags.FindS(tagname.c_str());
1909 if (tmp.empty() == true)
1910 continue;
18593cf7 1911
448c38bd
DK
1912 string hash, filename;
1913 unsigned long long size;
1914 std::stringstream ss(tmp);
03aa0847 1915
448c38bd 1916 while (ss >> hash >> size >> filename)
58702f85 1917 {
448c38bd
DK
1918 if (unlikely(hash.empty() == true || filename.empty() == true))
1919 continue;
146f7715 1920
448c38bd
DK
1921 // see if we have a record for this file already
1922 std::vector<DiffInfo>::iterator cur = available_patches.begin();
1923 for (; cur != available_patches.end(); ++cur)
146f7715 1924 {
448c38bd
DK
1925 if (cur->file != filename)
1926 continue;
4f51fd86
DK
1927 if (cur->patch_hashes.empty())
1928 cur->patch_hashes.FileSize(size);
448c38bd 1929 cur->patch_hashes.push_back(HashString(*type, hash));
448c38bd 1930 break;
146f7715 1931 }
448c38bd
DK
1932 if (cur != available_patches.end())
1933 continue;
1934 if (Debug == true)
1935 std::clog << "pkgAcqDiffIndex: " << IndexDiffFile << ": File " << filename
1936 << " wasn't in the list for the first parsed hash! (patches)" << std::endl;
146f7715 1937 break;
146f7715
DK
1938 }
1939 }
2d0a7bb4 1940
4f51fd86
DK
1941 for (char const * const * type = HashString::SupportedHashes(); *type != NULL; ++type)
1942 {
1943 std::string tagname = *type;
1944 tagname.append("-Download");
1945 std::string const tmp = Tags.FindS(tagname.c_str());
1946 if (tmp.empty() == true)
1947 continue;
1948
1949 string hash, filename;
1950 unsigned long long size;
1951 std::stringstream ss(tmp);
1952
1953 // FIXME: all of pdiff supports only .gz compressed patches
1954 while (ss >> hash >> size >> filename)
1955 {
1956 if (unlikely(hash.empty() == true || filename.empty() == true))
1957 continue;
1958 if (unlikely(APT::String::Endswith(filename, ".gz") == false))
1959 continue;
1960 filename.erase(filename.length() - 3);
1961
1962 // see if we have a record for this file already
1963 std::vector<DiffInfo>::iterator cur = available_patches.begin();
1964 for (; cur != available_patches.end(); ++cur)
1965 {
1966 if (cur->file != filename)
1967 continue;
1968 if (cur->download_hashes.empty())
1969 cur->download_hashes.FileSize(size);
1970 cur->download_hashes.push_back(HashString(*type, hash));
1971 break;
1972 }
1973 if (cur != available_patches.end())
1974 continue;
1975 if (Debug == true)
1976 std::clog << "pkgAcqDiffIndex: " << IndexDiffFile << ": File " << filename
1977 << " wasn't in the list for the first parsed hash! (download)" << std::endl;
1978 break;
1979 }
1980 }
1981
1982
448c38bd
DK
1983 bool foundStart = false;
1984 for (std::vector<DiffInfo>::iterator cur = available_patches.begin();
1985 cur != available_patches.end(); ++cur)
1986 {
1987 if (LocalHashes != cur->result_hashes)
1988 continue;
1989
1990 available_patches.erase(available_patches.begin(), cur);
1991 foundStart = true;
1992 break;
e6e89390 1993 }
b3d44315 1994
448c38bd
DK
1995 if (foundStart == false || unlikely(available_patches.empty() == true))
1996 {
1997 if (Debug)
1998 std::clog << "pkgAcqDiffIndex: " << IndexDiffFile << ": "
1999 << "Couldn't find the start of the patch series." << std::endl;
2000 return false;
2001 }
f6237efd 2002
448c38bd
DK
2003 // patching with too many files is rather slow compared to a fast download
2004 unsigned long const fileLimit = _config->FindI("Acquire::PDiffs::FileLimit", 0);
2005 if (fileLimit != 0 && fileLimit < available_patches.size())
2006 {
2007 if (Debug)
2008 std::clog << "Need " << available_patches.size() << " diffs (Limit is " << fileLimit
2009 << ") so fallback to complete download" << std::endl;
2010 return false;
2011 }
1f4dd8fd 2012
448c38bd
DK
2013 // calculate the size of all patches we have to get
2014 // note that all sizes are uncompressed, while we download compressed files
2015 unsigned long long patchesSize = 0;
2016 for (std::vector<DiffInfo>::const_iterator cur = available_patches.begin();
2017 cur != available_patches.end(); ++cur)
4f51fd86 2018 patchesSize += cur->patch_hashes.FileSize();
448c38bd
DK
2019 unsigned long long const sizeLimit = ServerSize * _config->FindI("Acquire::PDiffs::SizeLimit", 100);
2020 if (sizeLimit > 0 && (sizeLimit/100) < patchesSize)
2021 {
2022 if (Debug)
2023 std::clog << "Need " << patchesSize << " bytes (Limit is " << sizeLimit/100
2024 << ") so fallback to complete download" << std::endl;
2025 return false;
2026 }
2737f28a 2027
448c38bd
DK
2028 // we have something, queue the diffs
2029 string::size_type const last_space = Description.rfind(" ");
2030 if(last_space != string::npos)
2031 Description.erase(last_space, Description.size()-last_space);
2032
2033 /* decide if we should download patches one by one or in one go:
2034 The first is good if the server merges patches, but many don't so client
2035 based merging can be attempt in which case the second is better.
2036 "bad things" will happen if patches are merged on the server,
2037 but client side merging is attempt as well */
2038 bool pdiff_merge = _config->FindB("Acquire::PDiffs::Merge", true);
2039 if (pdiff_merge == true)
6bf93605 2040 {
448c38bd
DK
2041 // reprepro adds this flag if it has merged patches on the server
2042 std::string const precedence = Tags.FindS("X-Patch-Precedence");
2043 pdiff_merge = (precedence != "merged");
6bf93605 2044 }
448c38bd
DK
2045
2046 if (pdiff_merge == false)
2047 new pkgAcqIndexDiffs(Owner, TransactionManager, Target, available_patches);
6bf93605 2048 else
448c38bd 2049 {
3d8232bf 2050 diffs = new std::vector<pkgAcqIndexMergeDiffs*>(available_patches.size());
448c38bd
DK
2051 for(size_t i = 0; i < available_patches.size(); ++i)
2052 (*diffs)[i] = new pkgAcqIndexMergeDiffs(Owner, TransactionManager,
2053 Target,
2054 available_patches[i],
2055 diffs);
2056 }
2057
2058 Complete = false;
2059 Status = StatDone;
2060 Dequeue();
2061 return true;
6bf93605
DK
2062}
2063 /*}}}*/
448c38bd 2064void pkgAcqDiffIndex::Failed(string const &Message,pkgAcquire::MethodConfig const * const Cnf)/*{{{*/
6bf93605 2065{
448c38bd
DK
2066 Item::Failed(Message,Cnf);
2067 Status = StatDone;
2068
2069 if(Debug)
2070 std::clog << "pkgAcqDiffIndex failed: " << Desc.URI << " with " << Message << std::endl
2071 << "Falling back to normal index file acquire" << std::endl;
2072
2073 new pkgAcqIndex(Owner, TransactionManager, Target);
0118833a 2074}
61aea84d 2075 /*}}}*/
448c38bd
DK
2076void pkgAcqDiffIndex::Done(string const &Message,HashStringList const &Hashes, /*{{{*/
2077 pkgAcquire::MethodConfig const * const Cnf)
c88edf1d 2078{
448c38bd
DK
2079 if(Debug)
2080 std::clog << "pkgAcqDiffIndex::Done(): " << Desc.URI << std::endl;
c88edf1d 2081
448c38bd
DK
2082 Item::Done(Message, Hashes, Cnf);
2083
2084 string const FinalFile = GetFinalFilename();
2085 if(StringToBool(LookupTag(Message,"IMS-Hit"),false))
2086 DestFile = FinalFile;
2087
2088 if(ParseDiffIndex(DestFile) == false)
c88edf1d 2089 {
448c38bd
DK
2090 Failed("Message: Couldn't parse pdiff index", Cnf);
2091 // queue for final move - this should happen even if we fail
2092 // while parsing (e.g. on sizelimit) and download the complete file.
2093 TransactionManager->TransactionStageCopy(this, DestFile, FinalFile);
2737f28a
MV
2094 return;
2095 }
448c38bd
DK
2096
2097 TransactionManager->TransactionStageCopy(this, DestFile, FinalFile);
2098
2099 Complete = true;
2100 Status = StatDone;
2101 Dequeue();
2102
2103 return;
c88edf1d
AL
2104}
2105 /*}}}*/
3d8232bf
DK
2106pkgAcqDiffIndex::~pkgAcqDiffIndex()
2107{
2108 if (diffs != NULL)
2109 delete diffs;
2110}
448c38bd
DK
2111
2112// AcqIndexDiffs::AcqIndexDiffs - Constructor /*{{{*/
2113// ---------------------------------------------------------------------
2114/* The package diff is added to the queue. one object is constructed
2115 * for each diff and the index
2116 */
2117pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire * const Owner,
3d8232bf 2118 pkgAcqMetaClearSig * const TransactionManager,
e8afd168 2119 IndexTarget const &Target,
448c38bd 2120 vector<DiffInfo> const &diffs)
6c55f07a 2121 : pkgAcqBaseIndex(Owner, TransactionManager, Target), d(NULL),
448c38bd 2122 available_patches(diffs)
681d76d0 2123{
d7a51997 2124 DestFile = GetKeepCompressedFileName(GetPartialFileNameFromURI(Target.URI), Target);
e8b1db38 2125
448c38bd 2126 Debug = _config->FindB("Debug::pkgAcquire::Diffs",false);
e8b1db38 2127
448c38bd 2128 Desc.Owner = this;
dcbbb14d
DK
2129 Description = Target.Description;
2130 Desc.ShortDesc = Target.ShortDesc;
631a7dc7 2131
448c38bd 2132 if(available_patches.empty() == true)
631a7dc7 2133 {
448c38bd 2134 // we are done (yeah!), check hashes against the final file
d7a51997 2135 DestFile = GetKeepCompressedFileName(GetFinalFileNameFromURI(Target.URI), Target);
448c38bd 2136 Finish(true);
631a7dc7 2137 }
9d653a6d 2138 else
631a7dc7 2139 {
d7a51997 2140 if (BootstrapPDiffWith(GetPartialFileNameFromURI(Target.URI), GetFinalFilename(), Target) == false)
6bf93605 2141 {
d7a51997
DK
2142 Failed("Bootstrapping of " + DestFile + " failed", NULL);
2143 return;
6bf93605
DK
2144 }
2145
448c38bd
DK
2146 // get the next diff
2147 State = StateFetchDiff;
2148 QueueNextDiff();
631a7dc7 2149 }
448c38bd
DK
2150}
2151 /*}}}*/
2152void pkgAcqIndexDiffs::Failed(string const &Message,pkgAcquire::MethodConfig const * const Cnf)/*{{{*/
2153{
2154 Item::Failed(Message,Cnf);
2155 Status = StatDone;
631a7dc7 2156
d7a51997 2157 DestFile = GetKeepCompressedFileName(GetPartialFileNameFromURI(Target.URI), Target);
448c38bd
DK
2158 if(Debug)
2159 std::clog << "pkgAcqIndexDiffs failed: " << Desc.URI << " with " << Message << std::endl
d7a51997 2160 << "Falling back to normal index file acquire " << std::endl;
448c38bd 2161 RenameOnError(PDiffError);
36795154
DK
2162 std::string const patchname = GetDiffsPatchFileName(DestFile);
2163 if (RealFileExists(patchname))
2164 rename(patchname.c_str(), std::string(patchname + ".FAILED").c_str());
448c38bd
DK
2165 new pkgAcqIndex(Owner, TransactionManager, Target);
2166 Finish();
2167}
2168 /*}}}*/
2169// Finish - helper that cleans the item out of the fetcher queue /*{{{*/
2170void pkgAcqIndexDiffs::Finish(bool allDone)
2171{
2172 if(Debug)
2173 std::clog << "pkgAcqIndexDiffs::Finish(): "
2174 << allDone << " "
2175 << Desc.URI << std::endl;
2176
2177 // we restore the original name, this is required, otherwise
2178 // the file will be cleaned
2179 if(allDone)
4dbfe436 2180 {
d7a51997
DK
2181 std::string Final = GetFinalFilename();
2182 if (Target.KeepCompressed)
2183 {
2184 std::string const ext = flExtension(DestFile);
2185 if (ext.empty() == false)
2186 Final.append(".").append(ext);
2187 }
2188 TransactionManager->TransactionStageCopy(this, DestFile, Final);
448c38bd
DK
2189
2190 // this is for the "real" finish
2191 Complete = true;
e05672e8 2192 Status = StatDone;
448c38bd
DK
2193 Dequeue();
2194 if(Debug)
2195 std::clog << "\n\nallDone: " << DestFile << "\n" << std::endl;
2196 return;
e05672e8 2197 }
d7a51997
DK
2198 else
2199 DestFile.clear();
448c38bd
DK
2200
2201 if(Debug)
2202 std::clog << "Finishing: " << Desc.URI << std::endl;
2203 Complete = false;
2204 Status = StatDone;
2205 Dequeue();
2206 return;
681d76d0 2207}
92fcbfc1 2208 /*}}}*/
448c38bd 2209bool pkgAcqIndexDiffs::QueueNextDiff() /*{{{*/
b3d44315 2210{
448c38bd 2211 // calc sha1 of the just patched file
d7a51997 2212 std::string const FinalFile = GetKeepCompressedFileName(GetPartialFileNameFromURI(Target.URI), Target);
448c38bd 2213 if(!FileExists(FinalFile))
715c65de 2214 {
448c38bd
DK
2215 Failed("Message: No FinalFile " + FinalFile + " available", NULL);
2216 return false;
715c65de 2217 }
e05672e8 2218
d7a51997 2219 FileFd fd(FinalFile, FileFd::ReadOnly, FileFd::Extension);
448c38bd
DK
2220 Hashes LocalHashesCalc;
2221 LocalHashesCalc.AddFD(fd);
2222 HashStringList const LocalHashes = LocalHashesCalc.GetHashStringList();
b3d44315 2223
448c38bd
DK
2224 if(Debug)
2225 std::clog << "QueueNextDiff: " << FinalFile << " (" << LocalHashes.find(NULL)->toStr() << ")" << std::endl;
b3d44315 2226
dcbbb14d 2227 HashStringList const TargetFileHashes = GetExpectedHashesFor(Target.MetaKey);
448c38bd 2228 if (unlikely(LocalHashes.usable() == false || TargetFileHashes.usable() == false))
b3d44315 2229 {
448c38bd
DK
2230 Failed("Local/Expected hashes are not usable", NULL);
2231 return false;
b3d44315 2232 }
b3d44315 2233
448c38bd
DK
2234
2235 // final file reached before all patches are applied
2236 if(LocalHashes == TargetFileHashes)
6bf93605 2237 {
448c38bd
DK
2238 Finish(true);
2239 return true;
6bf93605
DK
2240 }
2241
448c38bd
DK
2242 // remove all patches until the next matching patch is found
2243 // this requires the Index file to be ordered
258b9e51
DK
2244 available_patches.erase(available_patches.begin(),
2245 std::find_if(available_patches.begin(), available_patches.end(), [&](DiffInfo const &I) {
2246 return I.result_hashes == LocalHashes;
2247 }));
56bc3358 2248
448c38bd
DK
2249 // error checking and falling back if no patch was found
2250 if(available_patches.empty() == true)
56bc3358 2251 {
448c38bd 2252 Failed("No patches left to reach target", NULL);
f3097647 2253 return false;
56bc3358 2254 }
f3097647 2255
448c38bd 2256 // queue the right diff
dcbbb14d 2257 Desc.URI = Target.URI + ".diff/" + available_patches[0].file + ".gz";
448c38bd 2258 Desc.Description = Description + " " + available_patches[0].file + string(".pdiff");
d7a51997 2259 DestFile = GetKeepCompressedFileName(GetPartialFileNameFromURI(Target.URI + ".diff/" + available_patches[0].file), Target);
f3097647 2260
448c38bd
DK
2261 if(Debug)
2262 std::clog << "pkgAcqIndexDiffs::QueueNextDiff(): " << Desc.URI << std::endl;
2263
2264 QueueURI(Desc);
f3097647
MV
2265
2266 return true;
2267}
2268 /*}}}*/
448c38bd
DK
2269void pkgAcqIndexDiffs::Done(string const &Message, HashStringList const &Hashes, /*{{{*/
2270 pkgAcquire::MethodConfig const * const Cnf)
27e6c17a 2271{
448c38bd
DK
2272 if(Debug)
2273 std::clog << "pkgAcqIndexDiffs::Done(): " << Desc.URI << std::endl;
27e6c17a 2274
448c38bd 2275 Item::Done(Message, Hashes, Cnf);
27e6c17a 2276
d7a51997 2277 std::string const FinalFile = GetKeepCompressedFileName(GetPartialFileNameFromURI(Target.URI), Target);
36795154 2278 std::string const PatchFile = GetDiffsPatchFileName(FinalFile);
b3d44315 2279
448c38bd
DK
2280 // success in downloading a diff, enter ApplyDiff state
2281 if(State == StateFetchDiff)
b3d44315 2282 {
36795154 2283 Rename(DestFile, PatchFile);
448c38bd
DK
2284
2285 if(Debug)
2286 std::clog << "Sending to rred method: " << FinalFile << std::endl;
2287
2288 State = StateApplyDiff;
2289 Local = true;
2290 Desc.URI = "rred:" + FinalFile;
2291 QueueURI(Desc);
2292 SetActiveSubprocess("rred");
2293 return;
36795154 2294 }
448c38bd
DK
2295
2296 // success in download/apply a diff, queue next (if needed)
2297 if(State == StateApplyDiff)
8eafc759 2298 {
448c38bd
DK
2299 // remove the just applied patch
2300 available_patches.erase(available_patches.begin());
51818f26 2301 RemoveFile("pkgAcqIndexDiffs::Done", PatchFile);
448c38bd
DK
2302
2303 // move into place
36795154 2304 if(Debug)
8eafc759 2305 {
448c38bd
DK
2306 std::clog << "Moving patched file in place: " << std::endl
2307 << DestFile << " -> " << FinalFile << std::endl;
8eafc759 2308 }
448c38bd
DK
2309 Rename(DestFile,FinalFile);
2310 chmod(FinalFile.c_str(),0644);
8eafc759 2311
448c38bd
DK
2312 // see if there is more to download
2313 if(available_patches.empty() == false) {
2314 new pkgAcqIndexDiffs(Owner, TransactionManager, Target,
2315 available_patches);
2316 return Finish();
2317 } else
2318 // update
2319 DestFile = FinalFile;
2320 return Finish(true);
ba6b79bd 2321 }
448c38bd
DK
2322}
2323 /*}}}*/
36795154
DK
2324std::string pkgAcqIndexDiffs::Custom600Headers() const /*{{{*/
2325{
2326 if(State != StateApplyDiff)
2327 return pkgAcqBaseIndex::Custom600Headers();
2328 std::ostringstream patchhashes;
2329 HashStringList const ExpectedHashes = available_patches[0].patch_hashes;
2330 for (HashStringList::const_iterator hs = ExpectedHashes.begin(); hs != ExpectedHashes.end(); ++hs)
2331 patchhashes << "\nPatch-0-" << hs->HashType() << "-Hash: " << hs->HashValue();
2332 patchhashes << pkgAcqBaseIndex::Custom600Headers();
2333 return patchhashes.str();
2334}
2335 /*}}}*/
c8a4ce6c 2336pkgAcqIndexDiffs::~pkgAcqIndexDiffs() {}
448c38bd
DK
2337
2338// AcqIndexMergeDiffs::AcqIndexMergeDiffs - Constructor /*{{{*/
2339pkgAcqIndexMergeDiffs::pkgAcqIndexMergeDiffs(pkgAcquire * const Owner,
3d8232bf 2340 pkgAcqMetaClearSig * const TransactionManager,
e8afd168 2341 IndexTarget const &Target,
448c38bd
DK
2342 DiffInfo const &patch,
2343 std::vector<pkgAcqIndexMergeDiffs*> const * const allPatches)
6c55f07a 2344 : pkgAcqBaseIndex(Owner, TransactionManager, Target), d(NULL),
448c38bd
DK
2345 patch(patch), allPatches(allPatches), State(StateFetchDiff)
2346{
2347 Debug = _config->FindB("Debug::pkgAcquire::Diffs",false);
2348
2349 Desc.Owner = this;
dcbbb14d
DK
2350 Description = Target.Description;
2351 Desc.ShortDesc = Target.ShortDesc;
448c38bd 2352
dcbbb14d 2353 Desc.URI = Target.URI + ".diff/" + patch.file + ".gz";
448c38bd
DK
2354 Desc.Description = Description + " " + patch.file + string(".pdiff");
2355
d7a51997 2356 DestFile = GetKeepCompressedFileName(GetPartialFileNameFromURI(Target.URI + ".diff/" + patch.file), Target);
448c38bd
DK
2357
2358 if(Debug)
2359 std::clog << "pkgAcqIndexMergeDiffs: " << Desc.URI << std::endl;
2360
2361 QueueURI(Desc);
2362}
2363 /*}}}*/
2364void pkgAcqIndexMergeDiffs::Failed(string const &Message,pkgAcquire::MethodConfig const * const Cnf)/*{{{*/
2365{
2366 if(Debug)
2367 std::clog << "pkgAcqIndexMergeDiffs failed: " << Desc.URI << " with " << Message << std::endl;
2737f28a 2368
448c38bd
DK
2369 Item::Failed(Message,Cnf);
2370 Status = StatDone;
b3d44315 2371
448c38bd
DK
2372 // check if we are the first to fail, otherwise we are done here
2373 State = StateDoneDiff;
2374 for (std::vector<pkgAcqIndexMergeDiffs *>::const_iterator I = allPatches->begin();
2375 I != allPatches->end(); ++I)
2376 if ((*I)->State == StateErrorDiff)
2377 return;
2378
2379 // first failure means we should fallback
2380 State = StateErrorDiff;
2381 if (Debug)
2382 std::clog << "Falling back to normal index file acquire" << std::endl;
d7a51997 2383 DestFile = GetKeepCompressedFileName(GetPartialFileNameFromURI(Target.URI), Target);
448c38bd 2384 RenameOnError(PDiffError);
36795154
DK
2385 std::string const patchname = GetMergeDiffsPatchFileName(DestFile, patch.file);
2386 if (RealFileExists(patchname))
2387 rename(patchname.c_str(), std::string(patchname + ".FAILED").c_str());
448c38bd 2388 new pkgAcqIndex(Owner, TransactionManager, Target);
d7a51997 2389 DestFile.clear();
b3d44315 2390}
92fcbfc1 2391 /*}}}*/
448c38bd
DK
2392void pkgAcqIndexMergeDiffs::Done(string const &Message, HashStringList const &Hashes, /*{{{*/
2393 pkgAcquire::MethodConfig const * const Cnf)
b3d44315 2394{
448c38bd
DK
2395 if(Debug)
2396 std::clog << "pkgAcqIndexMergeDiffs::Done(): " << Desc.URI << std::endl;
18593cf7 2397
448c38bd 2398 Item::Done(Message, Hashes, Cnf);
18593cf7 2399
d7a51997
DK
2400 std::string const UncompressedFinalFile = GetPartialFileNameFromURI(Target.URI);
2401 std::string const FinalFile = GetKeepCompressedFileName(GetPartialFileNameFromURI(Target.URI), Target);
448c38bd
DK
2402 if (State == StateFetchDiff)
2403 {
36795154 2404 Rename(DestFile, GetMergeDiffsPatchFileName(FinalFile, patch.file));
448c38bd
DK
2405
2406 // check if this is the last completed diff
2407 State = StateDoneDiff;
2408 for (std::vector<pkgAcqIndexMergeDiffs *>::const_iterator I = allPatches->begin();
2409 I != allPatches->end(); ++I)
2410 if ((*I)->State != StateDoneDiff)
2411 {
2412 if(Debug)
2413 std::clog << "Not the last done diff in the batch: " << Desc.URI << std::endl;
2414 return;
2415 }
2416
2417 // this is the last completed diff, so we are ready to apply now
2418 State = StateApplyDiff;
ab53c018 2419
d7a51997 2420 if (BootstrapPDiffWith(UncompressedFinalFile, GetFinalFilename(), Target) == false)
448c38bd 2421 {
d7a51997 2422 Failed("Bootstrapping of " + DestFile + " failed", NULL);
448c38bd 2423 return;
18593cf7 2424 }
448c38bd
DK
2425
2426 if(Debug)
2427 std::clog << "Sending to rred method: " << FinalFile << std::endl;
2428
2429 Local = true;
2430 Desc.URI = "rred:" + FinalFile;
2431 QueueURI(Desc);
2432 SetActiveSubprocess("rred");
2433 return;
2434 }
2435 // success in download/apply all diffs, clean up
2436 else if (State == StateApplyDiff)
2437 {
2438 // move the result into place
d7a51997 2439 std::string const Final = GetKeepCompressedFileName(GetFinalFilename(), Target);
448c38bd
DK
2440 if(Debug)
2441 std::clog << "Queue patched file in place: " << std::endl
2442 << DestFile << " -> " << Final << std::endl;
2443
2444 // queue for copy by the transaction manager
2445 TransactionManager->TransactionStageCopy(this, DestFile, Final);
2446
2447 // ensure the ed's are gone regardless of list-cleanup
2448 for (std::vector<pkgAcqIndexMergeDiffs *>::const_iterator I = allPatches->begin();
2449 I != allPatches->end(); ++I)
ab53c018 2450 {
d7a51997 2451 std::string const PartialFile = GetKeepCompressedFileName(GetPartialFileNameFromURI(Target.URI), Target);
36795154 2452 std::string const patch = GetMergeDiffsPatchFileName(PartialFile, (*I)->patch.file);
51818f26 2453 RemoveFile("pkgAcqIndexMergeDiffs::Done", patch);
b3d44315 2454 }
51818f26 2455 RemoveFile("pkgAcqIndexMergeDiffs::Done", FinalFile);
e1430400 2456
448c38bd
DK
2457 // all set and done
2458 Complete = true;
2459 if(Debug)
2460 std::clog << "allDone: " << DestFile << "\n" << std::endl;
b3d44315
MV
2461 }
2462}
92fcbfc1 2463 /*}}}*/
36795154
DK
2464std::string pkgAcqIndexMergeDiffs::Custom600Headers() const /*{{{*/
2465{
2466 if(State != StateApplyDiff)
2467 return pkgAcqBaseIndex::Custom600Headers();
2468 std::ostringstream patchhashes;
2469 unsigned int seen_patches = 0;
2470 for (std::vector<pkgAcqIndexMergeDiffs *>::const_iterator I = allPatches->begin();
2471 I != allPatches->end(); ++I)
2472 {
2473 HashStringList const ExpectedHashes = (*I)->patch.patch_hashes;
2474 for (HashStringList::const_iterator hs = ExpectedHashes.begin(); hs != ExpectedHashes.end(); ++hs)
2475 patchhashes << "\nPatch-" << seen_patches << "-" << hs->HashType() << "-Hash: " << hs->HashValue();
2476 ++seen_patches;
2477 }
2478 patchhashes << pkgAcqBaseIndex::Custom600Headers();
2479 return patchhashes.str();
2480}
2481 /*}}}*/
c8a4ce6c 2482pkgAcqIndexMergeDiffs::~pkgAcqIndexMergeDiffs() {}
448c38bd
DK
2483
2484// AcqIndex::AcqIndex - Constructor /*{{{*/
2485pkgAcqIndex::pkgAcqIndex(pkgAcquire * const Owner,
3d8232bf 2486 pkgAcqMetaClearSig * const TransactionManager,
e8afd168 2487 IndexTarget const &Target)
d7a51997
DK
2488 : pkgAcqBaseIndex(Owner, TransactionManager, Target), d(NULL), Stage(STAGE_DOWNLOAD),
2489 CompressionExtensions(Target.Option(IndexTarget::COMPRESSIONTYPES))
b3d44315 2490{
dcbbb14d 2491 Init(Target.URI, Target.Description, Target.ShortDesc);
ce424cd4 2492
448c38bd
DK
2493 if(_config->FindB("Debug::Acquire::Transaction", false) == true)
2494 std::clog << "New pkgIndex with TransactionManager "
2495 << TransactionManager << std::endl;
2496}
2497 /*}}}*/
448c38bd 2498// AcqIndex::Init - defered Constructor /*{{{*/
af81ab90 2499static void NextCompressionExtension(std::string &CurrentCompressionExtension, std::string &CompressionExtensions, bool const preview)
448c38bd 2500{
448c38bd
DK
2501 size_t const nextExt = CompressionExtensions.find(' ');
2502 if (nextExt == std::string::npos)
b3d44315 2503 {
448c38bd 2504 CurrentCompressionExtension = CompressionExtensions;
af81ab90
DK
2505 if (preview == false)
2506 CompressionExtensions.clear();
b3d44315 2507 }
448c38bd
DK
2508 else
2509 {
2510 CurrentCompressionExtension = CompressionExtensions.substr(0, nextExt);
af81ab90
DK
2511 if (preview == false)
2512 CompressionExtensions = CompressionExtensions.substr(nextExt+1);
1ddb8596 2513 }
af81ab90
DK
2514}
2515void pkgAcqIndex::Init(string const &URI, string const &URIDesc,
2516 string const &ShortDesc)
2517{
2518 Stage = STAGE_DOWNLOAD;
2519
2520 DestFile = GetPartialFileNameFromURI(URI);
2521 NextCompressionExtension(CurrentCompressionExtension, CompressionExtensions, false);
1ddb8596 2522
448c38bd 2523 if (CurrentCompressionExtension == "uncompressed")
6bf93605 2524 {
448c38bd 2525 Desc.URI = URI;
6bf93605 2526 }
af81ab90
DK
2527 else if (CurrentCompressionExtension == "by-hash")
2528 {
2529 NextCompressionExtension(CurrentCompressionExtension, CompressionExtensions, true);
2530 if(unlikely(TransactionManager->MetaIndexParser == NULL || CurrentCompressionExtension.empty()))
2531 return;
2532 if (CurrentCompressionExtension != "uncompressed")
2533 {
2534 Desc.URI = URI + '.' + CurrentCompressionExtension;
2535 DestFile = DestFile + '.' + CurrentCompressionExtension;
2536 }
2537
2538 HashStringList const Hashes = GetExpectedHashes();
2539 HashString const * const TargetHash = Hashes.find(NULL);
2540 if (unlikely(TargetHash == nullptr))
2541 return;
2542 std::string const ByHash = "/by-hash/" + TargetHash->HashType() + "/" + TargetHash->HashValue();
2543 size_t const trailing_slash = Desc.URI.find_last_of("/");
2544 if (unlikely(trailing_slash == std::string::npos))
2545 return;
2546 Desc.URI = Desc.URI.replace(
2547 trailing_slash,
2548 Desc.URI.substr(trailing_slash+1).size()+1,
2549 ByHash);
2550 }
448c38bd
DK
2551 else if (unlikely(CurrentCompressionExtension.empty()))
2552 return;
2553 else
b3d44315 2554 {
448c38bd
DK
2555 Desc.URI = URI + '.' + CurrentCompressionExtension;
2556 DestFile = DestFile + '.' + CurrentCompressionExtension;
b3d44315
MV
2557 }
2558
448c38bd
DK
2559
2560 Desc.Description = URIDesc;
2561 Desc.Owner = this;
2562 Desc.ShortDesc = ShortDesc;
2563
2564 QueueURI(Desc);
2565}
2566 /*}}}*/
448c38bd
DK
2567// AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
2568// ---------------------------------------------------------------------
2569/* The only header we use is the last-modified header. */
2570string pkgAcqIndex::Custom600Headers() const
b3d44315 2571{
c5fced38 2572
448c38bd 2573 string msg = "\nIndex-File: true";
abd6af5a
DK
2574
2575 if (TransactionManager->LastMetaIndexParser == NULL)
2576 {
2577 std::string const Final = GetFinalFilename();
2578
2579 struct stat Buf;
2580 if (stat(Final.c_str(),&Buf) == 0)
2581 msg += "\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
2582 }
1d970e6c 2583
dcbbb14d 2584 if(Target.IsOptional)
448c38bd
DK
2585 msg += "\nFail-Ignore: true";
2586
2587 return msg;
b3d44315 2588}
681d76d0 2589 /*}}}*/
448c38bd
DK
2590// AcqIndex::Failed - getting the indexfile failed /*{{{*/
2591void pkgAcqIndex::Failed(string const &Message,pkgAcquire::MethodConfig const * const Cnf)
56472095 2592{
448c38bd
DK
2593 Item::Failed(Message,Cnf);
2594
2595 // authorisation matches will not be fixed by other compression types
2596 if (Status != StatAuthError)
2597 {
2598 if (CompressionExtensions.empty() == false)
2599 {
dcbbb14d 2600 Init(Target.URI, Desc.Description, Desc.ShortDesc);
448c38bd
DK
2601 Status = StatIdle;
2602 return;
2603 }
2604 }
2605
dcbbb14d 2606 if(Target.IsOptional && GetExpectedHashes().empty() && Stage == STAGE_DOWNLOAD)
448c38bd
DK
2607 Status = StatDone;
2608 else
2609 TransactionManager->AbortTransaction();
56472095 2610}
8267fbd9 2611 /*}}}*/
448c38bd
DK
2612// AcqIndex::ReverifyAfterIMS - Reverify index after an ims-hit /*{{{*/
2613void pkgAcqIndex::ReverifyAfterIMS()
fe0f7911 2614{
448c38bd
DK
2615 // update destfile to *not* include the compression extension when doing
2616 // a reverify (as its uncompressed on disk already)
653ef26c 2617 DestFile = GetCompressedFileName(Target, GetPartialFileNameFromURI(Target.URI), CurrentCompressionExtension);
448c38bd
DK
2618
2619 // copy FinalFile into partial/ so that we check the hash again
2620 string FinalFile = GetFinalFilename();
2621 Stage = STAGE_DECOMPRESS_AND_VERIFY;
2622 Desc.URI = "copy:" + FinalFile;
2623 QueueURI(Desc);
fe0f7911
DK
2624}
2625 /*}}}*/
448c38bd
DK
2626// AcqIndex::Done - Finished a fetch /*{{{*/
2627// ---------------------------------------------------------------------
2628/* This goes through a number of states.. On the initial fetch the
2629 method could possibly return an alternate filename which points
2630 to the uncompressed version of the file. If this is so the file
2631 is copied into the partial directory. In all other cases the file
2632 is decompressed with a compressed uri. */
2633void pkgAcqIndex::Done(string const &Message,
2634 HashStringList const &Hashes,
2635 pkgAcquire::MethodConfig const * const Cfg)
8d6c5839 2636{
448c38bd
DK
2637 Item::Done(Message,Hashes,Cfg);
2638
2639 switch(Stage)
2640 {
2641 case STAGE_DOWNLOAD:
2642 StageDownloadDone(Message, Hashes, Cfg);
2643 break;
2644 case STAGE_DECOMPRESS_AND_VERIFY:
2645 StageDecompressDone(Message, Hashes, Cfg);
2646 break;
2647 }
8d6c5839
MV
2648}
2649 /*}}}*/
448c38bd
DK
2650// AcqIndex::StageDownloadDone - Queue for decompress and verify /*{{{*/
2651void pkgAcqIndex::StageDownloadDone(string const &Message, HashStringList const &,
2652 pkgAcquire::MethodConfig const * const)
6bf93605 2653{
448c38bd 2654 Complete = true;
6bf93605 2655
448c38bd 2656 // Handle the unzipd case
dd676dc7 2657 std::string FileName = LookupTag(Message,"Alt-Filename");
448c38bd 2658 if (FileName.empty() == false)
6bf93605 2659 {
448c38bd
DK
2660 Stage = STAGE_DECOMPRESS_AND_VERIFY;
2661 Local = true;
2662 DestFile += ".decomp";
2663 Desc.URI = "copy:" + FileName;
2664 QueueURI(Desc);
2665 SetActiveSubprocess("copy");
2666 return;
6bf93605 2667 }
448c38bd 2668 FileName = LookupTag(Message,"Filename");
f3097647 2669
448c38bd
DK
2670 // Methods like e.g. "file:" will give us a (compressed) FileName that is
2671 // not the "DestFile" we set, in this case we uncompress from the local file
08ea7806 2672 if (FileName != DestFile && RealFileExists(DestFile) == false)
af9e40c9 2673 {
448c38bd 2674 Local = true;
af9e40c9
DK
2675 if (Target.KeepCompressed == true)
2676 {
2677 // but if we don't keep the uncompress we copy the compressed file first
2678 Stage = STAGE_DOWNLOAD;
2679 Desc.URI = "copy:" + FileName;
2680 QueueURI(Desc);
2681 SetActiveSubprocess("copy");
2682 return;
2683 }
2684 }
448c38bd
DK
2685 else
2686 EraseFileName = FileName;
2687
2688 // we need to verify the file against the current Release file again
2689 // on if-modfied-since hit to avoid a stale attack against us
2690 if(StringToBool(LookupTag(Message,"IMS-Hit"),false) == true)
f3097647 2691 {
448c38bd
DK
2692 // The files timestamp matches, reverify by copy into partial/
2693 EraseFileName = "";
2694 ReverifyAfterIMS();
f3097647
MV
2695 return;
2696 }
448c38bd 2697
448c38bd
DK
2698 // get the binary name for your used compression type
2699 string decompProg;
2700 if(CurrentCompressionExtension == "uncompressed")
2701 decompProg = "copy";
2702 else
2703 decompProg = _config->Find(string("Acquire::CompressionTypes::").append(CurrentCompressionExtension),"");
2704 if(decompProg.empty() == true)
2705 {
2706 _error->Error("Unsupported extension: %s", CurrentCompressionExtension.c_str());
2707 return;
6bf93605 2708 }
448c38bd 2709
af9e40c9
DK
2710 if (Target.KeepCompressed == true)
2711 {
2712 DestFile = "/dev/null";
2713 EraseFileName.clear();
2714 }
2715 else
2716 DestFile += ".decomp";
2717
448c38bd
DK
2718 // queue uri for the next stage
2719 Stage = STAGE_DECOMPRESS_AND_VERIFY;
448c38bd
DK
2720 Desc.URI = decompProg + ":" + FileName;
2721 QueueURI(Desc);
2722 SetActiveSubprocess(decompProg);
a9bb651a
MV
2723}
2724 /*}}}*/
448c38bd 2725// AcqIndex::StageDecompressDone - Final verification /*{{{*/
4cd86fc6 2726void pkgAcqIndex::StageDecompressDone(string const &,
448c38bd 2727 HashStringList const &,
4cd86fc6 2728 pkgAcquire::MethodConfig const * const)
a9bb651a 2729{
af9e40c9
DK
2730 if (Target.KeepCompressed == true && DestFile == "/dev/null")
2731 DestFile = GetPartialFileNameFromURI(Target.URI + '.' + CurrentCompressionExtension);
2732
448c38bd
DK
2733 // Done, queue for rename on transaction finished
2734 TransactionManager->TransactionStageCopy(this, DestFile, GetFinalFilename());
448c38bd 2735 return;
fe0f7911
DK
2736}
2737 /*}}}*/
c8a4ce6c 2738pkgAcqIndex::~pkgAcqIndex() {}
448c38bd
DK
2739
2740
03e39e59
AL
2741// AcqArchive::AcqArchive - Constructor /*{{{*/
2742// ---------------------------------------------------------------------
17caf1b1
AL
2743/* This just sets up the initial fetch environment and queues the first
2744 possibilitiy */
448c38bd
DK
2745pkgAcqArchive::pkgAcqArchive(pkgAcquire * const Owner,pkgSourceList * const Sources,
2746 pkgRecords * const Recs,pkgCache::VerIterator const &Version,
30e1eab5 2747 string &StoreFilename) :
6c55f07a 2748 Item(Owner), d(NULL), LocalSource(false), Version(Version), Sources(Sources), Recs(Recs),
448c38bd 2749 StoreFilename(StoreFilename), Vf(Version.FileList()),
b3d44315 2750 Trusted(false)
03e39e59 2751{
7d8afa39 2752 Retries = _config->FindI("Acquire::Retries",0);
813c8eea
AL
2753
2754 if (Version.Arch() == 0)
bdae53f1 2755 {
d1f1f6a8 2756 _error->Error(_("I wasn't able to locate a file for the %s package. "
7a3c2ab0
AL
2757 "This might mean you need to manually fix this package. "
2758 "(due to missing arch)"),
40f8a8ba 2759 Version.ParentPkg().FullName().c_str());
bdae53f1
AL
2760 return;
2761 }
813c8eea 2762
b2e465d6
AL
2763 /* We need to find a filename to determine the extension. We make the
2764 assumption here that all the available sources for this version share
2765 the same extension.. */
2766 // Skip not source sources, they do not have file fields.
69c2ecbd 2767 for (; Vf.end() == false; ++Vf)
b2e465d6 2768 {
b07aeb1a 2769 if (Vf.File().Flagged(pkgCache::Flag::NotSource))
b2e465d6
AL
2770 continue;
2771 break;
2772 }
2773
2774 // Does not really matter here.. we are going to fail out below
2775 if (Vf.end() != true)
2776 {
2777 // If this fails to get a file name we will bomb out below.
2778 pkgRecords::Parser &Parse = Recs->Lookup(Vf);
2779 if (_error->PendingError() == true)
2780 return;
2781
2782 // Generate the final file name as: package_version_arch.foo
2783 StoreFilename = QuoteString(Version.ParentPkg().Name(),"_:") + '_' +
2784 QuoteString(Version.VerStr(),"_:") + '_' +
2785 QuoteString(Version.Arch(),"_:.") +
2786 "." + flExtension(Parse.FileName());
2787 }
b3d44315
MV
2788
2789 // check if we have one trusted source for the package. if so, switch
6c34ccca
DK
2790 // to "TrustedOnly" mode - but only if not in AllowUnauthenticated mode
2791 bool const allowUnauth = _config->FindB("APT::Get::AllowUnauthenticated", false);
2792 bool const debugAuth = _config->FindB("Debug::pkgAcquire::Auth", false);
2793 bool seenUntrusted = false;
f7f0d6c7 2794 for (pkgCache::VerFileIterator i = Version.FileList(); i.end() == false; ++i)
b3d44315
MV
2795 {
2796 pkgIndexFile *Index;
2797 if (Sources->FindIndex(i.File(),Index) == false)
2798 continue;
6c34ccca
DK
2799
2800 if (debugAuth == true)
b3d44315 2801 std::cerr << "Checking index: " << Index->Describe()
6c34ccca
DK
2802 << "(Trusted=" << Index->IsTrusted() << ")" << std::endl;
2803
2804 if (Index->IsTrusted() == true)
2805 {
b3d44315 2806 Trusted = true;
6c34ccca
DK
2807 if (allowUnauth == false)
2808 break;
b3d44315 2809 }
6c34ccca
DK
2810 else
2811 seenUntrusted = true;
b3d44315
MV
2812 }
2813
a3371852
MV
2814 // "allow-unauthenticated" restores apts old fetching behaviour
2815 // that means that e.g. unauthenticated file:// uris are higher
2816 // priority than authenticated http:// uris
6c34ccca 2817 if (allowUnauth == true && seenUntrusted == true)
a3371852
MV
2818 Trusted = false;
2819
03e39e59 2820 // Select a source
b185acc2 2821 if (QueueNext() == false && _error->PendingError() == false)
d57f6084
DK
2822 _error->Error(_("Can't find a source to download version '%s' of '%s'"),
2823 Version.VerStr(), Version.ParentPkg().FullName(false).c_str());
b185acc2
AL
2824}
2825 /*}}}*/
2826// AcqArchive::QueueNext - Queue the next file source /*{{{*/
2827// ---------------------------------------------------------------------
17caf1b1
AL
2828/* This queues the next available file version for download. It checks if
2829 the archive is already available in the cache and stashs the MD5 for
2830 checking later. */
b185acc2 2831bool pkgAcqArchive::QueueNext()
a722b2c5 2832{
f7f0d6c7 2833 for (; Vf.end() == false; ++Vf)
03e39e59 2834 {
448c38bd 2835 pkgCache::PkgFileIterator const PkgF = Vf.File();
03e39e59 2836 // Ignore not source sources
b07aeb1a 2837 if (PkgF.Flagged(pkgCache::Flag::NotSource))
03e39e59
AL
2838 continue;
2839
2840 // Try to cross match against the source list
b2e465d6 2841 pkgIndexFile *Index;
448c38bd 2842 if (Sources->FindIndex(PkgF, Index) == false)
b2e465d6 2843 continue;
b07aeb1a 2844 LocalSource = PkgF.Flagged(pkgCache::Flag::LocalSource);
448c38bd 2845
b3d44315
MV
2846 // only try to get a trusted package from another source if that source
2847 // is also trusted
2848 if(Trusted && !Index->IsTrusted())
2849 continue;
2850
03e39e59
AL
2851 // Grab the text package record
2852 pkgRecords::Parser &Parse = Recs->Lookup(Vf);
2853 if (_error->PendingError() == true)
b185acc2 2854 return false;
b3501edb 2855
b2e465d6 2856 string PkgFile = Parse.FileName();
b3501edb
DK
2857 ExpectedHashes = Parse.Hashes();
2858
03e39e59 2859 if (PkgFile.empty() == true)
b2e465d6
AL
2860 return _error->Error(_("The package index files are corrupted. No Filename: "
2861 "field for package %s."),
2862 Version.ParentPkg().Name());
a6568219 2863
b3d44315
MV
2864 Desc.URI = Index->ArchiveURI(PkgFile);
2865 Desc.Description = Index->ArchiveInfo(Version);
2866 Desc.Owner = this;
40f8a8ba 2867 Desc.ShortDesc = Version.ParentPkg().FullName(true);
b3d44315 2868
17caf1b1 2869 // See if we already have the file. (Legacy filenames)
a6568219
AL
2870 FileSize = Version->Size;
2871 string FinalFile = _config->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile);
2872 struct stat Buf;
2873 if (stat(FinalFile.c_str(),&Buf) == 0)
2874 {
2875 // Make sure the size matches
73da43e9 2876 if ((unsigned long long)Buf.st_size == Version->Size)
a6568219
AL
2877 {
2878 Complete = true;
2879 Local = true;
2880 Status = StatDone;
30e1eab5 2881 StoreFilename = DestFile = FinalFile;
b185acc2 2882 return true;
a6568219
AL
2883 }
2884
6b1ff003
AL
2885 /* Hmm, we have a file and its size does not match, this means it is
2886 an old style mismatched arch */
51818f26 2887 RemoveFile("pkgAcqArchive::QueueNext", FinalFile);
a6568219 2888 }
17caf1b1
AL
2889
2890 // Check it again using the new style output filenames
2891 FinalFile = _config->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename);
2892 if (stat(FinalFile.c_str(),&Buf) == 0)
2893 {
2894 // Make sure the size matches
73da43e9 2895 if ((unsigned long long)Buf.st_size == Version->Size)
17caf1b1
AL
2896 {
2897 Complete = true;
2898 Local = true;
2899 Status = StatDone;
2900 StoreFilename = DestFile = FinalFile;
2901 return true;
2902 }
2903
1e3f4083 2904 /* Hmm, we have a file and its size does not match, this shouldn't
17caf1b1 2905 happen.. */
51818f26 2906 RemoveFile("pkgAcqArchive::QueueNext", FinalFile);
17caf1b1
AL
2907 }
2908
2909 DestFile = _config->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename);
6b1ff003
AL
2910
2911 // Check the destination file
2912 if (stat(DestFile.c_str(),&Buf) == 0)
2913 {
2914 // Hmm, the partial file is too big, erase it
73da43e9 2915 if ((unsigned long long)Buf.st_size > Version->Size)
51818f26 2916 RemoveFile("pkgAcqArchive::QueueNext", DestFile);
6b1ff003
AL
2917 else
2918 PartialSize = Buf.st_size;
2919 }
de31189f
DK
2920
2921 // Disables download of archives - useful if no real installation follows,
2922 // e.g. if we are just interested in proposed installation order
2923 if (_config->FindB("Debug::pkgAcqArchive::NoQueue", false) == true)
2924 {
2925 Complete = true;
2926 Local = true;
2927 Status = StatDone;
2928 StoreFilename = DestFile = FinalFile;
2929 return true;
2930 }
2931
03e39e59 2932 // Create the item
b2e465d6 2933 Local = false;
03e39e59 2934 QueueURI(Desc);
b185acc2 2935
f7f0d6c7 2936 ++Vf;
b185acc2 2937 return true;
03e39e59 2938 }
b185acc2
AL
2939 return false;
2940}
03e39e59
AL
2941 /*}}}*/
2942// AcqArchive::Done - Finished fetching /*{{{*/
2943// ---------------------------------------------------------------------
2944/* */
448c38bd
DK
2945void pkgAcqArchive::Done(string const &Message, HashStringList const &Hashes,
2946 pkgAcquire::MethodConfig const * const Cfg)
03e39e59 2947{
448c38bd 2948 Item::Done(Message, Hashes, Cfg);
a6568219
AL
2949
2950 // Grab the output filename
dd676dc7 2951 std::string const FileName = LookupTag(Message,"Filename");
08ea7806 2952 if (DestFile != FileName && RealFileExists(DestFile) == false)
a6568219 2953 {
30e1eab5 2954 StoreFilename = DestFile = FileName;
a6568219 2955 Local = true;
5684f71f 2956 Complete = true;
a6568219
AL
2957 return;
2958 }
5684f71f 2959
a6568219 2960 // Done, move it into position
295d848b 2961 string const FinalFile = GetFinalFilename();
a6568219 2962 Rename(DestFile,FinalFile);
30e1eab5 2963 StoreFilename = DestFile = FinalFile;
03e39e59
AL
2964 Complete = true;
2965}
2966 /*}}}*/
db890fdb
AL
2967// AcqArchive::Failed - Failure handler /*{{{*/
2968// ---------------------------------------------------------------------
2969/* Here we try other sources */
448c38bd 2970void pkgAcqArchive::Failed(string const &Message,pkgAcquire::MethodConfig const * const Cnf)
db890fdb 2971{
03aa0847
DK
2972 Item::Failed(Message,Cnf);
2973
448c38bd 2974 /* We don't really want to retry on failed media swaps, this prevents
b2e465d6
AL
2975 that. An interesting observation is that permanent failures are not
2976 recorded. */
448c38bd 2977 if (Cnf->Removable == true &&
b2e465d6
AL
2978 StringToBool(LookupTag(Message,"Transient-Failure"),false) == true)
2979 {
2980 // Vf = Version.FileList();
f7f0d6c7 2981 while (Vf.end() == false) ++Vf;
b2e465d6 2982 StoreFilename = string();
b2e465d6
AL
2983 return;
2984 }
03aa0847
DK
2985
2986 Status = StatIdle;
db890fdb 2987 if (QueueNext() == false)
7d8afa39
AL
2988 {
2989 // This is the retry counter
2990 if (Retries != 0 &&
2991 Cnf->LocalOnly == false &&
2992 StringToBool(LookupTag(Message,"Transient-Failure"),false) == true)
2993 {
2994 Retries--;
2995 Vf = Version.FileList();
2996 if (QueueNext() == true)
2997 return;
2998 }
03aa0847 2999
9dbb421f 3000 StoreFilename = string();
03aa0847 3001 Status = StatError;
7d8afa39 3002 }
db890fdb
AL
3003}
3004 /*}}}*/
448c38bd 3005APT_PURE bool pkgAcqArchive::IsTrusted() const /*{{{*/
b3d44315
MV
3006{
3007 return Trusted;
3008}
92fcbfc1 3009 /*}}}*/
448c38bd 3010void pkgAcqArchive::Finished() /*{{{*/
ab559b35
AL
3011{
3012 if (Status == pkgAcquire::Item::StatDone &&
3013 Complete == true)
3014 return;
3015 StoreFilename = string();
3016}
3017 /*}}}*/
448c38bd
DK
3018std::string pkgAcqArchive::DescURI() const /*{{{*/
3019{
3020 return Desc.URI;
3021}
3022 /*}}}*/
3023std::string pkgAcqArchive::ShortDesc() const /*{{{*/
3024{
3025 return Desc.ShortDesc;
3026}
3027 /*}}}*/
c8a4ce6c 3028pkgAcqArchive::~pkgAcqArchive() {}
448c38bd 3029
d56e2917
DK
3030// AcqChangelog::pkgAcqChangelog - Constructors /*{{{*/
3031pkgAcqChangelog::pkgAcqChangelog(pkgAcquire * const Owner, pkgCache::VerIterator const &Ver,
3032 std::string const &DestDir, std::string const &DestFilename) :
3033 pkgAcquire::Item(Owner), d(NULL), SrcName(Ver.SourcePkgName()), SrcVersion(Ver.SourceVerStr())
3034{
3035 Desc.URI = URI(Ver);
3036 Init(DestDir, DestFilename);
3037}
3038// some parameters are char* here as they come likely from char* interfaces – which can also return NULL
3039pkgAcqChangelog::pkgAcqChangelog(pkgAcquire * const Owner, pkgCache::RlsFileIterator const &RlsFile,
3040 char const * const Component, char const * const SrcName, char const * const SrcVersion,
3041 const string &DestDir, const string &DestFilename) :
3042 pkgAcquire::Item(Owner), d(NULL), SrcName(SrcName), SrcVersion(SrcVersion)
3043{
3044 Desc.URI = URI(RlsFile, Component, SrcName, SrcVersion);
3045 Init(DestDir, DestFilename);
3046}
3047pkgAcqChangelog::pkgAcqChangelog(pkgAcquire * const Owner,
3048 std::string const &URI, char const * const SrcName, char const * const SrcVersion,
3049 const string &DestDir, const string &DestFilename) :
3050 pkgAcquire::Item(Owner), d(NULL), SrcName(SrcName), SrcVersion(SrcVersion)
3051{
3052 Desc.URI = URI;
3053 Init(DestDir, DestFilename);
3054}
3055void pkgAcqChangelog::Init(std::string const &DestDir, std::string const &DestFilename)
3056{
3057 if (Desc.URI.empty())
3058 {
3059 Status = StatError;
3060 // TRANSLATOR: %s=%s is sourcename=sourceversion, e.g. apt=1.1
3061 strprintf(ErrorText, _("Changelog unavailable for %s=%s"), SrcName.c_str(), SrcVersion.c_str());
3062 // Let the error message print something sensible rather than "Failed to fetch /"
3063 if (DestFilename.empty())
3064 DestFile = SrcName + ".changelog";
3065 else
3066 DestFile = DestFilename;
3067 Desc.URI = "changelog:/" + DestFile;
3068 return;
3069 }
3070
3071 if (DestDir.empty())
3072 {
dd6da7d2
DK
3073 std::string const SandboxUser = _config->Find("APT::Sandbox::User");
3074 std::string const systemTemp = GetTempDir(SandboxUser);
d56e2917
DK
3075 char tmpname[100];
3076 snprintf(tmpname, sizeof(tmpname), "%s/apt-changelog-XXXXXX", systemTemp.c_str());
3077 if (NULL == mkdtemp(tmpname))
3078 {
3079 _error->Errno("mkdtemp", "mkdtemp failed in changelog acquire of %s %s", SrcName.c_str(), SrcVersion.c_str());
3080 Status = StatError;
3081 return;
3082 }
3083 DestFile = TemporaryDirectory = tmpname;
d1256170 3084
d1256170
DK
3085 ChangeOwnerAndPermissionOfFile("Item::QueueURI", DestFile.c_str(),
3086 SandboxUser.c_str(), "root", 0700);
d56e2917
DK
3087 }
3088 else
3089 DestFile = DestDir;
3090
3091 if (DestFilename.empty())
3092 DestFile = flCombine(DestFile, SrcName + ".changelog");
3093 else
3094 DestFile = flCombine(DestFile, DestFilename);
3095
3096 Desc.ShortDesc = "Changelog";
3097 strprintf(Desc.Description, "%s %s %s Changelog", URI::SiteOnly(Desc.URI).c_str(), SrcName.c_str(), SrcVersion.c_str());
3098 Desc.Owner = this;
3099 QueueURI(Desc);
d56e2917
DK
3100}
3101 /*}}}*/
3102std::string pkgAcqChangelog::URI(pkgCache::VerIterator const &Ver) /*{{{*/
3103{
3104 char const * const SrcName = Ver.SourcePkgName();
3105 char const * const SrcVersion = Ver.SourceVerStr();
3106 pkgCache::PkgFileIterator PkgFile;
3107 // find the first source for this version which promises a changelog
3108 for (pkgCache::VerFileIterator VF = Ver.FileList(); VF.end() == false; ++VF)
3109 {
3110 pkgCache::PkgFileIterator const PF = VF.File();
3111 if (PF.Flagged(pkgCache::Flag::NotSource) || PF->Release == 0)
3112 continue;
3113 PkgFile = PF;
3114 pkgCache::RlsFileIterator const RF = PF.ReleaseFile();
3115 std::string const uri = URI(RF, PF.Component(), SrcName, SrcVersion);
3116 if (uri.empty())
3117 continue;
3118 return uri;
3119 }
3120 return "";
3121}
3122std::string pkgAcqChangelog::URITemplate(pkgCache::RlsFileIterator const &Rls)
3123{
3124 if (Rls.end() == true || (Rls->Label == 0 && Rls->Origin == 0))
3125 return "";
3126 std::string const serverConfig = "Acquire::Changelogs::URI";
3127 std::string server;
3128#define APT_EMPTY_SERVER \
3129 if (server.empty() == false) \
3130 { \
3131 if (server != "no") \
3132 return server; \
3133 return ""; \
3134 }
3135#define APT_CHECK_SERVER(X, Y) \
3136 if (Rls->X != 0) \
3137 { \
3138 std::string const specialServerConfig = serverConfig + "::" + Y + #X + "::" + Rls.X(); \
3139 server = _config->Find(specialServerConfig); \
3140 APT_EMPTY_SERVER \
3141 }
3142 // this way e.g. Debian-Security can fallback to Debian
3143 APT_CHECK_SERVER(Label, "Override::")
3144 APT_CHECK_SERVER(Origin, "Override::")
3145
3146 if (RealFileExists(Rls.FileName()))
3147 {
3148 _error->PushToStack();
3149 FileFd rf;
3150 /* This can be costly. A caller wanting to get millions of URIs might
3151 want to do this on its own once and use Override settings.
3152 We don't do this here as Origin/Label are not as unique as they
3153 should be so this could produce request order-dependent anomalies */
3154 if (OpenMaybeClearSignedFile(Rls.FileName(), rf) == true)
3155 {
3156 pkgTagFile TagFile(&rf, rf.Size());
3157 pkgTagSection Section;
3158 if (TagFile.Step(Section) == true)
3159 server = Section.FindS("Changelogs");
3160 }
3161 _error->RevertToStack();
3162 APT_EMPTY_SERVER
3163 }
3164
3165 APT_CHECK_SERVER(Label, "")
3166 APT_CHECK_SERVER(Origin, "")
3167#undef APT_CHECK_SERVER
3168#undef APT_EMPTY_SERVER
3169 return "";
3170}
3171std::string pkgAcqChangelog::URI(pkgCache::RlsFileIterator const &Rls,
3172 char const * const Component, char const * const SrcName,
3173 char const * const SrcVersion)
3174{
3175 return URI(URITemplate(Rls), Component, SrcName, SrcVersion);
3176}
3177std::string pkgAcqChangelog::URI(std::string const &Template,
3178 char const * const Component, char const * const SrcName,
3179 char const * const SrcVersion)
3180{
3181 if (Template.find("CHANGEPATH") == std::string::npos)
3182 return "";
3183
3184 // the path is: COMPONENT/SRC/SRCNAME/SRCNAME_SRCVER, e.g. main/a/apt/1.1 or contrib/liba/libapt/2.0
3185 std::string Src = SrcName;
3186 std::string path = APT::String::Startswith(SrcName, "lib") ? Src.substr(0, 4) : Src.substr(0,1);
3187 path.append("/").append(Src).append("/");
3188 path.append(Src).append("_").append(StripEpoch(SrcVersion));
3189 // we omit component for releases without one (= flat-style repositories)
3190 if (Component != NULL && strlen(Component) != 0)
3191 path = std::string(Component) + "/" + path;
3192
3193 return SubstVar(Template, "CHANGEPATH", path);
3194}
3195 /*}}}*/
3196// AcqChangelog::Failed - Failure handler /*{{{*/
3197void pkgAcqChangelog::Failed(string const &Message, pkgAcquire::MethodConfig const * const Cnf)
3198{
3199 Item::Failed(Message,Cnf);
3200
3201 std::string errText;
3202 // TRANSLATOR: %s=%s is sourcename=sourceversion, e.g. apt=1.1
3203 strprintf(errText, _("Changelog unavailable for %s=%s"), SrcName.c_str(), SrcVersion.c_str());
3204
3205 // Error is probably something techy like 404 Not Found
3206 if (ErrorText.empty())
3207 ErrorText = errText;
3208 else
3209 ErrorText = errText + " (" + ErrorText + ")";
3210 return;
3211}
3212 /*}}}*/
3213// AcqChangelog::Done - Item downloaded OK /*{{{*/
3214void pkgAcqChangelog::Done(string const &Message,HashStringList const &CalcHashes,
3215 pkgAcquire::MethodConfig const * const Cnf)
3216{
3217 Item::Done(Message,CalcHashes,Cnf);
3218
3219 Complete = true;
3220}
3221 /*}}}*/
3222pkgAcqChangelog::~pkgAcqChangelog() /*{{{*/
3223{
3224 if (TemporaryDirectory.empty() == false)
3225 {
51818f26 3226 RemoveFile("~pkgAcqChangelog", DestFile);
d56e2917
DK
3227 rmdir(TemporaryDirectory.c_str());
3228 }
3229}
3230 /*}}}*/
3231
36375005 3232// AcqFile::pkgAcqFile - Constructor /*{{{*/
448c38bd
DK
3233pkgAcqFile::pkgAcqFile(pkgAcquire * const Owner,string const &URI, HashStringList const &Hashes,
3234 unsigned long long const Size,string const &Dsc,string const &ShortDesc,
77278c2b 3235 const string &DestDir, const string &DestFilename,
448c38bd 3236 bool const IsIndexFile) :
6c55f07a 3237 Item(Owner), d(NULL), IsIndexFile(IsIndexFile), ExpectedHashes(Hashes)
36375005 3238{
08cfc005 3239 Retries = _config->FindI("Acquire::Retries",0);
448c38bd 3240
46e00f9d
MV
3241 if(!DestFilename.empty())
3242 DestFile = DestFilename;
3243 else if(!DestDir.empty())
3244 DestFile = DestDir + "/" + flNotDir(URI);
3245 else
3246 DestFile = flNotDir(URI);
3247
36375005
AL
3248 // Create the item
3249 Desc.URI = URI;
3250 Desc.Description = Dsc;
3251 Desc.Owner = this;
3252
3253 // Set the short description to the archive component
3254 Desc.ShortDesc = ShortDesc;
448c38bd 3255
36375005
AL
3256 // Get the transfer sizes
3257 FileSize = Size;
3258 struct stat Buf;
3259 if (stat(DestFile.c_str(),&Buf) == 0)
3260 {
3261 // Hmm, the partial file is too big, erase it
ed9665ae 3262 if ((Size > 0) && (unsigned long long)Buf.st_size > Size)
51818f26 3263 RemoveFile("pkgAcqFile", DestFile);
36375005
AL
3264 else
3265 PartialSize = Buf.st_size;
3266 }
092ae175 3267
36375005
AL
3268 QueueURI(Desc);
3269}
3270 /*}}}*/
3271// AcqFile::Done - Item downloaded OK /*{{{*/
448c38bd
DK
3272void pkgAcqFile::Done(string const &Message,HashStringList const &CalcHashes,
3273 pkgAcquire::MethodConfig const * const Cnf)
36375005 3274{
448c38bd 3275 Item::Done(Message,CalcHashes,Cnf);
495e5cb2 3276
dd676dc7 3277 std::string const FileName = LookupTag(Message,"Filename");
36375005 3278 Complete = true;
448c38bd 3279
36375005
AL
3280 // The files timestamp matches
3281 if (StringToBool(LookupTag(Message,"IMS-Hit"),false) == true)
3282 return;
448c38bd 3283
36375005 3284 // We have to copy it into place
08ea7806 3285 if (RealFileExists(DestFile.c_str()) == false)
36375005
AL
3286 {
3287 Local = true;
459681d3
AL
3288 if (_config->FindB("Acquire::Source-Symlinks",true) == false ||
3289 Cnf->Removable == true)
917ae805
AL
3290 {
3291 Desc.URI = "copy:" + FileName;
3292 QueueURI(Desc);
3293 return;
3294 }
448c38bd 3295
83ab33fc
AL
3296 // Erase the file if it is a symlink so we can overwrite it
3297 struct stat St;
3298 if (lstat(DestFile.c_str(),&St) == 0)
3299 {
3300 if (S_ISLNK(St.st_mode) != 0)
51818f26 3301 RemoveFile("pkgAcqFile::Done", DestFile);
83ab33fc 3302 }
448c38bd 3303
83ab33fc 3304 // Symlink the file
917ae805
AL
3305 if (symlink(FileName.c_str(),DestFile.c_str()) != 0)
3306 {
03aa0847
DK
3307 _error->PushToStack();
3308 _error->Errno("pkgAcqFile::Done", "Symlinking file %s failed", DestFile.c_str());
3309 std::stringstream msg;
95278287 3310 _error->DumpErrors(msg, GlobalError::DEBUG, false);
03aa0847
DK
3311 _error->RevertToStack();
3312 ErrorText = msg.str();
917ae805
AL
3313 Status = StatError;
3314 Complete = false;
448c38bd 3315 }
36375005
AL
3316 }
3317}
3318 /*}}}*/
08cfc005
AL
3319// AcqFile::Failed - Failure handler /*{{{*/
3320// ---------------------------------------------------------------------
3321/* Here we try other sources */
448c38bd 3322void pkgAcqFile::Failed(string const &Message, pkgAcquire::MethodConfig const * const Cnf)
08cfc005 3323{
03aa0847
DK
3324 Item::Failed(Message,Cnf);
3325
08cfc005
AL
3326 // This is the retry counter
3327 if (Retries != 0 &&
3328 Cnf->LocalOnly == false &&
3329 StringToBool(LookupTag(Message,"Transient-Failure"),false) == true)
3330 {
03aa0847 3331 --Retries;
08cfc005 3332 QueueURI(Desc);
03aa0847 3333 Status = StatIdle;
08cfc005
AL
3334 return;
3335 }
03aa0847 3336
08cfc005
AL
3337}
3338 /*}}}*/
448c38bd 3339string pkgAcqFile::Custom600Headers() const /*{{{*/
77278c2b
MV
3340{
3341 if (IsIndexFile)
3342 return "\nIndex-File: true";
61a07c57 3343 return "";
77278c2b
MV
3344}
3345 /*}}}*/
c8a4ce6c 3346pkgAcqFile::~pkgAcqFile() {}