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