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