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