]> git.saurik.com Git - apt.git/blame - apt-pkg/acquire-item.cc
Merge remote-tracking branch 'upstream/debian/experimental' into feature/acq-trans
[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
DK
903// AcqIndex::Init - defered Constructor /*{{{*/
904void pkgAcqIndex::Init(string const &URI, string const &URIDesc, string const &ShortDesc) {
8b89e57f 905 Decompression = false;
bfd22fc0 906 Erase = false;
13e8426f 907
0a8a80e5 908 DestFile = _config->FindDir("Dir::State::lists") + "partial/";
b2e465d6 909 DestFile += URItoFileName(URI);
8267fe24 910
5d885723
DK
911 std::string const comprExt = CompressionExtension.substr(0, CompressionExtension.find(' '));
912 if (comprExt == "uncompressed")
b11f9599 913 {
5d885723 914 Desc.URI = URI;
e39698a4
MV
915 if(Target)
916 MetaKey = string(Target->MetaKey);
b11f9599 917 }
5d885723 918 else
b11f9599 919 {
5d885723 920 Desc.URI = URI + '.' + comprExt;
e39698a4
MV
921 if(Target)
922 MetaKey = string(Target->MetaKey) + '.' + comprExt;
b11f9599
MV
923 }
924
925 // load the filesize
e39698a4
MV
926 if(MetaIndexParser)
927 {
928 indexRecords::checkSum *Record = MetaIndexParser->Lookup(MetaKey);
929 if(Record)
930 FileSize = Record->Size;
59194959
MV
931
932 InitByHashIfNeeded(MetaKey);
e39698a4 933 }
b3d44315 934
b2e465d6 935 Desc.Description = URIDesc;
8267fe24 936 Desc.Owner = this;
b2e465d6 937 Desc.ShortDesc = ShortDesc;
5d885723 938
8267fe24 939 QueueURI(Desc);
0118833a
AL
940}
941 /*}}}*/
59194959
MV
942// AcqIndex::AdjustForByHash - modify URI for by-hash support /*{{{*/
943// ---------------------------------------------------------------------
944/* */
945void pkgAcqIndex::InitByHashIfNeeded(const std::string MetaKey)
946{
947 // TODO:
948 // - (maybe?) add support for by-hash into the sources.list as flag
949 // - make apt-ftparchive generate the hashes (and expire?)
950 std::string HostKnob = "APT::Acquire::" + ::URI(Desc.URI).Host + "::By-Hash";
951 if(_config->FindB("APT::Acquire::By-Hash", false) == true ||
952 _config->FindB(HostKnob, false) == true ||
953 MetaIndexParser->GetSupportsAcquireByHash())
954 {
955 indexRecords::checkSum *Record = MetaIndexParser->Lookup(MetaKey);
956 if(Record)
957 {
958 // FIXME: should we really use the best hash here? or a fixed one?
959 const HashString *TargetHash = Record->Hashes.find("");
960 std::string ByHash = "/by-hash/" + TargetHash->HashType() + "/" + TargetHash->HashValue();
961 size_t trailing_slash = Desc.URI.find_last_of("/");
962 Desc.URI = Desc.URI.replace(
963 trailing_slash,
964 Desc.URI.substr(trailing_slash+1).size()+1,
965 ByHash);
966 } else {
967 _error->Warning(
968 "Fetching ByHash requested but can not find record for %s",
969 MetaKey.c_str());
970 }
971 }
972}
973 /*}}}*/
0a8a80e5 974// AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
0118833a 975// ---------------------------------------------------------------------
0a8a80e5 976/* The only header we use is the last-modified header. */
b3501edb 977string pkgAcqIndex::Custom600Headers() const
0118833a 978{
0a8a80e5 979 string Final = _config->FindDir("Dir::State::lists");
b2e465d6 980 Final += URItoFileName(RealURI);
01606def 981 if (_config->FindB("Acquire::GzipIndexes",false))
982 Final += ".gz";
0a8a80e5 983
97b65b10
MV
984 string msg = "\nIndex-File: true";
985 // FIXME: this really should use "IndexTarget::IsOptional()" but that
986 // seems to be difficult without breaking ABI
987 if (ShortDesc().find("Translation") != 0)
988 msg += "\nFail-Ignore: true";
0a8a80e5 989 struct stat Buf;
3a1f49c4 990 if (stat(Final.c_str(),&Buf) == 0)
97b65b10
MV
991 msg += "\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
992
993 return msg;
0118833a
AL
994}
995 /*}}}*/
63b7249e
MV
996// pkgAcqIndex::Failed - getting the indexfile failed /*{{{*/
997// ---------------------------------------------------------------------
998/* */
92fcbfc1 999void pkgAcqIndex::Failed(string Message,pkgAcquire::MethodConfig *Cnf) /*{{{*/
debc84b2 1000{
5d885723
DK
1001 size_t const nextExt = CompressionExtension.find(' ');
1002 if (nextExt != std::string::npos)
e85b4cd5 1003 {
5d885723
DK
1004 CompressionExtension = CompressionExtension.substr(nextExt+1);
1005 Init(RealURI, Desc.Description, Desc.ShortDesc);
6abe2699 1006 return;
0d7a243d
EL
1007 }
1008
17ff0930 1009 // on decompression failure, remove bad versions in partial/
5d885723 1010 if (Decompression && Erase) {
17ff0930 1011 string s = _config->FindDir("Dir::State::lists") + "partial/";
5d885723 1012 s.append(URItoFileName(RealURI));
17ff0930 1013 unlink(s.c_str());
debc84b2
MZ
1014 }
1015
debc84b2 1016 Item::Failed(Message,Cnf);
56472095
MV
1017
1018 /// cancel the entire transaction
715c65de 1019 TransactionManager->AbortTransaction();
debc84b2 1020}
92fcbfc1 1021 /*}}}*/
63b7249e
MV
1022// pkgAcqIndex::GetFinalFilename - Return the full final file path /*{{{*/
1023// ---------------------------------------------------------------------
1024/* */
1025std::string pkgAcqIndex::GetFinalFilename(std::string const &URI,
1026 std::string const &compExt)
1027{
1028 std::string FinalFile = _config->FindDir("Dir::State::lists");
1029 FinalFile += URItoFileName(URI);
1030 if (_config->FindB("Acquire::GzipIndexes",false) && compExt == "gz")
1031 FinalFile += ".gz";
1032 return FinalFile;
1033}
1034 /*}}}*/
1035// AcqIndex::ReverifyAfterIMS - Reverify index after an ims-hit /*{{{*/
1036// ---------------------------------------------------------------------
1037/* */
916b8910 1038void pkgAcqIndex::ReverifyAfterIMS()
63b7249e
MV
1039{
1040 std::string const compExt = CompressionExtension.substr(0, CompressionExtension.find(' '));
1041 if (_config->FindB("Acquire::GzipIndexes",false) && compExt == "gz")
1042 DestFile += ".gz";
1043
1044 // copy FinalFile into partial/ so that we check the hash again
1045 string FinalFile = GetFinalFilename(RealURI, compExt);
1046 Decompression = true;
1047 Desc.URI = "copy:" + FinalFile;
1048 QueueURI(Desc);
1049}
1050 /*}}}*/
8b89e57f
AL
1051// AcqIndex::Done - Finished a fetch /*{{{*/
1052// ---------------------------------------------------------------------
1053/* This goes through a number of states.. On the initial fetch the
1054 method could possibly return an alternate filename which points
1055 to the uncompressed version of the file. If this is so the file
1056 is copied into the partial directory. In all other cases the file
b6f0063c 1057 is decompressed with a compressed uri. */
b3501edb 1058void pkgAcqIndex::Done(string Message,unsigned long long Size,HashStringList const &Hashes,
459681d3 1059 pkgAcquire::MethodConfig *Cfg)
8b89e57f 1060{
b3501edb 1061 Item::Done(Message,Size,Hashes,Cfg);
63b7249e
MV
1062 std::string const compExt = CompressionExtension.substr(0, CompressionExtension.find(' '));
1063
8b89e57f
AL
1064 if (Decompression == true)
1065 {
b3501edb 1066 if (ExpectedHashes.usable() && ExpectedHashes != Hashes)
b3d44315 1067 {
ca7fd76c 1068 Desc.URI = RealURI;
3c8030a4 1069 RenameOnError(HashSumMismatch);
b3501edb 1070 printHashSumComparision(RealURI, ExpectedHashes, Hashes);
56472095 1071 Failed(Message, Cfg);
b3d44315
MV
1072 return;
1073 }
0901c5d0 1074
19818b65
MV
1075 // FIXME: this can go away once we only ever download stuff that
1076 // has a valid hash and we never do GET based probing
1077 //
1078 /* Always verify the index file for correctness (all indexes must
1079 * have a Package field) (LP: #346386) (Closes: #627642)
1080 */
5f6c6c6e 1081 FileFd fd(DestFile, FileFd::ReadOnly, FileFd::Extension);
b6f0063c
MV
1082 // Only test for correctness if the content of the file is not empty
1083 // (empty is ok)
1084 if (fd.Size() > 0)
0901c5d0 1085 {
19818b65
MV
1086 pkgTagSection sec;
1087 pkgTagFile tag(&fd);
1088
1089 // all our current indexes have a field 'Package' in each section
1090 if (_error->PendingError() == true || tag.Step(sec) == false || sec.Exists("Package") == false)
1091 {
1092 RenameOnError(InvalidFormat);
56472095 1093 Failed(Message, Cfg);
19818b65 1094 return;
a0c3110e 1095 }
0901c5d0
JAK
1096 }
1097
b6f0063c
MV
1098 // FIXME: can we void the "Erase" bool here as its very non-local?
1099 std::string CompressedFile = _config->FindDir("Dir::State::lists") + "partial/";
1100 CompressedFile += URItoFileName(RealURI);
ca7fd76c 1101
bfd22fc0
AL
1102 // Remove the compressed version.
1103 if (Erase == true)
b6f0063c 1104 unlink(CompressedFile.c_str());
63d0f853
MV
1105
1106 // Done, queue for rename on transaction finished
b6f0063c 1107 PartialFile = DestFile;
63b7249e 1108 DestFile = GetFinalFilename(RealURI, compExt);
63d0f853 1109
8b89e57f 1110 return;
5f6c6c6e
MV
1111 }
1112
1113 // FIXME: use the same method to find
1114 // check the compressed hash too
1115 if(MetaKey != "" && Hashes.size() > 0)
1116 {
1117 indexRecords::checkSum *Record = MetaIndexParser->Lookup(MetaKey);
1118 if(Record && Record->Hashes.usable() && Hashes != Record->Hashes)
7abcfdde 1119 {
5f6c6c6e
MV
1120 RenameOnError(HashSumMismatch);
1121 printHashSumComparision(RealURI, Record->Hashes, Hashes);
1122 Failed(Message, Cfg);
1123 return;
7abcfdde 1124 }
8b89e57f 1125 }
bfd22fc0
AL
1126
1127 Erase = false;
8267fe24 1128 Complete = true;
bfd22fc0 1129
8b89e57f
AL
1130 // Handle the unzipd case
1131 string FileName = LookupTag(Message,"Alt-Filename");
1132 if (FileName.empty() == false)
1133 {
8b89e57f 1134 Decompression = true;
a6568219 1135 Local = true;
8b89e57f 1136 DestFile += ".decomp";
8267fe24
AL
1137 Desc.URI = "copy:" + FileName;
1138 QueueURI(Desc);
b98f2859 1139 Mode = "copy";
8b89e57f
AL
1140 return;
1141 }
1142
1143 FileName = LookupTag(Message,"Filename");
1144 if (FileName.empty() == true)
1145 {
1146 Status = StatError;
1147 ErrorText = "Method gave a blank filename";
1148 }
5d885723 1149
bfd22fc0
AL
1150 if (FileName == DestFile)
1151 Erase = true;
8267fe24 1152 else
a6568219 1153 Local = true;
daff4aa3 1154
80174528
MV
1155 // do not reverify cdrom sources as apt-cdrom may rewrite the Packages
1156 // file when its doing the indexcopy
1157 if (RealURI.substr(0,6) == "cdrom:" &&
1158 StringToBool(LookupTag(Message,"IMS-Hit"),false) == true)
1159 return;
1160
23d0a6fb
MV
1161 // The files timestamp matches, for non-local URLs reverify the local
1162 // file, for local file, uncompress again to ensure the hashsum is still
1163 // matching the Release file
daff4aa3 1164 if (!Local && StringToBool(LookupTag(Message,"IMS-Hit"),false) == true)
ca7fd76c 1165 {
db1d1c32 1166 ReverifyAfterIMS();
8b89e57f 1167 return;
ca7fd76c 1168 }
e85b4cd5
DK
1169 string decompProg;
1170
ca7fd76c
MV
1171 // If we enable compressed indexes, queue for hash verification
1172 if (_config->FindB("Acquire::GzipIndexes",false) && compExt == "gz" && !Local)
1173 {
1174 DestFile = _config->FindDir("Dir::State::lists");
bb109d0b 1175 DestFile += URItoFileName(RealURI) + ".gz";
ca7fd76c
MV
1176
1177 Decompression = true;
1178 Desc.URI = "copy:" + FileName;
1179 QueueURI(Desc);
1180
bb109d0b 1181 return;
1182 }
1183
e85b4cd5
DK
1184 // get the binary name for your used compression type
1185 decompProg = _config->Find(string("Acquire::CompressionTypes::").append(compExt),"");
1186 if(decompProg.empty() == false);
5d885723 1187 else if(compExt == "uncompressed")
0d7a243d 1188 decompProg = "copy";
debc84b2
MZ
1189 else {
1190 _error->Error("Unsupported extension: %s", compExt.c_str());
1191 return;
1192 }
1193
8b89e57f
AL
1194 Decompression = true;
1195 DestFile += ".decomp";
e85b4cd5 1196 Desc.URI = decompProg + ":" + FileName;
8267fe24 1197 QueueURI(Desc);
70e0c168
MV
1198
1199 // FIXME: this points to a c++ string that goes out of scope
e85b4cd5 1200 Mode = decompProg.c_str();
8b89e57f 1201}
92fcbfc1 1202 /*}}}*/
a52f938b
OS
1203// AcqIndexTrans::pkgAcqIndexTrans - Constructor /*{{{*/
1204// ---------------------------------------------------------------------
1205/* The Translation file is added to the queue */
1206pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire *Owner,
495e5cb2 1207 string URI,string URIDesc,string ShortDesc)
916b8910 1208 : pkgAcqIndex(Owner, URI, URIDesc, ShortDesc, HashStringList())
a52f938b 1209{
ab53c018 1210}
56472095 1211 /*}}}*/
e05672e8 1212pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire *Owner,
715c65de 1213 pkgAcqMetaBase *TransactionManager,
e05672e8
MV
1214 IndexTarget const * const Target,
1215 HashStringList const &ExpectedHashes,
1216 indexRecords *MetaIndexParser)
715c65de 1217 : pkgAcqIndex(Owner, TransactionManager, Target, ExpectedHashes, MetaIndexParser)
ab53c018 1218{
1dca8dc5
MV
1219 // load the filesize
1220 indexRecords::checkSum *Record = MetaIndexParser->Lookup(string(Target->MetaKey));
1221 if(Record)
1222 FileSize = Record->Size;
963b16dc
MV
1223}
1224 /*}}}*/
1225// AcqIndexTrans::Custom600Headers - Insert custom request headers /*{{{*/
1226// ---------------------------------------------------------------------
b3501edb 1227string pkgAcqIndexTrans::Custom600Headers() const
963b16dc 1228{
c91d9a63
DK
1229 string Final = _config->FindDir("Dir::State::lists");
1230 Final += URItoFileName(RealURI);
1231
ca7fd76c
MV
1232 if (_config->FindB("Acquire::GzipIndexes",false))
1233 Final += ".gz";
1234
c91d9a63
DK
1235 struct stat Buf;
1236 if (stat(Final.c_str(),&Buf) != 0)
a3f7fff8
MV
1237 return "\nFail-Ignore: true\nIndex-File: true";
1238 return "\nFail-Ignore: true\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
a52f938b 1239}
a52f938b
OS
1240 /*}}}*/
1241// AcqIndexTrans::Failed - Silence failure messages for missing files /*{{{*/
1242// ---------------------------------------------------------------------
1243/* */
1244void pkgAcqIndexTrans::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
1245{
5d885723
DK
1246 size_t const nextExt = CompressionExtension.find(' ');
1247 if (nextExt != std::string::npos)
1248 {
1249 CompressionExtension = CompressionExtension.substr(nextExt+1);
1250 Init(RealURI, Desc.Description, Desc.ShortDesc);
1251 Status = StatIdle;
1252 return;
1253 }
1254
e05672e8 1255 // FIXME: this is used often (e.g. in pkgAcqIndexTrans) so refactor
a52f938b
OS
1256 if (Cnf->LocalOnly == true ||
1257 StringToBool(LookupTag(Message,"Transient-Failure"),false) == false)
1258 {
1259 // Ignore this
1260 Status = StatDone;
1261 Complete = false;
1262 Dequeue();
1263 return;
1264 }
5d885723 1265
a52f938b
OS
1266 Item::Failed(Message,Cnf);
1267}
1268 /*}}}*/
e6e89390 1269
715c65de 1270void pkgAcqMetaBase::Add(Item *I)
e6e89390 1271{
715c65de 1272 Transaction.push_back(I);
e6e89390 1273}
715c65de
MV
1274
1275void pkgAcqMetaBase::AbortTransaction()
1276{
1277 if(_config->FindB("Debug::Acquire::Transaction", false) == true)
1278 std::clog << "AbortTransaction: " << TransactionManager << std::endl;
1279
1280 for (std::vector<Item*>::iterator I = Transaction.begin();
1281 I != Transaction.end(); ++I)
1282 {
1283 if(_config->FindB("Debug::Acquire::Transaction", false) == true)
1284 std::clog << " Cancel: " << (*I)->DestFile << std::endl;
1285 // the transaction will abort, so stop anything that is idle
1286 if ((*I)->Status == pkgAcquire::Item::StatIdle)
1287 (*I)->Status = pkgAcquire::Item::StatDone;
1288 }
1289}
1290 /*}}}*/
1291bool pkgAcqMetaBase::TransactionHasError()
1292{
1293 for (pkgAcquire::ItemIterator I = Transaction.begin();
1294 I != Transaction.end(); ++I)
1295 if((*I)->Status != pkgAcquire::Item::StatDone &&
1296 (*I)->Status != pkgAcquire::Item::StatIdle)
1297 return true;
1298
1299 return false;
1300}
1301// Acquire::CommitTransaction - Commit a transaction /*{{{*/
1302void pkgAcqMetaBase::CommitTransaction()
1303{
1304 if(_config->FindB("Debug::Acquire::Transaction", false) == true)
1305 std::clog << "CommitTransaction: " << this << std::endl;
1306
1307 // move new files into place *and* remove files that are not
1308 // part of the transaction but are still on disk
1309 for (std::vector<Item*>::iterator I = Transaction.begin();
1310 I != Transaction.end(); ++I)
1311 {
1312 if((*I)->PartialFile != "")
1313 {
1314 if(_config->FindB("Debug::Acquire::Transaction", false) == true)
1315 std::clog << "mv "
1316 << (*I)->PartialFile << " -> "
1317 << (*I)->DestFile << std::endl;
1318 Rename((*I)->PartialFile, (*I)->DestFile);
1319 chmod((*I)->DestFile.c_str(),0644);
1320 } else {
1321 if(_config->FindB("Debug::Acquire::Transaction", false) == true)
1322 std::clog << "rm "
1323 << (*I)->DestFile << std::endl;
1324 unlink((*I)->DestFile.c_str());
1325 }
1326 // mark that this transaction is finished
1327 (*I)->TransactionManager = 0;
1328 }
1329}
1330
e6e89390 1331 /*{{{*/
715c65de
MV
1332bool pkgAcqMetaBase::GenerateAuthWarning(const std::string &RealURI,
1333 const std::string &Message)
e6e89390
MV
1334{
1335 string Final = _config->FindDir("Dir::State::lists") + URItoFileName(RealURI);
1336
1337 if(FileExists(Final))
1338 {
1339 Status = StatTransientNetworkError;
1340 _error->Warning(_("An error occurred during the signature "
1341 "verification. The repository is not updated "
1342 "and the previous index files will be used. "
1343 "GPG error: %s: %s\n"),
1344 Desc.Description.c_str(),
1345 LookupTag(Message,"Message").c_str());
1346 RunScripts("APT::Update::Auth-Failure");
1347 return true;
1348 } else if (LookupTag(Message,"Message").find("NODATA") != string::npos) {
1349 /* Invalid signature file, reject (LP: #346386) (Closes: #627642) */
1350 _error->Error(_("GPG error: %s: %s"),
1351 Desc.Description.c_str(),
1352 LookupTag(Message,"Message").c_str());
1353 Status = StatError;
1354 return true;
1355 } else {
1356 _error->Warning(_("GPG error: %s: %s"),
1357 Desc.Description.c_str(),
1358 LookupTag(Message,"Message").c_str());
1359 }
1360 // gpgv method failed
1361 ReportMirrorFailure("GPGFailure");
1362 return false;
1363}
1364 /*}}}*/
1365
1366
e05672e8 1367pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire *Owner, /*{{{*/
715c65de 1368 pkgAcqMetaBase *TransactionManager,
b3d44315 1369 string URI,string URIDesc,string ShortDesc,
2737f28a 1370 string MetaIndexFile,
b3d44315
MV
1371 const vector<IndexTarget*>* IndexTargets,
1372 indexRecords* MetaIndexParser) :
715c65de 1373 pkgAcqMetaBase(Owner, HashStringList(), TransactionManager), RealURI(URI),
2737f28a 1374 MetaIndexParser(MetaIndexParser), MetaIndexFile(MetaIndexFile),
1f4dd8fd 1375 IndexTargets(IndexTargets), AuthPass(false), IMSHit(false)
0118833a 1376{
0a8a80e5 1377 DestFile = _config->FindDir("Dir::State::lists") + "partial/";
b2e465d6 1378 DestFile += URItoFileName(URI);
b3d44315 1379
47eb38f4
MV
1380 // remove any partial downloaded sig-file in partial/.
1381 // it may confuse proxies and is too small to warrant a
1382 // partial download anyway
f6237efd
MV
1383 unlink(DestFile.c_str());
1384
715c65de 1385 // set the TransactionManager
e05672e8 1386 if(_config->FindB("Debug::Acquire::Transaction", false) == true)
715c65de
MV
1387 std::clog << "New pkgAcqMetaSig with TransactionManager "
1388 << TransactionManager << std::endl;
1f4dd8fd 1389
8267fe24 1390 // Create the item
b2e465d6 1391 Desc.Description = URIDesc;
8267fe24 1392 Desc.Owner = this;
b3d44315
MV
1393 Desc.ShortDesc = ShortDesc;
1394 Desc.URI = URI;
2737f28a 1395
8267fe24 1396 QueueURI(Desc);
ffcccd62
DK
1397}
1398 /*}}}*/
1399pkgAcqMetaSig::~pkgAcqMetaSig() /*{{{*/
1400{
0118833a
AL
1401}
1402 /*}}}*/
b3d44315 1403// pkgAcqMetaSig::Custom600Headers - Insert custom request headers /*{{{*/
0118833a 1404// ---------------------------------------------------------------------
0a8a80e5 1405/* The only header we use is the last-modified header. */
b3501edb 1406string pkgAcqMetaSig::Custom600Headers() const
0118833a 1407{
1f4dd8fd
MV
1408 string FinalFile = _config->FindDir("Dir::State::lists");
1409 FinalFile += URItoFileName(RealURI);
1410
0a8a80e5 1411 struct stat Buf;
1f4dd8fd 1412 if (stat(FinalFile.c_str(),&Buf) != 0)
a72ace20 1413 return "\nIndex-File: true";
a789b983 1414
a72ace20 1415 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
0118833a 1416}
b3d44315 1417
b3501edb 1418void pkgAcqMetaSig::Done(string Message,unsigned long long Size, HashStringList const &Hashes,
b3d44315 1419 pkgAcquire::MethodConfig *Cfg)
c88edf1d 1420{
b3501edb 1421 Item::Done(Message, Size, Hashes, Cfg);
c88edf1d
AL
1422
1423 string FileName = LookupTag(Message,"Filename");
1424 if (FileName.empty() == true)
1425 {
1426 Status = StatError;
1427 ErrorText = "Method gave a blank filename";
8b89e57f 1428 return;
c88edf1d 1429 }
8b89e57f 1430
c88edf1d
AL
1431 if (FileName != DestFile)
1432 {
b3d44315 1433 // We have to copy it into place
a6568219 1434 Local = true;
8267fe24
AL
1435 Desc.URI = "copy:" + FileName;
1436 QueueURI(Desc);
c88edf1d
AL
1437 return;
1438 }
b3d44315 1439
1f4dd8fd
MV
1440 if(StringToBool(LookupTag(Message,"IMS-Hit"),false) == true)
1441 IMSHit = true;
1442
1443 // adjust paths if its a ims-hit
1444 if(IMSHit)
1445 {
1446 string FinalFile = _config->FindDir("Dir::State::lists");
1447 FinalFile += URItoFileName(RealURI);
1448
1449 DestFile = PartialFile = FinalFile;
1450 }
1451
2737f28a
MV
1452 // queue for verify
1453 if(AuthPass == false)
1454 {
1455 AuthPass = true;
1456 Desc.URI = "gpgv:" + DestFile;
1457 DestFile = MetaIndexFile;
1458 QueueURI(Desc);
1459 return;
1460 }
b3d44315 1461
1f4dd8fd
MV
1462 // queue to copy the file in place if it was not a ims hit, on ims
1463 // hit the file is already at the right place
1464 if(IMSHit == false)
1465 {
1466 PartialFile = _config->FindDir("Dir::State::lists") + "partial/";
1467 PartialFile += URItoFileName(RealURI);
1468
1469 DestFile = _config->FindDir("Dir::State::lists");
1470 DestFile += URItoFileName(RealURI);
1471 }
56472095 1472
1f4dd8fd 1473 Complete = true;
b3d44315 1474
c88edf1d
AL
1475}
1476 /*}}}*/
92fcbfc1 1477void pkgAcqMetaSig::Failed(string Message,pkgAcquire::MethodConfig *Cnf)/*{{{*/
681d76d0 1478{
47eb38f4 1479 string Final = _config->FindDir("Dir::State::lists") + URItoFileName(RealURI);
7e5f33eb 1480
1f4dd8fd
MV
1481 // this ensures that any file in the lists/ dir is removed by the
1482 // transaction
1483 DestFile = _config->FindDir("Dir::State::lists") + "partial/";
1484 DestFile += URItoFileName(RealURI);
1485 PartialFile = "";
24057ad6 1486
09475beb
MV
1487 // FIXME: duplicated code from pkgAcqMetaIndex
1488 if (AuthPass == true)
1489 {
e6e89390
MV
1490 bool Stop = GenerateAuthWarning(RealURI, Message);
1491 if(Stop)
1492 return;
09475beb
MV
1493 }
1494
e05672e8
MV
1495 // FIXME: this is used often (e.g. in pkgAcqIndexTrans) so refactor
1496 if (Cnf->LocalOnly == true ||
1497 StringToBool(LookupTag(Message,"Transient-Failure"),false) == false)
1498 {
1499 // Ignore this
1500 Status = StatDone;
1501 Complete = false;
1502 Dequeue();
1503 return;
1504 }
681d76d0
AL
1505 Item::Failed(Message,Cnf);
1506}
92fcbfc1
DK
1507 /*}}}*/
1508pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire *Owner, /*{{{*/
715c65de 1509 pkgAcqMetaBase *TransactionManager,
b3d44315 1510 string URI,string URIDesc,string ShortDesc,
2737f28a 1511 string MetaIndexSigURI,string MetaIndexSigURIDesc, string MetaIndexSigShortDesc,
fa3b260f 1512 const vector<IndexTarget*>* IndexTargets,
b3d44315 1513 indexRecords* MetaIndexParser) :
715c65de 1514 pkgAcqMetaBase(Owner, HashStringList(), TransactionManager), RealURI(URI), IndexTargets(IndexTargets),
2737f28a
MV
1515 MetaIndexParser(MetaIndexParser), AuthPass(false), IMSHit(false),
1516 MetaIndexSigURI(MetaIndexSigURI), MetaIndexSigURIDesc(MetaIndexSigURIDesc),
1517 MetaIndexSigShortDesc(MetaIndexSigShortDesc)
b3d44315 1518{
715c65de
MV
1519 if(TransactionManager == NULL)
1520 {
1521 this->TransactionManager = this;
1522 this->TransactionManager->Add(this);
1523 }
e05672e8
MV
1524
1525 if(_config->FindB("Debug::Acquire::Transaction", false) == true)
715c65de
MV
1526 std::clog << "New pkgAcqMetaIndex with TransactionManager "
1527 << this->TransactionManager << std::endl;
1528
b3d44315 1529
e05672e8
MV
1530 Init(URIDesc, ShortDesc);
1531}
1532 /*}}}*/
1533// pkgAcqMetaIndex::Init - Delayed constructor /*{{{*/
1534void pkgAcqMetaIndex::Init(std::string URIDesc, std::string ShortDesc)
1535{
1536 DestFile = _config->FindDir("Dir::State::lists") + "partial/";
1537 DestFile += URItoFileName(RealURI);
56472095 1538
b3d44315
MV
1539 // Create the item
1540 Desc.Description = URIDesc;
1541 Desc.Owner = this;
1542 Desc.ShortDesc = ShortDesc;
e05672e8 1543 Desc.URI = RealURI;
b3d44315 1544
d0cfa8ad
MV
1545 // we expect more item
1546 ExpectedAdditionalItems = IndexTargets->size();
b3d44315
MV
1547 QueueURI(Desc);
1548}
b3d44315
MV
1549// pkgAcqMetaIndex::Custom600Headers - Insert custom request headers /*{{{*/
1550// ---------------------------------------------------------------------
1551/* The only header we use is the last-modified header. */
b3501edb 1552string pkgAcqMetaIndex::Custom600Headers() const
b3d44315
MV
1553{
1554 string Final = _config->FindDir("Dir::State::lists");
1555 Final += URItoFileName(RealURI);
1556
1557 struct stat Buf;
1558 if (stat(Final.c_str(),&Buf) != 0)
1559 return "\nIndex-File: true";
1560
1561 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
1562}
92fcbfc1 1563 /*}}}*/
b3501edb 1564void pkgAcqMetaIndex::Done(string Message,unsigned long long Size,HashStringList const &Hashes, /*{{{*/
b3d44315
MV
1565 pkgAcquire::MethodConfig *Cfg)
1566{
b3501edb 1567 Item::Done(Message,Size,Hashes,Cfg);
b3d44315
MV
1568
1569 // MetaIndexes are done in two passes: one to download the
1570 // metaindex with an appropriate method, and a second to verify it
1571 // with the gpgv method
1572
1573 if (AuthPass == true)
1574 {
1575 AuthDone(Message);
fce72602
MV
1576
1577 // all cool, move Release file into place
1578 Complete = true;
b3d44315
MV
1579 }
1580 else
1581 {
1582 RetrievalDone(Message);
1583 if (!Complete)
1584 // Still more retrieving to do
1585 return;
1586
1587 if (SigFile == "")
1588 {
2737f28a 1589 // load indexes, the signature will downloaded afterwards
3568a640 1590 MetaIndexParser->Load(DestFile);
2737f28a 1591 QueueIndexes(true);
b3d44315
MV
1592 }
1593 else
1594 {
1595 // There was a signature file, so pass it to gpgv for
1596 // verification
b3d44315
MV
1597 if (_config->FindB("Debug::pkgAcquire::Auth", false))
1598 std::cerr << "Metaindex acquired, queueing gpg verification ("
1599 << SigFile << "," << DestFile << ")\n";
1600 AuthPass = true;
1601 Desc.URI = "gpgv:" + SigFile;
1602 QueueURI(Desc);
1603 Mode = "gpgv";
56bc3358 1604 return;
b3d44315
MV
1605 }
1606 }
56bc3358
DK
1607
1608 if (Complete == true)
1609 {
1610 string FinalFile = _config->FindDir("Dir::State::lists");
1611 FinalFile += URItoFileName(RealURI);
fe0f7911
DK
1612 if (SigFile == DestFile)
1613 SigFile = FinalFile;
1f4dd8fd 1614 // queue for copy in place
56472095 1615 PartialFile = DestFile;
56bc3358
DK
1616 DestFile = FinalFile;
1617 }
b3d44315 1618}
92fcbfc1
DK
1619 /*}}}*/
1620void pkgAcqMetaIndex::RetrievalDone(string Message) /*{{{*/
b3d44315
MV
1621{
1622 // We have just finished downloading a Release file (it is not
1623 // verified yet)
1624
1625 string FileName = LookupTag(Message,"Filename");
1626 if (FileName.empty() == true)
1627 {
1628 Status = StatError;
1629 ErrorText = "Method gave a blank filename";
1630 return;
1631 }
1632
1633 if (FileName != DestFile)
1634 {
1635 Local = true;
1636 Desc.URI = "copy:" + FileName;
1637 QueueURI(Desc);
1638 return;
1639 }
1640
fce72602 1641 // make sure to verify against the right file on I-M-S hit
f381d68d 1642 IMSHit = StringToBool(LookupTag(Message,"IMS-Hit"),false);
fce72602
MV
1643 if(IMSHit)
1644 {
1645 string FinalFile = _config->FindDir("Dir::State::lists");
1646 FinalFile += URItoFileName(RealURI);
fe0f7911 1647 if (SigFile == DestFile)
0aec7d5c 1648 {
fe0f7911 1649 SigFile = FinalFile;
7712d13b 1650#if 0
0aec7d5c
DK
1651 // constructor of pkgAcqMetaClearSig moved it out of the way,
1652 // now move it back in on IMS hit for the 'old' file
1653 string const OldClearSig = DestFile + ".reverify";
1654 if (RealFileExists(OldClearSig) == true)
1655 Rename(OldClearSig, FinalFile);
7712d13b 1656#endif
0aec7d5c 1657 }
fce72602
MV
1658 DestFile = FinalFile;
1659 }
2737f28a
MV
1660
1661 // queue a signature
1662 if(SigFile != DestFile)
715c65de 1663 new pkgAcqMetaSig(Owner, TransactionManager,
e05672e8 1664 MetaIndexSigURI, MetaIndexSigURIDesc,
2737f28a
MV
1665 MetaIndexSigShortDesc, DestFile, IndexTargets,
1666 MetaIndexParser);
1667
b3d44315 1668 Complete = true;
b3d44315 1669}
92fcbfc1
DK
1670 /*}}}*/
1671void pkgAcqMetaIndex::AuthDone(string Message) /*{{{*/
b3d44315
MV
1672{
1673 // At this point, the gpgv method has succeeded, so there is a
1674 // valid signature from a key in the trusted keyring. We
1675 // perform additional verification of its contents, and use them
1676 // to verify the indexes we are about to download
1677
1678 if (!MetaIndexParser->Load(DestFile))
1679 {
1680 Status = StatAuthError;
1681 ErrorText = MetaIndexParser->ErrorText;
1682 return;
1683 }
1684
ce424cd4 1685 if (!VerifyVendor(Message))
b3d44315
MV
1686 {
1687 return;
1688 }
1689
1690 if (_config->FindB("Debug::pkgAcquire::Auth", false))
1691 std::cerr << "Signature verification succeeded: "
1692 << DestFile << std::endl;
1693
ca7fd76c
MV
1694 // do not trust any previously unverified content that we may have
1695 string LastGoodSigFile = _config->FindDir("Dir::State::lists").append("partial/").append(URItoFileName(RealURI));
1696 if (DestFile != SigFile)
1697 LastGoodSigFile.append(".gpg");
1698 LastGoodSigFile.append(".reverify");
1699 if(IMSHit == false && RealFileExists(LastGoodSigFile) == false)
1700 {
1701 for (vector <struct IndexTarget*>::const_iterator Target = IndexTargets->begin();
1702 Target != IndexTargets->end();
1703 ++Target)
1704 {
1705 // remove old indexes
1706 std::string index = _config->FindDir("Dir::State::lists") +
1707 URItoFileName((*Target)->URI);
1708 unlink(index.c_str());
1709 // and also old gzipindexes
1710 index += ".gz";
1711 unlink(index.c_str());
1712 }
1713 }
1714
1715
b3d44315
MV
1716 // Download further indexes with verification
1717 QueueIndexes(true);
1718
56472095 1719#if 0
fe0f7911
DK
1720 // is it a clearsigned MetaIndex file?
1721 if (DestFile == SigFile)
1722 return;
1723
b3d44315 1724 // Done, move signature file into position
b3d44315
MV
1725 string VerifiedSigFile = _config->FindDir("Dir::State::lists") +
1726 URItoFileName(RealURI) + ".gpg";
1727 Rename(SigFile,VerifiedSigFile);
1728 chmod(VerifiedSigFile.c_str(),0644);
56472095 1729#endif
b3d44315 1730}
92fcbfc1
DK
1731 /*}}}*/
1732void pkgAcqMetaIndex::QueueIndexes(bool verify) /*{{{*/
b3d44315 1733{
8e3900d0
DK
1734 bool transInRelease = false;
1735 {
1736 std::vector<std::string> const keys = MetaIndexParser->MetaKeys();
1737 for (std::vector<std::string>::const_iterator k = keys.begin(); k != keys.end(); ++k)
1738 // FIXME: Feels wrong to check for hardcoded string here, but what should we do else…
1739 if (k->find("Translation-") != std::string::npos)
1740 {
1741 transInRelease = true;
1742 break;
1743 }
1744 }
1745
d0cfa8ad
MV
1746 // at this point the real Items are loaded in the fetcher
1747 ExpectedAdditionalItems = 0;
fa3b260f 1748 for (vector <IndexTarget*>::const_iterator Target = IndexTargets->begin();
b3d44315 1749 Target != IndexTargets->end();
f7f0d6c7 1750 ++Target)
b3d44315 1751 {
b3501edb
DK
1752 HashStringList ExpectedIndexHashes;
1753 const indexRecords::checkSum *Record = MetaIndexParser->Lookup((*Target)->MetaKey);
a5b9f489 1754 bool compressedAvailable = false;
1207cf3f 1755 if (Record == NULL)
b3d44315 1756 {
a5b9f489
DK
1757 if ((*Target)->IsOptional() == true)
1758 {
1759 std::vector<std::string> types = APT::Configuration::getCompressionTypes();
1760 for (std::vector<std::string>::const_iterator t = types.begin(); t != types.end(); ++t)
e788a834 1761 if (MetaIndexParser->Exists((*Target)->MetaKey + "." + *t) == true)
a5b9f489
DK
1762 {
1763 compressedAvailable = true;
1764 break;
1765 }
1766 }
1767 else if (verify == true)
ab53c018 1768 {
1207cf3f
DK
1769 Status = StatAuthError;
1770 strprintf(ErrorText, _("Unable to find expected entry '%s' in Release file (Wrong sources.list entry or malformed file)"), (*Target)->MetaKey.c_str());
1771 return;
ab53c018 1772 }
1207cf3f
DK
1773 }
1774 else
1775 {
b3501edb 1776 ExpectedIndexHashes = Record->Hashes;
1207cf3f 1777 if (_config->FindB("Debug::pkgAcquire::Auth", false))
ab53c018 1778 {
b3501edb
DK
1779 std::cerr << "Queueing: " << (*Target)->URI << std::endl
1780 << "Expected Hash:" << std::endl;
1781 for (HashStringList::const_iterator hs = ExpectedIndexHashes.begin(); hs != ExpectedIndexHashes.end(); ++hs)
1782 std::cerr << "\t- " << hs->toStr() << std::endl;
1207cf3f
DK
1783 std::cerr << "For: " << Record->MetaKeyFilename << std::endl;
1784 }
b3501edb 1785 if (verify == true && ExpectedIndexHashes.empty() == true && (*Target)->IsOptional() == false)
1207cf3f
DK
1786 {
1787 Status = StatAuthError;
1788 strprintf(ErrorText, _("Unable to find hash sum for '%s' in Release file"), (*Target)->MetaKey.c_str());
1789 return;
ab53c018
DK
1790 }
1791 }
1792
1793 if ((*Target)->IsOptional() == true)
1794 {
f456b60b 1795 if (transInRelease == false || Record != NULL || compressedAvailable == true)
8e3900d0 1796 {
f55602cb 1797 if (_config->FindB("Acquire::PDiffs",true) == true && transInRelease == true &&
e788a834 1798 MetaIndexParser->Exists((*Target)->MetaKey + ".diff/Index") == true)
715c65de 1799 new pkgAcqDiffIndex(Owner, TransactionManager, *Target, ExpectedIndexHashes, MetaIndexParser);
f55602cb 1800 else
715c65de 1801 new pkgAcqIndexTrans(Owner, TransactionManager, *Target, ExpectedIndexHashes, MetaIndexParser);
8e3900d0 1802 }
ab53c018 1803 continue;
b3d44315 1804 }
e1430400
DK
1805
1806 /* Queue Packages file (either diff or full packages files, depending
1807 on the users option) - we also check if the PDiff Index file is listed
1808 in the Meta-Index file. Ideal would be if pkgAcqDiffIndex would test this
1809 instead, but passing the required info to it is to much hassle */
1810 if(_config->FindB("Acquire::PDiffs",true) == true && (verify == false ||
e788a834 1811 MetaIndexParser->Exists((*Target)->MetaKey + ".diff/Index") == true))
715c65de 1812 new pkgAcqDiffIndex(Owner, TransactionManager, *Target, ExpectedIndexHashes, MetaIndexParser);
e1430400 1813 else
715c65de 1814 new pkgAcqIndex(Owner, TransactionManager, *Target, ExpectedIndexHashes, MetaIndexParser);
b3d44315
MV
1815 }
1816}
92fcbfc1
DK
1817 /*}}}*/
1818bool pkgAcqMetaIndex::VerifyVendor(string Message) /*{{{*/
b3d44315 1819{
ce424cd4
MV
1820 string::size_type pos;
1821
1822 // check for missing sigs (that where not fatal because otherwise we had
1823 // bombed earlier)
1824 string missingkeys;
400ad7a4 1825 string msg = _("There is no public key available for the "
ce424cd4
MV
1826 "following key IDs:\n");
1827 pos = Message.find("NO_PUBKEY ");
1828 if (pos != std::string::npos)
1829 {
1830 string::size_type start = pos+strlen("NO_PUBKEY ");
1831 string Fingerprint = Message.substr(start, Message.find("\n")-start);
1832 missingkeys += (Fingerprint);
1833 }
1834 if(!missingkeys.empty())
e788a834 1835 _error->Warning("%s", (msg + missingkeys).c_str());
b3d44315
MV
1836
1837 string Transformed = MetaIndexParser->GetExpectedDist();
1838
1839 if (Transformed == "../project/experimental")
1840 {
1841 Transformed = "experimental";
1842 }
1843
ce424cd4 1844 pos = Transformed.rfind('/');
b3d44315
MV
1845 if (pos != string::npos)
1846 {
1847 Transformed = Transformed.substr(0, pos);
1848 }
1849
1850 if (Transformed == ".")
1851 {
1852 Transformed = "";
1853 }
1854
0323317c
DK
1855 if (_config->FindB("Acquire::Check-Valid-Until", true) == true &&
1856 MetaIndexParser->GetValidUntil() > 0) {
1857 time_t const invalid_since = time(NULL) - MetaIndexParser->GetValidUntil();
1858 if (invalid_since > 0)
1859 // TRANSLATOR: The first %s is the URL of the bad Release file, the second is
1860 // the time since then the file is invalid - formated in the same way as in
1861 // the download progress display (e.g. 7d 3h 42min 1s)
457bea86
MV
1862 return _error->Error(
1863 _("Release file for %s is expired (invalid since %s). "
1864 "Updates for this repository will not be applied."),
1865 RealURI.c_str(), TimeToStr(invalid_since).c_str());
1ddb8596
DK
1866 }
1867
b3d44315
MV
1868 if (_config->FindB("Debug::pkgAcquire::Auth", false))
1869 {
1870 std::cerr << "Got Codename: " << MetaIndexParser->GetDist() << std::endl;
1871 std::cerr << "Expecting Dist: " << MetaIndexParser->GetExpectedDist() << std::endl;
1872 std::cerr << "Transformed Dist: " << Transformed << std::endl;
1873 }
1874
1875 if (MetaIndexParser->CheckDist(Transformed) == false)
1876 {
1877 // This might become fatal one day
1878// Status = StatAuthError;
1879// ErrorText = "Conflicting distribution; expected "
1880// + MetaIndexParser->GetExpectedDist() + " but got "
1881// + MetaIndexParser->GetDist();
1882// return false;
1883 if (!Transformed.empty())
1884 {
1ddb8596 1885 _error->Warning(_("Conflicting distribution: %s (expected %s but got %s)"),
b3d44315
MV
1886 Desc.Description.c_str(),
1887 Transformed.c_str(),
1888 MetaIndexParser->GetDist().c_str());
1889 }
1890 }
1891
1892 return true;
1893}
92fcbfc1
DK
1894 /*}}}*/
1895// pkgAcqMetaIndex::Failed - no Release file present or no signature file present /*{{{*/
b3d44315
MV
1896// ---------------------------------------------------------------------
1897/* */
21638c3a 1898void pkgAcqMetaIndex::Failed(string Message,
56472095 1899 pkgAcquire::MethodConfig * /*Cnf*/)
b3d44315 1900{
09475beb
MV
1901 string Final = _config->FindDir("Dir::State::lists") + URItoFileName(RealURI);
1902
b3d44315
MV
1903 if (AuthPass == true)
1904 {
e6e89390
MV
1905 bool Stop = GenerateAuthWarning(RealURI, Message);
1906 if(Stop)
1907 return;
b3d44315 1908 }
c5fced38 1909
7ea7ac9e
JAK
1910 /* Always move the meta index, even if gpgv failed. This ensures
1911 * that PackageFile objects are correctly filled in */
a235ddf8 1912 if (FileExists(DestFile)) {
7ea7ac9e
JAK
1913 string FinalFile = _config->FindDir("Dir::State::lists");
1914 FinalFile += URItoFileName(RealURI);
1915 /* InRelease files become Release files, otherwise
1916 * they would be considered as trusted later on */
1917 if (SigFile == DestFile) {
1918 RealURI = RealURI.replace(RealURI.rfind("InRelease"), 9,
1919 "Release");
1920 FinalFile = FinalFile.replace(FinalFile.rfind("InRelease"), 9,
1921 "Release");
1922 SigFile = FinalFile;
1923 }
7ea7ac9e 1924
c5fced38
MV
1925 // Done, queue for rename on transaction finished
1926 PartialFile = DestFile;
7ea7ac9e
JAK
1927 DestFile = FinalFile;
1928 }
1929
b3d44315
MV
1930 // No Release file was present, or verification failed, so fall
1931 // back to queueing Packages files without verification
1932 QueueIndexes(false);
1933}
681d76d0 1934 /*}}}*/
56472095
MV
1935
1936void pkgAcqMetaIndex::Finished()
1937{
1938 if(_config->FindB("Debug::Acquire::Transaction", false) == true)
1939 std::clog << "Finished: " << DestFile <<std::endl;
715c65de
MV
1940 if(TransactionManager != NULL &&
1941 TransactionManager->TransactionHasError() == false)
1942 TransactionManager->CommitTransaction();
56472095
MV
1943}
1944
1945
fe0f7911
DK
1946pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire *Owner, /*{{{*/
1947 string const &URI, string const &URIDesc, string const &ShortDesc,
1948 string const &MetaIndexURI, string const &MetaIndexURIDesc, string const &MetaIndexShortDesc,
1949 string const &MetaSigURI, string const &MetaSigURIDesc, string const &MetaSigShortDesc,
fa3b260f 1950 const vector<IndexTarget*>* IndexTargets,
fe0f7911 1951 indexRecords* MetaIndexParser) :
715c65de 1952 pkgAcqMetaIndex(Owner, NULL, URI, URIDesc, ShortDesc, MetaSigURI, MetaSigURIDesc,MetaSigShortDesc, IndexTargets, MetaIndexParser),
2737f28a
MV
1953 MetaIndexURI(MetaIndexURI), MetaIndexURIDesc(MetaIndexURIDesc), MetaIndexShortDesc(MetaIndexShortDesc),
1954 MetaSigURI(MetaSigURI), MetaSigURIDesc(MetaSigURIDesc), MetaSigShortDesc(MetaSigShortDesc)
fe0f7911
DK
1955{
1956 SigFile = DestFile;
39f38a81 1957
d0cfa8ad
MV
1958 // index targets + (worst case:) Release/Release.gpg
1959 ExpectedAdditionalItems = IndexTargets->size() + 2;
1960
7712d13b 1961#if 0
39f38a81
DK
1962 // keep the old InRelease around in case of transistent network errors
1963 string const Final = _config->FindDir("Dir::State::lists") + URItoFileName(RealURI);
ffcccd62 1964 if (RealFileExists(Final) == true)
39f38a81
DK
1965 {
1966 string const LastGoodSig = DestFile + ".reverify";
1967 Rename(Final,LastGoodSig);
1968 }
7712d13b 1969#endif
fe0f7911
DK
1970}
1971 /*}}}*/
ffcccd62
DK
1972pkgAcqMetaClearSig::~pkgAcqMetaClearSig() /*{{{*/
1973{
7712d13b 1974#if 0
ffcccd62
DK
1975 // if the file was never queued undo file-changes done in the constructor
1976 if (QueueCounter == 1 && Status == StatIdle && FileSize == 0 && Complete == false)
1977 {
1978 string const Final = _config->FindDir("Dir::State::lists") + URItoFileName(RealURI);
1979 string const LastGoodSig = DestFile + ".reverify";
1980 if (RealFileExists(Final) == false && RealFileExists(LastGoodSig) == true)
1981 Rename(LastGoodSig, Final);
1982 }
7712d13b 1983#endif
ffcccd62
DK
1984}
1985 /*}}}*/
8d6c5839
MV
1986// pkgAcqMetaClearSig::Custom600Headers - Insert custom request headers /*{{{*/
1987// ---------------------------------------------------------------------
1988// FIXME: this can go away once the InRelease file is used widely
b3501edb 1989string pkgAcqMetaClearSig::Custom600Headers() const
8d6c5839
MV
1990{
1991 string Final = _config->FindDir("Dir::State::lists");
1992 Final += URItoFileName(RealURI);
1993
1994 struct stat Buf;
1995 if (stat(Final.c_str(),&Buf) != 0)
0aec7d5c 1996 {
0aec7d5c
DK
1997 if (stat(Final.c_str(),&Buf) != 0)
1998 return "\nIndex-File: true\nFail-Ignore: true\n";
1999 }
8d6c5839
MV
2000
2001 return "\nIndex-File: true\nFail-Ignore: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
2002}
2003 /*}}}*/
a9bb651a
MV
2004// pkgAcqMetaClearSig::Done - We got a file /*{{{*/
2005// ---------------------------------------------------------------------
2006void pkgAcqMetaClearSig::Done(std::string Message,unsigned long long Size,
2007 HashStringList const &Hashes,
2008 pkgAcquire::MethodConfig *Cnf)
fe0f7911 2009{
e84d3803
MV
2010 // if we expect a ClearTextSignature (InRelase), ensure that
2011 // this is what we get and if not fail to queue a
2012 // Release/Release.gpg, see #346386
a9bb651a 2013 if (FileExists(DestFile) && !StartsWithGPGClearTextSignature(DestFile))
e84d3803 2014 {
e84d3803 2015 pkgAcquire::Item::Failed(Message, Cnf);
09475beb 2016 ErrorText = _("Does not start with a cleartext signature");
e84d3803
MV
2017 return;
2018 }
a9bb651a
MV
2019 pkgAcqMetaIndex::Done(Message, Size, Hashes, Cnf);
2020}
2021 /*}}}*/
2022void pkgAcqMetaClearSig::Failed(string Message,pkgAcquire::MethodConfig *Cnf) /*{{{*/
2023{
2024 // we failed, we will not get additional items from this method
2025 ExpectedAdditionalItems = 0;
e84d3803 2026
fe0f7911
DK
2027 if (AuthPass == false)
2028 {
7712d13b
MV
2029 // Queue the 'old' InRelease file for removal if we try Release.gpg
2030 // as otherwise the file will stay around and gives a false-auth
2031 // impression (CVE-2012-0214)
de498a52
DK
2032 string FinalFile = _config->FindDir("Dir::State::lists");
2033 FinalFile.append(URItoFileName(RealURI));
7712d13b
MV
2034 PartialFile = "";
2035 DestFile = FinalFile;
de498a52 2036
715c65de 2037 new pkgAcqMetaIndex(Owner, TransactionManager,
fe0f7911 2038 MetaIndexURI, MetaIndexURIDesc, MetaIndexShortDesc,
2737f28a 2039 MetaSigURI, MetaSigURIDesc, MetaSigShortDesc,
fe0f7911
DK
2040 IndexTargets, MetaIndexParser);
2041 if (Cnf->LocalOnly == true ||
2042 StringToBool(LookupTag(Message, "Transient-Failure"), false) == false)
2043 Dequeue();
2044 }
2045 else
2046 pkgAcqMetaIndex::Failed(Message, Cnf);
2047}
2048 /*}}}*/
03e39e59
AL
2049// AcqArchive::AcqArchive - Constructor /*{{{*/
2050// ---------------------------------------------------------------------
17caf1b1
AL
2051/* This just sets up the initial fetch environment and queues the first
2052 possibilitiy */
03e39e59 2053pkgAcqArchive::pkgAcqArchive(pkgAcquire *Owner,pkgSourceList *Sources,
30e1eab5
AL
2054 pkgRecords *Recs,pkgCache::VerIterator const &Version,
2055 string &StoreFilename) :
fa3b260f 2056 Item(Owner, HashStringList()), Version(Version), Sources(Sources), Recs(Recs),
b3d44315
MV
2057 StoreFilename(StoreFilename), Vf(Version.FileList()),
2058 Trusted(false)
03e39e59 2059{
7d8afa39 2060 Retries = _config->FindI("Acquire::Retries",0);
813c8eea
AL
2061
2062 if (Version.Arch() == 0)
bdae53f1 2063 {
d1f1f6a8 2064 _error->Error(_("I wasn't able to locate a file for the %s package. "
7a3c2ab0
AL
2065 "This might mean you need to manually fix this package. "
2066 "(due to missing arch)"),
40f8a8ba 2067 Version.ParentPkg().FullName().c_str());
bdae53f1
AL
2068 return;
2069 }
813c8eea 2070
b2e465d6
AL
2071 /* We need to find a filename to determine the extension. We make the
2072 assumption here that all the available sources for this version share
2073 the same extension.. */
2074 // Skip not source sources, they do not have file fields.
69c2ecbd 2075 for (; Vf.end() == false; ++Vf)
b2e465d6
AL
2076 {
2077 if ((Vf.File()->Flags & pkgCache::Flag::NotSource) != 0)
2078 continue;
2079 break;
2080 }
2081
2082 // Does not really matter here.. we are going to fail out below
2083 if (Vf.end() != true)
2084 {
2085 // If this fails to get a file name we will bomb out below.
2086 pkgRecords::Parser &Parse = Recs->Lookup(Vf);
2087 if (_error->PendingError() == true)
2088 return;
2089
2090 // Generate the final file name as: package_version_arch.foo
2091 StoreFilename = QuoteString(Version.ParentPkg().Name(),"_:") + '_' +
2092 QuoteString(Version.VerStr(),"_:") + '_' +
2093 QuoteString(Version.Arch(),"_:.") +
2094 "." + flExtension(Parse.FileName());
2095 }
b3d44315
MV
2096
2097 // check if we have one trusted source for the package. if so, switch
6c34ccca
DK
2098 // to "TrustedOnly" mode - but only if not in AllowUnauthenticated mode
2099 bool const allowUnauth = _config->FindB("APT::Get::AllowUnauthenticated", false);
2100 bool const debugAuth = _config->FindB("Debug::pkgAcquire::Auth", false);
2101 bool seenUntrusted = false;
f7f0d6c7 2102 for (pkgCache::VerFileIterator i = Version.FileList(); i.end() == false; ++i)
b3d44315
MV
2103 {
2104 pkgIndexFile *Index;
2105 if (Sources->FindIndex(i.File(),Index) == false)
2106 continue;
6c34ccca
DK
2107
2108 if (debugAuth == true)
b3d44315 2109 std::cerr << "Checking index: " << Index->Describe()
6c34ccca
DK
2110 << "(Trusted=" << Index->IsTrusted() << ")" << std::endl;
2111
2112 if (Index->IsTrusted() == true)
2113 {
b3d44315 2114 Trusted = true;
6c34ccca
DK
2115 if (allowUnauth == false)
2116 break;
b3d44315 2117 }
6c34ccca
DK
2118 else
2119 seenUntrusted = true;
b3d44315
MV
2120 }
2121
a3371852
MV
2122 // "allow-unauthenticated" restores apts old fetching behaviour
2123 // that means that e.g. unauthenticated file:// uris are higher
2124 // priority than authenticated http:// uris
6c34ccca 2125 if (allowUnauth == true && seenUntrusted == true)
a3371852
MV
2126 Trusted = false;
2127
03e39e59 2128 // Select a source
b185acc2 2129 if (QueueNext() == false && _error->PendingError() == false)
d57f6084
DK
2130 _error->Error(_("Can't find a source to download version '%s' of '%s'"),
2131 Version.VerStr(), Version.ParentPkg().FullName(false).c_str());
b185acc2
AL
2132}
2133 /*}}}*/
2134// AcqArchive::QueueNext - Queue the next file source /*{{{*/
2135// ---------------------------------------------------------------------
17caf1b1
AL
2136/* This queues the next available file version for download. It checks if
2137 the archive is already available in the cache and stashs the MD5 for
2138 checking later. */
b185acc2 2139bool pkgAcqArchive::QueueNext()
a722b2c5 2140{
f7f0d6c7 2141 for (; Vf.end() == false; ++Vf)
03e39e59
AL
2142 {
2143 // Ignore not source sources
2144 if ((Vf.File()->Flags & pkgCache::Flag::NotSource) != 0)
2145 continue;
2146
2147 // Try to cross match against the source list
b2e465d6
AL
2148 pkgIndexFile *Index;
2149 if (Sources->FindIndex(Vf.File(),Index) == false)
2150 continue;
03e39e59 2151
b3d44315
MV
2152 // only try to get a trusted package from another source if that source
2153 // is also trusted
2154 if(Trusted && !Index->IsTrusted())
2155 continue;
2156
03e39e59
AL
2157 // Grab the text package record
2158 pkgRecords::Parser &Parse = Recs->Lookup(Vf);
2159 if (_error->PendingError() == true)
b185acc2 2160 return false;
b3501edb 2161
b2e465d6 2162 string PkgFile = Parse.FileName();
b3501edb
DK
2163 ExpectedHashes = Parse.Hashes();
2164
03e39e59 2165 if (PkgFile.empty() == true)
b2e465d6
AL
2166 return _error->Error(_("The package index files are corrupted. No Filename: "
2167 "field for package %s."),
2168 Version.ParentPkg().Name());
a6568219 2169
b3d44315
MV
2170 Desc.URI = Index->ArchiveURI(PkgFile);
2171 Desc.Description = Index->ArchiveInfo(Version);
2172 Desc.Owner = this;
40f8a8ba 2173 Desc.ShortDesc = Version.ParentPkg().FullName(true);
b3d44315 2174
17caf1b1 2175 // See if we already have the file. (Legacy filenames)
a6568219
AL
2176 FileSize = Version->Size;
2177 string FinalFile = _config->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile);
2178 struct stat Buf;
2179 if (stat(FinalFile.c_str(),&Buf) == 0)
2180 {
2181 // Make sure the size matches
73da43e9 2182 if ((unsigned long long)Buf.st_size == Version->Size)
a6568219
AL
2183 {
2184 Complete = true;
2185 Local = true;
2186 Status = StatDone;
30e1eab5 2187 StoreFilename = DestFile = FinalFile;
b185acc2 2188 return true;
a6568219
AL
2189 }
2190
6b1ff003
AL
2191 /* Hmm, we have a file and its size does not match, this means it is
2192 an old style mismatched arch */
a6568219
AL
2193 unlink(FinalFile.c_str());
2194 }
17caf1b1
AL
2195
2196 // Check it again using the new style output filenames
2197 FinalFile = _config->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename);
2198 if (stat(FinalFile.c_str(),&Buf) == 0)
2199 {
2200 // Make sure the size matches
73da43e9 2201 if ((unsigned long long)Buf.st_size == Version->Size)
17caf1b1
AL
2202 {
2203 Complete = true;
2204 Local = true;
2205 Status = StatDone;
2206 StoreFilename = DestFile = FinalFile;
2207 return true;
2208 }
2209
1e3f4083 2210 /* Hmm, we have a file and its size does not match, this shouldn't
17caf1b1
AL
2211 happen.. */
2212 unlink(FinalFile.c_str());
2213 }
2214
2215 DestFile = _config->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename);
6b1ff003
AL
2216
2217 // Check the destination file
2218 if (stat(DestFile.c_str(),&Buf) == 0)
2219 {
2220 // Hmm, the partial file is too big, erase it
73da43e9 2221 if ((unsigned long long)Buf.st_size > Version->Size)
6b1ff003
AL
2222 unlink(DestFile.c_str());
2223 else
2224 PartialSize = Buf.st_size;
2225 }
de31189f
DK
2226
2227 // Disables download of archives - useful if no real installation follows,
2228 // e.g. if we are just interested in proposed installation order
2229 if (_config->FindB("Debug::pkgAcqArchive::NoQueue", false) == true)
2230 {
2231 Complete = true;
2232 Local = true;
2233 Status = StatDone;
2234 StoreFilename = DestFile = FinalFile;
2235 return true;
2236 }
2237
03e39e59 2238 // Create the item
b2e465d6 2239 Local = false;
03e39e59 2240 QueueURI(Desc);
b185acc2 2241
f7f0d6c7 2242 ++Vf;
b185acc2 2243 return true;
03e39e59 2244 }
b185acc2
AL
2245 return false;
2246}
03e39e59
AL
2247 /*}}}*/
2248// AcqArchive::Done - Finished fetching /*{{{*/
2249// ---------------------------------------------------------------------
2250/* */
b3501edb 2251void pkgAcqArchive::Done(string Message,unsigned long long Size, HashStringList const &CalcHashes,
459681d3 2252 pkgAcquire::MethodConfig *Cfg)
03e39e59 2253{
b3501edb 2254 Item::Done(Message, Size, CalcHashes, Cfg);
03e39e59
AL
2255
2256 // Check the size
2257 if (Size != Version->Size)
2258 {
3c8030a4 2259 RenameOnError(SizeMismatch);
03e39e59
AL
2260 return;
2261 }
b3501edb 2262
0d29b9d4 2263 // FIXME: could this empty() check impose *any* sort of security issue?
b3501edb 2264 if(ExpectedHashes.usable() && ExpectedHashes != CalcHashes)
03e39e59 2265 {
3c8030a4 2266 RenameOnError(HashSumMismatch);
b3501edb 2267 printHashSumComparision(DestFile, ExpectedHashes, CalcHashes);
495e5cb2 2268 return;
03e39e59 2269 }
a6568219
AL
2270
2271 // Grab the output filename
03e39e59
AL
2272 string FileName = LookupTag(Message,"Filename");
2273 if (FileName.empty() == true)
2274 {
2275 Status = StatError;
2276 ErrorText = "Method gave a blank filename";
2277 return;
2278 }
a6568219
AL
2279
2280 Complete = true;
30e1eab5
AL
2281
2282 // Reference filename
a6568219
AL
2283 if (FileName != DestFile)
2284 {
30e1eab5 2285 StoreFilename = DestFile = FileName;
a6568219
AL
2286 Local = true;
2287 return;
2288 }
2289
2290 // Done, move it into position
2291 string FinalFile = _config->FindDir("Dir::Cache::Archives");
17caf1b1 2292 FinalFile += flNotDir(StoreFilename);
a6568219 2293 Rename(DestFile,FinalFile);
03e39e59 2294
30e1eab5 2295 StoreFilename = DestFile = FinalFile;
03e39e59
AL
2296 Complete = true;
2297}
2298 /*}}}*/
db890fdb
AL
2299// AcqArchive::Failed - Failure handler /*{{{*/
2300// ---------------------------------------------------------------------
2301/* Here we try other sources */
7d8afa39 2302void pkgAcqArchive::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
db890fdb
AL
2303{
2304 ErrorText = LookupTag(Message,"Message");
b2e465d6
AL
2305
2306 /* We don't really want to retry on failed media swaps, this prevents
2307 that. An interesting observation is that permanent failures are not
2308 recorded. */
2309 if (Cnf->Removable == true &&
2310 StringToBool(LookupTag(Message,"Transient-Failure"),false) == true)
2311 {
2312 // Vf = Version.FileList();
f7f0d6c7 2313 while (Vf.end() == false) ++Vf;
b2e465d6
AL
2314 StoreFilename = string();
2315 Item::Failed(Message,Cnf);
2316 return;
2317 }
2318
db890fdb 2319 if (QueueNext() == false)
7d8afa39
AL
2320 {
2321 // This is the retry counter
2322 if (Retries != 0 &&
2323 Cnf->LocalOnly == false &&
2324 StringToBool(LookupTag(Message,"Transient-Failure"),false) == true)
2325 {
2326 Retries--;
2327 Vf = Version.FileList();
2328 if (QueueNext() == true)
2329 return;
2330 }
2331
9dbb421f 2332 StoreFilename = string();
7d8afa39
AL
2333 Item::Failed(Message,Cnf);
2334 }
db890fdb
AL
2335}
2336 /*}}}*/
92fcbfc1 2337// AcqArchive::IsTrusted - Determine whether this archive comes from a trusted source /*{{{*/
b3d44315 2338// ---------------------------------------------------------------------
b3501edb 2339APT_PURE bool pkgAcqArchive::IsTrusted() const
b3d44315
MV
2340{
2341 return Trusted;
2342}
92fcbfc1 2343 /*}}}*/
ab559b35
AL
2344// AcqArchive::Finished - Fetching has finished, tidy up /*{{{*/
2345// ---------------------------------------------------------------------
2346/* */
2347void pkgAcqArchive::Finished()
2348{
2349 if (Status == pkgAcquire::Item::StatDone &&
2350 Complete == true)
2351 return;
2352 StoreFilename = string();
2353}
2354 /*}}}*/
36375005
AL
2355// AcqFile::pkgAcqFile - Constructor /*{{{*/
2356// ---------------------------------------------------------------------
2357/* The file is added to the queue */
b3501edb 2358pkgAcqFile::pkgAcqFile(pkgAcquire *Owner,string URI, HashStringList const &Hashes,
73da43e9 2359 unsigned long long Size,string Dsc,string ShortDesc,
77278c2b
MV
2360 const string &DestDir, const string &DestFilename,
2361 bool IsIndexFile) :
fa3b260f 2362 Item(Owner, Hashes), IsIndexFile(IsIndexFile)
36375005 2363{
08cfc005
AL
2364 Retries = _config->FindI("Acquire::Retries",0);
2365
46e00f9d
MV
2366 if(!DestFilename.empty())
2367 DestFile = DestFilename;
2368 else if(!DestDir.empty())
2369 DestFile = DestDir + "/" + flNotDir(URI);
2370 else
2371 DestFile = flNotDir(URI);
2372
36375005
AL
2373 // Create the item
2374 Desc.URI = URI;
2375 Desc.Description = Dsc;
2376 Desc.Owner = this;
2377
2378 // Set the short description to the archive component
2379 Desc.ShortDesc = ShortDesc;
2380
2381 // Get the transfer sizes
2382 FileSize = Size;
2383 struct stat Buf;
2384 if (stat(DestFile.c_str(),&Buf) == 0)
2385 {
2386 // Hmm, the partial file is too big, erase it
ed9665ae 2387 if ((Size > 0) && (unsigned long long)Buf.st_size > Size)
36375005
AL
2388 unlink(DestFile.c_str());
2389 else
2390 PartialSize = Buf.st_size;
2391 }
092ae175 2392
36375005
AL
2393 QueueURI(Desc);
2394}
2395 /*}}}*/
2396// AcqFile::Done - Item downloaded OK /*{{{*/
2397// ---------------------------------------------------------------------
2398/* */
b3501edb 2399void pkgAcqFile::Done(string Message,unsigned long long Size,HashStringList const &CalcHashes,
459681d3 2400 pkgAcquire::MethodConfig *Cnf)
36375005 2401{
b3501edb 2402 Item::Done(Message,Size,CalcHashes,Cnf);
495e5cb2 2403
8a8feb29 2404 // Check the hash
b3501edb 2405 if(ExpectedHashes.usable() && ExpectedHashes != CalcHashes)
b3c39978 2406 {
3c8030a4 2407 RenameOnError(HashSumMismatch);
b3501edb 2408 printHashSumComparision(DestFile, ExpectedHashes, CalcHashes);
495e5cb2 2409 return;
b3c39978
AL
2410 }
2411
36375005
AL
2412 string FileName = LookupTag(Message,"Filename");
2413 if (FileName.empty() == true)
2414 {
2415 Status = StatError;
2416 ErrorText = "Method gave a blank filename";
2417 return;
2418 }
2419
2420 Complete = true;
2421
2422 // The files timestamp matches
2423 if (StringToBool(LookupTag(Message,"IMS-Hit"),false) == true)
2424 return;
2425
2426 // We have to copy it into place
2427 if (FileName != DestFile)
2428 {
2429 Local = true;
459681d3
AL
2430 if (_config->FindB("Acquire::Source-Symlinks",true) == false ||
2431 Cnf->Removable == true)
917ae805
AL
2432 {
2433 Desc.URI = "copy:" + FileName;
2434 QueueURI(Desc);
2435 return;
2436 }
2437
83ab33fc
AL
2438 // Erase the file if it is a symlink so we can overwrite it
2439 struct stat St;
2440 if (lstat(DestFile.c_str(),&St) == 0)
2441 {
2442 if (S_ISLNK(St.st_mode) != 0)
2443 unlink(DestFile.c_str());
2444 }
2445
2446 // Symlink the file
917ae805
AL
2447 if (symlink(FileName.c_str(),DestFile.c_str()) != 0)
2448 {
83ab33fc 2449 ErrorText = "Link to " + DestFile + " failure ";
917ae805
AL
2450 Status = StatError;
2451 Complete = false;
2452 }
36375005
AL
2453 }
2454}
2455 /*}}}*/
08cfc005
AL
2456// AcqFile::Failed - Failure handler /*{{{*/
2457// ---------------------------------------------------------------------
2458/* Here we try other sources */
2459void pkgAcqFile::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
2460{
2461 ErrorText = LookupTag(Message,"Message");
2462
2463 // This is the retry counter
2464 if (Retries != 0 &&
2465 Cnf->LocalOnly == false &&
2466 StringToBool(LookupTag(Message,"Transient-Failure"),false) == true)
2467 {
2468 Retries--;
2469 QueueURI(Desc);
2470 return;
2471 }
2472
2473 Item::Failed(Message,Cnf);
2474}
2475 /*}}}*/
77278c2b
MV
2476// AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
2477// ---------------------------------------------------------------------
2478/* The only header we use is the last-modified header. */
b3501edb 2479string pkgAcqFile::Custom600Headers() const
77278c2b
MV
2480{
2481 if (IsIndexFile)
2482 return "\nIndex-File: true";
61a07c57 2483 return "";
77278c2b
MV
2484}
2485 /*}}}*/