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