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