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