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