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