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