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