]> git.saurik.com Git - apt.git/blame - apt-pkg/acquire-item.cc
guard const-ification API changes
[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
MV
25#include <apt-pkg/sha1.h>
26#include <apt-pkg/tagfile.h>
472ff00e 27#include <apt-pkg/indexrecords.h>
453b82a3
DK
28#include <apt-pkg/acquire.h>
29#include <apt-pkg/hashes.h>
30#include <apt-pkg/indexfile.h>
31#include <apt-pkg/pkgcache.h>
32#include <apt-pkg/cacheiterators.h>
33#include <apt-pkg/pkgrecords.h>
34
35#include <stddef.h>
36#include <stdlib.h>
37#include <string.h>
38#include <iostream>
39#include <vector>
0a8a80e5
AL
40#include <sys/stat.h>
41#include <unistd.h>
c88edf1d 42#include <errno.h>
5819a761 43#include <string>
ac5b205a 44#include <sstream>
c88edf1d 45#include <stdio.h>
1ddb8596 46#include <ctime>
ea542140
DK
47
48#include <apti18n.h>
0118833a
AL
49 /*}}}*/
50
b3d44315 51using namespace std;
5819a761 52
b3501edb
DK
53static void printHashSumComparision(std::string const &URI, HashStringList const &Expected, HashStringList const &Actual) /*{{{*/
54{
55 if (_config->FindB("Debug::Acquire::HashSumMismatch", false) == false)
56 return;
57 std::cerr << std::endl << URI << ":" << std::endl << " Expected Hash: " << std::endl;
58 for (HashStringList::const_iterator hs = Expected.begin(); hs != Expected.end(); ++hs)
59 std::cerr << "\t- " << hs->toStr() << std::endl;
60 std::cerr << " Actual Hash: " << std::endl;
61 for (HashStringList::const_iterator hs = Actual.begin(); hs != Actual.end(); ++hs)
62 std::cerr << "\t- " << hs->toStr() << std::endl;
63}
64 /*}}}*/
70b63c57 65static std::string GetPartialFileName(std::string const &file) /*{{{*/
5684f71f
DK
66{
67 std::string DestFile = _config->FindDir("Dir::State::lists") + "partial/";
68 DestFile += file;
69 return DestFile;
70}
70b63c57
DK
71 /*}}}*/
72static std::string GetPartialFileNameFromURI(std::string const &uri) /*{{{*/
5684f71f 73{
ea7682a0 74 return GetPartialFileName(URItoFileName(uri));
5684f71f 75}
70b63c57
DK
76 /*}}}*/
77static std::string GetCompressedFileName(std::string const &URI, std::string const &Name, std::string const &Ext) /*{{{*/
78{
79 if (Ext.empty() || Ext == "uncompressed")
80 return Name;
81
82 // do not reverify cdrom sources as apt-cdrom may rewrite the Packages
83 // file when its doing the indexcopy
84 if (URI.substr(0,6) == "cdrom:")
85 return Name;
5684f71f 86
70b63c57
DK
87 // adjust DestFile if its compressed on disk
88 if (_config->FindB("Acquire::GzipIndexes",false) == true)
89 return Name + '.' + Ext;
90 return Name;
91}
92 /*}}}*/
32532943
DK
93static bool AllowInsecureRepositories(indexRecords const * const MetaIndexParser, pkgAcqMetaBase * const TransactionManager, pkgAcquire::Item * const I) /*{{{*/
94{
95 if(MetaIndexParser->IsAlwaysTrusted() || _config->FindB("Acquire::AllowInsecureRepositories") == true)
96 return true;
97
98 _error->Error(_("Use --allow-insecure-repositories to force the update"));
99 TransactionManager->AbortTransaction();
100 I->Status = pkgAcquire::Item::StatError;
101 return false;
102}
103 /*}}}*/
104
b3501edb 105
0118833a 106// Acquire::Item::Item - Constructor /*{{{*/
586d8704 107APT_IGNORE_DEPRECATED_PUSH
e05672e8
MV
108pkgAcquire::Item::Item(pkgAcquire *Owner,
109 HashStringList const &ExpectedHashes,
715c65de 110 pkgAcqMetaBase *TransactionManager)
e05672e8 111 : Owner(Owner), FileSize(0), PartialSize(0), Mode(0), ID(0), Complete(false),
715c65de 112 Local(false), QueueCounter(0), TransactionManager(TransactionManager),
e05672e8 113 ExpectedAdditionalItems(0), ExpectedHashes(ExpectedHashes)
0118833a
AL
114{
115 Owner->Add(this);
c88edf1d 116 Status = StatIdle;
715c65de
MV
117 if(TransactionManager != NULL)
118 TransactionManager->Add(this);
0118833a 119}
586d8704 120APT_IGNORE_DEPRECATED_POP
0118833a
AL
121 /*}}}*/
122// Acquire::Item::~Item - Destructor /*{{{*/
123// ---------------------------------------------------------------------
124/* */
125pkgAcquire::Item::~Item()
126{
127 Owner->Remove(this);
128}
129 /*}}}*/
c88edf1d
AL
130// Acquire::Item::Failed - Item failed to download /*{{{*/
131// ---------------------------------------------------------------------
93bf083d
AL
132/* We return to an idle state if there are still other queues that could
133 fetch this object */
7d8afa39 134void pkgAcquire::Item::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
c88edf1d 135{
03aa0847 136 if(ErrorText.empty())
2737f28a 137 ErrorText = LookupTag(Message,"Message");
361593e9 138 UsedMirror = LookupTag(Message,"UsedMirror");
c88edf1d 139 if (QueueCounter <= 1)
93bf083d 140 {
a72ace20 141 /* This indicates that the file is not available right now but might
7d8afa39 142 be sometime later. If we do a retry cycle then this should be
17caf1b1 143 retried [CDROMs] */
4dbfe436 144 if (Cnf != NULL && Cnf->LocalOnly == true &&
7d8afa39 145 StringToBool(LookupTag(Message,"Transient-Failure"),false) == true)
a72ace20
AL
146 {
147 Status = StatIdle;
681d76d0 148 Dequeue();
a72ace20
AL
149 return;
150 }
7e5f33eb 151
93bf083d 152 Status = StatError;
4dbfe436 153 Complete = false;
681d76d0 154 Dequeue();
4dbfe436
DK
155 }
156 else
157 Status = StatIdle;
23c5897c 158
ee279506 159 // check fail reason
03aa0847 160 string const FailReason = LookupTag(Message, "FailReason");
ee279506 161 if(FailReason == "MaximumSizeExceeded")
03aa0847 162 RenameOnError(MaximumSizeExceeded);
ee279506
MV
163
164 // report mirror failure back to LP if we actually use a mirror
f0b509cd
MV
165 if(FailReason.size() != 0)
166 ReportMirrorFailure(FailReason);
167 else
168 ReportMirrorFailure(ErrorText);
c88edf1d
AL
169}
170 /*}}}*/
8267fe24
AL
171// Acquire::Item::Start - Item has begun to download /*{{{*/
172// ---------------------------------------------------------------------
17caf1b1
AL
173/* Stash status and the file size. Note that setting Complete means
174 sub-phases of the acquire process such as decompresion are operating */
73da43e9 175void pkgAcquire::Item::Start(string /*Message*/,unsigned long long Size)
8267fe24
AL
176{
177 Status = StatFetching;
03aa0847 178 ErrorText.clear();
8267fe24
AL
179 if (FileSize == 0 && Complete == false)
180 FileSize = Size;
181}
182 /*}}}*/
c88edf1d
AL
183// Acquire::Item::Done - Item downloaded OK /*{{{*/
184// ---------------------------------------------------------------------
185/* */
b3501edb 186void pkgAcquire::Item::Done(string Message,unsigned long long Size,HashStringList const &/*Hash*/,
65512241 187 pkgAcquire::MethodConfig * /*Cnf*/)
c88edf1d 188{
b98f2859
AL
189 // We just downloaded something..
190 string FileName = LookupTag(Message,"Filename");
1f4dd8fd 191 UsedMirror = LookupTag(Message,"UsedMirror");
8f30ca30 192 if (Complete == false && !Local && FileName == DestFile)
b98f2859
AL
193 {
194 if (Owner->Log != 0)
195 Owner->Log->Fetched(Size,atoi(LookupTag(Message,"Resume-Point","0").c_str()));
196 }
aa0e1101
AL
197
198 if (FileSize == 0)
199 FileSize= Size;
c88edf1d
AL
200 Status = StatDone;
201 ErrorText = string();
202 Owner->Dequeue(this);
203}
204 /*}}}*/
8b89e57f
AL
205// Acquire::Item::Rename - Rename a file /*{{{*/
206// ---------------------------------------------------------------------
1e3f4083 207/* This helper function is used by a lot of item methods as their final
8b89e57f 208 step */
03bfbc96 209bool pkgAcquire::Item::Rename(string From,string To)
8b89e57f 210{
cecc5532
DK
211 if (rename(From.c_str(),To.c_str()) == 0)
212 return true;
213
214 std::string S;
215 strprintf(S, _("rename failed, %s (%s -> %s)."), strerror(errno),
216 From.c_str(),To.c_str());
217 Status = StatError;
218 ErrorText += S;
219 return false;
8b89e57f
AL
220}
221 /*}}}*/
70b63c57 222void pkgAcquire::Item::QueueURI(ItemDesc &Item) /*{{{*/
5684f71f 223{
5684f71f
DK
224 Owner->Enqueue(Item);
225}
70b63c57
DK
226 /*}}}*/
227void pkgAcquire::Item::Dequeue() /*{{{*/
5684f71f
DK
228{
229 Owner->Dequeue(this);
230}
70b63c57 231 /*}}}*/
3c8030a4
DK
232bool pkgAcquire::Item::RenameOnError(pkgAcquire::Item::RenameOnErrorState const error)/*{{{*/
233{
03aa0847 234 if (RealFileExists(DestFile))
3c8030a4
DK
235 Rename(DestFile, DestFile + ".FAILED");
236
237 switch (error)
238 {
239 case HashSumMismatch:
240 ErrorText = _("Hash Sum mismatch");
241 Status = StatAuthError;
242 ReportMirrorFailure("HashChecksumFailure");
243 break;
244 case SizeMismatch:
245 ErrorText = _("Size mismatch");
246 Status = StatAuthError;
247 ReportMirrorFailure("SizeFailure");
248 break;
249 case InvalidFormat:
250 ErrorText = _("Invalid file format");
251 Status = StatError;
252 // do not report as usually its not the mirrors fault, but Portal/Proxy
253 break;
631a7dc7
MV
254 case SignatureError:
255 ErrorText = _("Signature error");
256 Status = StatError;
257 break;
258 case NotClearsigned:
03aa0847
DK
259 ErrorText = _("Does not start with a cleartext signature");
260 Status = StatError;
261 break;
262 case MaximumSizeExceeded:
263 // the method is expected to report a good error for this
631a7dc7
MV
264 Status = StatError;
265 break;
3c8030a4
DK
266 }
267 return false;
268}
269 /*}}}*/
8267fbd9 270void pkgAcquire::Item::SetActiveSubprocess(const std::string &subprocess)/*{{{*/
eeac6897
MV
271{
272 ActiveSubprocess = subprocess;
586d8704 273 APT_IGNORE_DEPRECATED(Mode = ActiveSubprocess.c_str();)
eeac6897 274}
8267fbd9 275 /*}}}*/
c91d9a63
DK
276// Acquire::Item::ReportMirrorFailure /*{{{*/
277// ---------------------------------------------------------------------
36280399
MV
278void pkgAcquire::Item::ReportMirrorFailure(string FailCode)
279{
59271f62
MV
280 // we only act if a mirror was used at all
281 if(UsedMirror.empty())
282 return;
36280399
MV
283#if 0
284 std::cerr << "\nReportMirrorFailure: "
285 << UsedMirror
59271f62 286 << " Uri: " << DescURI()
36280399
MV
287 << " FailCode: "
288 << FailCode << std::endl;
289#endif
36280399 290 string report = _config->Find("Methods::Mirror::ProblemReporting",
3f599bb7 291 "/usr/lib/apt/apt-report-mirror-failure");
36280399
MV
292 if(!FileExists(report))
293 return;
cecc5532
DK
294
295 std::vector<char const*> Args;
296 Args.push_back(report.c_str());
297 Args.push_back(UsedMirror.c_str());
298 Args.push_back(DescURI().c_str());
299 Args.push_back(FailCode.c_str());
300 Args.push_back(NULL);
301
36280399 302 pid_t pid = ExecFork();
cecc5532 303 if(pid < 0)
36280399
MV
304 {
305 _error->Error("ReportMirrorFailure Fork failed");
306 return;
307 }
cecc5532 308 else if(pid == 0)
36280399 309 {
cecc5532 310 execvp(Args[0], (char**)Args.data());
361593e9
MV
311 std::cerr << "Could not exec " << Args[0] << std::endl;
312 _exit(100);
36280399 313 }
cecc5532 314 if(!ExecWait(pid, "report-mirror-failure"))
36280399
MV
315 {
316 _error->Warning("Couldn't report problem to '%s'",
361593e9 317 _config->Find("Methods::Mirror::ProblemReporting").c_str());
36280399
MV
318 }
319}
c91d9a63 320 /*}}}*/
92fcbfc1 321// AcqDiffIndex::AcqDiffIndex - Constructor /*{{{*/
ac5b205a 322// ---------------------------------------------------------------------
1e3f4083 323/* Get the DiffIndex file first and see if there are patches available
2237bd01
MV
324 * If so, create a pkgAcqIndexDiffs fetcher that will get and apply the
325 * patches. If anything goes wrong in that process, it will fall back to
326 * the original packages file
ac5b205a 327 */
e05672e8 328pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire *Owner,
715c65de 329 pkgAcqMetaBase *TransactionManager,
e110d7bf
MV
330 IndexTarget const * const Target,
331 HashStringList const &ExpectedHashes,
e39698a4 332 indexRecords *MetaIndexParser)
715c65de 333 : pkgAcqBaseIndex(Owner, TransactionManager, Target, ExpectedHashes,
a64bf0eb 334 MetaIndexParser), PackagesFileReadyInPartial(false)
ac5b205a
MV
335{
336
ac5b205a
MV
337 Debug = _config->FindB("Debug::pkgAcquire::Diffs",false);
338
a64bf0eb 339 RealURI = Target->URI;
ac5b205a 340 Desc.Owner = this;
4d0818cc 341 Desc.Description = Target->Description + ".diff/Index";
e39698a4
MV
342 Desc.ShortDesc = Target->ShortDesc;
343 Desc.URI = Target->URI + ".diff/Index";
2237bd01 344
ea7682a0 345 DestFile = GetPartialFileNameFromURI(Desc.URI);
2237bd01
MV
346
347 if(Debug)
348 std::clog << "pkgAcqDiffIndex: " << Desc.URI << std::endl;
ac5b205a 349
2237bd01 350 // look for the current package file
ac5b205a
MV
351 CurrentPackagesFile = _config->FindDir("Dir::State::lists");
352 CurrentPackagesFile += URItoFileName(RealURI);
353
b4e57d2d
MV
354 // FIXME: this file:/ check is a hack to prevent fetching
355 // from local sources. this is really silly, and
356 // should be fixed cleanly as soon as possible
ac5b205a 357 if(!FileExists(CurrentPackagesFile) ||
81fcf9e2 358 Desc.URI.substr(0,strlen("file:/")) == "file:/")
2ac3eeb6 359 {
ac5b205a 360 // we don't have a pkg file or we don't want to queue
f6d4ab9a 361 Failed("No index file, local or canceld by user", NULL);
ac5b205a
MV
362 return;
363 }
364
1e4a2b76
AT
365 if(Debug)
366 std::clog << "pkgAcqDiffIndex::pkgAcqDiffIndex(): "
367 << CurrentPackagesFile << std::endl;
368
ac5b205a 369 QueueURI(Desc);
2237bd01 370
ac5b205a 371}
92fcbfc1 372 /*}}}*/
6cb30d01
MV
373// AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
374// ---------------------------------------------------------------------
375/* The only header we use is the last-modified header. */
02e20767 376#if APT_PKG_ABI >= 413
b3501edb 377string pkgAcqDiffIndex::Custom600Headers() const
02e20767
DK
378#else
379string pkgAcqDiffIndex::Custom600Headers()
380#endif
6cb30d01 381{
6cb30d01 382 string Final = _config->FindDir("Dir::State::lists");
31b9d841 383 Final += URItoFileName(Desc.URI);
4d0818cc 384
6cb30d01
MV
385 if(Debug)
386 std::clog << "Custom600Header-IMS: " << Final << std::endl;
387
388 struct stat Buf;
389 if (stat(Final.c_str(),&Buf) != 0)
390 return "\nIndex-File: true";
391
392 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
393}
92fcbfc1
DK
394 /*}}}*/
395bool pkgAcqDiffIndex::ParseDiffIndex(string IndexDiffFile) /*{{{*/
2237bd01 396{
f6d4ab9a
DK
397 // failing here is fine: our caller will take care of trying to
398 // get the complete file if patching fails
2237bd01 399 if(Debug)
1e4a2b76
AT
400 std::clog << "pkgAcqDiffIndex::ParseIndexDiff() " << IndexDiffFile
401 << std::endl;
2237bd01 402
2237bd01
MV
403 FileFd Fd(IndexDiffFile,FileFd::ReadOnly);
404 pkgTagFile TF(&Fd);
405 if (_error->PendingError() == true)
406 return false;
407
f6d4ab9a
DK
408 pkgTagSection Tags;
409 if(unlikely(TF.Step(Tags) == false))
410 return false;
002d9943 411
f6d4ab9a
DK
412 HashStringList ServerHashes;
413 unsigned long long ServerSize = 0;
414
415 for (char const * const * type = HashString::SupportedHashes(); *type != NULL; ++type)
416 {
417 std::string tagname = *type;
418 tagname.append("-Current");
419 std::string const tmp = Tags.FindS(tagname.c_str());
420 if (tmp.empty() == true)
421 continue;
422
423 string hash;
424 unsigned long long size;
2237bd01 425 std::stringstream ss(tmp);
f6d4ab9a
DK
426 ss >> hash >> size;
427 if (unlikely(hash.empty() == true))
428 continue;
429 if (unlikely(ServerSize != 0 && ServerSize != size))
430 continue;
431 ServerHashes.push_back(HashString(*type, hash));
432 ServerSize = size;
433 }
2237bd01 434
f6d4ab9a
DK
435 if (ServerHashes.usable() == false)
436 {
437 if (Debug == true)
438 std::clog << "pkgAcqDiffIndex: " << IndexDiffFile << ": Did not find a good hashsum in the index" << std::endl;
439 return false;
440 }
2237bd01 441
f6d4ab9a
DK
442 if (ServerHashes != HashSums())
443 {
444 if (Debug == true)
2ac3eeb6 445 {
f6d4ab9a 446 std::clog << "pkgAcqDiffIndex: " << IndexDiffFile << ": Index has different hashes than parser, probably older, so fail pdiffing" << std::endl;
4d0818cc 447 printHashSumComparision(CurrentPackagesFile, ServerHashes, HashSums());
5e1ed088 448 }
f6d4ab9a
DK
449 return false;
450 }
451
452 if (ServerHashes.VerifyFile(CurrentPackagesFile) == true)
453 {
454 // we have the same sha1 as the server so we are done here
455 if(Debug)
4d0818cc
MV
456 std::clog << "pkgAcqDiffIndex: Package file " << CurrentPackagesFile << " is up-to-date" << std::endl;
457
f6d4ab9a
DK
458 // list cleanup needs to know that this file as well as the already
459 // present index is ours, so we create an empty diff to save it for us
4d0818cc
MV
460 new pkgAcqIndexDiffs(Owner, TransactionManager, Target,
461 ExpectedHashes, MetaIndexParser);
f6d4ab9a
DK
462 return true;
463 }
464
465 FileFd fd(CurrentPackagesFile, FileFd::ReadOnly);
466 Hashes LocalHashesCalc;
467 LocalHashesCalc.AddFD(fd);
468 HashStringList const LocalHashes = LocalHashesCalc.GetHashStringList();
469
470 if(Debug)
471 std::clog << "Server-Current: " << ServerHashes.find(NULL)->toStr() << " and we start at "
472 << fd.Name() << " " << fd.FileSize() << " " << LocalHashes.find(NULL)->toStr() << std::endl;
473
474 // parse all of (provided) history
475 vector<DiffInfo> available_patches;
476 bool firstAcceptedHashes = true;
477 for (char const * const * type = HashString::SupportedHashes(); *type != NULL; ++type)
478 {
479 if (LocalHashes.find(*type) == NULL)
480 continue;
481
482 std::string tagname = *type;
483 tagname.append("-History");
484 std::string const tmp = Tags.FindS(tagname.c_str());
485 if (tmp.empty() == true)
486 continue;
487
488 string hash, filename;
489 unsigned long long size;
490 std::stringstream ss(tmp);
491
492 while (ss >> hash >> size >> filename)
2ac3eeb6 493 {
f6d4ab9a
DK
494 if (unlikely(hash.empty() == true || filename.empty() == true))
495 continue;
002d9943 496
f6d4ab9a
DK
497 // see if we have a record for this file already
498 std::vector<DiffInfo>::iterator cur = available_patches.begin();
499 for (; cur != available_patches.end(); ++cur)
2ac3eeb6 500 {
f6d4ab9a 501 if (cur->file != filename || unlikely(cur->result_size != size))
02dceb31 502 continue;
f6d4ab9a
DK
503 cur->result_hashes.push_back(HashString(*type, hash));
504 break;
02dceb31 505 }
f6d4ab9a
DK
506 if (cur != available_patches.end())
507 continue;
508 if (firstAcceptedHashes == true)
509 {
510 DiffInfo next;
511 next.file = filename;
512 next.result_hashes.push_back(HashString(*type, hash));
513 next.result_size = size;
514 next.patch_size = 0;
515 available_patches.push_back(next);
516 }
517 else
02dceb31 518 {
f6d4ab9a
DK
519 if (Debug == true)
520 std::clog << "pkgAcqDiffIndex: " << IndexDiffFile << ": File " << filename
521 << " wasn't in the list for the first parsed hash! (history)" << std::endl;
522 break;
2237bd01
MV
523 }
524 }
f6d4ab9a
DK
525 firstAcceptedHashes = false;
526 }
527
528 if (unlikely(available_patches.empty() == true))
529 {
530 if (Debug)
531 std::clog << "pkgAcqDiffIndex: " << IndexDiffFile << ": "
532 << "Couldn't find any patches for the patch series." << std::endl;
533 return false;
534 }
535
536 for (char const * const * type = HashString::SupportedHashes(); *type != NULL; ++type)
537 {
538 if (LocalHashes.find(*type) == NULL)
539 continue;
540
541 std::string tagname = *type;
542 tagname.append("-Patches");
543 std::string const tmp = Tags.FindS(tagname.c_str());
544 if (tmp.empty() == true)
545 continue;
2237bd01 546
f6d4ab9a
DK
547 string hash, filename;
548 unsigned long long size;
549 std::stringstream ss(tmp);
2237bd01 550
f6d4ab9a 551 while (ss >> hash >> size >> filename)
2ac3eeb6 552 {
f6d4ab9a
DK
553 if (unlikely(hash.empty() == true || filename.empty() == true))
554 continue;
47d2bc78 555
f6d4ab9a
DK
556 // see if we have a record for this file already
557 std::vector<DiffInfo>::iterator cur = available_patches.begin();
558 for (; cur != available_patches.end(); ++cur)
47d2bc78 559 {
f6d4ab9a
DK
560 if (cur->file != filename)
561 continue;
562 if (unlikely(cur->patch_size != 0 && cur->patch_size != size))
563 continue;
564 cur->patch_hashes.push_back(HashString(*type, hash));
565 cur->patch_size = size;
566 break;
47d2bc78 567 }
f6d4ab9a
DK
568 if (cur != available_patches.end())
569 continue;
570 if (Debug == true)
571 std::clog << "pkgAcqDiffIndex: " << IndexDiffFile << ": File " << filename
572 << " wasn't in the list for the first parsed hash! (patches)" << std::endl;
573 break;
2237bd01
MV
574 }
575 }
f6d4ab9a
DK
576
577 bool foundStart = false;
578 for (std::vector<DiffInfo>::iterator cur = available_patches.begin();
579 cur != available_patches.end(); ++cur)
580 {
581 if (LocalHashes != cur->result_hashes)
582 continue;
583
584 available_patches.erase(available_patches.begin(), cur);
585 foundStart = true;
586 break;
587 }
588
589 if (foundStart == false || unlikely(available_patches.empty() == true))
590 {
591 if (Debug)
592 std::clog << "pkgAcqDiffIndex: " << IndexDiffFile << ": "
593 << "Couldn't find the start of the patch series." << std::endl;
594 return false;
595 }
596
597 // patching with too many files is rather slow compared to a fast download
598 unsigned long const fileLimit = _config->FindI("Acquire::PDiffs::FileLimit", 0);
599 if (fileLimit != 0 && fileLimit < available_patches.size())
600 {
601 if (Debug)
602 std::clog << "Need " << available_patches.size() << " diffs (Limit is " << fileLimit
603 << ") so fallback to complete download" << std::endl;
604 return false;
605 }
606
607 // calculate the size of all patches we have to get
608 // note that all sizes are uncompressed, while we download compressed files
609 unsigned long long patchesSize = 0;
610 for (std::vector<DiffInfo>::const_iterator cur = available_patches.begin();
611 cur != available_patches.end(); ++cur)
612 patchesSize += cur->patch_size;
613 unsigned long long const sizeLimit = ServerSize * _config->FindI("Acquire::PDiffs::SizeLimit", 100);
c355ea30 614 if (sizeLimit > 0 && (sizeLimit/100) < patchesSize)
f6d4ab9a
DK
615 {
616 if (Debug)
617 std::clog << "Need " << patchesSize << " bytes (Limit is " << sizeLimit/100
618 << ") so fallback to complete download" << std::endl;
619 return false;
620 }
621
4d0818cc
MV
622 // FIXME: make this use the method
623 PackagesFileReadyInPartial = true;
624 std::string const Partial = GetPartialFileNameFromURI(RealURI);
625
626 FileFd From(CurrentPackagesFile, FileFd::ReadOnly);
627 FileFd To(Partial, FileFd::WriteEmpty);
628 if(CopyFile(From, To) == false)
629 return _error->Errno("CopyFile", "failed to copy");
05aab406 630
05aab406 631 if(Debug)
4d0818cc
MV
632 std::cerr << "Done copying " << CurrentPackagesFile
633 << " -> " << Partial
634 << std::endl;
635
f6d4ab9a
DK
636 // we have something, queue the diffs
637 string::size_type const last_space = Description.rfind(" ");
638 if(last_space != string::npos)
639 Description.erase(last_space, Description.size()-last_space);
640
641 /* decide if we should download patches one by one or in one go:
642 The first is good if the server merges patches, but many don't so client
643 based merging can be attempt in which case the second is better.
644 "bad things" will happen if patches are merged on the server,
645 but client side merging is attempt as well */
646 bool pdiff_merge = _config->FindB("Acquire::PDiffs::Merge", true);
647 if (pdiff_merge == true)
648 {
649 // reprepro adds this flag if it has merged patches on the server
650 std::string const precedence = Tags.FindS("X-Patch-Precedence");
651 pdiff_merge = (precedence != "merged");
652 }
653
654 if (pdiff_merge == false)
655 {
4d0818cc
MV
656 new pkgAcqIndexDiffs(Owner, TransactionManager, Target, ExpectedHashes,
657 MetaIndexParser, available_patches);
f6d4ab9a
DK
658 }
659 else
660 {
661 std::vector<pkgAcqIndexMergeDiffs*> *diffs = new std::vector<pkgAcqIndexMergeDiffs*>(available_patches.size());
662 for(size_t i = 0; i < available_patches.size(); ++i)
4d0818cc
MV
663 (*diffs)[i] = new pkgAcqIndexMergeDiffs(Owner, TransactionManager,
664 Target,
f6d4ab9a
DK
665 ExpectedHashes,
666 MetaIndexParser,
667 available_patches[i],
668 diffs);
669 }
670
671 Complete = false;
672 Status = StatDone;
673 Dequeue();
674 return true;
2237bd01 675}
92fcbfc1 676 /*}}}*/
4dbfe436 677void pkgAcqDiffIndex::Failed(string Message,pkgAcquire::MethodConfig * Cnf)/*{{{*/
2237bd01 678{
03aa0847
DK
679 Item::Failed(Message,Cnf);
680 Status = StatDone;
681
2237bd01 682 if(Debug)
65512241 683 std::clog << "pkgAcqDiffIndex failed: " << Desc.URI << " with " << Message << std::endl
1e3f4083 684 << "Falling back to normal index file acquire" << std::endl;
2237bd01 685
715c65de 686 new pkgAcqIndex(Owner, TransactionManager, Target, ExpectedHashes, MetaIndexParser);
2237bd01 687}
92fcbfc1 688 /*}}}*/
b3501edb 689void pkgAcqDiffIndex::Done(string Message,unsigned long long Size,HashStringList const &Hashes, /*{{{*/
2237bd01
MV
690 pkgAcquire::MethodConfig *Cnf)
691{
692 if(Debug)
693 std::clog << "pkgAcqDiffIndex::Done(): " << Desc.URI << std::endl;
694
b3501edb 695 Item::Done(Message, Size, Hashes, Cnf);
2237bd01 696
8d266656 697 // verify the index target
1e8ba0d4 698 if(Target && Target->MetaKey != "" && MetaIndexParser && Hashes.usable())
8d266656
MV
699 {
700 std::string IndexMetaKey = Target->MetaKey + ".diff/Index";
701 indexRecords::checkSum *Record = MetaIndexParser->Lookup(IndexMetaKey);
702 if(Record && Record->Hashes.usable() && Hashes != Record->Hashes)
703 {
704 RenameOnError(HashSumMismatch);
705 printHashSumComparision(RealURI, Record->Hashes, Hashes);
706 Failed(Message, Cnf);
707 return;
708 }
709
710 }
711
2237bd01 712 string FinalFile;
4d0818cc
MV
713 FinalFile = _config->FindDir("Dir::State::lists");
714 FinalFile += URItoFileName(Desc.URI);
2237bd01 715
4d0818cc
MV
716 if(StringToBool(LookupTag(Message,"IMS-Hit"),false))
717 DestFile = FinalFile;
2237bd01 718
22b2ef9d 719 if(!ParseDiffIndex(DestFile))
4dbfe436 720 return Failed("Message: Couldn't parse pdiff index", Cnf);
22b2ef9d
MV
721
722 // queue for final move
22b2ef9d 723 TransactionManager->TransactionStageCopy(this, DestFile, FinalFile);
2237bd01
MV
724
725 Complete = true;
726 Status = StatDone;
727 Dequeue();
728 return;
729}
92fcbfc1
DK
730 /*}}}*/
731// AcqIndexDiffs::AcqIndexDiffs - Constructor /*{{{*/
2237bd01
MV
732// ---------------------------------------------------------------------
733/* The package diff is added to the queue. one object is constructed
734 * for each diff and the index
735 */
e05672e8 736pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire *Owner,
715c65de 737 pkgAcqMetaBase *TransactionManager,
c2184314 738 struct IndexTarget const * const Target,
e110d7bf 739 HashStringList const &ExpectedHashes,
c2184314 740 indexRecords *MetaIndexParser,
495e5cb2 741 vector<DiffInfo> diffs)
a64bf0eb 742 : pkgAcqBaseIndex(Owner, TransactionManager, Target, ExpectedHashes, MetaIndexParser),
f6d4ab9a 743 available_patches(diffs)
2237bd01 744{
ea7682a0 745 DestFile = GetPartialFileNameFromURI(Target->URI);
2237bd01
MV
746
747 Debug = _config->FindB("Debug::pkgAcquire::Diffs",false);
748
a64bf0eb 749 RealURI = Target->URI;
2237bd01 750 Desc.Owner = this;
c2184314
MV
751 Description = Target->Description;
752 Desc.ShortDesc = Target->ShortDesc;
2237bd01 753
69c2ecbd 754 if(available_patches.empty() == true)
2ac3eeb6 755 {
03bfbc96
MV
756 // we are done (yeah!), check hashes against the final file
757 DestFile = _config->FindDir("Dir::State::lists");
758 DestFile += URItoFileName(Target->URI);
2237bd01 759 Finish(true);
2ac3eeb6
MV
760 }
761 else
762 {
2237bd01
MV
763 // get the next diff
764 State = StateFetchDiff;
765 QueueNextDiff();
766 }
767}
92fcbfc1 768 /*}}}*/
03aa0847 769void pkgAcqIndexDiffs::Failed(string Message,pkgAcquire::MethodConfig * Cnf)/*{{{*/
ac5b205a 770{
03aa0847
DK
771 Item::Failed(Message,Cnf);
772 Status = StatDone;
773
2237bd01 774 if(Debug)
65512241 775 std::clog << "pkgAcqIndexDiffs failed: " << Desc.URI << " with " << Message << std::endl
1e3f4083 776 << "Falling back to normal index file acquire" << std::endl;
715c65de 777 new pkgAcqIndex(Owner, TransactionManager, Target, ExpectedHashes, MetaIndexParser);
ac5b205a
MV
778 Finish();
779}
92fcbfc1
DK
780 /*}}}*/
781// Finish - helper that cleans the item out of the fetcher queue /*{{{*/
ac5b205a
MV
782void pkgAcqIndexDiffs::Finish(bool allDone)
783{
d4ab7e9c
MV
784 if(Debug)
785 std::clog << "pkgAcqIndexDiffs::Finish(): "
786 << allDone << " "
787 << Desc.URI << std::endl;
788
ac5b205a
MV
789 // we restore the original name, this is required, otherwise
790 // the file will be cleaned
2ac3eeb6
MV
791 if(allDone)
792 {
fa3b260f 793 if(HashSums().usable() && !HashSums().VerifyFile(DestFile))
2d4722e2 794 {
3c8030a4 795 RenameOnError(HashSumMismatch);
2d4722e2
MV
796 Dequeue();
797 return;
798 }
799
03bfbc96 800 // queue for copy
4d0818cc
MV
801 std::string FinalFile = _config->FindDir("Dir::State::lists");
802 FinalFile += URItoFileName(RealURI);
803 TransactionManager->TransactionStageCopy(this, DestFile, FinalFile);
fa3a96a1 804
2d4722e2 805 // this is for the "real" finish
ac5b205a 806 Complete = true;
cffc2ddd 807 Status = StatDone;
ac5b205a
MV
808 Dequeue();
809 if(Debug)
810 std::clog << "\n\nallDone: " << DestFile << "\n" << std::endl;
811 return;
ac5b205a
MV
812 }
813
814 if(Debug)
815 std::clog << "Finishing: " << Desc.URI << std::endl;
816 Complete = false;
817 Status = StatDone;
818 Dequeue();
819 return;
820}
92fcbfc1
DK
821 /*}}}*/
822bool pkgAcqIndexDiffs::QueueNextDiff() /*{{{*/
ac5b205a 823{
94dc9d7d 824 // calc sha1 of the just patched file
ea7682a0 825 std::string const FinalFile = GetPartialFileNameFromURI(RealURI);
03bfbc96
MV
826
827 if(!FileExists(FinalFile))
828 {
4dbfe436 829 Failed("Message: No FinalFile " + FinalFile + " available", NULL);
03bfbc96
MV
830 return false;
831 }
94dc9d7d 832
f213b6ea 833 FileFd fd(FinalFile, FileFd::ReadOnly);
f6d4ab9a
DK
834 Hashes LocalHashesCalc;
835 LocalHashesCalc.AddFD(fd);
836 HashStringList const LocalHashes = LocalHashesCalc.GetHashStringList();
837
3de9ff77 838 if(Debug)
f6d4ab9a
DK
839 std::clog << "QueueNextDiff: " << FinalFile << " (" << LocalHashes.find(NULL)->toStr() << ")" << std::endl;
840
841 if (unlikely(LocalHashes.usable() == false || ExpectedHashes.usable() == false))
842 {
843 Failed("Local/Expected hashes are not usable", NULL);
844 return false;
845 }
94dc9d7d 846
03bfbc96 847
8a3207f4 848 // final file reached before all patches are applied
f6d4ab9a 849 if(LocalHashes == ExpectedHashes)
8a3207f4
DK
850 {
851 Finish(true);
852 return true;
853 }
854
26d27645
MV
855 // remove all patches until the next matching patch is found
856 // this requires the Index file to be ordered
f6d4ab9a 857 for(vector<DiffInfo>::iterator I = available_patches.begin();
f7f0d6c7 858 available_patches.empty() == false &&
2ac3eeb6 859 I != available_patches.end() &&
f6d4ab9a 860 I->result_hashes != LocalHashes;
f7f0d6c7 861 ++I)
2ac3eeb6 862 {
26d27645 863 available_patches.erase(I);
59a704f0 864 }
94dc9d7d
MV
865
866 // error checking and falling back if no patch was found
f7f0d6c7
DK
867 if(available_patches.empty() == true)
868 {
f6d4ab9a 869 Failed("No patches left to reach target", NULL);
94dc9d7d
MV
870 return false;
871 }
6cb30d01 872
94dc9d7d 873 // queue the right diff
e788a834 874 Desc.URI = RealURI + ".diff/" + available_patches[0].file + ".gz";
05aab406 875 Desc.Description = Description + " " + available_patches[0].file + string(".pdiff");
ea7682a0 876 DestFile = GetPartialFileNameFromURI(RealURI + ".diff/" + available_patches[0].file);
ac5b205a
MV
877
878 if(Debug)
879 std::clog << "pkgAcqIndexDiffs::QueueNextDiff(): " << Desc.URI << std::endl;
f6d4ab9a 880
ac5b205a
MV
881 QueueURI(Desc);
882
883 return true;
884}
92fcbfc1 885 /*}}}*/
b3501edb 886void pkgAcqIndexDiffs::Done(string Message,unsigned long long Size, HashStringList const &Hashes, /*{{{*/
ac5b205a
MV
887 pkgAcquire::MethodConfig *Cnf)
888{
889 if(Debug)
890 std::clog << "pkgAcqIndexDiffs::Done(): " << Desc.URI << std::endl;
891
b3501edb 892 Item::Done(Message, Size, Hashes, Cnf);
ac5b205a 893
8d266656 894 // FIXME: verify this download too before feeding it to rred
ea7682a0 895 std::string const FinalFile = GetPartialFileNameFromURI(RealURI);
6cb30d01 896
1e3f4083 897 // success in downloading a diff, enter ApplyDiff state
caffd480 898 if(State == StateFetchDiff)
4a0a786f 899 {
f6d4ab9a
DK
900 FileFd fd(DestFile, FileFd::ReadOnly, FileFd::Gzip);
901 class Hashes LocalHashesCalc;
902 LocalHashesCalc.AddFD(fd);
903 HashStringList const LocalHashes = LocalHashesCalc.GetHashStringList();
904
905 if (fd.Size() != available_patches[0].patch_size ||
906 available_patches[0].patch_hashes != LocalHashes)
907 {
908 Failed("Patch has Size/Hashsum mismatch", NULL);
909 return;
910 }
4a0a786f
MV
911
912 // rred excepts the patch as $FinalFile.ed
913 Rename(DestFile,FinalFile+".ed");
914
915 if(Debug)
916 std::clog << "Sending to rred method: " << FinalFile << std::endl;
917
918 State = StateApplyDiff;
b7347826 919 Local = true;
4a0a786f
MV
920 Desc.URI = "rred:" + FinalFile;
921 QueueURI(Desc);
eeac6897 922 SetActiveSubprocess("rred");
4a0a786f
MV
923 return;
924 }
925
926
927 // success in download/apply a diff, queue next (if needed)
928 if(State == StateApplyDiff)
929 {
930 // remove the just applied patch
94dc9d7d 931 available_patches.erase(available_patches.begin());
34d6ece7 932 unlink((FinalFile + ".ed").c_str());
ac5b205a 933
4a0a786f 934 // move into place
59a704f0
MV
935 if(Debug)
936 {
4a0a786f
MV
937 std::clog << "Moving patched file in place: " << std::endl
938 << DestFile << " -> " << FinalFile << std::endl;
59a704f0 939 }
4a0a786f 940 Rename(DestFile,FinalFile);
1790e0cf 941 chmod(FinalFile.c_str(),0644);
4a0a786f
MV
942
943 // see if there is more to download
f7f0d6c7 944 if(available_patches.empty() == false) {
715c65de 945 new pkgAcqIndexDiffs(Owner, TransactionManager, Target,
e110d7bf 946 ExpectedHashes, MetaIndexParser,
f6d4ab9a 947 available_patches);
4a0a786f
MV
948 return Finish();
949 } else
03bfbc96
MV
950 // update
951 DestFile = FinalFile;
4a0a786f 952 return Finish(true);
ac5b205a 953 }
ac5b205a 954}
92fcbfc1 955 /*}}}*/
47d2bc78 956// AcqIndexMergeDiffs::AcqIndexMergeDiffs - Constructor /*{{{*/
e05672e8 957pkgAcqIndexMergeDiffs::pkgAcqIndexMergeDiffs(pkgAcquire *Owner,
715c65de 958 pkgAcqMetaBase *TransactionManager,
c2184314 959 struct IndexTarget const * const Target,
e110d7bf 960 HashStringList const &ExpectedHashes,
c2184314
MV
961 indexRecords *MetaIndexParser,
962 DiffInfo const &patch,
963 std::vector<pkgAcqIndexMergeDiffs*> const * const allPatches)
a64bf0eb 964 : pkgAcqBaseIndex(Owner, TransactionManager, Target, ExpectedHashes, MetaIndexParser),
0b58b3f8 965 patch(patch), allPatches(allPatches), State(StateFetchDiff)
47d2bc78 966{
47d2bc78
DK
967 Debug = _config->FindB("Debug::pkgAcquire::Diffs",false);
968
a64bf0eb 969 RealURI = Target->URI;
47d2bc78 970 Desc.Owner = this;
c2184314
MV
971 Description = Target->Description;
972 Desc.ShortDesc = Target->ShortDesc;
47d2bc78 973
e788a834 974 Desc.URI = RealURI + ".diff/" + patch.file + ".gz";
47d2bc78 975 Desc.Description = Description + " " + patch.file + string(".pdiff");
5684f71f 976
ea7682a0 977 DestFile = GetPartialFileNameFromURI(RealURI + ".diff/" + patch.file);
47d2bc78
DK
978
979 if(Debug)
980 std::clog << "pkgAcqIndexMergeDiffs: " << Desc.URI << std::endl;
981
982 QueueURI(Desc);
983}
984 /*}}}*/
4dbfe436 985void pkgAcqIndexMergeDiffs::Failed(string Message,pkgAcquire::MethodConfig * Cnf)/*{{{*/
47d2bc78
DK
986{
987 if(Debug)
988 std::clog << "pkgAcqIndexMergeDiffs failed: " << Desc.URI << " with " << Message << std::endl;
4dbfe436
DK
989
990 Item::Failed(Message,Cnf);
47d2bc78 991 Status = StatDone;
47d2bc78
DK
992
993 // check if we are the first to fail, otherwise we are done here
994 State = StateDoneDiff;
995 for (std::vector<pkgAcqIndexMergeDiffs *>::const_iterator I = allPatches->begin();
996 I != allPatches->end(); ++I)
997 if ((*I)->State == StateErrorDiff)
998 return;
999
1000 // first failure means we should fallback
1001 State = StateErrorDiff;
1e3f4083 1002 std::clog << "Falling back to normal index file acquire" << std::endl;
715c65de 1003 new pkgAcqIndex(Owner, TransactionManager, Target, ExpectedHashes, MetaIndexParser);
47d2bc78
DK
1004}
1005 /*}}}*/
b3501edb 1006void pkgAcqIndexMergeDiffs::Done(string Message,unsigned long long Size,HashStringList const &Hashes, /*{{{*/
47d2bc78
DK
1007 pkgAcquire::MethodConfig *Cnf)
1008{
1009 if(Debug)
1010 std::clog << "pkgAcqIndexMergeDiffs::Done(): " << Desc.URI << std::endl;
1011
b3501edb 1012 Item::Done(Message,Size,Hashes,Cnf);
47d2bc78 1013
8d266656 1014 // FIXME: verify download before feeding it to rred
ea7682a0 1015 string const FinalFile = GetPartialFileNameFromURI(RealURI);
47d2bc78
DK
1016
1017 if (State == StateFetchDiff)
1018 {
f6d4ab9a
DK
1019 FileFd fd(DestFile, FileFd::ReadOnly, FileFd::Gzip);
1020 class Hashes LocalHashesCalc;
1021 LocalHashesCalc.AddFD(fd);
1022 HashStringList const LocalHashes = LocalHashesCalc.GetHashStringList();
1023
1024 if (fd.Size() != patch.patch_size || patch.patch_hashes != LocalHashes)
1025 {
1026 Failed("Patch has Size/Hashsum mismatch", NULL);
1027 return;
1028 }
1029
47d2bc78
DK
1030 // rred expects the patch as $FinalFile.ed.$patchname.gz
1031 Rename(DestFile, FinalFile + ".ed." + patch.file + ".gz");
1032
1033 // check if this is the last completed diff
1034 State = StateDoneDiff;
1035 for (std::vector<pkgAcqIndexMergeDiffs *>::const_iterator I = allPatches->begin();
1036 I != allPatches->end(); ++I)
1037 if ((*I)->State != StateDoneDiff)
1038 {
1039 if(Debug)
1040 std::clog << "Not the last done diff in the batch: " << Desc.URI << std::endl;
1041 return;
1042 }
1043
1044 // this is the last completed diff, so we are ready to apply now
1045 State = StateApplyDiff;
1046
1047 if(Debug)
1048 std::clog << "Sending to rred method: " << FinalFile << std::endl;
1049
1050 Local = true;
1051 Desc.URI = "rred:" + FinalFile;
1052 QueueURI(Desc);
eeac6897 1053 SetActiveSubprocess("rred");
47d2bc78
DK
1054 return;
1055 }
1056 // success in download/apply all diffs, clean up
1057 else if (State == StateApplyDiff)
1058 {
1059 // see if we really got the expected file
b3501edb 1060 if(ExpectedHashes.usable() && !ExpectedHashes.VerifyFile(DestFile))
47d2bc78
DK
1061 {
1062 RenameOnError(HashSumMismatch);
1063 return;
1064 }
1065
03bfbc96
MV
1066
1067 std::string FinalFile = _config->FindDir("Dir::State::lists");
1068 FinalFile += URItoFileName(RealURI);
1069
47d2bc78
DK
1070 // move the result into place
1071 if(Debug)
03bfbc96 1072 std::clog << "Queue patched file in place: " << std::endl
47d2bc78 1073 << DestFile << " -> " << FinalFile << std::endl;
47d2bc78 1074
03bfbc96 1075 // queue for copy by the transaction manager
fa3a96a1 1076 TransactionManager->TransactionStageCopy(this, DestFile, FinalFile);
47d2bc78 1077
34d6ece7
DK
1078 // ensure the ed's are gone regardless of list-cleanup
1079 for (std::vector<pkgAcqIndexMergeDiffs *>::const_iterator I = allPatches->begin();
1080 I != allPatches->end(); ++I)
1081 {
844c9535
DK
1082 std::string const PartialFile = GetPartialFileNameFromURI(RealURI);
1083 std::string patch = PartialFile + ".ed." + (*I)->patch.file + ".gz";
1084 unlink(patch.c_str());
34d6ece7
DK
1085 }
1086
47d2bc78
DK
1087 // all set and done
1088 Complete = true;
1089 if(Debug)
1090 std::clog << "allDone: " << DestFile << "\n" << std::endl;
1091 }
1092}
1093 /*}}}*/
651bddad
MV
1094// AcqBaseIndex::VerifyHashByMetaKey - verify hash for the given metakey /*{{{*/
1095bool pkgAcqBaseIndex::VerifyHashByMetaKey(HashStringList const &Hashes)
1096{
1e8ba0d4 1097 if(MetaKey != "" && Hashes.usable())
651bddad
MV
1098 {
1099 indexRecords::checkSum *Record = MetaIndexParser->Lookup(MetaKey);
1100 if(Record && Record->Hashes.usable() && Hashes != Record->Hashes)
1101 {
1102 printHashSumComparision(RealURI, Record->Hashes, Hashes);
1103 return false;
1104 }
1105 }
1106 return true;
1107}
8267fbd9 1108 /*}}}*/
0118833a
AL
1109// AcqIndex::AcqIndex - Constructor /*{{{*/
1110// ---------------------------------------------------------------------
8267fbd9
DK
1111/* The package file is added to the queue and a second class is
1112 instantiated to fetch the revision file */
b2e465d6 1113pkgAcqIndex::pkgAcqIndex(pkgAcquire *Owner,
b3d44315 1114 string URI,string URIDesc,string ShortDesc,
916b8910 1115 HashStringList const &ExpectedHash)
a64bf0eb 1116 : pkgAcqBaseIndex(Owner, 0, NULL, ExpectedHash, NULL)
0118833a 1117{
a64bf0eb
MV
1118 RealURI = URI;
1119
56472095 1120 AutoSelectCompression();
21638c3a
MV
1121 Init(URI, URIDesc, ShortDesc);
1122
1123 if(_config->FindB("Debug::Acquire::Transaction", false) == true)
715c65de
MV
1124 std::clog << "New pkgIndex with TransactionManager "
1125 << TransactionManager << std::endl;
56472095 1126}
56472095 1127 /*}}}*/
21638c3a 1128// AcqIndex::AcqIndex - Constructor /*{{{*/
e05672e8 1129pkgAcqIndex::pkgAcqIndex(pkgAcquire *Owner,
715c65de 1130 pkgAcqMetaBase *TransactionManager,
56472095 1131 IndexTarget const *Target,
8267fbd9 1132 HashStringList const &ExpectedHash,
56472095 1133 indexRecords *MetaIndexParser)
8267fbd9 1134 : pkgAcqBaseIndex(Owner, TransactionManager, Target, ExpectedHash,
a64bf0eb 1135 MetaIndexParser)
56472095 1136{
a64bf0eb
MV
1137 RealURI = Target->URI;
1138
56472095
MV
1139 // autoselect the compression method
1140 AutoSelectCompression();
1141 Init(Target->URI, Target->Description, Target->ShortDesc);
1142
e05672e8 1143 if(_config->FindB("Debug::Acquire::Transaction", false) == true)
715c65de
MV
1144 std::clog << "New pkgIndex with TransactionManager "
1145 << TransactionManager << std::endl;
56472095
MV
1146}
1147 /*}}}*/
21638c3a 1148// AcqIndex::AutoSelectCompression - Select compression /*{{{*/
56472095
MV
1149void pkgAcqIndex::AutoSelectCompression()
1150{
5d885723 1151 std::vector<std::string> types = APT::Configuration::getCompressionTypes();
651bddad 1152 CompressionExtensions = "";
b3501edb 1153 if (ExpectedHashes.usable())
5d885723 1154 {
651bddad
MV
1155 for (std::vector<std::string>::const_iterator t = types.begin();
1156 t != types.end(); ++t)
1157 {
1158 std::string CompressedMetaKey = string(Target->MetaKey).append(".").append(*t);
8267fbd9 1159 if (*t == "uncompressed" ||
651bddad
MV
1160 MetaIndexParser->Exists(CompressedMetaKey) == true)
1161 CompressionExtensions.append(*t).append(" ");
1162 }
5d885723
DK
1163 }
1164 else
1165 {
1166 for (std::vector<std::string>::const_iterator t = types.begin(); t != types.end(); ++t)
651bddad 1167 CompressionExtensions.append(*t).append(" ");
5d885723 1168 }
651bddad
MV
1169 if (CompressionExtensions.empty() == false)
1170 CompressionExtensions.erase(CompressionExtensions.end()-1);
5d885723 1171}
8267fbd9 1172 /*}}}*/
5d885723 1173// AcqIndex::Init - defered Constructor /*{{{*/
8267fbd9 1174void pkgAcqIndex::Init(string const &URI, string const &URIDesc,
3f073d44
MV
1175 string const &ShortDesc)
1176{
651bddad 1177 Stage = STAGE_DOWNLOAD;
13e8426f 1178
ea7682a0 1179 DestFile = GetPartialFileNameFromURI(URI);
8267fe24 1180
1e8ba0d4
MV
1181 CurrentCompressionExtension = CompressionExtensions.substr(0, CompressionExtensions.find(' '));
1182 if (CurrentCompressionExtension == "uncompressed")
b11f9599 1183 {
5d885723 1184 Desc.URI = URI;
e39698a4
MV
1185 if(Target)
1186 MetaKey = string(Target->MetaKey);
b11f9599 1187 }
5d885723 1188 else
b11f9599 1189 {
1e8ba0d4
MV
1190 Desc.URI = URI + '.' + CurrentCompressionExtension;
1191 DestFile = DestFile + '.' + CurrentCompressionExtension;
e39698a4 1192 if(Target)
1e8ba0d4 1193 MetaKey = string(Target->MetaKey) + '.' + CurrentCompressionExtension;
b11f9599
MV
1194 }
1195
1196 // load the filesize
e39698a4
MV
1197 if(MetaIndexParser)
1198 {
1199 indexRecords::checkSum *Record = MetaIndexParser->Lookup(MetaKey);
1200 if(Record)
1201 FileSize = Record->Size;
8267fbd9 1202
59194959 1203 InitByHashIfNeeded(MetaKey);
e39698a4 1204 }
b3d44315 1205
b2e465d6 1206 Desc.Description = URIDesc;
8267fe24 1207 Desc.Owner = this;
b2e465d6 1208 Desc.ShortDesc = ShortDesc;
5d885723 1209
8267fe24 1210 QueueURI(Desc);
0118833a
AL
1211}
1212 /*}}}*/
59194959 1213// AcqIndex::AdjustForByHash - modify URI for by-hash support /*{{{*/
59194959
MV
1214void pkgAcqIndex::InitByHashIfNeeded(const std::string MetaKey)
1215{
1216 // TODO:
1217 // - (maybe?) add support for by-hash into the sources.list as flag
1218 // - make apt-ftparchive generate the hashes (and expire?)
1219 std::string HostKnob = "APT::Acquire::" + ::URI(Desc.URI).Host + "::By-Hash";
1220 if(_config->FindB("APT::Acquire::By-Hash", false) == true ||
1221 _config->FindB(HostKnob, false) == true ||
1222 MetaIndexParser->GetSupportsAcquireByHash())
1223 {
1224 indexRecords::checkSum *Record = MetaIndexParser->Lookup(MetaKey);
1225 if(Record)
1226 {
1227 // FIXME: should we really use the best hash here? or a fixed one?
1228 const HashString *TargetHash = Record->Hashes.find("");
1229 std::string ByHash = "/by-hash/" + TargetHash->HashType() + "/" + TargetHash->HashValue();
1230 size_t trailing_slash = Desc.URI.find_last_of("/");
1231 Desc.URI = Desc.URI.replace(
1232 trailing_slash,
1233 Desc.URI.substr(trailing_slash+1).size()+1,
1234 ByHash);
1235 } else {
1236 _error->Warning(
1237 "Fetching ByHash requested but can not find record for %s",
1238 MetaKey.c_str());
1239 }
1240 }
1241}
1242 /*}}}*/
0a8a80e5 1243// AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
0118833a 1244// ---------------------------------------------------------------------
0a8a80e5 1245/* The only header we use is the last-modified header. */
02e20767 1246#if APT_PKG_ABI >= 413
b3501edb 1247string pkgAcqIndex::Custom600Headers() const
02e20767
DK
1248#else
1249string pkgAcqIndex::Custom600Headers()
1250#endif
0118833a 1251{
3f073d44 1252 string Final = GetFinalFilename();
8267fbd9 1253
97b65b10 1254 string msg = "\nIndex-File: true";
0a8a80e5 1255 struct stat Buf;
3a1f49c4 1256 if (stat(Final.c_str(),&Buf) == 0)
97b65b10
MV
1257 msg += "\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
1258
18593cf7
MV
1259 if(Target->IsOptional())
1260 msg += "\nFail-Ignore: true";
1261
97b65b10 1262 return msg;
0118833a
AL
1263}
1264 /*}}}*/
8267fbd9
DK
1265// pkgAcqIndex::Failed - getting the indexfile failed /*{{{*/
1266void pkgAcqIndex::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
debc84b2 1267{
03aa0847
DK
1268 Item::Failed(Message,Cnf);
1269
651bddad 1270 size_t const nextExt = CompressionExtensions.find(' ');
5d885723 1271 if (nextExt != std::string::npos)
e85b4cd5 1272 {
651bddad 1273 CompressionExtensions = CompressionExtensions.substr(nextExt+1);
5d885723 1274 Init(RealURI, Desc.Description, Desc.ShortDesc);
03aa0847 1275 Status = StatIdle;
6abe2699 1276 return;
0d7a243d
EL
1277 }
1278
17ff0930 1279 // on decompression failure, remove bad versions in partial/
651bddad
MV
1280 if (Stage == STAGE_DECOMPRESS_AND_VERIFY)
1281 {
1e8ba0d4 1282 unlink(EraseFileName.c_str());
debc84b2
MZ
1283 }
1284
debc84b2 1285 Item::Failed(Message,Cnf);
56472095 1286
18593cf7
MV
1287 if(Target->IsOptional() && ExpectedHashes.empty() && Stage == STAGE_DOWNLOAD)
1288 Status = StatDone;
1289 else
1290 TransactionManager->AbortTransaction();
debc84b2 1291}
92fcbfc1 1292 /*}}}*/
8267fbd9 1293// pkgAcqIndex::GetFinalFilename - Return the full final file path /*{{{*/
3f073d44 1294std::string pkgAcqIndex::GetFinalFilename() const
63b7249e
MV
1295{
1296 std::string FinalFile = _config->FindDir("Dir::State::lists");
3f073d44 1297 FinalFile += URItoFileName(RealURI);
70b63c57 1298 return GetCompressedFileName(RealURI, FinalFile, CurrentCompressionExtension);
63b7249e 1299}
8267fbd9
DK
1300 /*}}}*/
1301// AcqIndex::ReverifyAfterIMS - Reverify index after an ims-hit /*{{{*/
916b8910 1302void pkgAcqIndex::ReverifyAfterIMS()
63b7249e 1303{
c36db2b5
MV
1304 // update destfile to *not* include the compression extension when doing
1305 // a reverify (as its uncompressed on disk already)
70b63c57 1306 DestFile = GetCompressedFileName(RealURI, GetPartialFileNameFromURI(RealURI), CurrentCompressionExtension);
63b7249e
MV
1307
1308 // copy FinalFile into partial/ so that we check the hash again
3f073d44 1309 string FinalFile = GetFinalFilename();
651bddad 1310 Stage = STAGE_DECOMPRESS_AND_VERIFY;
63b7249e
MV
1311 Desc.URI = "copy:" + FinalFile;
1312 QueueURI(Desc);
1313}
8267fbd9
DK
1314 /*}}}*/
1315// AcqIndex::ValidateFile - Validate the content of the downloaded file /*{{{*/
899e4ded
MV
1316bool pkgAcqIndex::ValidateFile(const std::string &FileName)
1317{
1318 // FIXME: this can go away once we only ever download stuff that
1319 // has a valid hash and we never do GET based probing
1320 // FIXME2: this also leaks debian-isms into the code and should go therefore
1321
1322 /* Always validate the index file for correctness (all indexes must
1323 * have a Package field) (LP: #346386) (Closes: #627642)
1324 */
651bddad 1325 FileFd fd(FileName, FileFd::ReadOnly, FileFd::Extension);
899e4ded
MV
1326 // Only test for correctness if the content of the file is not empty
1327 // (empty is ok)
1328 if (fd.Size() > 0)
1329 {
1330 pkgTagSection sec;
1331 pkgTagFile tag(&fd);
1332
1333 // all our current indexes have a field 'Package' in each section
1334 if (_error->PendingError() == true ||
1335 tag.Step(sec) == false ||
1336 sec.Exists("Package") == false)
1337 return false;
1338 }
1339 return true;
1340}
8267fbd9 1341 /*}}}*/
8b89e57f
AL
1342// AcqIndex::Done - Finished a fetch /*{{{*/
1343// ---------------------------------------------------------------------
1344/* This goes through a number of states.. On the initial fetch the
1345 method could possibly return an alternate filename which points
1346 to the uncompressed version of the file. If this is so the file
1347 is copied into the partial directory. In all other cases the file
b6f0063c 1348 is decompressed with a compressed uri. */
651bddad
MV
1349void pkgAcqIndex::Done(string Message,
1350 unsigned long long Size,
c8aa88aa 1351 HashStringList const &Hashes,
459681d3 1352 pkgAcquire::MethodConfig *Cfg)
8b89e57f 1353{
b3501edb 1354 Item::Done(Message,Size,Hashes,Cfg);
63b7249e 1355
651bddad 1356 switch(Stage)
8b89e57f 1357 {
651bddad
MV
1358 case STAGE_DOWNLOAD:
1359 StageDownloadDone(Message, Hashes, Cfg);
1360 break;
1361 case STAGE_DECOMPRESS_AND_VERIFY:
1362 StageDecompressDone(Message, Hashes, Cfg);
1363 break;
5f6c6c6e 1364 }
651bddad 1365}
8267fbd9
DK
1366 /*}}}*/
1367// AcqIndex::StageDownloadDone - Queue for decompress and verify /*{{{*/
651bddad
MV
1368void pkgAcqIndex::StageDownloadDone(string Message,
1369 HashStringList const &Hashes,
1370 pkgAcquire::MethodConfig *Cfg)
1371{
1372 // First check if the calculcated Hash of the (compressed) downloaded
1373 // file matches the hash we have in the MetaIndexRecords for this file
1374 if(VerifyHashByMetaKey(Hashes) == false)
5f6c6c6e 1375 {
651bddad
MV
1376 RenameOnError(HashSumMismatch);
1377 Failed(Message, Cfg);
1378 return;
8b89e57f 1379 }
bfd22fc0 1380
8267fe24 1381 Complete = true;
8267fbd9 1382
8b89e57f
AL
1383 // Handle the unzipd case
1384 string FileName = LookupTag(Message,"Alt-Filename");
1385 if (FileName.empty() == false)
1386 {
651bddad 1387 Stage = STAGE_DECOMPRESS_AND_VERIFY;
a6568219 1388 Local = true;
8b89e57f 1389 DestFile += ".decomp";
8267fe24
AL
1390 Desc.URI = "copy:" + FileName;
1391 QueueURI(Desc);
eeac6897 1392 SetActiveSubprocess("copy");
8b89e57f
AL
1393 return;
1394 }
1395
1396 FileName = LookupTag(Message,"Filename");
1397 if (FileName.empty() == true)
1398 {
1399 Status = StatError;
1400 ErrorText = "Method gave a blank filename";
1401 }
5d885723 1402
651bddad
MV
1403 // Methods like e.g. "file:" will give us a (compressed) FileName that is
1404 // not the "DestFile" we set, in this case we uncompress from the local file
1405 if (FileName != DestFile)
a6568219 1406 Local = true;
1e8ba0d4
MV
1407 else
1408 EraseFileName = FileName;
daff4aa3 1409
651bddad
MV
1410 // we need to verify the file against the current Release file again
1411 // on if-modfied-since hit to avoid a stale attack against us
1412 if(StringToBool(LookupTag(Message,"IMS-Hit"),false) == true)
ca7fd76c 1413 {
651bddad 1414 // The files timestamp matches, reverify by copy into partial/
1e8ba0d4 1415 EraseFileName = "";
651bddad 1416 ReverifyAfterIMS();
8b89e57f 1417 return;
ca7fd76c 1418 }
e85b4cd5 1419
651bddad 1420 // If we have compressed indexes enabled, queue for hash verification
b0f4b486 1421 if (_config->FindB("Acquire::GzipIndexes",false))
ca7fd76c 1422 {
ea7682a0 1423 DestFile = GetPartialFileNameFromURI(RealURI + '.' + CurrentCompressionExtension);
1e8ba0d4 1424 EraseFileName = "";
651bddad 1425 Stage = STAGE_DECOMPRESS_AND_VERIFY;
ca7fd76c
MV
1426 Desc.URI = "copy:" + FileName;
1427 QueueURI(Desc);
4dbfe436 1428 SetActiveSubprocess("copy");
bb109d0b 1429 return;
1430 }
1431
e85b4cd5 1432 // get the binary name for your used compression type
651bddad 1433 string decompProg;
1e8ba0d4 1434 if(CurrentCompressionExtension == "uncompressed")
0d7a243d 1435 decompProg = "copy";
651bddad 1436 else
1e8ba0d4 1437 decompProg = _config->Find(string("Acquire::CompressionTypes::").append(CurrentCompressionExtension),"");
651bddad
MV
1438 if(decompProg.empty() == true)
1439 {
1e8ba0d4 1440 _error->Error("Unsupported extension: %s", CurrentCompressionExtension.c_str());
debc84b2
MZ
1441 return;
1442 }
1443
651bddad
MV
1444 // queue uri for the next stage
1445 Stage = STAGE_DECOMPRESS_AND_VERIFY;
8b89e57f 1446 DestFile += ".decomp";
e85b4cd5 1447 Desc.URI = decompProg + ":" + FileName;
8267fe24 1448 QueueURI(Desc);
eeac6897 1449 SetActiveSubprocess(decompProg);
8b89e57f 1450}
8267fbd9
DK
1451 /*}}}*/
1452// pkgAcqIndex::StageDecompressDone - Final verification /*{{{*/
651bddad
MV
1453void pkgAcqIndex::StageDecompressDone(string Message,
1454 HashStringList const &Hashes,
1455 pkgAcquire::MethodConfig *Cfg)
1456{
1457 if (ExpectedHashes.usable() && ExpectedHashes != Hashes)
1458 {
1459 Desc.URI = RealURI;
1460 RenameOnError(HashSumMismatch);
1461 printHashSumComparision(RealURI, ExpectedHashes, Hashes);
1462 Failed(Message, Cfg);
1463 return;
1464 }
1465
1466 if(!ValidateFile(DestFile))
1467 {
1468 RenameOnError(InvalidFormat);
1469 Failed(Message, Cfg);
1470 return;
1471 }
8267fbd9 1472
1e8ba0d4
MV
1473 // remove the compressed version of the file
1474 unlink(EraseFileName.c_str());
8267fbd9 1475
651bddad
MV
1476 // Done, queue for rename on transaction finished
1477 TransactionManager->TransactionStageCopy(this, DestFile, GetFinalFilename());
8267fbd9 1478
651bddad
MV
1479 return;
1480}
92fcbfc1 1481 /*}}}*/
8267fbd9 1482// AcqMetaBase::Add - Add a item to the current Transaction /*{{{*/
715c65de 1483void pkgAcqMetaBase::Add(Item *I)
e6e89390 1484{
715c65de 1485 Transaction.push_back(I);
e6e89390 1486}
61aea84d 1487 /*}}}*/
8267fbd9 1488// AcqMetaBase::AbortTransaction - Abort the current Transaction /*{{{*/
715c65de
MV
1489void pkgAcqMetaBase::AbortTransaction()
1490{
1491 if(_config->FindB("Debug::Acquire::Transaction", false) == true)
1492 std::clog << "AbortTransaction: " << TransactionManager << std::endl;
1493
631a7dc7 1494 // ensure the toplevel is in error state too
715c65de
MV
1495 for (std::vector<Item*>::iterator I = Transaction.begin();
1496 I != Transaction.end(); ++I)
1497 {
1498 if(_config->FindB("Debug::Acquire::Transaction", false) == true)
1499 std::clog << " Cancel: " << (*I)->DestFile << std::endl;
1500 // the transaction will abort, so stop anything that is idle
1501 if ((*I)->Status == pkgAcquire::Item::StatIdle)
edd007cd 1502 {
715c65de 1503 (*I)->Status = pkgAcquire::Item::StatDone;
53702a59 1504 (*I)->Dequeue();
edd007cd 1505 }
715c65de 1506 }
12796fa2 1507 Transaction.clear();
715c65de
MV
1508}
1509 /*}}}*/
8267fbd9 1510// AcqMetaBase::TransactionHasError - Check for errors in Transaction /*{{{*/
715c65de
MV
1511bool pkgAcqMetaBase::TransactionHasError()
1512{
1513 for (pkgAcquire::ItemIterator I = Transaction.begin();
1514 I != Transaction.end(); ++I)
1515 if((*I)->Status != pkgAcquire::Item::StatDone &&
1516 (*I)->Status != pkgAcquire::Item::StatIdle)
1517 return true;
1518
1519 return false;
1520}
61aea84d
MV
1521 /*}}}*/
1522// AcqMetaBase::CommitTransaction - Commit a transaction /*{{{*/
715c65de
MV
1523void pkgAcqMetaBase::CommitTransaction()
1524{
1525 if(_config->FindB("Debug::Acquire::Transaction", false) == true)
1526 std::clog << "CommitTransaction: " << this << std::endl;
1527
1528 // move new files into place *and* remove files that are not
1529 // part of the transaction but are still on disk
1530 for (std::vector<Item*>::iterator I = Transaction.begin();
1531 I != Transaction.end(); ++I)
1532 {
1533 if((*I)->PartialFile != "")
1534 {
5684f71f
DK
1535 if(_config->FindB("Debug::Acquire::Transaction", false) == true)
1536 std::clog << "mv " << (*I)->PartialFile << " -> "<< (*I)->DestFile << " "
1537 << (*I)->DescURI() << std::endl;
1538
1539 Rename((*I)->PartialFile, (*I)->DestFile);
715c65de
MV
1540 } else {
1541 if(_config->FindB("Debug::Acquire::Transaction", false) == true)
5684f71f 1542 std::clog << "rm "
03bfbc96 1543 << (*I)->DestFile
5684f71f 1544 << " "
03bfbc96
MV
1545 << (*I)->DescURI()
1546 << std::endl;
715c65de
MV
1547 unlink((*I)->DestFile.c_str());
1548 }
1549 // mark that this transaction is finished
1550 (*I)->TransactionManager = 0;
1551 }
12796fa2 1552 Transaction.clear();
715c65de 1553}
61aea84d 1554 /*}}}*/
61a360be 1555// AcqMetaBase::TransactionStageCopy - Stage a file for copying /*{{{*/
fa3a96a1
MV
1556void pkgAcqMetaBase::TransactionStageCopy(Item *I,
1557 const std::string &From,
1558 const std::string &To)
1559{
1560 I->PartialFile = From;
1561 I->DestFile = To;
1562}
61aea84d 1563 /*}}}*/
61a360be 1564// AcqMetaBase::TransactionStageRemoval - Sage a file for removal /*{{{*/
fa3a96a1
MV
1565void pkgAcqMetaBase::TransactionStageRemoval(Item *I,
1566 const std::string &FinalFile)
1567{
1568 I->PartialFile = "";
1569 I->DestFile = FinalFile;
1570}
61aea84d 1571 /*}}}*/
61aea84d 1572// AcqMetaBase::GenerateAuthWarning - Check gpg authentication error /*{{{*/
2d0a7bb4
MV
1573bool pkgAcqMetaBase::CheckStopAuthentication(const std::string &RealURI,
1574 const std::string &Message)
e6e89390 1575{
2d0a7bb4
MV
1576 // FIXME: this entire function can do now that we disallow going to
1577 // a unauthenticated state and can cleanly rollback
1578
e6e89390 1579 string Final = _config->FindDir("Dir::State::lists") + URItoFileName(RealURI);
8267fbd9 1580
e6e89390
MV
1581 if(FileExists(Final))
1582 {
1583 Status = StatTransientNetworkError;
1584 _error->Warning(_("An error occurred during the signature "
1585 "verification. The repository is not updated "
1586 "and the previous index files will be used. "
1587 "GPG error: %s: %s\n"),
1588 Desc.Description.c_str(),
1589 LookupTag(Message,"Message").c_str());
1590 RunScripts("APT::Update::Auth-Failure");
1591 return true;
1592 } else if (LookupTag(Message,"Message").find("NODATA") != string::npos) {
1593 /* Invalid signature file, reject (LP: #346386) (Closes: #627642) */
1594 _error->Error(_("GPG error: %s: %s"),
1595 Desc.Description.c_str(),
1596 LookupTag(Message,"Message").c_str());
1597 Status = StatError;
1598 return true;
1599 } else {
1600 _error->Warning(_("GPG error: %s: %s"),
1601 Desc.Description.c_str(),
1602 LookupTag(Message,"Message").c_str());
1603 }
8267fbd9 1604 // gpgv method failed
e6e89390
MV
1605 ReportMirrorFailure("GPGFailure");
1606 return false;
1607}
1608 /*}}}*/
8267fbd9 1609// AcqMetaSig::AcqMetaSig - Constructor /*{{{*/
61aea84d 1610pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire *Owner,
715c65de 1611 pkgAcqMetaBase *TransactionManager,
b3d44315 1612 string URI,string URIDesc,string ShortDesc,
2737f28a 1613 string MetaIndexFile,
b3d44315
MV
1614 const vector<IndexTarget*>* IndexTargets,
1615 indexRecords* MetaIndexParser) :
8267fbd9 1616 pkgAcqMetaBase(Owner, IndexTargets, MetaIndexParser,
c045cc02
MV
1617 HashStringList(), TransactionManager),
1618 RealURI(URI), MetaIndexFile(MetaIndexFile), URIDesc(URIDesc),
fa3a96a1 1619 ShortDesc(ShortDesc)
0118833a 1620{
0a8a80e5 1621 DestFile = _config->FindDir("Dir::State::lists") + "partial/";
1ce24318 1622 DestFile += URItoFileName(RealURI);
b3d44315 1623
8267fbd9
DK
1624 // remove any partial downloaded sig-file in partial/.
1625 // it may confuse proxies and is too small to warrant a
47eb38f4 1626 // partial download anyway
f6237efd
MV
1627 unlink(DestFile.c_str());
1628
715c65de 1629 // set the TransactionManager
e05672e8 1630 if(_config->FindB("Debug::Acquire::Transaction", false) == true)
715c65de
MV
1631 std::clog << "New pkgAcqMetaSig with TransactionManager "
1632 << TransactionManager << std::endl;
1f4dd8fd 1633
8267fe24 1634 // Create the item
b2e465d6 1635 Desc.Description = URIDesc;
8267fe24 1636 Desc.Owner = this;
b3d44315
MV
1637 Desc.ShortDesc = ShortDesc;
1638 Desc.URI = URI;
2737f28a 1639
8267fe24 1640 QueueURI(Desc);
ffcccd62
DK
1641}
1642 /*}}}*/
1643pkgAcqMetaSig::~pkgAcqMetaSig() /*{{{*/
1644{
0118833a
AL
1645}
1646 /*}}}*/
b3d44315 1647// pkgAcqMetaSig::Custom600Headers - Insert custom request headers /*{{{*/
0118833a 1648// ---------------------------------------------------------------------
02e20767 1649#if APT_PKG_ABI >= 413
b3501edb 1650string pkgAcqMetaSig::Custom600Headers() const
02e20767
DK
1651#else
1652string pkgAcqMetaSig::Custom600Headers()
1653#endif
0118833a 1654{
27e6c17a
MV
1655 std::string Header = GetCustom600Headers(RealURI);
1656 return Header;
0118833a 1657}
61aea84d 1658 /*}}}*/
8267fbd9 1659// pkgAcqMetaSig::Done - The signature was downloaded/verified /*{{{*/
61aea84d
MV
1660// ---------------------------------------------------------------------
1661/* The only header we use is the last-modified header. */
1662void pkgAcqMetaSig::Done(string Message,unsigned long long Size,
1663 HashStringList const &Hashes,
b3d44315 1664 pkgAcquire::MethodConfig *Cfg)
c88edf1d 1665{
b3501edb 1666 Item::Done(Message, Size, Hashes, Cfg);
c88edf1d 1667
1ce24318 1668 if(AuthPass == false)
c88edf1d 1669 {
f3097647 1670 if(CheckDownloadDone(Message, RealURI) == true)
1ce24318 1671 {
f3097647
MV
1672 // destfile will be modified to point to MetaIndexFile for the
1673 // gpgv method, so we need to save it here
1674 MetaIndexFileSignature = DestFile;
1675 QueueForSignatureVerify(MetaIndexFile, MetaIndexFileSignature);
1ce24318 1676 }
2737f28a
MV
1677 return;
1678 }
8267fbd9 1679 else
1f4dd8fd 1680 {
ba8a8421 1681 if(CheckAuthDone(Message, RealURI) == true)
f3097647
MV
1682 {
1683 std::string FinalFile = _config->FindDir("Dir::State::lists");
1684 FinalFile += URItoFileName(RealURI);
f3097647
MV
1685 TransactionManager->TransactionStageCopy(this, MetaIndexFileSignature, FinalFile);
1686 }
1ce24318 1687 }
c88edf1d
AL
1688}
1689 /*}}}*/
92fcbfc1 1690void pkgAcqMetaSig::Failed(string Message,pkgAcquire::MethodConfig *Cnf)/*{{{*/
681d76d0 1691{
03aa0847 1692 Item::Failed(Message,Cnf);
e8b1db38 1693
673c9469 1694 // check if we need to fail at this point
2d0a7bb4 1695 if (AuthPass == true && CheckStopAuthentication(RealURI, Message))
e8b1db38 1696 return;
e8b1db38 1697
631a7dc7 1698 // FIXME: meh, this is not really elegant
03aa0847
DK
1699 string const Final = _config->FindDir("Dir::State::lists") + URItoFileName(RealURI);
1700 string const InReleaseURI = RealURI.replace(RealURI.rfind("Release.gpg"), 12,
631a7dc7 1701 "InRelease");
03aa0847 1702 string const FinalInRelease = _config->FindDir("Dir::State::lists") + URItoFileName(InReleaseURI);
631a7dc7 1703
c99fe2e1 1704 if (RealFileExists(Final) || RealFileExists(FinalInRelease))
631a7dc7 1705 {
c99fe2e1
MV
1706 std::string downgrade_msg;
1707 strprintf(downgrade_msg, _("The repository '%s' is no longer signed."),
1708 URIDesc.c_str());
1709 if(_config->FindB("Acquire::AllowDowngradeToInsecureRepositories"))
1710 {
1711 // meh, the users wants to take risks (we still mark the packages
1712 // from this repository as unauthenticated)
1713 _error->Warning("%s", downgrade_msg.c_str());
1714 _error->Warning(_("This is normally not allowed, but the option "
1715 "Acquire::AllowDowngradeToInsecureRepositories was "
1716 "given to override it."));
03aa0847 1717 Status = StatDone;
c99fe2e1
MV
1718 } else {
1719 _error->Error("%s", downgrade_msg.c_str());
1720 Rename(MetaIndexFile, MetaIndexFile+".FAILED");
4dbfe436 1721 Item::Failed("Message: " + downgrade_msg, Cnf);
c99fe2e1
MV
1722 TransactionManager->AbortTransaction();
1723 return;
1724 }
631a7dc7 1725 }
9d653a6d
DK
1726 else
1727 _error->Warning(_("The data from '%s' is not signed. Packages "
1728 "from that repository can not be authenticated."),
1729 URIDesc.c_str());
7e5f33eb 1730
1f4dd8fd
MV
1731 // this ensures that any file in the lists/ dir is removed by the
1732 // transaction
ea7682a0 1733 DestFile = GetPartialFileNameFromURI(RealURI);
fa3a96a1 1734 TransactionManager->TransactionStageRemoval(this, DestFile);
24057ad6 1735
631a7dc7 1736 // only allow going further if the users explicitely wants it
32532943 1737 if(AllowInsecureRepositories(MetaIndexParser, TransactionManager, this) == true)
631a7dc7
MV
1738 {
1739 // we parse the indexes here because at this point the user wanted
1740 // a repository that may potentially harm him
1741 MetaIndexParser->Load(MetaIndexFile);
c045cc02 1742 QueueIndexes(true);
631a7dc7
MV
1743 }
1744
e05672e8 1745 // FIXME: this is used often (e.g. in pkgAcqIndexTrans) so refactor
4dbfe436 1746 if (Cnf->LocalOnly == true ||
e05672e8 1747 StringToBool(LookupTag(Message,"Transient-Failure"),false) == false)
4dbfe436 1748 {
e05672e8
MV
1749 // Ignore this
1750 Status = StatDone;
e05672e8 1751 }
681d76d0 1752}
92fcbfc1
DK
1753 /*}}}*/
1754pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire *Owner, /*{{{*/
715c65de 1755 pkgAcqMetaBase *TransactionManager,
b3d44315 1756 string URI,string URIDesc,string ShortDesc,
2737f28a 1757 string MetaIndexSigURI,string MetaIndexSigURIDesc, string MetaIndexSigShortDesc,
fa3b260f 1758 const vector<IndexTarget*>* IndexTargets,
b3d44315 1759 indexRecords* MetaIndexParser) :
c045cc02
MV
1760 pkgAcqMetaBase(Owner, IndexTargets, MetaIndexParser, HashStringList(),
1761 TransactionManager),
1762 RealURI(URI), URIDesc(URIDesc), ShortDesc(ShortDesc),
2737f28a
MV
1763 MetaIndexSigURI(MetaIndexSigURI), MetaIndexSigURIDesc(MetaIndexSigURIDesc),
1764 MetaIndexSigShortDesc(MetaIndexSigShortDesc)
b3d44315 1765{
715c65de
MV
1766 if(TransactionManager == NULL)
1767 {
1768 this->TransactionManager = this;
1769 this->TransactionManager->Add(this);
1770 }
e05672e8
MV
1771
1772 if(_config->FindB("Debug::Acquire::Transaction", false) == true)
715c65de
MV
1773 std::clog << "New pkgAcqMetaIndex with TransactionManager "
1774 << this->TransactionManager << std::endl;
1775
b3d44315 1776
e05672e8
MV
1777 Init(URIDesc, ShortDesc);
1778}
1779 /*}}}*/
8267fbd9 1780// pkgAcqMetaIndex::Init - Delayed constructor /*{{{*/
e05672e8
MV
1781void pkgAcqMetaIndex::Init(std::string URIDesc, std::string ShortDesc)
1782{
ea7682a0 1783 DestFile = GetPartialFileNameFromURI(RealURI);
56472095 1784
b3d44315
MV
1785 // Create the item
1786 Desc.Description = URIDesc;
1787 Desc.Owner = this;
1788 Desc.ShortDesc = ShortDesc;
e05672e8 1789 Desc.URI = RealURI;
b3d44315 1790
d0cfa8ad
MV
1791 // we expect more item
1792 ExpectedAdditionalItems = IndexTargets->size();
b3d44315
MV
1793 QueueURI(Desc);
1794}
8267fbd9 1795 /*}}}*/
b3d44315
MV
1796// pkgAcqMetaIndex::Custom600Headers - Insert custom request headers /*{{{*/
1797// ---------------------------------------------------------------------
02e20767 1798#if APT_PKG_ABI >= 413
b3501edb 1799string pkgAcqMetaIndex::Custom600Headers() const
02e20767
DK
1800#else
1801string pkgAcqMetaIndex::Custom600Headers()
1802#endif
b3d44315 1803{
27e6c17a 1804 return GetCustom600Headers(RealURI);
b3d44315 1805}
92fcbfc1 1806 /*}}}*/
f3097647
MV
1807void pkgAcqMetaIndex::Done(string Message,unsigned long long Size, /*{{{*/
1808 HashStringList const &Hashes,
b3d44315
MV
1809 pkgAcquire::MethodConfig *Cfg)
1810{
b3501edb 1811 Item::Done(Message,Size,Hashes,Cfg);
b3d44315 1812
f3097647 1813 if(CheckDownloadDone(Message, RealURI))
b3d44315 1814 {
f3097647
MV
1815 // we have a Release file, now download the Signature, all further
1816 // verify/queue for additional downloads will be done in the
1817 // pkgAcqMetaSig::Done() code
1818 std::string MetaIndexFile = DestFile;
1819 new pkgAcqMetaSig(Owner, TransactionManager,
1820 MetaIndexSigURI, MetaIndexSigURIDesc,
1821 MetaIndexSigShortDesc, MetaIndexFile, IndexTargets,
1822 MetaIndexParser);
fce72602 1823
f3097647
MV
1824 string FinalFile = _config->FindDir("Dir::State::lists");
1825 FinalFile += URItoFileName(RealURI);
1826 TransactionManager->TransactionStageCopy(this, DestFile, FinalFile);
b3d44315 1827 }
f3097647
MV
1828}
1829 /*}}}*/
ba8a8421 1830bool pkgAcqMetaBase::CheckAuthDone(string Message, const string &RealURI) /*{{{*/
f3097647
MV
1831{
1832 // At this point, the gpgv method has succeeded, so there is a
1833 // valid signature from a key in the trusted keyring. We
1834 // perform additional verification of its contents, and use them
1835 // to verify the indexes we are about to download
b3d44315 1836
f3097647
MV
1837 if (!MetaIndexParser->Load(DestFile))
1838 {
1839 Status = StatAuthError;
1840 ErrorText = MetaIndexParser->ErrorText;
1841 return false;
b3d44315 1842 }
56bc3358 1843
f3097647 1844 if (!VerifyVendor(Message, RealURI))
56bc3358 1845 {
f3097647 1846 return false;
56bc3358 1847 }
f3097647
MV
1848
1849 if (_config->FindB("Debug::pkgAcquire::Auth", false))
1850 std::cerr << "Signature verification succeeded: "
1851 << DestFile << std::endl;
1852
1853 // Download further indexes with verification
1854 //
1855 // it would be really nice if we could simply do
1856 // if (IMSHit == false) QueueIndexes(true)
1857 // and skip the download if the Release file has not changed
1858 // - but right now the list cleaner will needs to be tricked
1859 // to not delete all our packages/source indexes in this case
1860 QueueIndexes(true);
1861
1862 return true;
1863}
1864 /*}}}*/
27e6c17a
MV
1865// pkgAcqMetaBase::GetCustom600Headers - Get header for AcqMetaBase /*{{{*/
1866// ---------------------------------------------------------------------
1867string pkgAcqMetaBase::GetCustom600Headers(const string &RealURI) const
1868{
1869 std::string Header = "\nIndex-File: true";
1870 std::string MaximumSize;
1871 strprintf(MaximumSize, "\nMaximum-Size: %i",
1872 _config->FindI("Acquire::MaxReleaseFileSize", 10*1000*1000));
1873 Header += MaximumSize;
1874
1875 string FinalFile = _config->FindDir("Dir::State::lists");
1876 FinalFile += URItoFileName(RealURI);
1877
1878 struct stat Buf;
1879 if (stat(FinalFile.c_str(),&Buf) == 0)
1880 Header += "\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
1881
1882 return Header;
1883}
1884 /*}}}*/
5684f71f 1885// pkgAcqMetaBase::QueueForSignatureVerify /*{{{*/
f3097647
MV
1886void pkgAcqMetaBase::QueueForSignatureVerify(const std::string &MetaIndexFile,
1887 const std::string &MetaIndexFileSignature)
1888{
1889 AuthPass = true;
1890 Desc.URI = "gpgv:" + MetaIndexFileSignature;
1891 DestFile = MetaIndexFile;
1892 QueueURI(Desc);
1893 SetActiveSubprocess("gpgv");
b3d44315 1894}
92fcbfc1 1895 /*}}}*/
5684f71f 1896// pkgAcqMetaBase::CheckDownloadDone /*{{{*/
f3097647
MV
1897bool pkgAcqMetaBase::CheckDownloadDone(const std::string &Message,
1898 const std::string &RealURI)
b3d44315
MV
1899{
1900 // We have just finished downloading a Release file (it is not
1901 // verified yet)
1902
1903 string FileName = LookupTag(Message,"Filename");
1904 if (FileName.empty() == true)
1905 {
1906 Status = StatError;
1907 ErrorText = "Method gave a blank filename";
f3097647 1908 return false;
b3d44315
MV
1909 }
1910
1911 if (FileName != DestFile)
1912 {
1913 Local = true;
1914 Desc.URI = "copy:" + FileName;
1915 QueueURI(Desc);
f3097647 1916 return false;
b3d44315
MV
1917 }
1918
fce72602 1919 // make sure to verify against the right file on I-M-S hit
f381d68d 1920 IMSHit = StringToBool(LookupTag(Message,"IMS-Hit"),false);
fce72602
MV
1921 if(IMSHit)
1922 {
1923 string FinalFile = _config->FindDir("Dir::State::lists");
1924 FinalFile += URItoFileName(RealURI);
1925 DestFile = FinalFile;
1926 }
2737f28a 1927
f3097647 1928 // set Item to complete as the remaining work is all local (verify etc)
b3d44315 1929 Complete = true;
b3d44315 1930
f3097647 1931 return true;
b3d44315 1932}
92fcbfc1 1933 /*}}}*/
c045cc02 1934void pkgAcqMetaBase::QueueIndexes(bool verify) /*{{{*/
b3d44315 1935{
d0cfa8ad
MV
1936 // at this point the real Items are loaded in the fetcher
1937 ExpectedAdditionalItems = 0;
18593cf7
MV
1938
1939 vector <struct IndexTarget*>::const_iterator Target;
1940 for (Target = IndexTargets->begin();
b3d44315 1941 Target != IndexTargets->end();
f7f0d6c7 1942 ++Target)
b3d44315 1943 {
b3501edb
DK
1944 HashStringList ExpectedIndexHashes;
1945 const indexRecords::checkSum *Record = MetaIndexParser->Lookup((*Target)->MetaKey);
18593cf7
MV
1946
1947 // optional target that we do not have in the Release file are
1948 // skipped
1949 if (verify == true && Record == NULL && (*Target)->IsOptional())
1950 continue;
1951
1952 // targets without a hash record are a error when verify is required
1953 if (verify == true && Record == NULL)
b3d44315 1954 {
18593cf7
MV
1955 Status = StatAuthError;
1956 strprintf(ErrorText, _("Unable to find expected entry '%s' in Release file (Wrong sources.list entry or malformed file)"), (*Target)->MetaKey.c_str());
1957 return;
1207cf3f 1958 }
18593cf7
MV
1959
1960 if (Record)
1961 ExpectedIndexHashes = Record->Hashes;
1962
1963 if (_config->FindB("Debug::pkgAcquire::Auth", false))
1207cf3f 1964 {
18593cf7
MV
1965 std::cerr << "Queueing: " << (*Target)->URI << std::endl
1966 << "Expected Hash:" << std::endl;
1967 for (HashStringList::const_iterator hs = ExpectedIndexHashes.begin(); hs != ExpectedIndexHashes.end(); ++hs)
1968 std::cerr << "\t- " << hs->toStr() << std::endl;
1969 std::cerr << "For: " << Record->MetaKeyFilename << std::endl;
ab53c018 1970
18593cf7
MV
1971 }
1972 if (verify == true && ExpectedIndexHashes.empty() == true)
ab53c018 1973 {
18593cf7
MV
1974 Status = StatAuthError;
1975 strprintf(ErrorText, _("Unable to find hash sum for '%s' in Release file"), (*Target)->MetaKey.c_str());
1976 return;
b3d44315 1977 }
e1430400 1978
18593cf7
MV
1979 /* Queue the Index file (Packages, Sources, Translation-$foo
1980 (either diff or full packages files, depending
e1430400
DK
1981 on the users option) - we also check if the PDiff Index file is listed
1982 in the Meta-Index file. Ideal would be if pkgAcqDiffIndex would test this
1983 instead, but passing the required info to it is to much hassle */
1984 if(_config->FindB("Acquire::PDiffs",true) == true && (verify == false ||
18593cf7
MV
1985 MetaIndexParser->Exists((*Target)->MetaKey + ".diff/Index") == true))
1986 new pkgAcqDiffIndex(Owner, TransactionManager, *Target, ExpectedIndexHashes, MetaIndexParser);
e1430400 1987 else
18593cf7 1988 new pkgAcqIndex(Owner, TransactionManager, *Target, ExpectedIndexHashes, MetaIndexParser);
b3d44315
MV
1989 }
1990}
92fcbfc1 1991 /*}}}*/
f3097647 1992bool pkgAcqMetaBase::VerifyVendor(string Message, const string &RealURI)/*{{{*/
b3d44315 1993{
ce424cd4
MV
1994 string::size_type pos;
1995
1996 // check for missing sigs (that where not fatal because otherwise we had
1997 // bombed earlier)
1998 string missingkeys;
400ad7a4 1999 string msg = _("There is no public key available for the "
ce424cd4
MV
2000 "following key IDs:\n");
2001 pos = Message.find("NO_PUBKEY ");
2002 if (pos != std::string::npos)
2003 {
2004 string::size_type start = pos+strlen("NO_PUBKEY ");
2005 string Fingerprint = Message.substr(start, Message.find("\n")-start);
2006 missingkeys += (Fingerprint);
2007 }
2008 if(!missingkeys.empty())
e788a834 2009 _error->Warning("%s", (msg + missingkeys).c_str());
b3d44315
MV
2010
2011 string Transformed = MetaIndexParser->GetExpectedDist();
2012
2013 if (Transformed == "../project/experimental")
2014 {
2015 Transformed = "experimental";
2016 }
2017
ce424cd4 2018 pos = Transformed.rfind('/');
b3d44315
MV
2019 if (pos != string::npos)
2020 {
2021 Transformed = Transformed.substr(0, pos);
2022 }
2023
2024 if (Transformed == ".")
2025 {
2026 Transformed = "";
2027 }
2028
0323317c
DK
2029 if (_config->FindB("Acquire::Check-Valid-Until", true) == true &&
2030 MetaIndexParser->GetValidUntil() > 0) {
2031 time_t const invalid_since = time(NULL) - MetaIndexParser->GetValidUntil();
2032 if (invalid_since > 0)
2033 // TRANSLATOR: The first %s is the URL of the bad Release file, the second is
2034 // the time since then the file is invalid - formated in the same way as in
2035 // the download progress display (e.g. 7d 3h 42min 1s)
457bea86
MV
2036 return _error->Error(
2037 _("Release file for %s is expired (invalid since %s). "
2038 "Updates for this repository will not be applied."),
2039 RealURI.c_str(), TimeToStr(invalid_since).c_str());
1ddb8596
DK
2040 }
2041
b3d44315
MV
2042 if (_config->FindB("Debug::pkgAcquire::Auth", false))
2043 {
2044 std::cerr << "Got Codename: " << MetaIndexParser->GetDist() << std::endl;
2045 std::cerr << "Expecting Dist: " << MetaIndexParser->GetExpectedDist() << std::endl;
2046 std::cerr << "Transformed Dist: " << Transformed << std::endl;
2047 }
2048
2049 if (MetaIndexParser->CheckDist(Transformed) == false)
2050 {
2051 // This might become fatal one day
2052// Status = StatAuthError;
2053// ErrorText = "Conflicting distribution; expected "
2054// + MetaIndexParser->GetExpectedDist() + " but got "
2055// + MetaIndexParser->GetDist();
2056// return false;
2057 if (!Transformed.empty())
2058 {
1ddb8596 2059 _error->Warning(_("Conflicting distribution: %s (expected %s but got %s)"),
b3d44315
MV
2060 Desc.Description.c_str(),
2061 Transformed.c_str(),
2062 MetaIndexParser->GetDist().c_str());
2063 }
2064 }
2065
2066 return true;
2067}
92fcbfc1 2068 /*}}}*/
8267fbd9 2069// pkgAcqMetaIndex::Failed - no Release file present /*{{{*/
4dbfe436
DK
2070void pkgAcqMetaIndex::Failed(string Message,
2071 pkgAcquire::MethodConfig * Cnf)
b3d44315 2072{
4dbfe436
DK
2073 pkgAcquire::Item::Failed(Message, Cnf);
2074 Status = StatDone;
2075
673c9469 2076 string FinalFile = _config->FindDir("Dir::State::lists") + URItoFileName(RealURI);
09475beb 2077
673c9469
MV
2078 _error->Warning(_("The repository '%s' does not have a Release file. "
2079 "This is deprecated, please contact the owner of the "
2080 "repository."), URIDesc.c_str());
c5fced38 2081
673c9469 2082 // No Release file was present so fall
b3d44315 2083 // back to queueing Packages files without verification
631a7dc7 2084 // only allow going further if the users explicitely wants it
32532943 2085 if(AllowInsecureRepositories(MetaIndexParser, TransactionManager, this) == true)
631a7dc7 2086 {
673c9469 2087 // Done, queue for rename on transaction finished
1d970e6c 2088 if (FileExists(DestFile))
1d970e6c 2089 TransactionManager->TransactionStageCopy(this, DestFile, FinalFile);
1d970e6c 2090
673c9469 2091 // queue without any kind of hashsum support
631a7dc7 2092 QueueIndexes(false);
8267fbd9 2093 }
b3d44315 2094}
681d76d0 2095 /*}}}*/
8267fbd9 2096void pkgAcqMetaIndex::Finished() /*{{{*/
56472095
MV
2097{
2098 if(_config->FindB("Debug::Acquire::Transaction", false) == true)
2099 std::clog << "Finished: " << DestFile <<std::endl;
715c65de
MV
2100 if(TransactionManager != NULL &&
2101 TransactionManager->TransactionHasError() == false)
2102 TransactionManager->CommitTransaction();
56472095 2103}
8267fbd9 2104 /*}}}*/
fe0f7911
DK
2105pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire *Owner, /*{{{*/
2106 string const &URI, string const &URIDesc, string const &ShortDesc,
2107 string const &MetaIndexURI, string const &MetaIndexURIDesc, string const &MetaIndexShortDesc,
2108 string const &MetaSigURI, string const &MetaSigURIDesc, string const &MetaSigShortDesc,
fa3b260f 2109 const vector<IndexTarget*>* IndexTargets,
fe0f7911 2110 indexRecords* MetaIndexParser) :
715c65de 2111 pkgAcqMetaIndex(Owner, NULL, URI, URIDesc, ShortDesc, MetaSigURI, MetaSigURIDesc,MetaSigShortDesc, IndexTargets, MetaIndexParser),
2737f28a
MV
2112 MetaIndexURI(MetaIndexURI), MetaIndexURIDesc(MetaIndexURIDesc), MetaIndexShortDesc(MetaIndexShortDesc),
2113 MetaSigURI(MetaSigURI), MetaSigURIDesc(MetaSigURIDesc), MetaSigShortDesc(MetaSigShortDesc)
fe0f7911 2114{
d0cfa8ad
MV
2115 // index targets + (worst case:) Release/Release.gpg
2116 ExpectedAdditionalItems = IndexTargets->size() + 2;
2117
fe0f7911
DK
2118}
2119 /*}}}*/
ffcccd62
DK
2120pkgAcqMetaClearSig::~pkgAcqMetaClearSig() /*{{{*/
2121{
ffcccd62
DK
2122}
2123 /*}}}*/
8d6c5839
MV
2124// pkgAcqMetaClearSig::Custom600Headers - Insert custom request headers /*{{{*/
2125// ---------------------------------------------------------------------
02e20767 2126#if APT_PKG_ABI >= 413
b3501edb 2127string pkgAcqMetaClearSig::Custom600Headers() const
02e20767
DK
2128#else
2129string pkgAcqMetaClearSig::Custom600Headers()
2130#endif
8d6c5839 2131{
27e6c17a
MV
2132 string Header = GetCustom600Headers(RealURI);
2133 Header += "\nFail-Ignore: true";
2134 return Header;
8d6c5839
MV
2135}
2136 /*}}}*/
a9bb651a
MV
2137// pkgAcqMetaClearSig::Done - We got a file /*{{{*/
2138// ---------------------------------------------------------------------
03aa0847
DK
2139void pkgAcqMetaClearSig::Done(std::string Message,unsigned long long Size,
2140 HashStringList const &Hashes,
a9bb651a 2141 pkgAcquire::MethodConfig *Cnf)
fe0f7911 2142{
03aa0847
DK
2143 Item::Done(Message, Size, Hashes, Cnf);
2144
e84d3803
MV
2145 // if we expect a ClearTextSignature (InRelase), ensure that
2146 // this is what we get and if not fail to queue a
2147 // Release/Release.gpg, see #346386
a9bb651a 2148 if (FileExists(DestFile) && !StartsWithGPGClearTextSignature(DestFile))
e84d3803 2149 {
e84d3803 2150 pkgAcquire::Item::Failed(Message, Cnf);
631a7dc7
MV
2151 RenameOnError(NotClearsigned);
2152 TransactionManager->AbortTransaction();
e84d3803
MV
2153 return;
2154 }
f3097647
MV
2155
2156 if(AuthPass == false)
2157 {
2158 if(CheckDownloadDone(Message, RealURI) == true)
2159 QueueForSignatureVerify(DestFile, DestFile);
2160 return;
2161 }
2162 else
2163 {
ba8a8421 2164 if(CheckAuthDone(Message, RealURI) == true)
f3097647
MV
2165 {
2166 string FinalFile = _config->FindDir("Dir::State::lists");
2167 FinalFile += URItoFileName(RealURI);
2168
2169 // queue for copy in place
2170 TransactionManager->TransactionStageCopy(this, DestFile, FinalFile);
2171 }
2172 }
a9bb651a
MV
2173}
2174 /*}}}*/
2175void pkgAcqMetaClearSig::Failed(string Message,pkgAcquire::MethodConfig *Cnf) /*{{{*/
2176{
4dbfe436
DK
2177 Item::Failed(Message, Cnf);
2178
a9bb651a
MV
2179 // we failed, we will not get additional items from this method
2180 ExpectedAdditionalItems = 0;
e84d3803 2181
fe0f7911
DK
2182 if (AuthPass == false)
2183 {
7712d13b
MV
2184 // Queue the 'old' InRelease file for removal if we try Release.gpg
2185 // as otherwise the file will stay around and gives a false-auth
2186 // impression (CVE-2012-0214)
de498a52
DK
2187 string FinalFile = _config->FindDir("Dir::State::lists");
2188 FinalFile.append(URItoFileName(RealURI));
fa3a96a1 2189 TransactionManager->TransactionStageRemoval(this, FinalFile);
4dbfe436 2190 Status = StatDone;
de498a52 2191
715c65de 2192 new pkgAcqMetaIndex(Owner, TransactionManager,
fe0f7911 2193 MetaIndexURI, MetaIndexURIDesc, MetaIndexShortDesc,
2737f28a 2194 MetaSigURI, MetaSigURIDesc, MetaSigShortDesc,
fe0f7911 2195 IndexTargets, MetaIndexParser);
fe0f7911
DK
2196 }
2197 else
673c9469 2198 {
2d0a7bb4 2199 if(CheckStopAuthentication(RealURI, Message))
673c9469
MV
2200 return;
2201
2202 _error->Warning(_("The data from '%s' is not signed. Packages "
2203 "from that repository can not be authenticated."),
2204 URIDesc.c_str());
2205
2206 // No Release file was present, or verification failed, so fall
2207 // back to queueing Packages files without verification
2208 // only allow going further if the users explicitely wants it
32532943 2209 if(AllowInsecureRepositories(MetaIndexParser, TransactionManager, this) == true)
673c9469 2210 {
4dbfe436
DK
2211 Status = StatDone;
2212
673c9469
MV
2213 /* Always move the meta index, even if gpgv failed. This ensures
2214 * that PackageFile objects are correctly filled in */
4dbfe436 2215 if (FileExists(DestFile))
673c9469
MV
2216 {
2217 string FinalFile = _config->FindDir("Dir::State::lists");
2218 FinalFile += URItoFileName(RealURI);
2219 /* InRelease files become Release files, otherwise
2220 * they would be considered as trusted later on */
2221 RealURI = RealURI.replace(RealURI.rfind("InRelease"), 9,
2222 "Release");
2223 FinalFile = FinalFile.replace(FinalFile.rfind("InRelease"), 9,
2224 "Release");
4dbfe436 2225
673c9469
MV
2226 // Done, queue for rename on transaction finished
2227 TransactionManager->TransactionStageCopy(this, DestFile, FinalFile);
2228 }
2229 QueueIndexes(false);
4dbfe436 2230 }
673c9469 2231 }
fe0f7911
DK
2232}
2233 /*}}}*/
03e39e59
AL
2234// AcqArchive::AcqArchive - Constructor /*{{{*/
2235// ---------------------------------------------------------------------
17caf1b1
AL
2236/* This just sets up the initial fetch environment and queues the first
2237 possibilitiy */
03e39e59 2238pkgAcqArchive::pkgAcqArchive(pkgAcquire *Owner,pkgSourceList *Sources,
30e1eab5
AL
2239 pkgRecords *Recs,pkgCache::VerIterator const &Version,
2240 string &StoreFilename) :
fa3b260f 2241 Item(Owner, HashStringList()), Version(Version), Sources(Sources), Recs(Recs),
b3d44315
MV
2242 StoreFilename(StoreFilename), Vf(Version.FileList()),
2243 Trusted(false)
03e39e59 2244{
7d8afa39 2245 Retries = _config->FindI("Acquire::Retries",0);
813c8eea
AL
2246
2247 if (Version.Arch() == 0)
bdae53f1 2248 {
d1f1f6a8 2249 _error->Error(_("I wasn't able to locate a file for the %s package. "
7a3c2ab0
AL
2250 "This might mean you need to manually fix this package. "
2251 "(due to missing arch)"),
40f8a8ba 2252 Version.ParentPkg().FullName().c_str());
bdae53f1
AL
2253 return;
2254 }
813c8eea 2255
b2e465d6
AL
2256 /* We need to find a filename to determine the extension. We make the
2257 assumption here that all the available sources for this version share
2258 the same extension.. */
2259 // Skip not source sources, they do not have file fields.
69c2ecbd 2260 for (; Vf.end() == false; ++Vf)
b2e465d6
AL
2261 {
2262 if ((Vf.File()->Flags & pkgCache::Flag::NotSource) != 0)
2263 continue;
2264 break;
2265 }
2266
2267 // Does not really matter here.. we are going to fail out below
2268 if (Vf.end() != true)
2269 {
2270 // If this fails to get a file name we will bomb out below.
2271 pkgRecords::Parser &Parse = Recs->Lookup(Vf);
2272 if (_error->PendingError() == true)
2273 return;
2274
2275 // Generate the final file name as: package_version_arch.foo
2276 StoreFilename = QuoteString(Version.ParentPkg().Name(),"_:") + '_' +
2277 QuoteString(Version.VerStr(),"_:") + '_' +
2278 QuoteString(Version.Arch(),"_:.") +
2279 "." + flExtension(Parse.FileName());
2280 }
b3d44315
MV
2281
2282 // check if we have one trusted source for the package. if so, switch
6c34ccca
DK
2283 // to "TrustedOnly" mode - but only if not in AllowUnauthenticated mode
2284 bool const allowUnauth = _config->FindB("APT::Get::AllowUnauthenticated", false);
2285 bool const debugAuth = _config->FindB("Debug::pkgAcquire::Auth", false);
2286 bool seenUntrusted = false;
f7f0d6c7 2287 for (pkgCache::VerFileIterator i = Version.FileList(); i.end() == false; ++i)
b3d44315
MV
2288 {
2289 pkgIndexFile *Index;
2290 if (Sources->FindIndex(i.File(),Index) == false)
2291 continue;
6c34ccca
DK
2292
2293 if (debugAuth == true)
b3d44315 2294 std::cerr << "Checking index: " << Index->Describe()
6c34ccca
DK
2295 << "(Trusted=" << Index->IsTrusted() << ")" << std::endl;
2296
2297 if (Index->IsTrusted() == true)
2298 {
b3d44315 2299 Trusted = true;
6c34ccca
DK
2300 if (allowUnauth == false)
2301 break;
b3d44315 2302 }
6c34ccca
DK
2303 else
2304 seenUntrusted = true;
b3d44315
MV
2305 }
2306
a3371852
MV
2307 // "allow-unauthenticated" restores apts old fetching behaviour
2308 // that means that e.g. unauthenticated file:// uris are higher
2309 // priority than authenticated http:// uris
6c34ccca 2310 if (allowUnauth == true && seenUntrusted == true)
a3371852
MV
2311 Trusted = false;
2312
03e39e59 2313 // Select a source
b185acc2 2314 if (QueueNext() == false && _error->PendingError() == false)
d57f6084
DK
2315 _error->Error(_("Can't find a source to download version '%s' of '%s'"),
2316 Version.VerStr(), Version.ParentPkg().FullName(false).c_str());
b185acc2
AL
2317}
2318 /*}}}*/
2319// AcqArchive::QueueNext - Queue the next file source /*{{{*/
2320// ---------------------------------------------------------------------
17caf1b1
AL
2321/* This queues the next available file version for download. It checks if
2322 the archive is already available in the cache and stashs the MD5 for
2323 checking later. */
b185acc2 2324bool pkgAcqArchive::QueueNext()
a722b2c5 2325{
f7f0d6c7 2326 for (; Vf.end() == false; ++Vf)
03e39e59
AL
2327 {
2328 // Ignore not source sources
2329 if ((Vf.File()->Flags & pkgCache::Flag::NotSource) != 0)
2330 continue;
2331
2332 // Try to cross match against the source list
b2e465d6
AL
2333 pkgIndexFile *Index;
2334 if (Sources->FindIndex(Vf.File(),Index) == false)
2335 continue;
03e39e59 2336
b3d44315
MV
2337 // only try to get a trusted package from another source if that source
2338 // is also trusted
2339 if(Trusted && !Index->IsTrusted())
2340 continue;
2341
03e39e59
AL
2342 // Grab the text package record
2343 pkgRecords::Parser &Parse = Recs->Lookup(Vf);
2344 if (_error->PendingError() == true)
b185acc2 2345 return false;
b3501edb 2346
b2e465d6 2347 string PkgFile = Parse.FileName();
b3501edb
DK
2348 ExpectedHashes = Parse.Hashes();
2349
03e39e59 2350 if (PkgFile.empty() == true)
b2e465d6
AL
2351 return _error->Error(_("The package index files are corrupted. No Filename: "
2352 "field for package %s."),
2353 Version.ParentPkg().Name());
a6568219 2354
b3d44315
MV
2355 Desc.URI = Index->ArchiveURI(PkgFile);
2356 Desc.Description = Index->ArchiveInfo(Version);
2357 Desc.Owner = this;
40f8a8ba 2358 Desc.ShortDesc = Version.ParentPkg().FullName(true);
b3d44315 2359
17caf1b1 2360 // See if we already have the file. (Legacy filenames)
a6568219
AL
2361 FileSize = Version->Size;
2362 string FinalFile = _config->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile);
2363 struct stat Buf;
2364 if (stat(FinalFile.c_str(),&Buf) == 0)
2365 {
2366 // Make sure the size matches
73da43e9 2367 if ((unsigned long long)Buf.st_size == Version->Size)
a6568219
AL
2368 {
2369 Complete = true;
2370 Local = true;
2371 Status = StatDone;
30e1eab5 2372 StoreFilename = DestFile = FinalFile;
b185acc2 2373 return true;
a6568219
AL
2374 }
2375
6b1ff003
AL
2376 /* Hmm, we have a file and its size does not match, this means it is
2377 an old style mismatched arch */
a6568219
AL
2378 unlink(FinalFile.c_str());
2379 }
17caf1b1
AL
2380
2381 // Check it again using the new style output filenames
2382 FinalFile = _config->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename);
2383 if (stat(FinalFile.c_str(),&Buf) == 0)
2384 {
2385 // Make sure the size matches
73da43e9 2386 if ((unsigned long long)Buf.st_size == Version->Size)
17caf1b1
AL
2387 {
2388 Complete = true;
2389 Local = true;
2390 Status = StatDone;
2391 StoreFilename = DestFile = FinalFile;
2392 return true;
2393 }
2394
1e3f4083 2395 /* Hmm, we have a file and its size does not match, this shouldn't
17caf1b1
AL
2396 happen.. */
2397 unlink(FinalFile.c_str());
2398 }
2399
2400 DestFile = _config->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename);
6b1ff003
AL
2401
2402 // Check the destination file
2403 if (stat(DestFile.c_str(),&Buf) == 0)
2404 {
2405 // Hmm, the partial file is too big, erase it
73da43e9 2406 if ((unsigned long long)Buf.st_size > Version->Size)
6b1ff003
AL
2407 unlink(DestFile.c_str());
2408 else
2409 PartialSize = Buf.st_size;
2410 }
de31189f
DK
2411
2412 // Disables download of archives - useful if no real installation follows,
2413 // e.g. if we are just interested in proposed installation order
2414 if (_config->FindB("Debug::pkgAcqArchive::NoQueue", false) == true)
2415 {
2416 Complete = true;
2417 Local = true;
2418 Status = StatDone;
2419 StoreFilename = DestFile = FinalFile;
2420 return true;
2421 }
2422
03e39e59 2423 // Create the item
b2e465d6 2424 Local = false;
03e39e59 2425 QueueURI(Desc);
b185acc2 2426
f7f0d6c7 2427 ++Vf;
b185acc2 2428 return true;
03e39e59 2429 }
b185acc2
AL
2430 return false;
2431}
03e39e59
AL
2432 /*}}}*/
2433// AcqArchive::Done - Finished fetching /*{{{*/
2434// ---------------------------------------------------------------------
2435/* */
b3501edb 2436void pkgAcqArchive::Done(string Message,unsigned long long Size, HashStringList const &CalcHashes,
459681d3 2437 pkgAcquire::MethodConfig *Cfg)
03e39e59 2438{
b3501edb 2439 Item::Done(Message, Size, CalcHashes, Cfg);
03e39e59
AL
2440
2441 // Check the size
2442 if (Size != Version->Size)
2443 {
3c8030a4 2444 RenameOnError(SizeMismatch);
03e39e59
AL
2445 return;
2446 }
b3501edb 2447
0d29b9d4 2448 // FIXME: could this empty() check impose *any* sort of security issue?
b3501edb 2449 if(ExpectedHashes.usable() && ExpectedHashes != CalcHashes)
03e39e59 2450 {
3c8030a4 2451 RenameOnError(HashSumMismatch);
b3501edb 2452 printHashSumComparision(DestFile, ExpectedHashes, CalcHashes);
495e5cb2 2453 return;
03e39e59 2454 }
a6568219
AL
2455
2456 // Grab the output filename
03e39e59
AL
2457 string FileName = LookupTag(Message,"Filename");
2458 if (FileName.empty() == true)
2459 {
2460 Status = StatError;
2461 ErrorText = "Method gave a blank filename";
2462 return;
2463 }
a6568219 2464
30e1eab5 2465 // Reference filename
a6568219
AL
2466 if (FileName != DestFile)
2467 {
30e1eab5 2468 StoreFilename = DestFile = FileName;
a6568219 2469 Local = true;
5684f71f 2470 Complete = true;
a6568219
AL
2471 return;
2472 }
5684f71f 2473
a6568219
AL
2474 // Done, move it into position
2475 string FinalFile = _config->FindDir("Dir::Cache::Archives");
17caf1b1 2476 FinalFile += flNotDir(StoreFilename);
a6568219 2477 Rename(DestFile,FinalFile);
30e1eab5 2478 StoreFilename = DestFile = FinalFile;
03e39e59
AL
2479 Complete = true;
2480}
2481 /*}}}*/
db890fdb
AL
2482// AcqArchive::Failed - Failure handler /*{{{*/
2483// ---------------------------------------------------------------------
2484/* Here we try other sources */
7d8afa39 2485void pkgAcqArchive::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
db890fdb 2486{
03aa0847
DK
2487 Item::Failed(Message,Cnf);
2488
b2e465d6
AL
2489 /* We don't really want to retry on failed media swaps, this prevents
2490 that. An interesting observation is that permanent failures are not
2491 recorded. */
2492 if (Cnf->Removable == true &&
2493 StringToBool(LookupTag(Message,"Transient-Failure"),false) == true)
2494 {
2495 // Vf = Version.FileList();
f7f0d6c7 2496 while (Vf.end() == false) ++Vf;
b2e465d6 2497 StoreFilename = string();
b2e465d6
AL
2498 return;
2499 }
03aa0847
DK
2500
2501 Status = StatIdle;
db890fdb 2502 if (QueueNext() == false)
7d8afa39
AL
2503 {
2504 // This is the retry counter
2505 if (Retries != 0 &&
2506 Cnf->LocalOnly == false &&
2507 StringToBool(LookupTag(Message,"Transient-Failure"),false) == true)
2508 {
2509 Retries--;
2510 Vf = Version.FileList();
2511 if (QueueNext() == true)
2512 return;
2513 }
03aa0847 2514
9dbb421f 2515 StoreFilename = string();
03aa0847 2516 Status = StatError;
7d8afa39 2517 }
db890fdb
AL
2518}
2519 /*}}}*/
92fcbfc1 2520// AcqArchive::IsTrusted - Determine whether this archive comes from a trusted source /*{{{*/
b3d44315 2521// ---------------------------------------------------------------------
02e20767 2522#if APT_PKG_ABI >= 413
b3501edb 2523APT_PURE bool pkgAcqArchive::IsTrusted() const
02e20767
DK
2524#else
2525APT_PURE bool pkgAcqArchive::IsTrusted()
2526#endif
b3d44315
MV
2527{
2528 return Trusted;
2529}
92fcbfc1 2530 /*}}}*/
ab559b35
AL
2531// AcqArchive::Finished - Fetching has finished, tidy up /*{{{*/
2532// ---------------------------------------------------------------------
2533/* */
2534void pkgAcqArchive::Finished()
2535{
2536 if (Status == pkgAcquire::Item::StatDone &&
2537 Complete == true)
2538 return;
2539 StoreFilename = string();
2540}
2541 /*}}}*/
36375005
AL
2542// AcqFile::pkgAcqFile - Constructor /*{{{*/
2543// ---------------------------------------------------------------------
2544/* The file is added to the queue */
b3501edb 2545pkgAcqFile::pkgAcqFile(pkgAcquire *Owner,string URI, HashStringList const &Hashes,
73da43e9 2546 unsigned long long Size,string Dsc,string ShortDesc,
77278c2b
MV
2547 const string &DestDir, const string &DestFilename,
2548 bool IsIndexFile) :
fa3b260f 2549 Item(Owner, Hashes), IsIndexFile(IsIndexFile)
36375005 2550{
08cfc005
AL
2551 Retries = _config->FindI("Acquire::Retries",0);
2552
46e00f9d
MV
2553 if(!DestFilename.empty())
2554 DestFile = DestFilename;
2555 else if(!DestDir.empty())
2556 DestFile = DestDir + "/" + flNotDir(URI);
2557 else
2558 DestFile = flNotDir(URI);
2559
36375005
AL
2560 // Create the item
2561 Desc.URI = URI;
2562 Desc.Description = Dsc;
2563 Desc.Owner = this;
2564
2565 // Set the short description to the archive component
2566 Desc.ShortDesc = ShortDesc;
2567
2568 // Get the transfer sizes
2569 FileSize = Size;
2570 struct stat Buf;
2571 if (stat(DestFile.c_str(),&Buf) == 0)
2572 {
2573 // Hmm, the partial file is too big, erase it
ed9665ae 2574 if ((Size > 0) && (unsigned long long)Buf.st_size > Size)
36375005
AL
2575 unlink(DestFile.c_str());
2576 else
2577 PartialSize = Buf.st_size;
2578 }
092ae175 2579
36375005
AL
2580 QueueURI(Desc);
2581}
2582 /*}}}*/
2583// AcqFile::Done - Item downloaded OK /*{{{*/
2584// ---------------------------------------------------------------------
2585/* */
b3501edb 2586void pkgAcqFile::Done(string Message,unsigned long long Size,HashStringList const &CalcHashes,
459681d3 2587 pkgAcquire::MethodConfig *Cnf)
36375005 2588{
b3501edb 2589 Item::Done(Message,Size,CalcHashes,Cnf);
495e5cb2 2590
8a8feb29 2591 // Check the hash
b3501edb 2592 if(ExpectedHashes.usable() && ExpectedHashes != CalcHashes)
b3c39978 2593 {
3c8030a4 2594 RenameOnError(HashSumMismatch);
b3501edb 2595 printHashSumComparision(DestFile, ExpectedHashes, CalcHashes);
495e5cb2 2596 return;
b3c39978
AL
2597 }
2598
36375005
AL
2599 string FileName = LookupTag(Message,"Filename");
2600 if (FileName.empty() == true)
2601 {
2602 Status = StatError;
2603 ErrorText = "Method gave a blank filename";
2604 return;
2605 }
2606
2607 Complete = true;
2608
2609 // The files timestamp matches
2610 if (StringToBool(LookupTag(Message,"IMS-Hit"),false) == true)
2611 return;
2612
2613 // We have to copy it into place
2614 if (FileName != DestFile)
2615 {
2616 Local = true;
459681d3
AL
2617 if (_config->FindB("Acquire::Source-Symlinks",true) == false ||
2618 Cnf->Removable == true)
917ae805
AL
2619 {
2620 Desc.URI = "copy:" + FileName;
2621 QueueURI(Desc);
2622 return;
2623 }
2624
83ab33fc
AL
2625 // Erase the file if it is a symlink so we can overwrite it
2626 struct stat St;
2627 if (lstat(DestFile.c_str(),&St) == 0)
2628 {
2629 if (S_ISLNK(St.st_mode) != 0)
2630 unlink(DestFile.c_str());
2631 }
2632
2633 // Symlink the file
917ae805
AL
2634 if (symlink(FileName.c_str(),DestFile.c_str()) != 0)
2635 {
03aa0847
DK
2636 _error->PushToStack();
2637 _error->Errno("pkgAcqFile::Done", "Symlinking file %s failed", DestFile.c_str());
2638 std::stringstream msg;
2639 _error->DumpErrors(msg);
2640 _error->RevertToStack();
2641 ErrorText = msg.str();
917ae805
AL
2642 Status = StatError;
2643 Complete = false;
2644 }
36375005
AL
2645 }
2646}
2647 /*}}}*/
08cfc005
AL
2648// AcqFile::Failed - Failure handler /*{{{*/
2649// ---------------------------------------------------------------------
2650/* Here we try other sources */
2651void pkgAcqFile::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
2652{
03aa0847
DK
2653 Item::Failed(Message,Cnf);
2654
08cfc005
AL
2655 // This is the retry counter
2656 if (Retries != 0 &&
2657 Cnf->LocalOnly == false &&
2658 StringToBool(LookupTag(Message,"Transient-Failure"),false) == true)
2659 {
03aa0847 2660 --Retries;
08cfc005 2661 QueueURI(Desc);
03aa0847 2662 Status = StatIdle;
08cfc005
AL
2663 return;
2664 }
03aa0847 2665
08cfc005
AL
2666}
2667 /*}}}*/
77278c2b
MV
2668// AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
2669// ---------------------------------------------------------------------
2670/* The only header we use is the last-modified header. */
02e20767 2671#if APT_PKG_ABI >= 413
b3501edb 2672string pkgAcqFile::Custom600Headers() const
02e20767
DK
2673#else
2674string pkgAcqFile::Custom600Headers()
2675#endif
77278c2b
MV
2676{
2677 if (IsIndexFile)
2678 return "\nIndex-File: true";
61a07c57 2679 return "";
77278c2b
MV
2680}
2681 /*}}}*/