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