]> git.saurik.com Git - apt.git/blame - apt-pkg/acquire-item.cc
enable APT in unpack/configure ordering to handle loops as well
[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();
f7f0d6c7 686 available_patches.empty() == false &&
2ac3eeb6 687 I != available_patches.end() &&
f7f0d6c7
DK
688 I->sha1 != local_sha1;
689 ++I)
2ac3eeb6 690 {
26d27645 691 available_patches.erase(I);
59a704f0 692 }
94dc9d7d
MV
693
694 // error checking and falling back if no patch was found
f7f0d6c7
DK
695 if(available_patches.empty() == true)
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
f7f0d6c7 761 if(available_patches.empty() == false) {
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
97efc27f
MV
813 // only verify non-optional targets, see acquire-item.h for a FIXME
814 // to make this more flexible
c5f661b7
MV
815 if (Target->IsOptional())
816 Verify = false;
97efc27f
MV
817 else
818 Verify = true;
c5f661b7 819
5d885723
DK
820 Init(Target->URI, Target->Description, Target->ShortDesc);
821}
822 /*}}}*/
823// AcqIndex::Init - defered Constructor /*{{{*/
824void pkgAcqIndex::Init(string const &URI, string const &URIDesc, string const &ShortDesc) {
8b89e57f 825 Decompression = false;
bfd22fc0 826 Erase = false;
13e8426f 827
0a8a80e5 828 DestFile = _config->FindDir("Dir::State::lists") + "partial/";
b2e465d6 829 DestFile += URItoFileName(URI);
8267fe24 830
5d885723
DK
831 std::string const comprExt = CompressionExtension.substr(0, CompressionExtension.find(' '));
832 if (comprExt == "uncompressed")
833 Desc.URI = URI;
834 else
835 Desc.URI = URI + '.' + comprExt;
b3d44315 836
b2e465d6 837 Desc.Description = URIDesc;
8267fe24 838 Desc.Owner = this;
b2e465d6 839 Desc.ShortDesc = ShortDesc;
5d885723 840
8267fe24 841 QueueURI(Desc);
0118833a
AL
842}
843 /*}}}*/
0a8a80e5 844// AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
0118833a 845// ---------------------------------------------------------------------
0a8a80e5
AL
846/* The only header we use is the last-modified header. */
847string pkgAcqIndex::Custom600Headers()
0118833a 848{
0a8a80e5 849 string Final = _config->FindDir("Dir::State::lists");
b2e465d6 850 Final += URItoFileName(RealURI);
01606def 851 if (_config->FindB("Acquire::GzipIndexes",false))
852 Final += ".gz";
0a8a80e5 853
97b65b10
MV
854 string msg = "\nIndex-File: true";
855 // FIXME: this really should use "IndexTarget::IsOptional()" but that
856 // seems to be difficult without breaking ABI
857 if (ShortDesc().find("Translation") != 0)
858 msg += "\nFail-Ignore: true";
0a8a80e5 859 struct stat Buf;
3a1f49c4 860 if (stat(Final.c_str(),&Buf) == 0)
97b65b10
MV
861 msg += "\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
862
863 return msg;
0118833a
AL
864}
865 /*}}}*/
92fcbfc1 866void pkgAcqIndex::Failed(string Message,pkgAcquire::MethodConfig *Cnf) /*{{{*/
debc84b2 867{
5d885723
DK
868 size_t const nextExt = CompressionExtension.find(' ');
869 if (nextExt != std::string::npos)
e85b4cd5 870 {
5d885723
DK
871 CompressionExtension = CompressionExtension.substr(nextExt+1);
872 Init(RealURI, Desc.Description, Desc.ShortDesc);
6abe2699 873 return;
0d7a243d
EL
874 }
875
17ff0930 876 // on decompression failure, remove bad versions in partial/
5d885723 877 if (Decompression && Erase) {
17ff0930 878 string s = _config->FindDir("Dir::State::lists") + "partial/";
5d885723 879 s.append(URItoFileName(RealURI));
17ff0930 880 unlink(s.c_str());
debc84b2
MZ
881 }
882
debc84b2
MZ
883 Item::Failed(Message,Cnf);
884}
92fcbfc1 885 /*}}}*/
8b89e57f
AL
886// AcqIndex::Done - Finished a fetch /*{{{*/
887// ---------------------------------------------------------------------
888/* This goes through a number of states.. On the initial fetch the
889 method could possibly return an alternate filename which points
890 to the uncompressed version of the file. If this is so the file
891 is copied into the partial directory. In all other cases the file
892 is decompressed with a gzip uri. */
73da43e9 893void pkgAcqIndex::Done(string Message,unsigned long long Size,string Hash,
459681d3 894 pkgAcquire::MethodConfig *Cfg)
8b89e57f 895{
495e5cb2 896 Item::Done(Message,Size,Hash,Cfg);
8b89e57f
AL
897
898 if (Decompression == true)
899 {
b3d44315
MV
900 if (_config->FindB("Debug::pkgAcquire::Auth", false))
901 {
495e5cb2
MV
902 std::cerr << std::endl << RealURI << ": Computed Hash: " << Hash;
903 std::cerr << " Expected Hash: " << ExpectedHash.toStr() << std::endl;
b3d44315
MV
904 }
905
8a8feb29 906 if (!ExpectedHash.empty() && ExpectedHash.toStr() != Hash)
b3d44315
MV
907 {
908 Status = StatAuthError;
9498d182 909 ErrorText = _("Hash Sum mismatch");
b3d44315 910 Rename(DestFile,DestFile + ".FAILED");
59271f62 911 ReportMirrorFailure("HashChecksumFailure");
b3d44315
MV
912 return;
913 }
0901c5d0
JAK
914
915 /* Verify the index file for correctness (all indexes must
4fdb6123 916 * have a Package field) (LP: #346386) (Closes: #627642) */
c5f661b7 917 if (Verify == true)
0901c5d0
JAK
918 {
919 FileFd fd(DestFile, FileFd::ReadOnly);
920 pkgTagSection sec;
921 pkgTagFile tag(&fd);
922
a0c3110e
MV
923 // Only test for correctness if the file is not empty (empty is ok)
924 if (fd.Size() > 0) {
925 if (_error->PendingError() || !tag.Step(sec)) {
926 Status = StatError;
927 _error->DumpErrors();
928 Rename(DestFile,DestFile + ".FAILED");
929 return;
930 } else if (!sec.Exists("Package")) {
931 Status = StatError;
932 ErrorText = ("Encountered a section with no Package: header");
933 Rename(DestFile,DestFile + ".FAILED");
934 return;
935 }
936 }
0901c5d0
JAK
937 }
938
8b89e57f
AL
939 // Done, move it into position
940 string FinalFile = _config->FindDir("Dir::State::lists");
b2e465d6 941 FinalFile += URItoFileName(RealURI);
8b89e57f 942 Rename(DestFile,FinalFile);
7a3c2ab0 943 chmod(FinalFile.c_str(),0644);
bfd22fc0 944
7a7fa5f0
AL
945 /* We restore the original name to DestFile so that the clean operation
946 will work OK */
947 DestFile = _config->FindDir("Dir::State::lists") + "partial/";
b2e465d6 948 DestFile += URItoFileName(RealURI);
7a7fa5f0 949
bfd22fc0
AL
950 // Remove the compressed version.
951 if (Erase == true)
bfd22fc0 952 unlink(DestFile.c_str());
8b89e57f
AL
953 return;
954 }
bfd22fc0
AL
955
956 Erase = false;
8267fe24 957 Complete = true;
bfd22fc0 958
8b89e57f
AL
959 // Handle the unzipd case
960 string FileName = LookupTag(Message,"Alt-Filename");
961 if (FileName.empty() == false)
962 {
963 // The files timestamp matches
964 if (StringToBool(LookupTag(Message,"Alt-IMS-Hit"),false) == true)
965 return;
8b89e57f 966 Decompression = true;
a6568219 967 Local = true;
8b89e57f 968 DestFile += ".decomp";
8267fe24
AL
969 Desc.URI = "copy:" + FileName;
970 QueueURI(Desc);
b98f2859 971 Mode = "copy";
8b89e57f
AL
972 return;
973 }
974
975 FileName = LookupTag(Message,"Filename");
976 if (FileName.empty() == true)
977 {
978 Status = StatError;
979 ErrorText = "Method gave a blank filename";
980 }
5d885723
DK
981
982 std::string const compExt = CompressionExtension.substr(0, CompressionExtension.find(' '));
0b9032b1 983
8b89e57f 984 // The files timestamp matches
0b9032b1 985 if (StringToBool(LookupTag(Message,"IMS-Hit"),false) == true) {
986 if (_config->FindB("Acquire::GzipIndexes",false) && compExt == "gz")
987 // Update DestFile for .gz suffix so that the clean operation keeps it
988 DestFile += ".gz";
8b89e57f 989 return;
0b9032b1 990 }
bfd22fc0
AL
991
992 if (FileName == DestFile)
993 Erase = true;
8267fe24 994 else
a6568219 995 Local = true;
8b89e57f 996
e85b4cd5
DK
997 string decompProg;
998
bb109d0b 999 // If we enable compressed indexes and already have gzip, keep it
7aeee365 1000 if (_config->FindB("Acquire::GzipIndexes",false) && compExt == "gz" && !Local) {
bb109d0b 1001 string FinalFile = _config->FindDir("Dir::State::lists");
1002 FinalFile += URItoFileName(RealURI) + ".gz";
bb109d0b 1003 Rename(DestFile,FinalFile);
1004 chmod(FinalFile.c_str(),0644);
1005
1006 // Update DestFile for .gz suffix so that the clean operation keeps it
1007 DestFile = _config->FindDir("Dir::State::lists") + "partial/";
1008 DestFile += URItoFileName(RealURI) + ".gz";
1009 return;
1010 }
1011
e85b4cd5
DK
1012 // get the binary name for your used compression type
1013 decompProg = _config->Find(string("Acquire::CompressionTypes::").append(compExt),"");
1014 if(decompProg.empty() == false);
5d885723 1015 else if(compExt == "uncompressed")
0d7a243d 1016 decompProg = "copy";
debc84b2
MZ
1017 else {
1018 _error->Error("Unsupported extension: %s", compExt.c_str());
1019 return;
1020 }
1021
8b89e57f
AL
1022 Decompression = true;
1023 DestFile += ".decomp";
e85b4cd5 1024 Desc.URI = decompProg + ":" + FileName;
8267fe24 1025 QueueURI(Desc);
e85b4cd5 1026 Mode = decompProg.c_str();
8b89e57f 1027}
92fcbfc1 1028 /*}}}*/
a52f938b
OS
1029// AcqIndexTrans::pkgAcqIndexTrans - Constructor /*{{{*/
1030// ---------------------------------------------------------------------
1031/* The Translation file is added to the queue */
1032pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire *Owner,
495e5cb2
MV
1033 string URI,string URIDesc,string ShortDesc)
1034 : pkgAcqIndex(Owner, URI, URIDesc, ShortDesc, HashString(), "")
a52f938b 1035{
ab53c018
DK
1036}
1037pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire *Owner, IndexTarget const *Target,
1038 HashString const &ExpectedHash, indexRecords const *MetaIndexParser)
1039 : pkgAcqIndex(Owner, Target, ExpectedHash, MetaIndexParser)
1040{
963b16dc
MV
1041}
1042 /*}}}*/
1043// AcqIndexTrans::Custom600Headers - Insert custom request headers /*{{{*/
1044// ---------------------------------------------------------------------
1045string pkgAcqIndexTrans::Custom600Headers()
1046{
c91d9a63
DK
1047 string Final = _config->FindDir("Dir::State::lists");
1048 Final += URItoFileName(RealURI);
1049
1050 struct stat Buf;
1051 if (stat(Final.c_str(),&Buf) != 0)
a3f7fff8
MV
1052 return "\nFail-Ignore: true\nIndex-File: true";
1053 return "\nFail-Ignore: true\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
a52f938b 1054}
a52f938b
OS
1055 /*}}}*/
1056// AcqIndexTrans::Failed - Silence failure messages for missing files /*{{{*/
1057// ---------------------------------------------------------------------
1058/* */
1059void pkgAcqIndexTrans::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
1060{
5d885723
DK
1061 size_t const nextExt = CompressionExtension.find(' ');
1062 if (nextExt != std::string::npos)
1063 {
1064 CompressionExtension = CompressionExtension.substr(nextExt+1);
1065 Init(RealURI, Desc.Description, Desc.ShortDesc);
1066 Status = StatIdle;
1067 return;
1068 }
1069
a52f938b
OS
1070 if (Cnf->LocalOnly == true ||
1071 StringToBool(LookupTag(Message,"Transient-Failure"),false) == false)
1072 {
1073 // Ignore this
1074 Status = StatDone;
1075 Complete = false;
1076 Dequeue();
1077 return;
1078 }
5d885723 1079
a52f938b
OS
1080 Item::Failed(Message,Cnf);
1081}
1082 /*}}}*/
92fcbfc1 1083pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire *Owner, /*{{{*/
b3d44315
MV
1084 string URI,string URIDesc,string ShortDesc,
1085 string MetaIndexURI, string MetaIndexURIDesc,
1086 string MetaIndexShortDesc,
1087 const vector<IndexTarget*>* IndexTargets,
1088 indexRecords* MetaIndexParser) :
1089 Item(Owner), RealURI(URI), MetaIndexURI(MetaIndexURI),
46e00f9d
MV
1090 MetaIndexURIDesc(MetaIndexURIDesc), MetaIndexShortDesc(MetaIndexShortDesc),
1091 MetaIndexParser(MetaIndexParser), IndexTargets(IndexTargets)
0118833a 1092{
0a8a80e5 1093 DestFile = _config->FindDir("Dir::State::lists") + "partial/";
b2e465d6 1094 DestFile += URItoFileName(URI);
b3d44315 1095
47eb38f4
MV
1096 // remove any partial downloaded sig-file in partial/.
1097 // it may confuse proxies and is too small to warrant a
1098 // partial download anyway
f6237efd
MV
1099 unlink(DestFile.c_str());
1100
8267fe24 1101 // Create the item
b2e465d6 1102 Desc.Description = URIDesc;
8267fe24 1103 Desc.Owner = this;
b3d44315
MV
1104 Desc.ShortDesc = ShortDesc;
1105 Desc.URI = URI;
b3d44315
MV
1106
1107 string Final = _config->FindDir("Dir::State::lists");
1108 Final += URItoFileName(RealURI);
1109 struct stat Buf;
1110 if (stat(Final.c_str(),&Buf) == 0)
1111 {
ef942597
MV
1112 // File was already in place. It needs to be re-downloaded/verified
1113 // because Release might have changed, we do give it a differnt
1114 // name than DestFile because otherwise the http method will
1115 // send If-Range requests and there are too many broken servers
1116 // out there that do not understand them
1117 LastGoodSig = DestFile+".reverify";
1118 Rename(Final,LastGoodSig);
b3d44315 1119 }
8267fe24 1120
8267fe24 1121 QueueURI(Desc);
0118833a
AL
1122}
1123 /*}}}*/
b3d44315 1124// pkgAcqMetaSig::Custom600Headers - Insert custom request headers /*{{{*/
0118833a 1125// ---------------------------------------------------------------------
0a8a80e5 1126/* The only header we use is the last-modified header. */
b3d44315 1127string pkgAcqMetaSig::Custom600Headers()
0118833a 1128{
0a8a80e5 1129 struct stat Buf;
ef942597 1130 if (stat(LastGoodSig.c_str(),&Buf) != 0)
a72ace20 1131 return "\nIndex-File: true";
a789b983 1132
a72ace20 1133 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
0118833a 1134}
b3d44315 1135
73da43e9 1136void pkgAcqMetaSig::Done(string Message,unsigned long long Size,string MD5,
b3d44315 1137 pkgAcquire::MethodConfig *Cfg)
c88edf1d 1138{
459681d3 1139 Item::Done(Message,Size,MD5,Cfg);
c88edf1d
AL
1140
1141 string FileName = LookupTag(Message,"Filename");
1142 if (FileName.empty() == true)
1143 {
1144 Status = StatError;
1145 ErrorText = "Method gave a blank filename";
8b89e57f 1146 return;
c88edf1d 1147 }
8b89e57f 1148
c88edf1d
AL
1149 if (FileName != DestFile)
1150 {
b3d44315 1151 // We have to copy it into place
a6568219 1152 Local = true;
8267fe24
AL
1153 Desc.URI = "copy:" + FileName;
1154 QueueURI(Desc);
c88edf1d
AL
1155 return;
1156 }
b3d44315
MV
1157
1158 Complete = true;
1159
ef942597
MV
1160 // put the last known good file back on i-m-s hit (it will
1161 // be re-verified again)
1162 // Else do nothing, we have the new file in DestFile then
1163 if(StringToBool(LookupTag(Message,"IMS-Hit"),false) == true)
1164 Rename(LastGoodSig, DestFile);
1165
b3d44315 1166 // queue a pkgAcqMetaIndex to be verified against the sig we just retrieved
fce72602
MV
1167 new pkgAcqMetaIndex(Owner, MetaIndexURI, MetaIndexURIDesc,
1168 MetaIndexShortDesc, DestFile, IndexTargets,
1169 MetaIndexParser);
b3d44315 1170
c88edf1d
AL
1171}
1172 /*}}}*/
92fcbfc1 1173void pkgAcqMetaSig::Failed(string Message,pkgAcquire::MethodConfig *Cnf)/*{{{*/
681d76d0 1174{
47eb38f4 1175 string Final = _config->FindDir("Dir::State::lists") + URItoFileName(RealURI);
a789b983 1176
75dd8af1 1177 // if we get a network error we fail gracefully
7e5f33eb
MV
1178 if(Status == StatTransientNetworkError)
1179 {
24057ad6 1180 Item::Failed(Message,Cnf);
484dbb81 1181 // move the sigfile back on transient network failures
7730e095 1182 if(FileExists(LastGoodSig))
ef942597 1183 Rename(LastGoodSig,Final);
7e5f33eb
MV
1184
1185 // set the status back to , Item::Failed likes to reset it
1186 Status = pkgAcquire::Item::StatTransientNetworkError;
24057ad6
MV
1187 return;
1188 }
1189
75dd8af1 1190 // Delete any existing sigfile when the acquire failed
75dd8af1
MV
1191 unlink(Final.c_str());
1192
b3d44315
MV
1193 // queue a pkgAcqMetaIndex with no sigfile
1194 new pkgAcqMetaIndex(Owner, MetaIndexURI, MetaIndexURIDesc, MetaIndexShortDesc,
1195 "", IndexTargets, MetaIndexParser);
1196
681d76d0
AL
1197 if (Cnf->LocalOnly == true ||
1198 StringToBool(LookupTag(Message,"Transient-Failure"),false) == false)
1199 {
2b154e53
AL
1200 // Ignore this
1201 Status = StatDone;
1202 Complete = false;
681d76d0
AL
1203 Dequeue();
1204 return;
1205 }
1206
1207 Item::Failed(Message,Cnf);
1208}
92fcbfc1
DK
1209 /*}}}*/
1210pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire *Owner, /*{{{*/
b3d44315
MV
1211 string URI,string URIDesc,string ShortDesc,
1212 string SigFile,
1213 const vector<struct IndexTarget*>* IndexTargets,
1214 indexRecords* MetaIndexParser) :
21fd1746
OS
1215 Item(Owner), RealURI(URI), SigFile(SigFile), IndexTargets(IndexTargets),
1216 MetaIndexParser(MetaIndexParser), AuthPass(false), IMSHit(false)
b3d44315 1217{
b3d44315
MV
1218 DestFile = _config->FindDir("Dir::State::lists") + "partial/";
1219 DestFile += URItoFileName(URI);
1220
1221 // Create the item
1222 Desc.Description = URIDesc;
1223 Desc.Owner = this;
1224 Desc.ShortDesc = ShortDesc;
1225 Desc.URI = URI;
1226
1227 QueueURI(Desc);
1228}
b3d44315
MV
1229 /*}}}*/
1230// pkgAcqMetaIndex::Custom600Headers - Insert custom request headers /*{{{*/
1231// ---------------------------------------------------------------------
1232/* The only header we use is the last-modified header. */
1233string pkgAcqMetaIndex::Custom600Headers()
1234{
1235 string Final = _config->FindDir("Dir::State::lists");
1236 Final += URItoFileName(RealURI);
1237
1238 struct stat Buf;
1239 if (stat(Final.c_str(),&Buf) != 0)
1240 return "\nIndex-File: true";
1241
1242 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
1243}
92fcbfc1 1244 /*}}}*/
73da43e9 1245void pkgAcqMetaIndex::Done(string Message,unsigned long long Size,string Hash, /*{{{*/
b3d44315
MV
1246 pkgAcquire::MethodConfig *Cfg)
1247{
495e5cb2 1248 Item::Done(Message,Size,Hash,Cfg);
b3d44315
MV
1249
1250 // MetaIndexes are done in two passes: one to download the
1251 // metaindex with an appropriate method, and a second to verify it
1252 // with the gpgv method
1253
1254 if (AuthPass == true)
1255 {
1256 AuthDone(Message);
fce72602
MV
1257
1258 // all cool, move Release file into place
1259 Complete = true;
b3d44315
MV
1260 }
1261 else
1262 {
1263 RetrievalDone(Message);
1264 if (!Complete)
1265 // Still more retrieving to do
1266 return;
1267
1268 if (SigFile == "")
1269 {
1270 // There was no signature file, so we are finished. Download
1207cf3f 1271 // the indexes and do only hashsum verification if possible
3568a640 1272 MetaIndexParser->Load(DestFile);
1207cf3f 1273 QueueIndexes(false);
b3d44315
MV
1274 }
1275 else
1276 {
1277 // There was a signature file, so pass it to gpgv for
1278 // verification
1279
1280 if (_config->FindB("Debug::pkgAcquire::Auth", false))
1281 std::cerr << "Metaindex acquired, queueing gpg verification ("
1282 << SigFile << "," << DestFile << ")\n";
1283 AuthPass = true;
1284 Desc.URI = "gpgv:" + SigFile;
1285 QueueURI(Desc);
1286 Mode = "gpgv";
56bc3358 1287 return;
b3d44315
MV
1288 }
1289 }
56bc3358
DK
1290
1291 if (Complete == true)
1292 {
1293 string FinalFile = _config->FindDir("Dir::State::lists");
1294 FinalFile += URItoFileName(RealURI);
fe0f7911
DK
1295 if (SigFile == DestFile)
1296 SigFile = FinalFile;
56bc3358
DK
1297 Rename(DestFile,FinalFile);
1298 chmod(FinalFile.c_str(),0644);
1299 DestFile = FinalFile;
1300 }
b3d44315 1301}
92fcbfc1
DK
1302 /*}}}*/
1303void pkgAcqMetaIndex::RetrievalDone(string Message) /*{{{*/
b3d44315
MV
1304{
1305 // We have just finished downloading a Release file (it is not
1306 // verified yet)
1307
1308 string FileName = LookupTag(Message,"Filename");
1309 if (FileName.empty() == true)
1310 {
1311 Status = StatError;
1312 ErrorText = "Method gave a blank filename";
1313 return;
1314 }
1315
1316 if (FileName != DestFile)
1317 {
1318 Local = true;
1319 Desc.URI = "copy:" + FileName;
1320 QueueURI(Desc);
1321 return;
1322 }
1323
fce72602 1324 // make sure to verify against the right file on I-M-S hit
f381d68d 1325 IMSHit = StringToBool(LookupTag(Message,"IMS-Hit"),false);
fce72602
MV
1326 if(IMSHit)
1327 {
1328 string FinalFile = _config->FindDir("Dir::State::lists");
1329 FinalFile += URItoFileName(RealURI);
fe0f7911
DK
1330 if (SigFile == DestFile)
1331 SigFile = FinalFile;
fce72602
MV
1332 DestFile = FinalFile;
1333 }
b3d44315 1334 Complete = true;
b3d44315 1335}
92fcbfc1
DK
1336 /*}}}*/
1337void pkgAcqMetaIndex::AuthDone(string Message) /*{{{*/
b3d44315
MV
1338{
1339 // At this point, the gpgv method has succeeded, so there is a
1340 // valid signature from a key in the trusted keyring. We
1341 // perform additional verification of its contents, and use them
1342 // to verify the indexes we are about to download
1343
1344 if (!MetaIndexParser->Load(DestFile))
1345 {
1346 Status = StatAuthError;
1347 ErrorText = MetaIndexParser->ErrorText;
1348 return;
1349 }
1350
ce424cd4 1351 if (!VerifyVendor(Message))
b3d44315
MV
1352 {
1353 return;
1354 }
1355
1356 if (_config->FindB("Debug::pkgAcquire::Auth", false))
1357 std::cerr << "Signature verification succeeded: "
1358 << DestFile << std::endl;
1359
1360 // Download further indexes with verification
1361 QueueIndexes(true);
1362
fe0f7911
DK
1363 // is it a clearsigned MetaIndex file?
1364 if (DestFile == SigFile)
1365 return;
1366
b3d44315 1367 // Done, move signature file into position
b3d44315
MV
1368 string VerifiedSigFile = _config->FindDir("Dir::State::lists") +
1369 URItoFileName(RealURI) + ".gpg";
1370 Rename(SigFile,VerifiedSigFile);
1371 chmod(VerifiedSigFile.c_str(),0644);
1372}
92fcbfc1
DK
1373 /*}}}*/
1374void pkgAcqMetaIndex::QueueIndexes(bool verify) /*{{{*/
b3d44315 1375{
0901c5d0 1376#if 0
4fdb6123 1377 /* Reject invalid, existing Release files (LP: #346386) (Closes: #627642)
0901c5d0
JAK
1378 * FIXME: Disabled; it breaks unsigned repositories without hashes */
1379 if (!verify && FileExists(DestFile) && !MetaIndexParser->Load(DestFile))
1380 {
1381 Status = StatError;
1382 ErrorText = MetaIndexParser->ErrorText;
1383 return;
1384 }
1385#endif
b3d44315
MV
1386 for (vector <struct IndexTarget*>::const_iterator Target = IndexTargets->begin();
1387 Target != IndexTargets->end();
f7f0d6c7 1388 ++Target)
b3d44315 1389 {
495e5cb2 1390 HashString ExpectedIndexHash;
1207cf3f
DK
1391 const indexRecords::checkSum *Record = MetaIndexParser->Lookup((*Target)->MetaKey);
1392 if (Record == NULL)
b3d44315 1393 {
1207cf3f 1394 if (verify == true && (*Target)->IsOptional() == false)
ab53c018 1395 {
1207cf3f
DK
1396 Status = StatAuthError;
1397 strprintf(ErrorText, _("Unable to find expected entry '%s' in Release file (Wrong sources.list entry or malformed file)"), (*Target)->MetaKey.c_str());
1398 return;
ab53c018 1399 }
1207cf3f
DK
1400 }
1401 else
1402 {
1403 ExpectedIndexHash = Record->Hash;
1404 if (_config->FindB("Debug::pkgAcquire::Auth", false))
ab53c018 1405 {
1207cf3f
DK
1406 std::cerr << "Queueing: " << (*Target)->URI << std::endl;
1407 std::cerr << "Expected Hash: " << ExpectedIndexHash.toStr() << std::endl;
1408 std::cerr << "For: " << Record->MetaKeyFilename << std::endl;
1409 }
1410 if (verify == true && ExpectedIndexHash.empty() == true && (*Target)->IsOptional() == false)
1411 {
1412 Status = StatAuthError;
1413 strprintf(ErrorText, _("Unable to find hash sum for '%s' in Release file"), (*Target)->MetaKey.c_str());
1414 return;
ab53c018
DK
1415 }
1416 }
1417
1418 if ((*Target)->IsOptional() == true)
1419 {
1420 if ((*Target)->IsSubIndex() == true)
1421 new pkgAcqSubIndex(Owner, (*Target)->URI, (*Target)->Description,
1422 (*Target)->ShortDesc, ExpectedIndexHash);
1423 else
1424 new pkgAcqIndexTrans(Owner, *Target, ExpectedIndexHash, MetaIndexParser);
1425 continue;
b3d44315 1426 }
e1430400
DK
1427
1428 /* Queue Packages file (either diff or full packages files, depending
1429 on the users option) - we also check if the PDiff Index file is listed
1430 in the Meta-Index file. Ideal would be if pkgAcqDiffIndex would test this
1431 instead, but passing the required info to it is to much hassle */
1432 if(_config->FindB("Acquire::PDiffs",true) == true && (verify == false ||
1433 MetaIndexParser->Exists(string((*Target)->MetaKey).append(".diff/Index")) == true))
2ac3eeb6 1434 new pkgAcqDiffIndex(Owner, (*Target)->URI, (*Target)->Description,
495e5cb2 1435 (*Target)->ShortDesc, ExpectedIndexHash);
e1430400 1436 else
5d885723 1437 new pkgAcqIndex(Owner, *Target, ExpectedIndexHash, MetaIndexParser);
b3d44315
MV
1438 }
1439}
92fcbfc1
DK
1440 /*}}}*/
1441bool pkgAcqMetaIndex::VerifyVendor(string Message) /*{{{*/
b3d44315 1442{
ce424cd4
MV
1443 string::size_type pos;
1444
1445 // check for missing sigs (that where not fatal because otherwise we had
1446 // bombed earlier)
1447 string missingkeys;
400ad7a4 1448 string msg = _("There is no public key available for the "
ce424cd4
MV
1449 "following key IDs:\n");
1450 pos = Message.find("NO_PUBKEY ");
1451 if (pos != std::string::npos)
1452 {
1453 string::size_type start = pos+strlen("NO_PUBKEY ");
1454 string Fingerprint = Message.substr(start, Message.find("\n")-start);
1455 missingkeys += (Fingerprint);
1456 }
1457 if(!missingkeys.empty())
1458 _error->Warning("%s", string(msg+missingkeys).c_str());
b3d44315
MV
1459
1460 string Transformed = MetaIndexParser->GetExpectedDist();
1461
1462 if (Transformed == "../project/experimental")
1463 {
1464 Transformed = "experimental";
1465 }
1466
ce424cd4 1467 pos = Transformed.rfind('/');
b3d44315
MV
1468 if (pos != string::npos)
1469 {
1470 Transformed = Transformed.substr(0, pos);
1471 }
1472
1473 if (Transformed == ".")
1474 {
1475 Transformed = "";
1476 }
1477
0323317c
DK
1478 if (_config->FindB("Acquire::Check-Valid-Until", true) == true &&
1479 MetaIndexParser->GetValidUntil() > 0) {
1480 time_t const invalid_since = time(NULL) - MetaIndexParser->GetValidUntil();
1481 if (invalid_since > 0)
1482 // TRANSLATOR: The first %s is the URL of the bad Release file, the second is
1483 // the time since then the file is invalid - formated in the same way as in
1484 // the download progress display (e.g. 7d 3h 42min 1s)
457bea86
MV
1485 return _error->Error(
1486 _("Release file for %s is expired (invalid since %s). "
1487 "Updates for this repository will not be applied."),
1488 RealURI.c_str(), TimeToStr(invalid_since).c_str());
1ddb8596
DK
1489 }
1490
b3d44315
MV
1491 if (_config->FindB("Debug::pkgAcquire::Auth", false))
1492 {
1493 std::cerr << "Got Codename: " << MetaIndexParser->GetDist() << std::endl;
1494 std::cerr << "Expecting Dist: " << MetaIndexParser->GetExpectedDist() << std::endl;
1495 std::cerr << "Transformed Dist: " << Transformed << std::endl;
1496 }
1497
1498 if (MetaIndexParser->CheckDist(Transformed) == false)
1499 {
1500 // This might become fatal one day
1501// Status = StatAuthError;
1502// ErrorText = "Conflicting distribution; expected "
1503// + MetaIndexParser->GetExpectedDist() + " but got "
1504// + MetaIndexParser->GetDist();
1505// return false;
1506 if (!Transformed.empty())
1507 {
1ddb8596 1508 _error->Warning(_("Conflicting distribution: %s (expected %s but got %s)"),
b3d44315
MV
1509 Desc.Description.c_str(),
1510 Transformed.c_str(),
1511 MetaIndexParser->GetDist().c_str());
1512 }
1513 }
1514
1515 return true;
1516}
92fcbfc1
DK
1517 /*}}}*/
1518// pkgAcqMetaIndex::Failed - no Release file present or no signature file present /*{{{*/
b3d44315
MV
1519// ---------------------------------------------------------------------
1520/* */
1521void pkgAcqMetaIndex::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
1522{
1523 if (AuthPass == true)
1524 {
fce72602 1525 // gpgv method failed, if we have a good signature
fe0f7911
DK
1526 string LastGoodSigFile = _config->FindDir("Dir::State::lists");
1527 if (DestFile == SigFile)
1528 LastGoodSigFile.append(URItoFileName(RealURI));
1529 else
1530 LastGoodSigFile.append("partial/").append(URItoFileName(RealURI)).append(".gpg.reverify");
1531
fce72602 1532 if(FileExists(LastGoodSigFile))
f381d68d 1533 {
fe0f7911
DK
1534 if (DestFile != SigFile)
1535 {
1536 string VerifiedSigFile = _config->FindDir("Dir::State::lists") +
1537 URItoFileName(RealURI) + ".gpg";
1538 Rename(LastGoodSigFile,VerifiedSigFile);
1539 }
fce72602
MV
1540 Status = StatTransientNetworkError;
1541 _error->Warning(_("A error occurred during the signature "
1542 "verification. The repository is not updated "
2493f4b5 1543 "and the previous index files will be used. "
76b8e5a5 1544 "GPG error: %s: %s\n"),
fce72602
MV
1545 Desc.Description.c_str(),
1546 LookupTag(Message,"Message").c_str());
5d149bfc 1547 RunScripts("APT::Update::Auth-Failure");
f381d68d 1548 return;
0901c5d0 1549 } else if (LookupTag(Message,"Message").find("NODATA") != string::npos) {
4fdb6123 1550 /* Invalid signature file, reject (LP: #346386) (Closes: #627642) */
0901c5d0
JAK
1551 _error->Error(_("GPG error: %s: %s"),
1552 Desc.Description.c_str(),
1553 LookupTag(Message,"Message").c_str());
1554 return;
fce72602
MV
1555 } else {
1556 _error->Warning(_("GPG error: %s: %s"),
1557 Desc.Description.c_str(),
1558 LookupTag(Message,"Message").c_str());
f381d68d 1559 }
f381d68d 1560 // gpgv method failed
59271f62 1561 ReportMirrorFailure("GPGFailure");
b3d44315
MV
1562 }
1563
7ea7ac9e
JAK
1564 /* Always move the meta index, even if gpgv failed. This ensures
1565 * that PackageFile objects are correctly filled in */
a235ddf8 1566 if (FileExists(DestFile)) {
7ea7ac9e
JAK
1567 string FinalFile = _config->FindDir("Dir::State::lists");
1568 FinalFile += URItoFileName(RealURI);
1569 /* InRelease files become Release files, otherwise
1570 * they would be considered as trusted later on */
1571 if (SigFile == DestFile) {
1572 RealURI = RealURI.replace(RealURI.rfind("InRelease"), 9,
1573 "Release");
1574 FinalFile = FinalFile.replace(FinalFile.rfind("InRelease"), 9,
1575 "Release");
1576 SigFile = FinalFile;
1577 }
1578 Rename(DestFile,FinalFile);
1579 chmod(FinalFile.c_str(),0644);
1580
1581 DestFile = FinalFile;
1582 }
1583
b3d44315
MV
1584 // No Release file was present, or verification failed, so fall
1585 // back to queueing Packages files without verification
1586 QueueIndexes(false);
1587}
681d76d0 1588 /*}}}*/
fe0f7911
DK
1589pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire *Owner, /*{{{*/
1590 string const &URI, string const &URIDesc, string const &ShortDesc,
1591 string const &MetaIndexURI, string const &MetaIndexURIDesc, string const &MetaIndexShortDesc,
1592 string const &MetaSigURI, string const &MetaSigURIDesc, string const &MetaSigShortDesc,
1593 const vector<struct IndexTarget*>* IndexTargets,
1594 indexRecords* MetaIndexParser) :
1595 pkgAcqMetaIndex(Owner, URI, URIDesc, ShortDesc, "", IndexTargets, MetaIndexParser),
1596 MetaIndexURI(MetaIndexURI), MetaIndexURIDesc(MetaIndexURIDesc), MetaIndexShortDesc(MetaIndexShortDesc),
1597 MetaSigURI(MetaSigURI), MetaSigURIDesc(MetaSigURIDesc), MetaSigShortDesc(MetaSigShortDesc)
1598{
1599 SigFile = DestFile;
1600}
1601 /*}}}*/
8d6c5839
MV
1602// pkgAcqMetaClearSig::Custom600Headers - Insert custom request headers /*{{{*/
1603// ---------------------------------------------------------------------
1604// FIXME: this can go away once the InRelease file is used widely
1605string pkgAcqMetaClearSig::Custom600Headers()
1606{
1607 string Final = _config->FindDir("Dir::State::lists");
1608 Final += URItoFileName(RealURI);
1609
1610 struct stat Buf;
1611 if (stat(Final.c_str(),&Buf) != 0)
1612 return "\nIndex-File: true\nFail-Ignore: true\n";
1613
1614 return "\nIndex-File: true\nFail-Ignore: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
1615}
1616 /*}}}*/
fe0f7911
DK
1617void pkgAcqMetaClearSig::Failed(string Message,pkgAcquire::MethodConfig *Cnf) /*{{{*/
1618{
1619 if (AuthPass == false)
1620 {
1621 new pkgAcqMetaSig(Owner,
1622 MetaSigURI, MetaSigURIDesc, MetaSigShortDesc,
1623 MetaIndexURI, MetaIndexURIDesc, MetaIndexShortDesc,
1624 IndexTargets, MetaIndexParser);
1625 if (Cnf->LocalOnly == true ||
1626 StringToBool(LookupTag(Message, "Transient-Failure"), false) == false)
1627 Dequeue();
1628 }
1629 else
1630 pkgAcqMetaIndex::Failed(Message, Cnf);
1631}
1632 /*}}}*/
03e39e59
AL
1633// AcqArchive::AcqArchive - Constructor /*{{{*/
1634// ---------------------------------------------------------------------
17caf1b1
AL
1635/* This just sets up the initial fetch environment and queues the first
1636 possibilitiy */
03e39e59 1637pkgAcqArchive::pkgAcqArchive(pkgAcquire *Owner,pkgSourceList *Sources,
30e1eab5
AL
1638 pkgRecords *Recs,pkgCache::VerIterator const &Version,
1639 string &StoreFilename) :
1640 Item(Owner), Version(Version), Sources(Sources), Recs(Recs),
b3d44315
MV
1641 StoreFilename(StoreFilename), Vf(Version.FileList()),
1642 Trusted(false)
03e39e59 1643{
7d8afa39 1644 Retries = _config->FindI("Acquire::Retries",0);
813c8eea
AL
1645
1646 if (Version.Arch() == 0)
bdae53f1 1647 {
d1f1f6a8 1648 _error->Error(_("I wasn't able to locate a file for the %s package. "
7a3c2ab0
AL
1649 "This might mean you need to manually fix this package. "
1650 "(due to missing arch)"),
813c8eea 1651 Version.ParentPkg().Name());
bdae53f1
AL
1652 return;
1653 }
813c8eea 1654
b2e465d6
AL
1655 /* We need to find a filename to determine the extension. We make the
1656 assumption here that all the available sources for this version share
1657 the same extension.. */
1658 // Skip not source sources, they do not have file fields.
1659 for (; Vf.end() == false; Vf++)
1660 {
1661 if ((Vf.File()->Flags & pkgCache::Flag::NotSource) != 0)
1662 continue;
1663 break;
1664 }
1665
1666 // Does not really matter here.. we are going to fail out below
1667 if (Vf.end() != true)
1668 {
1669 // If this fails to get a file name we will bomb out below.
1670 pkgRecords::Parser &Parse = Recs->Lookup(Vf);
1671 if (_error->PendingError() == true)
1672 return;
1673
1674 // Generate the final file name as: package_version_arch.foo
1675 StoreFilename = QuoteString(Version.ParentPkg().Name(),"_:") + '_' +
1676 QuoteString(Version.VerStr(),"_:") + '_' +
1677 QuoteString(Version.Arch(),"_:.") +
1678 "." + flExtension(Parse.FileName());
1679 }
b3d44315
MV
1680
1681 // check if we have one trusted source for the package. if so, switch
1682 // to "TrustedOnly" mode
f7f0d6c7 1683 for (pkgCache::VerFileIterator i = Version.FileList(); i.end() == false; ++i)
b3d44315
MV
1684 {
1685 pkgIndexFile *Index;
1686 if (Sources->FindIndex(i.File(),Index) == false)
1687 continue;
1688 if (_config->FindB("Debug::pkgAcquire::Auth", false))
1689 {
1690 std::cerr << "Checking index: " << Index->Describe()
1691 << "(Trusted=" << Index->IsTrusted() << ")\n";
1692 }
1693 if (Index->IsTrusted()) {
1694 Trusted = true;
1695 break;
1696 }
1697 }
1698
a3371852
MV
1699 // "allow-unauthenticated" restores apts old fetching behaviour
1700 // that means that e.g. unauthenticated file:// uris are higher
1701 // priority than authenticated http:// uris
1702 if (_config->FindB("APT::Get::AllowUnauthenticated",false) == true)
1703 Trusted = false;
1704
03e39e59 1705 // Select a source
b185acc2 1706 if (QueueNext() == false && _error->PendingError() == false)
2d5102e8 1707 _error->Error(_("I wasn't able to locate a file for the %s package. "
b2e465d6 1708 "This might mean you need to manually fix this package."),
b185acc2
AL
1709 Version.ParentPkg().Name());
1710}
1711 /*}}}*/
1712// AcqArchive::QueueNext - Queue the next file source /*{{{*/
1713// ---------------------------------------------------------------------
17caf1b1
AL
1714/* This queues the next available file version for download. It checks if
1715 the archive is already available in the cache and stashs the MD5 for
1716 checking later. */
b185acc2 1717bool pkgAcqArchive::QueueNext()
a722b2c5
DK
1718{
1719 string const ForceHash = _config->Find("Acquire::ForceHash");
f7f0d6c7 1720 for (; Vf.end() == false; ++Vf)
03e39e59
AL
1721 {
1722 // Ignore not source sources
1723 if ((Vf.File()->Flags & pkgCache::Flag::NotSource) != 0)
1724 continue;
1725
1726 // Try to cross match against the source list
b2e465d6
AL
1727 pkgIndexFile *Index;
1728 if (Sources->FindIndex(Vf.File(),Index) == false)
1729 continue;
03e39e59 1730
b3d44315
MV
1731 // only try to get a trusted package from another source if that source
1732 // is also trusted
1733 if(Trusted && !Index->IsTrusted())
1734 continue;
1735
03e39e59
AL
1736 // Grab the text package record
1737 pkgRecords::Parser &Parse = Recs->Lookup(Vf);
1738 if (_error->PendingError() == true)
b185acc2 1739 return false;
03e39e59 1740
b2e465d6 1741 string PkgFile = Parse.FileName();
a722b2c5
DK
1742 if (ForceHash.empty() == false)
1743 {
d9b9e9e2
MV
1744 if(stringcasecmp(ForceHash, "sha512") == 0)
1745 ExpectedHash = HashString("SHA512", Parse.SHA512Hash());
a722b2c5
DK
1746 if(stringcasecmp(ForceHash, "sha256") == 0)
1747 ExpectedHash = HashString("SHA256", Parse.SHA256Hash());
1748 else if (stringcasecmp(ForceHash, "sha1") == 0)
1749 ExpectedHash = HashString("SHA1", Parse.SHA1Hash());
1750 else
1751 ExpectedHash = HashString("MD5Sum", Parse.MD5Hash());
1752 }
1753 else
1754 {
1755 string Hash;
d9b9e9e2
MV
1756 if ((Hash = Parse.SHA512Hash()).empty() == false)
1757 ExpectedHash = HashString("SHA512", Hash);
1758 else if ((Hash = Parse.SHA256Hash()).empty() == false)
a722b2c5
DK
1759 ExpectedHash = HashString("SHA256", Hash);
1760 else if ((Hash = Parse.SHA1Hash()).empty() == false)
1761 ExpectedHash = HashString("SHA1", Hash);
1762 else
1763 ExpectedHash = HashString("MD5Sum", Parse.MD5Hash());
1764 }
03e39e59 1765 if (PkgFile.empty() == true)
b2e465d6
AL
1766 return _error->Error(_("The package index files are corrupted. No Filename: "
1767 "field for package %s."),
1768 Version.ParentPkg().Name());
a6568219 1769
b3d44315
MV
1770 Desc.URI = Index->ArchiveURI(PkgFile);
1771 Desc.Description = Index->ArchiveInfo(Version);
1772 Desc.Owner = this;
1773 Desc.ShortDesc = Version.ParentPkg().Name();
1774
17caf1b1 1775 // See if we already have the file. (Legacy filenames)
a6568219
AL
1776 FileSize = Version->Size;
1777 string FinalFile = _config->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile);
1778 struct stat Buf;
1779 if (stat(FinalFile.c_str(),&Buf) == 0)
1780 {
1781 // Make sure the size matches
73da43e9 1782 if ((unsigned long long)Buf.st_size == Version->Size)
a6568219
AL
1783 {
1784 Complete = true;
1785 Local = true;
1786 Status = StatDone;
30e1eab5 1787 StoreFilename = DestFile = FinalFile;
b185acc2 1788 return true;
a6568219
AL
1789 }
1790
6b1ff003
AL
1791 /* Hmm, we have a file and its size does not match, this means it is
1792 an old style mismatched arch */
a6568219
AL
1793 unlink(FinalFile.c_str());
1794 }
17caf1b1
AL
1795
1796 // Check it again using the new style output filenames
1797 FinalFile = _config->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename);
1798 if (stat(FinalFile.c_str(),&Buf) == 0)
1799 {
1800 // Make sure the size matches
73da43e9 1801 if ((unsigned long long)Buf.st_size == Version->Size)
17caf1b1
AL
1802 {
1803 Complete = true;
1804 Local = true;
1805 Status = StatDone;
1806 StoreFilename = DestFile = FinalFile;
1807 return true;
1808 }
1809
1810 /* Hmm, we have a file and its size does not match, this shouldnt
1811 happen.. */
1812 unlink(FinalFile.c_str());
1813 }
1814
1815 DestFile = _config->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename);
6b1ff003
AL
1816
1817 // Check the destination file
1818 if (stat(DestFile.c_str(),&Buf) == 0)
1819 {
1820 // Hmm, the partial file is too big, erase it
73da43e9 1821 if ((unsigned long long)Buf.st_size > Version->Size)
6b1ff003
AL
1822 unlink(DestFile.c_str());
1823 else
1824 PartialSize = Buf.st_size;
1825 }
1826
03e39e59 1827 // Create the item
b2e465d6
AL
1828 Local = false;
1829 Desc.URI = Index->ArchiveURI(PkgFile);
1830 Desc.Description = Index->ArchiveInfo(Version);
03e39e59
AL
1831 Desc.Owner = this;
1832 Desc.ShortDesc = Version.ParentPkg().Name();
1833 QueueURI(Desc);
b185acc2 1834
f7f0d6c7 1835 ++Vf;
b185acc2 1836 return true;
03e39e59 1837 }
b185acc2
AL
1838 return false;
1839}
03e39e59
AL
1840 /*}}}*/
1841// AcqArchive::Done - Finished fetching /*{{{*/
1842// ---------------------------------------------------------------------
1843/* */
73da43e9 1844void pkgAcqArchive::Done(string Message,unsigned long long Size,string CalcHash,
459681d3 1845 pkgAcquire::MethodConfig *Cfg)
03e39e59 1846{
495e5cb2 1847 Item::Done(Message,Size,CalcHash,Cfg);
03e39e59
AL
1848
1849 // Check the size
1850 if (Size != Version->Size)
1851 {
bdae53f1 1852 Status = StatError;
b2e465d6 1853 ErrorText = _("Size mismatch");
03e39e59
AL
1854 return;
1855 }
1856
495e5cb2 1857 // Check the hash
8a8feb29 1858 if(ExpectedHash.toStr() != CalcHash)
03e39e59 1859 {
495e5cb2 1860 Status = StatError;
9498d182 1861 ErrorText = _("Hash Sum mismatch");
495e5cb2
MV
1862 if(FileExists(DestFile))
1863 Rename(DestFile,DestFile + ".FAILED");
1864 return;
03e39e59 1865 }
a6568219
AL
1866
1867 // Grab the output filename
03e39e59
AL
1868 string FileName = LookupTag(Message,"Filename");
1869 if (FileName.empty() == true)
1870 {
1871 Status = StatError;
1872 ErrorText = "Method gave a blank filename";
1873 return;
1874 }
a6568219
AL
1875
1876 Complete = true;
30e1eab5
AL
1877
1878 // Reference filename
a6568219
AL
1879 if (FileName != DestFile)
1880 {
30e1eab5 1881 StoreFilename = DestFile = FileName;
a6568219
AL
1882 Local = true;
1883 return;
1884 }
1885
1886 // Done, move it into position
1887 string FinalFile = _config->FindDir("Dir::Cache::Archives");
17caf1b1 1888 FinalFile += flNotDir(StoreFilename);
a6568219 1889 Rename(DestFile,FinalFile);
03e39e59 1890
30e1eab5 1891 StoreFilename = DestFile = FinalFile;
03e39e59
AL
1892 Complete = true;
1893}
1894 /*}}}*/
db890fdb
AL
1895// AcqArchive::Failed - Failure handler /*{{{*/
1896// ---------------------------------------------------------------------
1897/* Here we try other sources */
7d8afa39 1898void pkgAcqArchive::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
db890fdb
AL
1899{
1900 ErrorText = LookupTag(Message,"Message");
b2e465d6
AL
1901
1902 /* We don't really want to retry on failed media swaps, this prevents
1903 that. An interesting observation is that permanent failures are not
1904 recorded. */
1905 if (Cnf->Removable == true &&
1906 StringToBool(LookupTag(Message,"Transient-Failure"),false) == true)
1907 {
1908 // Vf = Version.FileList();
f7f0d6c7 1909 while (Vf.end() == false) ++Vf;
b2e465d6
AL
1910 StoreFilename = string();
1911 Item::Failed(Message,Cnf);
1912 return;
1913 }
1914
db890fdb 1915 if (QueueNext() == false)
7d8afa39
AL
1916 {
1917 // This is the retry counter
1918 if (Retries != 0 &&
1919 Cnf->LocalOnly == false &&
1920 StringToBool(LookupTag(Message,"Transient-Failure"),false) == true)
1921 {
1922 Retries--;
1923 Vf = Version.FileList();
1924 if (QueueNext() == true)
1925 return;
1926 }
1927
9dbb421f 1928 StoreFilename = string();
7d8afa39
AL
1929 Item::Failed(Message,Cnf);
1930 }
db890fdb
AL
1931}
1932 /*}}}*/
92fcbfc1 1933// AcqArchive::IsTrusted - Determine whether this archive comes from a trusted source /*{{{*/
b3d44315
MV
1934// ---------------------------------------------------------------------
1935bool pkgAcqArchive::IsTrusted()
1936{
1937 return Trusted;
1938}
92fcbfc1 1939 /*}}}*/
ab559b35
AL
1940// AcqArchive::Finished - Fetching has finished, tidy up /*{{{*/
1941// ---------------------------------------------------------------------
1942/* */
1943void pkgAcqArchive::Finished()
1944{
1945 if (Status == pkgAcquire::Item::StatDone &&
1946 Complete == true)
1947 return;
1948 StoreFilename = string();
1949}
1950 /*}}}*/
36375005
AL
1951// AcqFile::pkgAcqFile - Constructor /*{{{*/
1952// ---------------------------------------------------------------------
1953/* The file is added to the queue */
8a8feb29 1954pkgAcqFile::pkgAcqFile(pkgAcquire *Owner,string URI,string Hash,
73da43e9 1955 unsigned long long Size,string Dsc,string ShortDesc,
77278c2b
MV
1956 const string &DestDir, const string &DestFilename,
1957 bool IsIndexFile) :
1958 Item(Owner), ExpectedHash(Hash), IsIndexFile(IsIndexFile)
36375005 1959{
08cfc005
AL
1960 Retries = _config->FindI("Acquire::Retries",0);
1961
46e00f9d
MV
1962 if(!DestFilename.empty())
1963 DestFile = DestFilename;
1964 else if(!DestDir.empty())
1965 DestFile = DestDir + "/" + flNotDir(URI);
1966 else
1967 DestFile = flNotDir(URI);
1968
36375005
AL
1969 // Create the item
1970 Desc.URI = URI;
1971 Desc.Description = Dsc;
1972 Desc.Owner = this;
1973
1974 // Set the short description to the archive component
1975 Desc.ShortDesc = ShortDesc;
1976
1977 // Get the transfer sizes
1978 FileSize = Size;
1979 struct stat Buf;
1980 if (stat(DestFile.c_str(),&Buf) == 0)
1981 {
1982 // Hmm, the partial file is too big, erase it
73da43e9 1983 if ((unsigned long long)Buf.st_size > Size)
36375005
AL
1984 unlink(DestFile.c_str());
1985 else
1986 PartialSize = Buf.st_size;
1987 }
092ae175 1988
36375005
AL
1989 QueueURI(Desc);
1990}
1991 /*}}}*/
1992// AcqFile::Done - Item downloaded OK /*{{{*/
1993// ---------------------------------------------------------------------
1994/* */
73da43e9 1995void pkgAcqFile::Done(string Message,unsigned long long Size,string CalcHash,
459681d3 1996 pkgAcquire::MethodConfig *Cnf)
36375005 1997{
495e5cb2
MV
1998 Item::Done(Message,Size,CalcHash,Cnf);
1999
8a8feb29 2000 // Check the hash
2c941d89 2001 if(!ExpectedHash.empty() && ExpectedHash.toStr() != CalcHash)
b3c39978 2002 {
495e5cb2 2003 Status = StatError;
f5eb830c 2004 ErrorText = _("Hash Sum mismatch");
495e5cb2
MV
2005 Rename(DestFile,DestFile + ".FAILED");
2006 return;
b3c39978
AL
2007 }
2008
36375005
AL
2009 string FileName = LookupTag(Message,"Filename");
2010 if (FileName.empty() == true)
2011 {
2012 Status = StatError;
2013 ErrorText = "Method gave a blank filename";
2014 return;
2015 }
2016
2017 Complete = true;
2018
2019 // The files timestamp matches
2020 if (StringToBool(LookupTag(Message,"IMS-Hit"),false) == true)
2021 return;
2022
2023 // We have to copy it into place
2024 if (FileName != DestFile)
2025 {
2026 Local = true;
459681d3
AL
2027 if (_config->FindB("Acquire::Source-Symlinks",true) == false ||
2028 Cnf->Removable == true)
917ae805
AL
2029 {
2030 Desc.URI = "copy:" + FileName;
2031 QueueURI(Desc);
2032 return;
2033 }
2034
83ab33fc
AL
2035 // Erase the file if it is a symlink so we can overwrite it
2036 struct stat St;
2037 if (lstat(DestFile.c_str(),&St) == 0)
2038 {
2039 if (S_ISLNK(St.st_mode) != 0)
2040 unlink(DestFile.c_str());
2041 }
2042
2043 // Symlink the file
917ae805
AL
2044 if (symlink(FileName.c_str(),DestFile.c_str()) != 0)
2045 {
83ab33fc 2046 ErrorText = "Link to " + DestFile + " failure ";
917ae805
AL
2047 Status = StatError;
2048 Complete = false;
2049 }
36375005
AL
2050 }
2051}
2052 /*}}}*/
08cfc005
AL
2053// AcqFile::Failed - Failure handler /*{{{*/
2054// ---------------------------------------------------------------------
2055/* Here we try other sources */
2056void pkgAcqFile::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
2057{
2058 ErrorText = LookupTag(Message,"Message");
2059
2060 // This is the retry counter
2061 if (Retries != 0 &&
2062 Cnf->LocalOnly == false &&
2063 StringToBool(LookupTag(Message,"Transient-Failure"),false) == true)
2064 {
2065 Retries--;
2066 QueueURI(Desc);
2067 return;
2068 }
2069
2070 Item::Failed(Message,Cnf);
2071}
2072 /*}}}*/
77278c2b
MV
2073// AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
2074// ---------------------------------------------------------------------
2075/* The only header we use is the last-modified header. */
2076string pkgAcqFile::Custom600Headers()
2077{
2078 if (IsIndexFile)
2079 return "\nIndex-File: true";
61a07c57 2080 return "";
77278c2b
MV
2081}
2082 /*}}}*/