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