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