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