]> git.saurik.com Git - apt.git/blame - apt-pkg/acquire-item.cc
load the size from the metaindex into the fetcher to have even more accurate progress...
[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
1dca8dc5
MV
966 // load the filesize
967 indexRecords::checkSum *Record = MetaIndexParser->Lookup(string(Target->MetaKey));
968 if(Record)
969 FileSize = Record->Size;
970
5d885723
DK
971 Init(Target->URI, Target->Description, Target->ShortDesc);
972}
973 /*}}}*/
974// AcqIndex::Init - defered Constructor /*{{{*/
975void pkgAcqIndex::Init(string const &URI, string const &URIDesc, string const &ShortDesc) {
8b89e57f 976 Decompression = false;
bfd22fc0 977 Erase = false;
13e8426f 978
0a8a80e5 979 DestFile = _config->FindDir("Dir::State::lists") + "partial/";
b2e465d6 980 DestFile += URItoFileName(URI);
8267fe24 981
5d885723
DK
982 std::string const comprExt = CompressionExtension.substr(0, CompressionExtension.find(' '));
983 if (comprExt == "uncompressed")
984 Desc.URI = URI;
985 else
986 Desc.URI = URI + '.' + comprExt;
b3d44315 987
b2e465d6 988 Desc.Description = URIDesc;
8267fe24 989 Desc.Owner = this;
b2e465d6 990 Desc.ShortDesc = ShortDesc;
5d885723 991
8267fe24 992 QueueURI(Desc);
0118833a
AL
993}
994 /*}}}*/
0a8a80e5 995// AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
0118833a 996// ---------------------------------------------------------------------
0a8a80e5
AL
997/* The only header we use is the last-modified header. */
998string pkgAcqIndex::Custom600Headers()
0118833a 999{
0a8a80e5 1000 string Final = _config->FindDir("Dir::State::lists");
b2e465d6 1001 Final += URItoFileName(RealURI);
01606def 1002 if (_config->FindB("Acquire::GzipIndexes",false))
1003 Final += ".gz";
0a8a80e5 1004
97b65b10
MV
1005 string msg = "\nIndex-File: true";
1006 // FIXME: this really should use "IndexTarget::IsOptional()" but that
1007 // seems to be difficult without breaking ABI
1008 if (ShortDesc().find("Translation") != 0)
1009 msg += "\nFail-Ignore: true";
0a8a80e5 1010 struct stat Buf;
3a1f49c4 1011 if (stat(Final.c_str(),&Buf) == 0)
97b65b10
MV
1012 msg += "\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
1013
1014 return msg;
0118833a
AL
1015}
1016 /*}}}*/
92fcbfc1 1017void pkgAcqIndex::Failed(string Message,pkgAcquire::MethodConfig *Cnf) /*{{{*/
debc84b2 1018{
5d885723
DK
1019 size_t const nextExt = CompressionExtension.find(' ');
1020 if (nextExt != std::string::npos)
e85b4cd5 1021 {
5d885723
DK
1022 CompressionExtension = CompressionExtension.substr(nextExt+1);
1023 Init(RealURI, Desc.Description, Desc.ShortDesc);
6abe2699 1024 return;
0d7a243d
EL
1025 }
1026
17ff0930 1027 // on decompression failure, remove bad versions in partial/
5d885723 1028 if (Decompression && Erase) {
17ff0930 1029 string s = _config->FindDir("Dir::State::lists") + "partial/";
5d885723 1030 s.append(URItoFileName(RealURI));
17ff0930 1031 unlink(s.c_str());
debc84b2
MZ
1032 }
1033
debc84b2
MZ
1034 Item::Failed(Message,Cnf);
1035}
92fcbfc1 1036 /*}}}*/
8b89e57f
AL
1037// AcqIndex::Done - Finished a fetch /*{{{*/
1038// ---------------------------------------------------------------------
1039/* This goes through a number of states.. On the initial fetch the
1040 method could possibly return an alternate filename which points
1041 to the uncompressed version of the file. If this is so the file
1042 is copied into the partial directory. In all other cases the file
1043 is decompressed with a gzip uri. */
73da43e9 1044void pkgAcqIndex::Done(string Message,unsigned long long Size,string Hash,
459681d3 1045 pkgAcquire::MethodConfig *Cfg)
8b89e57f 1046{
495e5cb2 1047 Item::Done(Message,Size,Hash,Cfg);
8b89e57f
AL
1048
1049 if (Decompression == true)
1050 {
b3d44315
MV
1051 if (_config->FindB("Debug::pkgAcquire::Auth", false))
1052 {
495e5cb2
MV
1053 std::cerr << std::endl << RealURI << ": Computed Hash: " << Hash;
1054 std::cerr << " Expected Hash: " << ExpectedHash.toStr() << std::endl;
b3d44315
MV
1055 }
1056
8a8feb29 1057 if (!ExpectedHash.empty() && ExpectedHash.toStr() != Hash)
b3d44315 1058 {
3c8030a4 1059 RenameOnError(HashSumMismatch);
b3d44315
MV
1060 return;
1061 }
0901c5d0
JAK
1062
1063 /* Verify the index file for correctness (all indexes must
4fdb6123 1064 * have a Package field) (LP: #346386) (Closes: #627642) */
c5f661b7 1065 if (Verify == true)
0901c5d0
JAK
1066 {
1067 FileFd fd(DestFile, FileFd::ReadOnly);
3c8030a4
DK
1068 // Only test for correctness if the file is not empty (empty is ok)
1069 if (fd.FileSize() > 0)
1070 {
1071 pkgTagSection sec;
1072 pkgTagFile tag(&fd);
1073
1074 // all our current indexes have a field 'Package' in each section
1075 if (_error->PendingError() == true || tag.Step(sec) == false || sec.Exists("Package") == false)
1076 {
1077 RenameOnError(InvalidFormat);
1078 return;
1079 }
a0c3110e 1080 }
0901c5d0
JAK
1081 }
1082
8b89e57f
AL
1083 // Done, move it into position
1084 string FinalFile = _config->FindDir("Dir::State::lists");
b2e465d6 1085 FinalFile += URItoFileName(RealURI);
8b89e57f 1086 Rename(DestFile,FinalFile);
7a3c2ab0 1087 chmod(FinalFile.c_str(),0644);
bfd22fc0 1088
7a7fa5f0
AL
1089 /* We restore the original name to DestFile so that the clean operation
1090 will work OK */
1091 DestFile = _config->FindDir("Dir::State::lists") + "partial/";
b2e465d6 1092 DestFile += URItoFileName(RealURI);
7a7fa5f0 1093
bfd22fc0
AL
1094 // Remove the compressed version.
1095 if (Erase == true)
bfd22fc0 1096 unlink(DestFile.c_str());
8b89e57f
AL
1097 return;
1098 }
bfd22fc0
AL
1099
1100 Erase = false;
8267fe24 1101 Complete = true;
bfd22fc0 1102
8b89e57f
AL
1103 // Handle the unzipd case
1104 string FileName = LookupTag(Message,"Alt-Filename");
1105 if (FileName.empty() == false)
1106 {
1107 // The files timestamp matches
1108 if (StringToBool(LookupTag(Message,"Alt-IMS-Hit"),false) == true)
1109 return;
8b89e57f 1110 Decompression = true;
a6568219 1111 Local = true;
8b89e57f 1112 DestFile += ".decomp";
8267fe24
AL
1113 Desc.URI = "copy:" + FileName;
1114 QueueURI(Desc);
b98f2859 1115 Mode = "copy";
8b89e57f
AL
1116 return;
1117 }
1118
1119 FileName = LookupTag(Message,"Filename");
1120 if (FileName.empty() == true)
1121 {
1122 Status = StatError;
1123 ErrorText = "Method gave a blank filename";
1124 }
5d885723
DK
1125
1126 std::string const compExt = CompressionExtension.substr(0, CompressionExtension.find(' '));
0b9032b1 1127
8b89e57f 1128 // The files timestamp matches
0b9032b1 1129 if (StringToBool(LookupTag(Message,"IMS-Hit"),false) == true) {
1130 if (_config->FindB("Acquire::GzipIndexes",false) && compExt == "gz")
1131 // Update DestFile for .gz suffix so that the clean operation keeps it
1132 DestFile += ".gz";
8b89e57f 1133 return;
0b9032b1 1134 }
bfd22fc0
AL
1135
1136 if (FileName == DestFile)
1137 Erase = true;
8267fe24 1138 else
a6568219 1139 Local = true;
8b89e57f 1140
e85b4cd5
DK
1141 string decompProg;
1142
bb109d0b 1143 // If we enable compressed indexes and already have gzip, keep it
7aeee365 1144 if (_config->FindB("Acquire::GzipIndexes",false) && compExt == "gz" && !Local) {
bb109d0b 1145 string FinalFile = _config->FindDir("Dir::State::lists");
1146 FinalFile += URItoFileName(RealURI) + ".gz";
bb109d0b 1147 Rename(DestFile,FinalFile);
1148 chmod(FinalFile.c_str(),0644);
1149
1150 // Update DestFile for .gz suffix so that the clean operation keeps it
1151 DestFile = _config->FindDir("Dir::State::lists") + "partial/";
1152 DestFile += URItoFileName(RealURI) + ".gz";
1153 return;
1154 }
1155
e85b4cd5
DK
1156 // get the binary name for your used compression type
1157 decompProg = _config->Find(string("Acquire::CompressionTypes::").append(compExt),"");
1158 if(decompProg.empty() == false);
5d885723 1159 else if(compExt == "uncompressed")
0d7a243d 1160 decompProg = "copy";
debc84b2
MZ
1161 else {
1162 _error->Error("Unsupported extension: %s", compExt.c_str());
1163 return;
1164 }
1165
8b89e57f
AL
1166 Decompression = true;
1167 DestFile += ".decomp";
e85b4cd5 1168 Desc.URI = decompProg + ":" + FileName;
8267fe24 1169 QueueURI(Desc);
70e0c168
MV
1170
1171 // FIXME: this points to a c++ string that goes out of scope
e85b4cd5 1172 Mode = decompProg.c_str();
8b89e57f 1173}
92fcbfc1 1174 /*}}}*/
a52f938b
OS
1175// AcqIndexTrans::pkgAcqIndexTrans - Constructor /*{{{*/
1176// ---------------------------------------------------------------------
1177/* The Translation file is added to the queue */
1178pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire *Owner,
495e5cb2
MV
1179 string URI,string URIDesc,string ShortDesc)
1180 : pkgAcqIndex(Owner, URI, URIDesc, ShortDesc, HashString(), "")
a52f938b 1181{
ab53c018
DK
1182}
1183pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire *Owner, IndexTarget const *Target,
1dca8dc5 1184 HashString const &ExpectedHash, indexRecords *MetaIndexParser)
ab53c018
DK
1185 : pkgAcqIndex(Owner, Target, ExpectedHash, MetaIndexParser)
1186{
1dca8dc5
MV
1187 // load the filesize
1188 indexRecords::checkSum *Record = MetaIndexParser->Lookup(string(Target->MetaKey));
1189 if(Record)
1190 FileSize = Record->Size;
963b16dc
MV
1191}
1192 /*}}}*/
1193// AcqIndexTrans::Custom600Headers - Insert custom request headers /*{{{*/
1194// ---------------------------------------------------------------------
1195string pkgAcqIndexTrans::Custom600Headers()
1196{
c91d9a63
DK
1197 string Final = _config->FindDir("Dir::State::lists");
1198 Final += URItoFileName(RealURI);
1199
1200 struct stat Buf;
1201 if (stat(Final.c_str(),&Buf) != 0)
a3f7fff8
MV
1202 return "\nFail-Ignore: true\nIndex-File: true";
1203 return "\nFail-Ignore: true\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
a52f938b 1204}
a52f938b
OS
1205 /*}}}*/
1206// AcqIndexTrans::Failed - Silence failure messages for missing files /*{{{*/
1207// ---------------------------------------------------------------------
1208/* */
1209void pkgAcqIndexTrans::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
1210{
5d885723
DK
1211 size_t const nextExt = CompressionExtension.find(' ');
1212 if (nextExt != std::string::npos)
1213 {
1214 CompressionExtension = CompressionExtension.substr(nextExt+1);
1215 Init(RealURI, Desc.Description, Desc.ShortDesc);
1216 Status = StatIdle;
1217 return;
1218 }
1219
a52f938b
OS
1220 if (Cnf->LocalOnly == true ||
1221 StringToBool(LookupTag(Message,"Transient-Failure"),false) == false)
1222 {
1223 // Ignore this
1224 Status = StatDone;
1225 Complete = false;
1226 Dequeue();
1227 return;
1228 }
5d885723 1229
a52f938b
OS
1230 Item::Failed(Message,Cnf);
1231}
1232 /*}}}*/
92fcbfc1 1233pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire *Owner, /*{{{*/
b3d44315
MV
1234 string URI,string URIDesc,string ShortDesc,
1235 string MetaIndexURI, string MetaIndexURIDesc,
1236 string MetaIndexShortDesc,
1237 const vector<IndexTarget*>* IndexTargets,
1238 indexRecords* MetaIndexParser) :
1239 Item(Owner), RealURI(URI), MetaIndexURI(MetaIndexURI),
46e00f9d
MV
1240 MetaIndexURIDesc(MetaIndexURIDesc), MetaIndexShortDesc(MetaIndexShortDesc),
1241 MetaIndexParser(MetaIndexParser), IndexTargets(IndexTargets)
0118833a 1242{
0a8a80e5 1243 DestFile = _config->FindDir("Dir::State::lists") + "partial/";
b2e465d6 1244 DestFile += URItoFileName(URI);
b3d44315 1245
47eb38f4
MV
1246 // remove any partial downloaded sig-file in partial/.
1247 // it may confuse proxies and is too small to warrant a
1248 // partial download anyway
f6237efd
MV
1249 unlink(DestFile.c_str());
1250
8267fe24 1251 // Create the item
b2e465d6 1252 Desc.Description = URIDesc;
8267fe24 1253 Desc.Owner = this;
b3d44315
MV
1254 Desc.ShortDesc = ShortDesc;
1255 Desc.URI = URI;
b3d44315
MV
1256
1257 string Final = _config->FindDir("Dir::State::lists");
1258 Final += URItoFileName(RealURI);
ffcccd62 1259 if (RealFileExists(Final) == true)
b3d44315 1260 {
ef942597 1261 // File was already in place. It needs to be re-downloaded/verified
1e3f4083 1262 // because Release might have changed, we do give it a different
ef942597
MV
1263 // name than DestFile because otherwise the http method will
1264 // send If-Range requests and there are too many broken servers
1265 // out there that do not understand them
1266 LastGoodSig = DestFile+".reverify";
1267 Rename(Final,LastGoodSig);
b3d44315 1268 }
8267fe24 1269
d0cfa8ad
MV
1270 // we expect the indextargets + one additional Release file
1271 ExpectedAdditionalItems = IndexTargets->size() + 1;
1272
8267fe24 1273 QueueURI(Desc);
ffcccd62
DK
1274}
1275 /*}}}*/
1276pkgAcqMetaSig::~pkgAcqMetaSig() /*{{{*/
1277{
1278 // if the file was never queued undo file-changes done in the constructor
1279 if (QueueCounter == 1 && Status == StatIdle && FileSize == 0 && Complete == false &&
1280 LastGoodSig.empty() == false)
1281 {
1282 string const Final = _config->FindDir("Dir::State::lists") + URItoFileName(RealURI);
1283 if (RealFileExists(Final) == false && RealFileExists(LastGoodSig) == true)
1284 Rename(LastGoodSig, Final);
1285 }
1286
0118833a
AL
1287}
1288 /*}}}*/
b3d44315 1289// pkgAcqMetaSig::Custom600Headers - Insert custom request headers /*{{{*/
0118833a 1290// ---------------------------------------------------------------------
0a8a80e5 1291/* The only header we use is the last-modified header. */
b3d44315 1292string pkgAcqMetaSig::Custom600Headers()
0118833a 1293{
0a8a80e5 1294 struct stat Buf;
ef942597 1295 if (stat(LastGoodSig.c_str(),&Buf) != 0)
a72ace20 1296 return "\nIndex-File: true";
a789b983 1297
a72ace20 1298 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
0118833a 1299}
b3d44315 1300
73da43e9 1301void pkgAcqMetaSig::Done(string Message,unsigned long long Size,string MD5,
b3d44315 1302 pkgAcquire::MethodConfig *Cfg)
c88edf1d 1303{
459681d3 1304 Item::Done(Message,Size,MD5,Cfg);
c88edf1d
AL
1305
1306 string FileName = LookupTag(Message,"Filename");
1307 if (FileName.empty() == true)
1308 {
1309 Status = StatError;
1310 ErrorText = "Method gave a blank filename";
8b89e57f 1311 return;
c88edf1d 1312 }
8b89e57f 1313
c88edf1d
AL
1314 if (FileName != DestFile)
1315 {
b3d44315 1316 // We have to copy it into place
a6568219 1317 Local = true;
8267fe24
AL
1318 Desc.URI = "copy:" + FileName;
1319 QueueURI(Desc);
c88edf1d
AL
1320 return;
1321 }
b3d44315
MV
1322
1323 Complete = true;
1324
d0cfa8ad
MV
1325 // at this point pkgAcqMetaIndex takes over
1326 ExpectedAdditionalItems = 0;
1327
ef942597
MV
1328 // put the last known good file back on i-m-s hit (it will
1329 // be re-verified again)
1330 // Else do nothing, we have the new file in DestFile then
1331 if(StringToBool(LookupTag(Message,"IMS-Hit"),false) == true)
1332 Rename(LastGoodSig, DestFile);
1333
b3d44315 1334 // queue a pkgAcqMetaIndex to be verified against the sig we just retrieved
fce72602
MV
1335 new pkgAcqMetaIndex(Owner, MetaIndexURI, MetaIndexURIDesc,
1336 MetaIndexShortDesc, DestFile, IndexTargets,
1337 MetaIndexParser);
b3d44315 1338
c88edf1d
AL
1339}
1340 /*}}}*/
92fcbfc1 1341void pkgAcqMetaSig::Failed(string Message,pkgAcquire::MethodConfig *Cnf)/*{{{*/
681d76d0 1342{
47eb38f4 1343 string Final = _config->FindDir("Dir::State::lists") + URItoFileName(RealURI);
a789b983 1344
d0cfa8ad
MV
1345 // at this point pkgAcqMetaIndex takes over
1346 ExpectedAdditionalItems = 0;
1347
75dd8af1 1348 // if we get a network error we fail gracefully
7e5f33eb
MV
1349 if(Status == StatTransientNetworkError)
1350 {
24057ad6 1351 Item::Failed(Message,Cnf);
484dbb81 1352 // move the sigfile back on transient network failures
7730e095 1353 if(FileExists(LastGoodSig))
ef942597 1354 Rename(LastGoodSig,Final);
7e5f33eb
MV
1355
1356 // set the status back to , Item::Failed likes to reset it
1357 Status = pkgAcquire::Item::StatTransientNetworkError;
24057ad6
MV
1358 return;
1359 }
1360
75dd8af1 1361 // Delete any existing sigfile when the acquire failed
75dd8af1
MV
1362 unlink(Final.c_str());
1363
b3d44315
MV
1364 // queue a pkgAcqMetaIndex with no sigfile
1365 new pkgAcqMetaIndex(Owner, MetaIndexURI, MetaIndexURIDesc, MetaIndexShortDesc,
1366 "", IndexTargets, MetaIndexParser);
1367
681d76d0
AL
1368 if (Cnf->LocalOnly == true ||
1369 StringToBool(LookupTag(Message,"Transient-Failure"),false) == false)
1370 {
2b154e53
AL
1371 // Ignore this
1372 Status = StatDone;
1373 Complete = false;
681d76d0
AL
1374 Dequeue();
1375 return;
1376 }
1377
1378 Item::Failed(Message,Cnf);
1379}
92fcbfc1
DK
1380 /*}}}*/
1381pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire *Owner, /*{{{*/
b3d44315
MV
1382 string URI,string URIDesc,string ShortDesc,
1383 string SigFile,
1384 const vector<struct IndexTarget*>* IndexTargets,
1385 indexRecords* MetaIndexParser) :
21fd1746
OS
1386 Item(Owner), RealURI(URI), SigFile(SigFile), IndexTargets(IndexTargets),
1387 MetaIndexParser(MetaIndexParser), AuthPass(false), IMSHit(false)
b3d44315 1388{
b3d44315
MV
1389 DestFile = _config->FindDir("Dir::State::lists") + "partial/";
1390 DestFile += URItoFileName(URI);
1391
1392 // Create the item
1393 Desc.Description = URIDesc;
1394 Desc.Owner = this;
1395 Desc.ShortDesc = ShortDesc;
1396 Desc.URI = URI;
1397
d0cfa8ad
MV
1398 // we expect more item
1399 ExpectedAdditionalItems = IndexTargets->size();
1400
b3d44315
MV
1401 QueueURI(Desc);
1402}
b3d44315
MV
1403 /*}}}*/
1404// pkgAcqMetaIndex::Custom600Headers - Insert custom request headers /*{{{*/
1405// ---------------------------------------------------------------------
1406/* The only header we use is the last-modified header. */
1407string pkgAcqMetaIndex::Custom600Headers()
1408{
1409 string Final = _config->FindDir("Dir::State::lists");
1410 Final += URItoFileName(RealURI);
1411
1412 struct stat Buf;
1413 if (stat(Final.c_str(),&Buf) != 0)
1414 return "\nIndex-File: true";
1415
1416 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
1417}
92fcbfc1 1418 /*}}}*/
73da43e9 1419void pkgAcqMetaIndex::Done(string Message,unsigned long long Size,string Hash, /*{{{*/
b3d44315
MV
1420 pkgAcquire::MethodConfig *Cfg)
1421{
495e5cb2 1422 Item::Done(Message,Size,Hash,Cfg);
b3d44315
MV
1423
1424 // MetaIndexes are done in two passes: one to download the
1425 // metaindex with an appropriate method, and a second to verify it
1426 // with the gpgv method
1427
1428 if (AuthPass == true)
1429 {
1430 AuthDone(Message);
fce72602
MV
1431
1432 // all cool, move Release file into place
1433 Complete = true;
b3d44315
MV
1434 }
1435 else
1436 {
1437 RetrievalDone(Message);
1438 if (!Complete)
1439 // Still more retrieving to do
1440 return;
1441
1442 if (SigFile == "")
1443 {
1444 // There was no signature file, so we are finished. Download
1207cf3f 1445 // the indexes and do only hashsum verification if possible
3568a640 1446 MetaIndexParser->Load(DestFile);
1207cf3f 1447 QueueIndexes(false);
b3d44315
MV
1448 }
1449 else
1450 {
1451 // There was a signature file, so pass it to gpgv for
1452 // verification
1453
1454 if (_config->FindB("Debug::pkgAcquire::Auth", false))
1455 std::cerr << "Metaindex acquired, queueing gpg verification ("
1456 << SigFile << "," << DestFile << ")\n";
1457 AuthPass = true;
1458 Desc.URI = "gpgv:" + SigFile;
1459 QueueURI(Desc);
1460 Mode = "gpgv";
56bc3358 1461 return;
b3d44315
MV
1462 }
1463 }
56bc3358
DK
1464
1465 if (Complete == true)
1466 {
1467 string FinalFile = _config->FindDir("Dir::State::lists");
1468 FinalFile += URItoFileName(RealURI);
fe0f7911
DK
1469 if (SigFile == DestFile)
1470 SigFile = FinalFile;
56bc3358
DK
1471 Rename(DestFile,FinalFile);
1472 chmod(FinalFile.c_str(),0644);
1473 DestFile = FinalFile;
1474 }
b3d44315 1475}
92fcbfc1
DK
1476 /*}}}*/
1477void pkgAcqMetaIndex::RetrievalDone(string Message) /*{{{*/
b3d44315
MV
1478{
1479 // We have just finished downloading a Release file (it is not
1480 // verified yet)
1481
1482 string FileName = LookupTag(Message,"Filename");
1483 if (FileName.empty() == true)
1484 {
1485 Status = StatError;
1486 ErrorText = "Method gave a blank filename";
1487 return;
1488 }
1489
1490 if (FileName != DestFile)
1491 {
1492 Local = true;
1493 Desc.URI = "copy:" + FileName;
1494 QueueURI(Desc);
1495 return;
1496 }
1497
fce72602 1498 // make sure to verify against the right file on I-M-S hit
f381d68d 1499 IMSHit = StringToBool(LookupTag(Message,"IMS-Hit"),false);
fce72602
MV
1500 if(IMSHit)
1501 {
1502 string FinalFile = _config->FindDir("Dir::State::lists");
1503 FinalFile += URItoFileName(RealURI);
fe0f7911 1504 if (SigFile == DestFile)
0aec7d5c 1505 {
fe0f7911 1506 SigFile = FinalFile;
0aec7d5c
DK
1507 // constructor of pkgAcqMetaClearSig moved it out of the way,
1508 // now move it back in on IMS hit for the 'old' file
1509 string const OldClearSig = DestFile + ".reverify";
1510 if (RealFileExists(OldClearSig) == true)
1511 Rename(OldClearSig, FinalFile);
1512 }
fce72602
MV
1513 DestFile = FinalFile;
1514 }
b3d44315 1515 Complete = true;
b3d44315 1516}
92fcbfc1
DK
1517 /*}}}*/
1518void pkgAcqMetaIndex::AuthDone(string Message) /*{{{*/
b3d44315
MV
1519{
1520 // At this point, the gpgv method has succeeded, so there is a
1521 // valid signature from a key in the trusted keyring. We
1522 // perform additional verification of its contents, and use them
1523 // to verify the indexes we are about to download
1524
1525 if (!MetaIndexParser->Load(DestFile))
1526 {
1527 Status = StatAuthError;
1528 ErrorText = MetaIndexParser->ErrorText;
1529 return;
1530 }
1531
ce424cd4 1532 if (!VerifyVendor(Message))
b3d44315
MV
1533 {
1534 return;
1535 }
1536
1537 if (_config->FindB("Debug::pkgAcquire::Auth", false))
1538 std::cerr << "Signature verification succeeded: "
1539 << DestFile << std::endl;
1540
1541 // Download further indexes with verification
1542 QueueIndexes(true);
1543
fe0f7911
DK
1544 // is it a clearsigned MetaIndex file?
1545 if (DestFile == SigFile)
1546 return;
1547
b3d44315 1548 // Done, move signature file into position
b3d44315
MV
1549 string VerifiedSigFile = _config->FindDir("Dir::State::lists") +
1550 URItoFileName(RealURI) + ".gpg";
1551 Rename(SigFile,VerifiedSigFile);
1552 chmod(VerifiedSigFile.c_str(),0644);
1553}
92fcbfc1
DK
1554 /*}}}*/
1555void pkgAcqMetaIndex::QueueIndexes(bool verify) /*{{{*/
b3d44315 1556{
0901c5d0 1557#if 0
4fdb6123 1558 /* Reject invalid, existing Release files (LP: #346386) (Closes: #627642)
0901c5d0
JAK
1559 * FIXME: Disabled; it breaks unsigned repositories without hashes */
1560 if (!verify && FileExists(DestFile) && !MetaIndexParser->Load(DestFile))
1561 {
1562 Status = StatError;
1563 ErrorText = MetaIndexParser->ErrorText;
1564 return;
1565 }
1566#endif
8e3900d0
DK
1567 bool transInRelease = false;
1568 {
1569 std::vector<std::string> const keys = MetaIndexParser->MetaKeys();
1570 for (std::vector<std::string>::const_iterator k = keys.begin(); k != keys.end(); ++k)
1571 // FIXME: Feels wrong to check for hardcoded string here, but what should we do else…
1572 if (k->find("Translation-") != std::string::npos)
1573 {
1574 transInRelease = true;
1575 break;
1576 }
1577 }
1578
d0cfa8ad
MV
1579 // at this point the real Items are loaded in the fetcher
1580 ExpectedAdditionalItems = 0;
1581
b3d44315
MV
1582 for (vector <struct IndexTarget*>::const_iterator Target = IndexTargets->begin();
1583 Target != IndexTargets->end();
f7f0d6c7 1584 ++Target)
b3d44315 1585 {
495e5cb2 1586 HashString ExpectedIndexHash;
1dca8dc5 1587 indexRecords::checkSum *Record = MetaIndexParser->Lookup((*Target)->MetaKey);
a5b9f489 1588 bool compressedAvailable = false;
1207cf3f 1589 if (Record == NULL)
b3d44315 1590 {
a5b9f489
DK
1591 if ((*Target)->IsOptional() == true)
1592 {
1593 std::vector<std::string> types = APT::Configuration::getCompressionTypes();
1594 for (std::vector<std::string>::const_iterator t = types.begin(); t != types.end(); ++t)
e788a834 1595 if (MetaIndexParser->Exists((*Target)->MetaKey + "." + *t) == true)
a5b9f489
DK
1596 {
1597 compressedAvailable = true;
1598 break;
1599 }
1600 }
1601 else if (verify == true)
ab53c018 1602 {
1207cf3f
DK
1603 Status = StatAuthError;
1604 strprintf(ErrorText, _("Unable to find expected entry '%s' in Release file (Wrong sources.list entry or malformed file)"), (*Target)->MetaKey.c_str());
1605 return;
ab53c018 1606 }
1207cf3f
DK
1607 }
1608 else
1609 {
1610 ExpectedIndexHash = Record->Hash;
1611 if (_config->FindB("Debug::pkgAcquire::Auth", false))
ab53c018 1612 {
1207cf3f
DK
1613 std::cerr << "Queueing: " << (*Target)->URI << std::endl;
1614 std::cerr << "Expected Hash: " << ExpectedIndexHash.toStr() << std::endl;
1615 std::cerr << "For: " << Record->MetaKeyFilename << std::endl;
1616 }
1617 if (verify == true && ExpectedIndexHash.empty() == true && (*Target)->IsOptional() == false)
1618 {
1619 Status = StatAuthError;
1620 strprintf(ErrorText, _("Unable to find hash sum for '%s' in Release file"), (*Target)->MetaKey.c_str());
1621 return;
ab53c018
DK
1622 }
1623 }
1624
1625 if ((*Target)->IsOptional() == true)
1626 {
1627 if ((*Target)->IsSubIndex() == true)
1628 new pkgAcqSubIndex(Owner, (*Target)->URI, (*Target)->Description,
1629 (*Target)->ShortDesc, ExpectedIndexHash);
a5b9f489 1630 else if (transInRelease == false || Record != NULL || compressedAvailable == true)
8e3900d0 1631 {
f55602cb 1632 if (_config->FindB("Acquire::PDiffs",true) == true && transInRelease == true &&
e788a834 1633 MetaIndexParser->Exists((*Target)->MetaKey + ".diff/Index") == true)
f55602cb
DK
1634 new pkgAcqDiffIndex(Owner, (*Target)->URI, (*Target)->Description,
1635 (*Target)->ShortDesc, ExpectedIndexHash);
1636 else
1637 new pkgAcqIndexTrans(Owner, *Target, ExpectedIndexHash, MetaIndexParser);
8e3900d0 1638 }
ab53c018 1639 continue;
b3d44315 1640 }
e1430400
DK
1641
1642 /* Queue Packages file (either diff or full packages files, depending
1643 on the users option) - we also check if the PDiff Index file is listed
1644 in the Meta-Index file. Ideal would be if pkgAcqDiffIndex would test this
1645 instead, but passing the required info to it is to much hassle */
1646 if(_config->FindB("Acquire::PDiffs",true) == true && (verify == false ||
e788a834 1647 MetaIndexParser->Exists((*Target)->MetaKey + ".diff/Index") == true))
2ac3eeb6 1648 new pkgAcqDiffIndex(Owner, (*Target)->URI, (*Target)->Description,
495e5cb2 1649 (*Target)->ShortDesc, ExpectedIndexHash);
e1430400 1650 else
5d885723 1651 new pkgAcqIndex(Owner, *Target, ExpectedIndexHash, MetaIndexParser);
b3d44315
MV
1652 }
1653}
92fcbfc1
DK
1654 /*}}}*/
1655bool pkgAcqMetaIndex::VerifyVendor(string Message) /*{{{*/
b3d44315 1656{
ce424cd4
MV
1657 string::size_type pos;
1658
1659 // check for missing sigs (that where not fatal because otherwise we had
1660 // bombed earlier)
1661 string missingkeys;
400ad7a4 1662 string msg = _("There is no public key available for the "
ce424cd4
MV
1663 "following key IDs:\n");
1664 pos = Message.find("NO_PUBKEY ");
1665 if (pos != std::string::npos)
1666 {
1667 string::size_type start = pos+strlen("NO_PUBKEY ");
1668 string Fingerprint = Message.substr(start, Message.find("\n")-start);
1669 missingkeys += (Fingerprint);
1670 }
1671 if(!missingkeys.empty())
e788a834 1672 _error->Warning("%s", (msg + missingkeys).c_str());
b3d44315
MV
1673
1674 string Transformed = MetaIndexParser->GetExpectedDist();
1675
1676 if (Transformed == "../project/experimental")
1677 {
1678 Transformed = "experimental";
1679 }
1680
ce424cd4 1681 pos = Transformed.rfind('/');
b3d44315
MV
1682 if (pos != string::npos)
1683 {
1684 Transformed = Transformed.substr(0, pos);
1685 }
1686
1687 if (Transformed == ".")
1688 {
1689 Transformed = "";
1690 }
1691
0323317c
DK
1692 if (_config->FindB("Acquire::Check-Valid-Until", true) == true &&
1693 MetaIndexParser->GetValidUntil() > 0) {
1694 time_t const invalid_since = time(NULL) - MetaIndexParser->GetValidUntil();
1695 if (invalid_since > 0)
1696 // TRANSLATOR: The first %s is the URL of the bad Release file, the second is
1697 // the time since then the file is invalid - formated in the same way as in
1698 // the download progress display (e.g. 7d 3h 42min 1s)
457bea86
MV
1699 return _error->Error(
1700 _("Release file for %s is expired (invalid since %s). "
1701 "Updates for this repository will not be applied."),
1702 RealURI.c_str(), TimeToStr(invalid_since).c_str());
1ddb8596
DK
1703 }
1704
b3d44315
MV
1705 if (_config->FindB("Debug::pkgAcquire::Auth", false))
1706 {
1707 std::cerr << "Got Codename: " << MetaIndexParser->GetDist() << std::endl;
1708 std::cerr << "Expecting Dist: " << MetaIndexParser->GetExpectedDist() << std::endl;
1709 std::cerr << "Transformed Dist: " << Transformed << std::endl;
1710 }
1711
1712 if (MetaIndexParser->CheckDist(Transformed) == false)
1713 {
1714 // This might become fatal one day
1715// Status = StatAuthError;
1716// ErrorText = "Conflicting distribution; expected "
1717// + MetaIndexParser->GetExpectedDist() + " but got "
1718// + MetaIndexParser->GetDist();
1719// return false;
1720 if (!Transformed.empty())
1721 {
1ddb8596 1722 _error->Warning(_("Conflicting distribution: %s (expected %s but got %s)"),
b3d44315
MV
1723 Desc.Description.c_str(),
1724 Transformed.c_str(),
1725 MetaIndexParser->GetDist().c_str());
1726 }
1727 }
1728
1729 return true;
1730}
92fcbfc1
DK
1731 /*}}}*/
1732// pkgAcqMetaIndex::Failed - no Release file present or no signature file present /*{{{*/
b3d44315
MV
1733// ---------------------------------------------------------------------
1734/* */
65512241 1735void pkgAcqMetaIndex::Failed(string Message,pkgAcquire::MethodConfig * /*Cnf*/)
b3d44315
MV
1736{
1737 if (AuthPass == true)
1738 {
fce72602 1739 // gpgv method failed, if we have a good signature
39f38a81
DK
1740 string LastGoodSigFile = _config->FindDir("Dir::State::lists").append("partial/").append(URItoFileName(RealURI));
1741 if (DestFile != SigFile)
1742 LastGoodSigFile.append(".gpg");
1743 LastGoodSigFile.append(".reverify");
fe0f7911 1744
fce72602 1745 if(FileExists(LastGoodSigFile))
f381d68d 1746 {
39f38a81 1747 string VerifiedSigFile = _config->FindDir("Dir::State::lists") + URItoFileName(RealURI);
fe0f7911 1748 if (DestFile != SigFile)
39f38a81
DK
1749 VerifiedSigFile.append(".gpg");
1750 Rename(LastGoodSigFile, VerifiedSigFile);
fce72602 1751 Status = StatTransientNetworkError;
b5595da9 1752 _error->Warning(_("An error occurred during the signature "
fce72602 1753 "verification. The repository is not updated "
2493f4b5 1754 "and the previous index files will be used. "
76b8e5a5 1755 "GPG error: %s: %s\n"),
fce72602
MV
1756 Desc.Description.c_str(),
1757 LookupTag(Message,"Message").c_str());
5d149bfc 1758 RunScripts("APT::Update::Auth-Failure");
f381d68d 1759 return;
0901c5d0 1760 } else if (LookupTag(Message,"Message").find("NODATA") != string::npos) {
4fdb6123 1761 /* Invalid signature file, reject (LP: #346386) (Closes: #627642) */
0901c5d0
JAK
1762 _error->Error(_("GPG error: %s: %s"),
1763 Desc.Description.c_str(),
1764 LookupTag(Message,"Message").c_str());
1765 return;
fce72602
MV
1766 } else {
1767 _error->Warning(_("GPG error: %s: %s"),
1768 Desc.Description.c_str(),
1769 LookupTag(Message,"Message").c_str());
f381d68d 1770 }
f381d68d 1771 // gpgv method failed
59271f62 1772 ReportMirrorFailure("GPGFailure");
b3d44315
MV
1773 }
1774
7ea7ac9e
JAK
1775 /* Always move the meta index, even if gpgv failed. This ensures
1776 * that PackageFile objects are correctly filled in */
a235ddf8 1777 if (FileExists(DestFile)) {
7ea7ac9e
JAK
1778 string FinalFile = _config->FindDir("Dir::State::lists");
1779 FinalFile += URItoFileName(RealURI);
1780 /* InRelease files become Release files, otherwise
1781 * they would be considered as trusted later on */
1782 if (SigFile == DestFile) {
1783 RealURI = RealURI.replace(RealURI.rfind("InRelease"), 9,
1784 "Release");
1785 FinalFile = FinalFile.replace(FinalFile.rfind("InRelease"), 9,
1786 "Release");
1787 SigFile = FinalFile;
1788 }
1789 Rename(DestFile,FinalFile);
1790 chmod(FinalFile.c_str(),0644);
1791
1792 DestFile = FinalFile;
1793 }
1794
b3d44315
MV
1795 // No Release file was present, or verification failed, so fall
1796 // back to queueing Packages files without verification
1797 QueueIndexes(false);
1798}
681d76d0 1799 /*}}}*/
fe0f7911
DK
1800pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire *Owner, /*{{{*/
1801 string const &URI, string const &URIDesc, string const &ShortDesc,
1802 string const &MetaIndexURI, string const &MetaIndexURIDesc, string const &MetaIndexShortDesc,
1803 string const &MetaSigURI, string const &MetaSigURIDesc, string const &MetaSigShortDesc,
1804 const vector<struct IndexTarget*>* IndexTargets,
1805 indexRecords* MetaIndexParser) :
1806 pkgAcqMetaIndex(Owner, URI, URIDesc, ShortDesc, "", IndexTargets, MetaIndexParser),
1807 MetaIndexURI(MetaIndexURI), MetaIndexURIDesc(MetaIndexURIDesc), MetaIndexShortDesc(MetaIndexShortDesc),
1808 MetaSigURI(MetaSigURI), MetaSigURIDesc(MetaSigURIDesc), MetaSigShortDesc(MetaSigShortDesc)
1809{
1810 SigFile = DestFile;
39f38a81 1811
d0cfa8ad
MV
1812 // index targets + (worst case:) Release/Release.gpg
1813 ExpectedAdditionalItems = IndexTargets->size() + 2;
1814
1815
39f38a81
DK
1816 // keep the old InRelease around in case of transistent network errors
1817 string const Final = _config->FindDir("Dir::State::lists") + URItoFileName(RealURI);
ffcccd62 1818 if (RealFileExists(Final) == true)
39f38a81
DK
1819 {
1820 string const LastGoodSig = DestFile + ".reverify";
1821 Rename(Final,LastGoodSig);
1822 }
fe0f7911
DK
1823}
1824 /*}}}*/
ffcccd62
DK
1825pkgAcqMetaClearSig::~pkgAcqMetaClearSig() /*{{{*/
1826{
1827 // if the file was never queued undo file-changes done in the constructor
1828 if (QueueCounter == 1 && Status == StatIdle && FileSize == 0 && Complete == false)
1829 {
1830 string const Final = _config->FindDir("Dir::State::lists") + URItoFileName(RealURI);
1831 string const LastGoodSig = DestFile + ".reverify";
1832 if (RealFileExists(Final) == false && RealFileExists(LastGoodSig) == true)
1833 Rename(LastGoodSig, Final);
1834 }
1835}
1836 /*}}}*/
8d6c5839
MV
1837// pkgAcqMetaClearSig::Custom600Headers - Insert custom request headers /*{{{*/
1838// ---------------------------------------------------------------------
1839// FIXME: this can go away once the InRelease file is used widely
1840string pkgAcqMetaClearSig::Custom600Headers()
1841{
1842 string Final = _config->FindDir("Dir::State::lists");
1843 Final += URItoFileName(RealURI);
1844
1845 struct stat Buf;
1846 if (stat(Final.c_str(),&Buf) != 0)
0aec7d5c
DK
1847 {
1848 Final = DestFile + ".reverify";
1849 if (stat(Final.c_str(),&Buf) != 0)
1850 return "\nIndex-File: true\nFail-Ignore: true\n";
1851 }
8d6c5839
MV
1852
1853 return "\nIndex-File: true\nFail-Ignore: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
1854}
1855 /*}}}*/
fe0f7911
DK
1856void pkgAcqMetaClearSig::Failed(string Message,pkgAcquire::MethodConfig *Cnf) /*{{{*/
1857{
d0cfa8ad
MV
1858 // we failed, we will not get additional items from this method
1859 ExpectedAdditionalItems = 0;
1860
fe0f7911
DK
1861 if (AuthPass == false)
1862 {
de498a52
DK
1863 // Remove the 'old' InRelease file if we try Release.gpg now as otherwise
1864 // the file will stay around and gives a false-auth impression (CVE-2012-0214)
1865 string FinalFile = _config->FindDir("Dir::State::lists");
1866 FinalFile.append(URItoFileName(RealURI));
1867 if (FileExists(FinalFile))
1868 unlink(FinalFile.c_str());
1869
fe0f7911
DK
1870 new pkgAcqMetaSig(Owner,
1871 MetaSigURI, MetaSigURIDesc, MetaSigShortDesc,
1872 MetaIndexURI, MetaIndexURIDesc, MetaIndexShortDesc,
1873 IndexTargets, MetaIndexParser);
1874 if (Cnf->LocalOnly == true ||
1875 StringToBool(LookupTag(Message, "Transient-Failure"), false) == false)
1876 Dequeue();
1877 }
1878 else
1879 pkgAcqMetaIndex::Failed(Message, Cnf);
1880}
1881 /*}}}*/
03e39e59
AL
1882// AcqArchive::AcqArchive - Constructor /*{{{*/
1883// ---------------------------------------------------------------------
17caf1b1
AL
1884/* This just sets up the initial fetch environment and queues the first
1885 possibilitiy */
03e39e59 1886pkgAcqArchive::pkgAcqArchive(pkgAcquire *Owner,pkgSourceList *Sources,
30e1eab5
AL
1887 pkgRecords *Recs,pkgCache::VerIterator const &Version,
1888 string &StoreFilename) :
1889 Item(Owner), Version(Version), Sources(Sources), Recs(Recs),
b3d44315
MV
1890 StoreFilename(StoreFilename), Vf(Version.FileList()),
1891 Trusted(false)
03e39e59 1892{
7d8afa39 1893 Retries = _config->FindI("Acquire::Retries",0);
813c8eea
AL
1894
1895 if (Version.Arch() == 0)
bdae53f1 1896 {
d1f1f6a8 1897 _error->Error(_("I wasn't able to locate a file for the %s package. "
7a3c2ab0
AL
1898 "This might mean you need to manually fix this package. "
1899 "(due to missing arch)"),
40f8a8ba 1900 Version.ParentPkg().FullName().c_str());
bdae53f1
AL
1901 return;
1902 }
813c8eea 1903
b2e465d6
AL
1904 /* We need to find a filename to determine the extension. We make the
1905 assumption here that all the available sources for this version share
1906 the same extension.. */
1907 // Skip not source sources, they do not have file fields.
69c2ecbd 1908 for (; Vf.end() == false; ++Vf)
b2e465d6
AL
1909 {
1910 if ((Vf.File()->Flags & pkgCache::Flag::NotSource) != 0)
1911 continue;
1912 break;
1913 }
1914
1915 // Does not really matter here.. we are going to fail out below
1916 if (Vf.end() != true)
1917 {
1918 // If this fails to get a file name we will bomb out below.
1919 pkgRecords::Parser &Parse = Recs->Lookup(Vf);
1920 if (_error->PendingError() == true)
1921 return;
1922
1923 // Generate the final file name as: package_version_arch.foo
1924 StoreFilename = QuoteString(Version.ParentPkg().Name(),"_:") + '_' +
1925 QuoteString(Version.VerStr(),"_:") + '_' +
1926 QuoteString(Version.Arch(),"_:.") +
1927 "." + flExtension(Parse.FileName());
1928 }
b3d44315
MV
1929
1930 // check if we have one trusted source for the package. if so, switch
6c34ccca
DK
1931 // to "TrustedOnly" mode - but only if not in AllowUnauthenticated mode
1932 bool const allowUnauth = _config->FindB("APT::Get::AllowUnauthenticated", false);
1933 bool const debugAuth = _config->FindB("Debug::pkgAcquire::Auth", false);
1934 bool seenUntrusted = false;
f7f0d6c7 1935 for (pkgCache::VerFileIterator i = Version.FileList(); i.end() == false; ++i)
b3d44315
MV
1936 {
1937 pkgIndexFile *Index;
1938 if (Sources->FindIndex(i.File(),Index) == false)
1939 continue;
6c34ccca
DK
1940
1941 if (debugAuth == true)
b3d44315 1942 std::cerr << "Checking index: " << Index->Describe()
6c34ccca
DK
1943 << "(Trusted=" << Index->IsTrusted() << ")" << std::endl;
1944
1945 if (Index->IsTrusted() == true)
1946 {
b3d44315 1947 Trusted = true;
6c34ccca
DK
1948 if (allowUnauth == false)
1949 break;
b3d44315 1950 }
6c34ccca
DK
1951 else
1952 seenUntrusted = true;
b3d44315
MV
1953 }
1954
a3371852
MV
1955 // "allow-unauthenticated" restores apts old fetching behaviour
1956 // that means that e.g. unauthenticated file:// uris are higher
1957 // priority than authenticated http:// uris
6c34ccca 1958 if (allowUnauth == true && seenUntrusted == true)
a3371852
MV
1959 Trusted = false;
1960
03e39e59 1961 // Select a source
b185acc2 1962 if (QueueNext() == false && _error->PendingError() == false)
d57f6084
DK
1963 _error->Error(_("Can't find a source to download version '%s' of '%s'"),
1964 Version.VerStr(), Version.ParentPkg().FullName(false).c_str());
b185acc2
AL
1965}
1966 /*}}}*/
1967// AcqArchive::QueueNext - Queue the next file source /*{{{*/
1968// ---------------------------------------------------------------------
17caf1b1
AL
1969/* This queues the next available file version for download. It checks if
1970 the archive is already available in the cache and stashs the MD5 for
1971 checking later. */
b185acc2 1972bool pkgAcqArchive::QueueNext()
a722b2c5
DK
1973{
1974 string const ForceHash = _config->Find("Acquire::ForceHash");
f7f0d6c7 1975 for (; Vf.end() == false; ++Vf)
03e39e59
AL
1976 {
1977 // Ignore not source sources
1978 if ((Vf.File()->Flags & pkgCache::Flag::NotSource) != 0)
1979 continue;
1980
1981 // Try to cross match against the source list
b2e465d6
AL
1982 pkgIndexFile *Index;
1983 if (Sources->FindIndex(Vf.File(),Index) == false)
1984 continue;
03e39e59 1985
b3d44315
MV
1986 // only try to get a trusted package from another source if that source
1987 // is also trusted
1988 if(Trusted && !Index->IsTrusted())
1989 continue;
1990
03e39e59
AL
1991 // Grab the text package record
1992 pkgRecords::Parser &Parse = Recs->Lookup(Vf);
1993 if (_error->PendingError() == true)
b185acc2 1994 return false;
03e39e59 1995
b2e465d6 1996 string PkgFile = Parse.FileName();
a722b2c5
DK
1997 if (ForceHash.empty() == false)
1998 {
d9b9e9e2
MV
1999 if(stringcasecmp(ForceHash, "sha512") == 0)
2000 ExpectedHash = HashString("SHA512", Parse.SHA512Hash());
ee5f5d25 2001 else if(stringcasecmp(ForceHash, "sha256") == 0)
a722b2c5
DK
2002 ExpectedHash = HashString("SHA256", Parse.SHA256Hash());
2003 else if (stringcasecmp(ForceHash, "sha1") == 0)
2004 ExpectedHash = HashString("SHA1", Parse.SHA1Hash());
2005 else
2006 ExpectedHash = HashString("MD5Sum", Parse.MD5Hash());
2007 }
2008 else
2009 {
2010 string Hash;
d9b9e9e2
MV
2011 if ((Hash = Parse.SHA512Hash()).empty() == false)
2012 ExpectedHash = HashString("SHA512", Hash);
2013 else if ((Hash = Parse.SHA256Hash()).empty() == false)
a722b2c5
DK
2014 ExpectedHash = HashString("SHA256", Hash);
2015 else if ((Hash = Parse.SHA1Hash()).empty() == false)
2016 ExpectedHash = HashString("SHA1", Hash);
2017 else
2018 ExpectedHash = HashString("MD5Sum", Parse.MD5Hash());
2019 }
03e39e59 2020 if (PkgFile.empty() == true)
b2e465d6
AL
2021 return _error->Error(_("The package index files are corrupted. No Filename: "
2022 "field for package %s."),
2023 Version.ParentPkg().Name());
a6568219 2024
b3d44315
MV
2025 Desc.URI = Index->ArchiveURI(PkgFile);
2026 Desc.Description = Index->ArchiveInfo(Version);
2027 Desc.Owner = this;
40f8a8ba 2028 Desc.ShortDesc = Version.ParentPkg().FullName(true);
b3d44315 2029
17caf1b1 2030 // See if we already have the file. (Legacy filenames)
a6568219
AL
2031 FileSize = Version->Size;
2032 string FinalFile = _config->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile);
2033 struct stat Buf;
2034 if (stat(FinalFile.c_str(),&Buf) == 0)
2035 {
2036 // Make sure the size matches
73da43e9 2037 if ((unsigned long long)Buf.st_size == Version->Size)
a6568219
AL
2038 {
2039 Complete = true;
2040 Local = true;
2041 Status = StatDone;
30e1eab5 2042 StoreFilename = DestFile = FinalFile;
b185acc2 2043 return true;
a6568219
AL
2044 }
2045
6b1ff003
AL
2046 /* Hmm, we have a file and its size does not match, this means it is
2047 an old style mismatched arch */
a6568219
AL
2048 unlink(FinalFile.c_str());
2049 }
17caf1b1
AL
2050
2051 // Check it again using the new style output filenames
2052 FinalFile = _config->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename);
2053 if (stat(FinalFile.c_str(),&Buf) == 0)
2054 {
2055 // Make sure the size matches
73da43e9 2056 if ((unsigned long long)Buf.st_size == Version->Size)
17caf1b1
AL
2057 {
2058 Complete = true;
2059 Local = true;
2060 Status = StatDone;
2061 StoreFilename = DestFile = FinalFile;
2062 return true;
2063 }
2064
1e3f4083 2065 /* Hmm, we have a file and its size does not match, this shouldn't
17caf1b1
AL
2066 happen.. */
2067 unlink(FinalFile.c_str());
2068 }
2069
2070 DestFile = _config->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename);
6b1ff003
AL
2071
2072 // Check the destination file
2073 if (stat(DestFile.c_str(),&Buf) == 0)
2074 {
2075 // Hmm, the partial file is too big, erase it
73da43e9 2076 if ((unsigned long long)Buf.st_size > Version->Size)
6b1ff003
AL
2077 unlink(DestFile.c_str());
2078 else
2079 PartialSize = Buf.st_size;
2080 }
de31189f
DK
2081
2082 // Disables download of archives - useful if no real installation follows,
2083 // e.g. if we are just interested in proposed installation order
2084 if (_config->FindB("Debug::pkgAcqArchive::NoQueue", false) == true)
2085 {
2086 Complete = true;
2087 Local = true;
2088 Status = StatDone;
2089 StoreFilename = DestFile = FinalFile;
2090 return true;
2091 }
2092
03e39e59 2093 // Create the item
b2e465d6 2094 Local = false;
03e39e59 2095 QueueURI(Desc);
b185acc2 2096
f7f0d6c7 2097 ++Vf;
b185acc2 2098 return true;
03e39e59 2099 }
b185acc2
AL
2100 return false;
2101}
03e39e59
AL
2102 /*}}}*/
2103// AcqArchive::Done - Finished fetching /*{{{*/
2104// ---------------------------------------------------------------------
2105/* */
73da43e9 2106void pkgAcqArchive::Done(string Message,unsigned long long Size,string CalcHash,
459681d3 2107 pkgAcquire::MethodConfig *Cfg)
03e39e59 2108{
495e5cb2 2109 Item::Done(Message,Size,CalcHash,Cfg);
03e39e59
AL
2110
2111 // Check the size
2112 if (Size != Version->Size)
2113 {
3c8030a4 2114 RenameOnError(SizeMismatch);
03e39e59
AL
2115 return;
2116 }
2117
495e5cb2 2118 // Check the hash
8a8feb29 2119 if(ExpectedHash.toStr() != CalcHash)
03e39e59 2120 {
3c8030a4 2121 RenameOnError(HashSumMismatch);
495e5cb2 2122 return;
03e39e59 2123 }
a6568219
AL
2124
2125 // Grab the output filename
03e39e59
AL
2126 string FileName = LookupTag(Message,"Filename");
2127 if (FileName.empty() == true)
2128 {
2129 Status = StatError;
2130 ErrorText = "Method gave a blank filename";
2131 return;
2132 }
a6568219
AL
2133
2134 Complete = true;
30e1eab5
AL
2135
2136 // Reference filename
a6568219
AL
2137 if (FileName != DestFile)
2138 {
30e1eab5 2139 StoreFilename = DestFile = FileName;
a6568219
AL
2140 Local = true;
2141 return;
2142 }
2143
2144 // Done, move it into position
2145 string FinalFile = _config->FindDir("Dir::Cache::Archives");
17caf1b1 2146 FinalFile += flNotDir(StoreFilename);
a6568219 2147 Rename(DestFile,FinalFile);
03e39e59 2148
30e1eab5 2149 StoreFilename = DestFile = FinalFile;
03e39e59
AL
2150 Complete = true;
2151}
2152 /*}}}*/
db890fdb
AL
2153// AcqArchive::Failed - Failure handler /*{{{*/
2154// ---------------------------------------------------------------------
2155/* Here we try other sources */
7d8afa39 2156void pkgAcqArchive::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
db890fdb
AL
2157{
2158 ErrorText = LookupTag(Message,"Message");
b2e465d6
AL
2159
2160 /* We don't really want to retry on failed media swaps, this prevents
2161 that. An interesting observation is that permanent failures are not
2162 recorded. */
2163 if (Cnf->Removable == true &&
2164 StringToBool(LookupTag(Message,"Transient-Failure"),false) == true)
2165 {
2166 // Vf = Version.FileList();
f7f0d6c7 2167 while (Vf.end() == false) ++Vf;
b2e465d6
AL
2168 StoreFilename = string();
2169 Item::Failed(Message,Cnf);
2170 return;
2171 }
2172
db890fdb 2173 if (QueueNext() == false)
7d8afa39
AL
2174 {
2175 // This is the retry counter
2176 if (Retries != 0 &&
2177 Cnf->LocalOnly == false &&
2178 StringToBool(LookupTag(Message,"Transient-Failure"),false) == true)
2179 {
2180 Retries--;
2181 Vf = Version.FileList();
2182 if (QueueNext() == true)
2183 return;
2184 }
2185
9dbb421f 2186 StoreFilename = string();
7d8afa39
AL
2187 Item::Failed(Message,Cnf);
2188 }
db890fdb
AL
2189}
2190 /*}}}*/
92fcbfc1 2191// AcqArchive::IsTrusted - Determine whether this archive comes from a trusted source /*{{{*/
b3d44315 2192// ---------------------------------------------------------------------
a02db58f 2193APT_PURE bool pkgAcqArchive::IsTrusted()
b3d44315
MV
2194{
2195 return Trusted;
2196}
92fcbfc1 2197 /*}}}*/
ab559b35
AL
2198// AcqArchive::Finished - Fetching has finished, tidy up /*{{{*/
2199// ---------------------------------------------------------------------
2200/* */
2201void pkgAcqArchive::Finished()
2202{
2203 if (Status == pkgAcquire::Item::StatDone &&
2204 Complete == true)
2205 return;
2206 StoreFilename = string();
2207}
2208 /*}}}*/
36375005
AL
2209// AcqFile::pkgAcqFile - Constructor /*{{{*/
2210// ---------------------------------------------------------------------
2211/* The file is added to the queue */
8a8feb29 2212pkgAcqFile::pkgAcqFile(pkgAcquire *Owner,string URI,string Hash,
73da43e9 2213 unsigned long long Size,string Dsc,string ShortDesc,
77278c2b
MV
2214 const string &DestDir, const string &DestFilename,
2215 bool IsIndexFile) :
2216 Item(Owner), ExpectedHash(Hash), IsIndexFile(IsIndexFile)
36375005 2217{
08cfc005
AL
2218 Retries = _config->FindI("Acquire::Retries",0);
2219
46e00f9d
MV
2220 if(!DestFilename.empty())
2221 DestFile = DestFilename;
2222 else if(!DestDir.empty())
2223 DestFile = DestDir + "/" + flNotDir(URI);
2224 else
2225 DestFile = flNotDir(URI);
2226
36375005
AL
2227 // Create the item
2228 Desc.URI = URI;
2229 Desc.Description = Dsc;
2230 Desc.Owner = this;
2231
2232 // Set the short description to the archive component
2233 Desc.ShortDesc = ShortDesc;
2234
2235 // Get the transfer sizes
2236 FileSize = Size;
2237 struct stat Buf;
2238 if (stat(DestFile.c_str(),&Buf) == 0)
2239 {
2240 // Hmm, the partial file is too big, erase it
ed9665ae 2241 if ((Size > 0) && (unsigned long long)Buf.st_size > Size)
36375005
AL
2242 unlink(DestFile.c_str());
2243 else
2244 PartialSize = Buf.st_size;
2245 }
092ae175 2246
36375005
AL
2247 QueueURI(Desc);
2248}
2249 /*}}}*/
2250// AcqFile::Done - Item downloaded OK /*{{{*/
2251// ---------------------------------------------------------------------
2252/* */
73da43e9 2253void pkgAcqFile::Done(string Message,unsigned long long Size,string CalcHash,
459681d3 2254 pkgAcquire::MethodConfig *Cnf)
36375005 2255{
495e5cb2
MV
2256 Item::Done(Message,Size,CalcHash,Cnf);
2257
8a8feb29 2258 // Check the hash
2c941d89 2259 if(!ExpectedHash.empty() && ExpectedHash.toStr() != CalcHash)
b3c39978 2260 {
3c8030a4 2261 RenameOnError(HashSumMismatch);
495e5cb2 2262 return;
b3c39978
AL
2263 }
2264
36375005
AL
2265 string FileName = LookupTag(Message,"Filename");
2266 if (FileName.empty() == true)
2267 {
2268 Status = StatError;
2269 ErrorText = "Method gave a blank filename";
2270 return;
2271 }
2272
2273 Complete = true;
2274
2275 // The files timestamp matches
2276 if (StringToBool(LookupTag(Message,"IMS-Hit"),false) == true)
2277 return;
2278
2279 // We have to copy it into place
2280 if (FileName != DestFile)
2281 {
2282 Local = true;
459681d3
AL
2283 if (_config->FindB("Acquire::Source-Symlinks",true) == false ||
2284 Cnf->Removable == true)
917ae805
AL
2285 {
2286 Desc.URI = "copy:" + FileName;
2287 QueueURI(Desc);
2288 return;
2289 }
2290
83ab33fc
AL
2291 // Erase the file if it is a symlink so we can overwrite it
2292 struct stat St;
2293 if (lstat(DestFile.c_str(),&St) == 0)
2294 {
2295 if (S_ISLNK(St.st_mode) != 0)
2296 unlink(DestFile.c_str());
2297 }
2298
2299 // Symlink the file
917ae805
AL
2300 if (symlink(FileName.c_str(),DestFile.c_str()) != 0)
2301 {
83ab33fc 2302 ErrorText = "Link to " + DestFile + " failure ";
917ae805
AL
2303 Status = StatError;
2304 Complete = false;
2305 }
36375005
AL
2306 }
2307}
2308 /*}}}*/
08cfc005
AL
2309// AcqFile::Failed - Failure handler /*{{{*/
2310// ---------------------------------------------------------------------
2311/* Here we try other sources */
2312void pkgAcqFile::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
2313{
2314 ErrorText = LookupTag(Message,"Message");
2315
2316 // This is the retry counter
2317 if (Retries != 0 &&
2318 Cnf->LocalOnly == false &&
2319 StringToBool(LookupTag(Message,"Transient-Failure"),false) == true)
2320 {
2321 Retries--;
2322 QueueURI(Desc);
2323 return;
2324 }
2325
2326 Item::Failed(Message,Cnf);
2327}
2328 /*}}}*/
77278c2b
MV
2329// AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
2330// ---------------------------------------------------------------------
2331/* The only header we use is the last-modified header. */
2332string pkgAcqFile::Custom600Headers()
2333{
2334 if (IsIndexFile)
2335 return "\nIndex-File: true";
61a07c57 2336 return "";
77278c2b
MV
2337}
2338 /*}}}*/