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