1 // -*- mode: cpp; mode: fold -*-
3 // $Id: acquire-item.cc,v 1.46.2.9 2004/01/16 18:51:11 mdz Exp $
4 /* ######################################################################
6 Acquire Item - Item to acquire
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.
13 ##################################################################### */
15 // Include Files /*{{{*/
18 #include <apt-pkg/acquire-item.h>
19 #include <apt-pkg/configuration.h>
20 #include <apt-pkg/aptconfiguration.h>
21 #include <apt-pkg/sourcelist.h>
22 #include <apt-pkg/error.h>
23 #include <apt-pkg/strutl.h>
24 #include <apt-pkg/fileutl.h>
25 #include <apt-pkg/sha1.h>
26 #include <apt-pkg/tagfile.h>
27 #include <apt-pkg/indexrecords.h>
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>
53 static void printHashSumComparision(std::string
const &URI
, HashStringList
const &Expected
, HashStringList
const &Actual
) /*{{{*/
55 if (_config
->FindB("Debug::Acquire::HashSumMismatch", false) == false)
57 std::cerr
<< std::endl
<< URI
<< ":" << std::endl
<< " Expected Hash: " << std::endl
;
58 for (HashStringList::const_iterator hs
= Expected
.begin(); hs
!= Expected
.end(); ++hs
)
59 std::cerr
<< "\t- " << hs
->toStr() << std::endl
;
60 std::cerr
<< " Actual Hash: " << std::endl
;
61 for (HashStringList::const_iterator hs
= Actual
.begin(); hs
!= Actual
.end(); ++hs
)
62 std::cerr
<< "\t- " << hs
->toStr() << std::endl
;
66 // Acquire::Item::Item - Constructor /*{{{*/
68 #pragma GCC diagnostic push
69 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
71 pkgAcquire::Item::Item(pkgAcquire
*Owner
,
72 HashStringList
const &ExpectedHashes
,
73 pkgAcqMetaBase
*TransactionManager
)
74 : Owner(Owner
), FileSize(0), PartialSize(0), Mode(0), ID(0), Complete(false),
75 Local(false), QueueCounter(0), TransactionManager(TransactionManager
),
76 ExpectedAdditionalItems(0), ExpectedHashes(ExpectedHashes
)
80 if(TransactionManager
!= NULL
)
81 TransactionManager
->Add(this);
84 #pragma GCC diagnostic pop
87 // Acquire::Item::~Item - Destructor /*{{{*/
88 // ---------------------------------------------------------------------
90 pkgAcquire::Item::~Item()
95 // Acquire::Item::Failed - Item failed to download /*{{{*/
96 // ---------------------------------------------------------------------
97 /* We return to an idle state if there are still other queues that could
99 void pkgAcquire::Item::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
103 ErrorText
= LookupTag(Message
,"Message");
104 UsedMirror
= LookupTag(Message
,"UsedMirror");
105 if (QueueCounter
<= 1)
107 /* This indicates that the file is not available right now but might
108 be sometime later. If we do a retry cycle then this should be
110 if (Cnf
->LocalOnly
== true &&
111 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
122 // report mirror failure back to LP if we actually use a mirror
123 string FailReason
= LookupTag(Message
, "FailReason");
124 if(FailReason
.size() != 0)
125 ReportMirrorFailure(FailReason
);
127 ReportMirrorFailure(ErrorText
);
130 // Acquire::Item::Start - Item has begun to download /*{{{*/
131 // ---------------------------------------------------------------------
132 /* Stash status and the file size. Note that setting Complete means
133 sub-phases of the acquire process such as decompresion are operating */
134 void pkgAcquire::Item::Start(string
/*Message*/,unsigned long long Size
)
136 Status
= StatFetching
;
137 if (FileSize
== 0 && Complete
== false)
141 // Acquire::Item::Done - Item downloaded OK /*{{{*/
142 // ---------------------------------------------------------------------
144 void pkgAcquire::Item::Done(string Message
,unsigned long long Size
,HashStringList
const &/*Hash*/,
145 pkgAcquire::MethodConfig
* /*Cnf*/)
147 // We just downloaded something..
148 string FileName
= LookupTag(Message
,"Filename");
149 UsedMirror
= LookupTag(Message
,"UsedMirror");
150 if (Complete
== false && !Local
&& FileName
== DestFile
)
153 Owner
->Log
->Fetched(Size
,atoi(LookupTag(Message
,"Resume-Point","0").c_str()));
159 ErrorText
= string();
160 Owner
->Dequeue(this);
163 // Acquire::Item::Rename - Rename a file /*{{{*/
164 // ---------------------------------------------------------------------
165 /* This helper function is used by a lot of item methods as their final
167 bool pkgAcquire::Item::Rename(string From
,string To
)
169 if (rename(From
.c_str(),To
.c_str()) != 0)
172 snprintf(S
,sizeof(S
),_("rename failed, %s (%s -> %s)."),strerror(errno
),
173 From
.c_str(),To
.c_str());
181 bool pkgAcquire::Item::RenameOnError(pkgAcquire::Item::RenameOnErrorState
const error
)/*{{{*/
183 if(FileExists(DestFile
))
184 Rename(DestFile
, DestFile
+ ".FAILED");
188 case HashSumMismatch
:
189 ErrorText
= _("Hash Sum mismatch");
190 Status
= StatAuthError
;
191 ReportMirrorFailure("HashChecksumFailure");
194 ErrorText
= _("Size mismatch");
195 Status
= StatAuthError
;
196 ReportMirrorFailure("SizeFailure");
199 ErrorText
= _("Invalid file format");
201 // do not report as usually its not the mirrors fault, but Portal/Proxy
204 ErrorText
= _("Signature error");
208 ErrorText
= _("Does not start with a cleartext signature");
215 // Acquire::Item::ReportMirrorFailure /*{{{*/
216 // ---------------------------------------------------------------------
217 void pkgAcquire::Item::ReportMirrorFailure(string FailCode
)
219 // we only act if a mirror was used at all
220 if(UsedMirror
.empty())
223 std::cerr
<< "\nReportMirrorFailure: "
225 << " Uri: " << DescURI()
227 << FailCode
<< std::endl
;
229 const char *Args
[40];
231 string report
= _config
->Find("Methods::Mirror::ProblemReporting",
232 "/usr/lib/apt/apt-report-mirror-failure");
233 if(!FileExists(report
))
235 Args
[i
++] = report
.c_str();
236 Args
[i
++] = UsedMirror
.c_str();
237 Args
[i
++] = DescURI().c_str();
238 Args
[i
++] = FailCode
.c_str();
240 pid_t pid
= ExecFork();
243 _error
->Error("ReportMirrorFailure Fork failed");
248 execvp(Args
[0], (char**)Args
);
249 std::cerr
<< "Could not exec " << Args
[0] << std::endl
;
252 if(!ExecWait(pid
, "report-mirror-failure"))
254 _error
->Warning("Couldn't report problem to '%s'",
255 _config
->Find("Methods::Mirror::ProblemReporting").c_str());
259 // AcqDiffIndex::AcqDiffIndex - Constructor /*{{{*/
260 // ---------------------------------------------------------------------
261 /* Get the DiffIndex file first and see if there are patches available
262 * If so, create a pkgAcqIndexDiffs fetcher that will get and apply the
263 * patches. If anything goes wrong in that process, it will fall back to
264 * the original packages file
266 pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire
*Owner
,
267 pkgAcqMetaBase
*TransactionManager
,
268 IndexTarget
const * const Target
,
269 HashStringList
const &ExpectedHashes
,
270 indexRecords
*MetaIndexParser
)
271 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
,
272 MetaIndexParser
), PackagesFileReadyInPartial(false)
275 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
277 RealURI
= Target
->URI
;
279 Desc
.Description
= Target
->Description
+ "/DiffIndex";
280 Desc
.ShortDesc
= Target
->ShortDesc
;
281 Desc
.URI
= Target
->URI
+ ".diff/Index";
283 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
284 DestFile
+= URItoFileName(Desc
.URI
);
287 std::clog
<< "pkgAcqDiffIndex: " << Desc
.URI
<< std::endl
;
289 // look for the current package file
290 CurrentPackagesFile
= _config
->FindDir("Dir::State::lists");
291 CurrentPackagesFile
+= URItoFileName(RealURI
);
293 // FIXME: this file:/ check is a hack to prevent fetching
294 // from local sources. this is really silly, and
295 // should be fixed cleanly as soon as possible
296 if(!FileExists(CurrentPackagesFile
) ||
297 Desc
.URI
.substr(0,strlen("file:/")) == "file:/")
299 // we don't have a pkg file or we don't want to queue
301 std::clog
<< "No index file, local or canceld by user" << std::endl
;
307 std::clog
<< "pkgAcqDiffIndex::pkgAcqDiffIndex(): "
308 << CurrentPackagesFile
<< std::endl
;
314 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
315 // ---------------------------------------------------------------------
316 /* The only header we use is the last-modified header. */
317 string
pkgAcqDiffIndex::Custom600Headers() const
319 string Final
= _config
->FindDir("Dir::State::lists");
320 Final
+= URItoFileName(Desc
.URI
);
323 std::clog
<< "Custom600Header-IMS: " << Final
<< std::endl
;
326 if (stat(Final
.c_str(),&Buf
) != 0)
327 return "\nIndex-File: true";
329 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
332 bool pkgAcqDiffIndex::ParseDiffIndex(string IndexDiffFile
) /*{{{*/
335 std::clog
<< "pkgAcqDiffIndex::ParseIndexDiff() " << IndexDiffFile
340 vector
<DiffInfo
> available_patches
;
342 FileFd
Fd(IndexDiffFile
,FileFd::ReadOnly
);
344 if (_error
->PendingError() == true)
347 if(TF
.Step(Tags
) == true)
353 string
const tmp
= Tags
.FindS("SHA1-Current");
354 std::stringstream
ss(tmp
);
355 ss
>> ServerSha1
>> size
;
356 unsigned long const ServerSize
= atol(size
.c_str());
358 FileFd
fd(CurrentPackagesFile
, FileFd::ReadOnly
);
361 string
const local_sha1
= SHA1
.Result();
363 if(local_sha1
== ServerSha1
)
365 // we have the same sha1 as the server so we are done here
367 std::clog
<< "Package file is up-to-date" << std::endl
;
368 // ensure we have no leftovers from previous runs
369 std::string Partial
= _config
->FindDir("Dir::State::lists");
370 Partial
+= "partial/" + URItoFileName(RealURI
);
371 unlink(Partial
.c_str());
372 // list cleanup needs to know that this file as well as the already
373 // present index is ours, so we create an empty diff to save it for us
374 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
,
375 ExpectedHashes
, MetaIndexParser
,
376 ServerSha1
, available_patches
);
382 std::clog
<< "SHA1-Current: " << ServerSha1
<< " and we start at "<< fd
.Name() << " " << fd
.Size() << " " << local_sha1
<< std::endl
;
384 // check the historie and see what patches we need
385 string
const history
= Tags
.FindS("SHA1-History");
386 std::stringstream
hist(history
);
387 while(hist
>> d
.sha1
>> size
>> d
.file
)
389 // read until the first match is found
390 // from that point on, we probably need all diffs
391 if(d
.sha1
== local_sha1
)
393 else if (found
== false)
397 std::clog
<< "Need to get diff: " << d
.file
<< std::endl
;
398 available_patches
.push_back(d
);
401 if (available_patches
.empty() == false)
403 // patching with too many files is rather slow compared to a fast download
404 unsigned long const fileLimit
= _config
->FindI("Acquire::PDiffs::FileLimit", 0);
405 if (fileLimit
!= 0 && fileLimit
< available_patches
.size())
408 std::clog
<< "Need " << available_patches
.size() << " diffs (Limit is " << fileLimit
409 << ") so fallback to complete download" << std::endl
;
413 // see if the patches are too big
414 found
= false; // it was true and it will be true again at the end
415 d
= *available_patches
.begin();
416 string
const firstPatch
= d
.file
;
417 unsigned long patchesSize
= 0;
418 std::stringstream
patches(Tags
.FindS("SHA1-Patches"));
419 while(patches
>> d
.sha1
>> size
>> d
.file
)
421 if (firstPatch
== d
.file
)
423 else if (found
== false)
426 patchesSize
+= atol(size
.c_str());
428 unsigned long const sizeLimit
= ServerSize
* _config
->FindI("Acquire::PDiffs::SizeLimit", 100);
429 if (sizeLimit
> 0 && (sizeLimit
/100) < patchesSize
)
432 std::clog
<< "Need " << patchesSize
<< " bytes (Limit is " << sizeLimit
/100
433 << ") so fallback to complete download" << std::endl
;
439 // we have something, queue the next diff
442 // FIXME: make this use the method
443 PackagesFileReadyInPartial
= true;
444 std::string Partial
= _config
->FindDir("Dir::State::lists");
445 Partial
+= "partial/" + URItoFileName(RealURI
);
447 FileFd
From(CurrentPackagesFile
, FileFd::ReadOnly
);
448 FileFd
To(Partial
, FileFd::WriteEmpty
);
449 if(CopyFile(From
, To
) == false)
450 return _error
->Errno("CopyFile", "failed to copy");
453 std::cerr
<< "Done copying " << CurrentPackagesFile
458 string::size_type
const last_space
= Description
.rfind(" ");
459 if(last_space
!= string::npos
)
460 Description
.erase(last_space
, Description
.size()-last_space
);
462 /* decide if we should download patches one by one or in one go:
463 The first is good if the server merges patches, but many don't so client
464 based merging can be attempt in which case the second is better.
465 "bad things" will happen if patches are merged on the server,
466 but client side merging is attempt as well */
467 bool pdiff_merge
= _config
->FindB("Acquire::PDiffs::Merge", true);
468 if (pdiff_merge
== true)
470 // reprepro adds this flag if it has merged patches on the server
471 std::string
const precedence
= Tags
.FindS("X-Patch-Precedence");
472 pdiff_merge
= (precedence
!= "merged");
475 if (pdiff_merge
== false)
477 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
, ExpectedHashes
,
479 ServerSha1
, available_patches
);
483 std::vector
<pkgAcqIndexMergeDiffs
*> *diffs
= new std::vector
<pkgAcqIndexMergeDiffs
*>(available_patches
.size());
484 for(size_t i
= 0; i
< available_patches
.size(); ++i
)
485 (*diffs
)[i
] = new pkgAcqIndexMergeDiffs(Owner
,
490 available_patches
[i
],
501 // Nothing found, report and return false
502 // Failing here is ok, if we return false later, the full
503 // IndexFile is queued
505 std::clog
<< "Can't find a patch in the index file" << std::endl
;
509 void pkgAcqDiffIndex::Failed(string Message
,pkgAcquire::MethodConfig
* /*Cnf*/)/*{{{*/
512 std::clog
<< "pkgAcqDiffIndex failed: " << Desc
.URI
<< " with " << Message
<< std::endl
513 << "Falling back to normal index file acquire" << std::endl
;
515 new pkgAcqIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
);
522 void pkgAcqDiffIndex::Done(string Message
,unsigned long long Size
,HashStringList
const &Hashes
, /*{{{*/
523 pkgAcquire::MethodConfig
*Cnf
)
526 std::clog
<< "pkgAcqDiffIndex::Done(): " << Desc
.URI
<< std::endl
;
528 Item::Done(Message
, Size
, Hashes
, Cnf
);
531 FinalFile
= _config
->FindDir("Dir::State::lists")+URItoFileName(RealURI
);
533 // success in downloading the index
535 FinalFile
+= string(".IndexDiff");
537 std::clog
<< "Renaming: " << DestFile
<< " -> " << FinalFile
539 Rename(DestFile
,FinalFile
);
540 chmod(FinalFile
.c_str(),0644);
541 DestFile
= FinalFile
;
543 if(!ParseDiffIndex(DestFile
))
544 return Failed("", NULL
);
552 // AcqIndexDiffs::AcqIndexDiffs - Constructor /*{{{*/
553 // ---------------------------------------------------------------------
554 /* The package diff is added to the queue. one object is constructed
555 * for each diff and the index
557 pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire
*Owner
,
558 pkgAcqMetaBase
*TransactionManager
,
559 struct IndexTarget
const * const Target
,
560 HashStringList
const &ExpectedHashes
,
561 indexRecords
*MetaIndexParser
,
563 vector
<DiffInfo
> diffs
)
564 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
),
565 available_patches(diffs
), ServerSha1(ServerSha1
)
568 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
569 DestFile
+= URItoFileName(Target
->URI
);
571 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
573 RealURI
= Target
->URI
;
575 Description
= Target
->Description
;
576 Desc
.ShortDesc
= Target
->ShortDesc
;
578 if(available_patches
.empty() == true)
580 // we are done (yeah!), check hashes against the final file
581 DestFile
= _config
->FindDir("Dir::State::lists");
582 DestFile
+= URItoFileName(Target
->URI
);
588 State
= StateFetchDiff
;
593 void pkgAcqIndexDiffs::Failed(string Message
,pkgAcquire::MethodConfig
* /*Cnf*/)/*{{{*/
596 std::clog
<< "pkgAcqIndexDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
597 << "Falling back to normal index file acquire" << std::endl
;
598 new pkgAcqIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
);
602 // Finish - helper that cleans the item out of the fetcher queue /*{{{*/
603 void pkgAcqIndexDiffs::Finish(bool allDone
)
606 std::clog
<< "pkgAcqIndexDiffs::Finish(): "
608 << Desc
.URI
<< std::endl
;
610 // we restore the original name, this is required, otherwise
611 // the file will be cleaned
614 if(HashSums().usable() && !HashSums().VerifyFile(DestFile
))
616 RenameOnError(HashSumMismatch
);
622 PartialFile
= _config
->FindDir("Dir::State::lists")+"partial/"+URItoFileName(RealURI
);
624 DestFile
= _config
->FindDir("Dir::State::lists");
625 DestFile
+= URItoFileName(RealURI
);
627 // this happens if we have a up-to-date indexfile
628 if(!FileExists(PartialFile
))
629 PartialFile
= DestFile
;
631 // this is for the "real" finish
636 std::clog
<< "\n\nallDone: " << DestFile
<< "\n" << std::endl
;
641 std::clog
<< "Finishing: " << Desc
.URI
<< std::endl
;
648 bool pkgAcqIndexDiffs::QueueNextDiff() /*{{{*/
650 // calc sha1 of the just patched file
651 string FinalFile
= _config
->FindDir("Dir::State::lists");
652 FinalFile
+= "partial/" + URItoFileName(RealURI
);
654 if(!FileExists(FinalFile
))
656 Failed("No FinalFile " + FinalFile
+ " available", NULL
);
660 FileFd
fd(FinalFile
, FileFd::ReadOnly
);
663 string local_sha1
= string(SHA1
.Result());
665 std::clog
<< "QueueNextDiff: "
666 << FinalFile
<< " (" << local_sha1
<< ")"<<std::endl
;
669 // final file reached before all patches are applied
670 if(local_sha1
== ServerSha1
)
676 // remove all patches until the next matching patch is found
677 // this requires the Index file to be ordered
678 for(vector
<DiffInfo
>::iterator I
=available_patches
.begin();
679 available_patches
.empty() == false &&
680 I
!= available_patches
.end() &&
681 I
->sha1
!= local_sha1
;
684 available_patches
.erase(I
);
687 // error checking and falling back if no patch was found
688 if(available_patches
.empty() == true)
690 Failed("No patches available", NULL
);
694 // queue the right diff
695 Desc
.URI
= RealURI
+ ".diff/" + available_patches
[0].file
+ ".gz";
696 Desc
.Description
= Description
+ " " + available_patches
[0].file
+ string(".pdiff");
697 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
698 DestFile
+= URItoFileName(RealURI
+ ".diff/" + available_patches
[0].file
);
701 std::clog
<< "pkgAcqIndexDiffs::QueueNextDiff(): " << Desc
.URI
<< std::endl
;
708 void pkgAcqIndexDiffs::Done(string Message
,unsigned long long Size
, HashStringList
const &Hashes
, /*{{{*/
709 pkgAcquire::MethodConfig
*Cnf
)
712 std::clog
<< "pkgAcqIndexDiffs::Done(): " << Desc
.URI
<< std::endl
;
714 Item::Done(Message
, Size
, Hashes
, Cnf
);
717 FinalFile
= _config
->FindDir("Dir::State::lists")+"partial/"+URItoFileName(RealURI
);
719 // success in downloading a diff, enter ApplyDiff state
720 if(State
== StateFetchDiff
)
723 // rred excepts the patch as $FinalFile.ed
724 Rename(DestFile
,FinalFile
+".ed");
727 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
729 State
= StateApplyDiff
;
731 Desc
.URI
= "rred:" + FinalFile
;
733 ActiveSubprocess
= "rred";
735 #pragma GCC diagnostic push
736 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
740 #pragma GCC diagnostic pop
746 // success in download/apply a diff, queue next (if needed)
747 if(State
== StateApplyDiff
)
749 // remove the just applied patch
750 available_patches
.erase(available_patches
.begin());
751 unlink((FinalFile
+ ".ed").c_str());
756 std::clog
<< "Moving patched file in place: " << std::endl
757 << DestFile
<< " -> " << FinalFile
<< std::endl
;
759 Rename(DestFile
,FinalFile
);
760 chmod(FinalFile
.c_str(),0644);
762 // see if there is more to download
763 if(available_patches
.empty() == false) {
764 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
,
765 ExpectedHashes
, MetaIndexParser
,
766 ServerSha1
, available_patches
);
770 DestFile
= FinalFile
;
775 // AcqIndexMergeDiffs::AcqIndexMergeDiffs - Constructor /*{{{*/
776 pkgAcqIndexMergeDiffs::pkgAcqIndexMergeDiffs(pkgAcquire
*Owner
,
777 pkgAcqMetaBase
*TransactionManager
,
778 struct IndexTarget
const * const Target
,
779 HashStringList
const &ExpectedHashes
,
780 indexRecords
*MetaIndexParser
,
781 DiffInfo
const &patch
,
782 std::vector
<pkgAcqIndexMergeDiffs
*> const * const allPatches
)
783 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
),
784 patch(patch
), allPatches(allPatches
), State(StateFetchDiff
)
787 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
788 DestFile
+= URItoFileName(Target
->URI
);
790 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
792 RealURI
= Target
->URI
;
794 Description
= Target
->Description
;
795 Desc
.ShortDesc
= Target
->ShortDesc
;
797 Desc
.URI
= RealURI
+ ".diff/" + patch
.file
+ ".gz";
798 Desc
.Description
= Description
+ " " + patch
.file
+ string(".pdiff");
799 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
800 DestFile
+= URItoFileName(RealURI
+ ".diff/" + patch
.file
);
803 std::clog
<< "pkgAcqIndexMergeDiffs: " << Desc
.URI
<< std::endl
;
808 void pkgAcqIndexMergeDiffs::Failed(string Message
,pkgAcquire::MethodConfig
* /*Cnf*/)/*{{{*/
811 std::clog
<< "pkgAcqIndexMergeDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
;
816 // check if we are the first to fail, otherwise we are done here
817 State
= StateDoneDiff
;
818 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
819 I
!= allPatches
->end(); ++I
)
820 if ((*I
)->State
== StateErrorDiff
)
823 // first failure means we should fallback
824 State
= StateErrorDiff
;
825 std::clog
<< "Falling back to normal index file acquire" << std::endl
;
826 new pkgAcqIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
);
829 void pkgAcqIndexMergeDiffs::Done(string Message
,unsigned long long Size
,HashStringList
const &Hashes
, /*{{{*/
830 pkgAcquire::MethodConfig
*Cnf
)
833 std::clog
<< "pkgAcqIndexMergeDiffs::Done(): " << Desc
.URI
<< std::endl
;
835 Item::Done(Message
,Size
,Hashes
,Cnf
);
837 string
const FinalFile
= _config
->FindDir("Dir::State::lists") + "partial/" + URItoFileName(RealURI
);
839 if (State
== StateFetchDiff
)
841 // rred expects the patch as $FinalFile.ed.$patchname.gz
842 Rename(DestFile
, FinalFile
+ ".ed." + patch
.file
+ ".gz");
844 // check if this is the last completed diff
845 State
= StateDoneDiff
;
846 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
847 I
!= allPatches
->end(); ++I
)
848 if ((*I
)->State
!= StateDoneDiff
)
851 std::clog
<< "Not the last done diff in the batch: " << Desc
.URI
<< std::endl
;
855 // this is the last completed diff, so we are ready to apply now
856 State
= StateApplyDiff
;
859 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
862 Desc
.URI
= "rred:" + FinalFile
;
864 ActiveSubprocess
= "rred";
866 #pragma GCC diagnostic push
867 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
871 #pragma GCC diagnostic pop
875 // success in download/apply all diffs, clean up
876 else if (State
== StateApplyDiff
)
878 // see if we really got the expected file
879 if(ExpectedHashes
.usable() && !ExpectedHashes
.VerifyFile(DestFile
))
881 RenameOnError(HashSumMismatch
);
886 std::string FinalFile
= _config
->FindDir("Dir::State::lists");
887 FinalFile
+= URItoFileName(RealURI
);
889 // move the result into place
891 std::clog
<< "Queue patched file in place: " << std::endl
892 << DestFile
<< " -> " << FinalFile
<< std::endl
;
894 // queue for copy by the transaction manager
895 PartialFile
= DestFile
;
896 DestFile
= FinalFile
;
898 // ensure the ed's are gone regardless of list-cleanup
899 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
900 I
!= allPatches
->end(); ++I
)
902 std::string PartialFile
= _config
->FindDir("Dir::State::lists");
903 PartialFile
+= "partial/" + URItoFileName(RealURI
);
904 std::string patch
= PartialFile
+ ".ed." + (*I
)->patch
.file
+ ".gz";
905 std::cerr
<< patch
<< std::endl
;
906 unlink(patch
.c_str());
912 std::clog
<< "allDone: " << DestFile
<< "\n" << std::endl
;
916 // AcqIndex::AcqIndex - Constructor /*{{{*/
917 // ---------------------------------------------------------------------
918 /* The package file is added to the queue and a second class is
919 instantiated to fetch the revision file */
920 pkgAcqIndex::pkgAcqIndex(pkgAcquire
*Owner
,
921 string URI
,string URIDesc
,string ShortDesc
,
922 HashStringList
const &ExpectedHash
)
923 : pkgAcqBaseIndex(Owner
, 0, NULL
, ExpectedHash
, NULL
), RealURI(URI
)
925 AutoSelectCompression();
926 Init(URI
, URIDesc
, ShortDesc
);
928 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
929 std::clog
<< "New pkgIndex with TransactionManager "
930 << TransactionManager
<< std::endl
;
933 // AcqIndex::AcqIndex - Constructor /*{{{*/
934 // ---------------------------------------------------------------------
935 pkgAcqIndex::pkgAcqIndex(pkgAcquire
*Owner
,
936 pkgAcqMetaBase
*TransactionManager
,
937 IndexTarget
const *Target
,
938 HashStringList
const &ExpectedHash
,
939 indexRecords
*MetaIndexParser
)
940 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
, ExpectedHash
,
941 MetaIndexParser
), RealURI(Target
->URI
)
943 // autoselect the compression method
944 AutoSelectCompression();
945 Init(Target
->URI
, Target
->Description
, Target
->ShortDesc
);
947 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
948 std::clog
<< "New pkgIndex with TransactionManager "
949 << TransactionManager
<< std::endl
;
952 // AcqIndex::AutoSelectCompression - Select compression /*{{{*/
953 // ---------------------------------------------------------------------
954 void pkgAcqIndex::AutoSelectCompression()
956 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
957 CompressionExtension
= "";
958 if (ExpectedHashes
.usable())
960 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
961 if (*t
== "uncompressed" || MetaIndexParser
->Exists(string(Target
->MetaKey
).append(".").append(*t
)) == true)
962 CompressionExtension
.append(*t
).append(" ");
966 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
967 CompressionExtension
.append(*t
).append(" ");
969 if (CompressionExtension
.empty() == false)
970 CompressionExtension
.erase(CompressionExtension
.end()-1);
972 // AcqIndex::Init - defered Constructor /*{{{*/
973 // ---------------------------------------------------------------------
974 void pkgAcqIndex::Init(string
const &URI
, string
const &URIDesc
,
975 string
const &ShortDesc
)
977 Decompression
= false;
980 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
981 DestFile
+= URItoFileName(URI
);
983 std::string
const comprExt
= CompressionExtension
.substr(0, CompressionExtension
.find(' '));
984 if (comprExt
== "uncompressed")
988 MetaKey
= string(Target
->MetaKey
);
992 Desc
.URI
= URI
+ '.' + comprExt
;
993 DestFile
= DestFile
+ '.' + comprExt
;
995 MetaKey
= string(Target
->MetaKey
) + '.' + comprExt
;
1001 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(MetaKey
);
1003 FileSize
= Record
->Size
;
1005 InitByHashIfNeeded(MetaKey
);
1008 Desc
.Description
= URIDesc
;
1010 Desc
.ShortDesc
= ShortDesc
;
1015 // AcqIndex::AdjustForByHash - modify URI for by-hash support /*{{{*/
1016 // ---------------------------------------------------------------------
1018 void pkgAcqIndex::InitByHashIfNeeded(const std::string MetaKey
)
1021 // - (maybe?) add support for by-hash into the sources.list as flag
1022 // - make apt-ftparchive generate the hashes (and expire?)
1023 std::string HostKnob
= "APT::Acquire::" + ::URI(Desc
.URI
).Host
+ "::By-Hash";
1024 if(_config
->FindB("APT::Acquire::By-Hash", false) == true ||
1025 _config
->FindB(HostKnob
, false) == true ||
1026 MetaIndexParser
->GetSupportsAcquireByHash())
1028 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(MetaKey
);
1031 // FIXME: should we really use the best hash here? or a fixed one?
1032 const HashString
*TargetHash
= Record
->Hashes
.find("");
1033 std::string ByHash
= "/by-hash/" + TargetHash
->HashType() + "/" + TargetHash
->HashValue();
1034 size_t trailing_slash
= Desc
.URI
.find_last_of("/");
1035 Desc
.URI
= Desc
.URI
.replace(
1037 Desc
.URI
.substr(trailing_slash
+1).size()+1,
1041 "Fetching ByHash requested but can not find record for %s",
1047 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
1048 // ---------------------------------------------------------------------
1049 /* The only header we use is the last-modified header. */
1050 string
pkgAcqIndex::Custom600Headers() const
1052 string Final
= GetFinalFilename();
1054 string msg
= "\nIndex-File: true";
1056 if (stat(Final
.c_str(),&Buf
) == 0)
1057 msg
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1062 // pkgAcqIndex::Failed - getting the indexfile failed /*{{{*/
1063 // ---------------------------------------------------------------------
1065 void pkgAcqIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
1067 size_t const nextExt
= CompressionExtension
.find(' ');
1068 if (nextExt
!= std::string::npos
)
1070 CompressionExtension
= CompressionExtension
.substr(nextExt
+1);
1071 Init(RealURI
, Desc
.Description
, Desc
.ShortDesc
);
1075 // on decompression failure, remove bad versions in partial/
1076 if (Decompression
&& Erase
) {
1077 string s
= _config
->FindDir("Dir::State::lists") + "partial/";
1078 s
.append(URItoFileName(RealURI
));
1082 Item::Failed(Message
,Cnf
);
1084 /// cancel the entire transaction
1085 TransactionManager
->AbortTransaction();
1088 // pkgAcqIndex::GetFinalFilename - Return the full final file path /*{{{*/
1089 // ---------------------------------------------------------------------
1091 std::string
pkgAcqIndex::GetFinalFilename() const
1093 std::string
const compExt
= CompressionExtension
.substr(0, CompressionExtension
.find(' '));
1094 std::string FinalFile
= _config
->FindDir("Dir::State::lists");
1095 FinalFile
+= URItoFileName(RealURI
);
1096 if (_config
->FindB("Acquire::GzipIndexes",false) == true)
1097 FinalFile
+= '.' + compExt
;
1101 // AcqIndex::ReverifyAfterIMS - Reverify index after an ims-hit /*{{{*/
1102 // ---------------------------------------------------------------------
1104 void pkgAcqIndex::ReverifyAfterIMS()
1106 std::string
const compExt
= CompressionExtension
.substr(0, CompressionExtension
.find(' '));
1108 // update destfile to *not* include the compression extension when doing
1109 // a reverify (as its uncompressed on disk already)
1110 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1111 DestFile
+= URItoFileName(RealURI
);
1113 // adjust DestFile if its compressed on disk
1114 if (_config
->FindB("Acquire::GzipIndexes",false) == true)
1115 DestFile
+= '.' + compExt
;
1117 // copy FinalFile into partial/ so that we check the hash again
1118 string FinalFile
= GetFinalFilename();
1119 Decompression
= true;
1120 Desc
.URI
= "copy:" + FinalFile
;
1124 // AcqIndex::Done - Finished a fetch /*{{{*/
1125 // ---------------------------------------------------------------------
1126 /* This goes through a number of states.. On the initial fetch the
1127 method could possibly return an alternate filename which points
1128 to the uncompressed version of the file. If this is so the file
1129 is copied into the partial directory. In all other cases the file
1130 is decompressed with a compressed uri. */
1131 void pkgAcqIndex::Done(string Message
, unsigned long long Size
,
1132 HashStringList
const &Hashes
,
1133 pkgAcquire::MethodConfig
*Cfg
)
1135 Item::Done(Message
,Size
,Hashes
,Cfg
);
1136 std::string
const compExt
= CompressionExtension
.substr(0, CompressionExtension
.find(' '));
1138 if (Decompression
== true)
1140 if (ExpectedHashes
.usable() && ExpectedHashes
!= Hashes
)
1143 RenameOnError(HashSumMismatch
);
1144 printHashSumComparision(RealURI
, ExpectedHashes
, Hashes
);
1145 Failed(Message
, Cfg
);
1149 // FIXME: this can go away once we only ever download stuff that
1150 // has a valid hash and we never do GET based probing
1152 /* Always verify the index file for correctness (all indexes must
1153 * have a Package field) (LP: #346386) (Closes: #627642)
1155 FileFd
fd(DestFile
, FileFd::ReadOnly
, FileFd::Extension
);
1156 // Only test for correctness if the content of the file is not empty
1161 pkgTagFile
tag(&fd
);
1163 // all our current indexes have a field 'Package' in each section
1164 if (_error
->PendingError() == true || tag
.Step(sec
) == false || sec
.Exists("Package") == false)
1166 RenameOnError(InvalidFormat
);
1167 Failed(Message
, Cfg
);
1172 // FIXME: can we void the "Erase" bool here as its very non-local?
1173 std::string CompressedFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1174 CompressedFile
+= URItoFileName(RealURI
);
1176 // Remove the compressed version.
1178 unlink(CompressedFile
.c_str());
1180 // Done, queue for rename on transaction finished
1181 PartialFile
= DestFile
;
1182 DestFile
= GetFinalFilename();
1187 // FIXME: use the same method to find
1188 // check the compressed hash too
1189 if(MetaKey
!= "" && Hashes
.size() > 0)
1191 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(MetaKey
);
1192 if(Record
&& Record
->Hashes
.usable() && Hashes
!= Record
->Hashes
)
1194 RenameOnError(HashSumMismatch
);
1195 printHashSumComparision(RealURI
, Record
->Hashes
, Hashes
);
1196 Failed(Message
, Cfg
);
1204 // Handle the unzipd case
1205 string FileName
= LookupTag(Message
,"Alt-Filename");
1206 if (FileName
.empty() == false)
1208 Decompression
= true;
1210 DestFile
+= ".decomp";
1211 Desc
.URI
= "copy:" + FileName
;
1213 ActiveSubprocess
= "copy";
1215 #pragma GCC diagnostic push
1216 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
1220 #pragma GCC diagnostic pop
1225 FileName
= LookupTag(Message
,"Filename");
1226 if (FileName
.empty() == true)
1229 ErrorText
= "Method gave a blank filename";
1232 if (FileName
== DestFile
)
1237 // do not reverify cdrom sources as apt-cdrom may rewrite the Packages
1238 // file when its doing the indexcopy
1239 if (RealURI
.substr(0,6) == "cdrom:" &&
1240 StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
1243 // The files timestamp matches, reverify by copy into partial/
1244 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
1249 // set destfile to the final destfile
1250 if(_config
->FindB("Acquire::GzipIndexes",false) == false)
1252 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1253 DestFile
+= URItoFileName(RealURI
);
1256 ReverifyAfterIMS(FileName
);
1262 // If we enable compressed indexes, queue for hash verification
1263 if (_config
->FindB("Acquire::GzipIndexes",false))
1265 DestFile
= _config
->FindDir("Dir::State::lists");
1266 DestFile
+= URItoFileName(RealURI
) + '.' + compExt
;
1268 Decompression
= true;
1269 Desc
.URI
= "copy:" + FileName
;
1275 // get the binary name for your used compression type
1276 decompProg
= _config
->Find(string("Acquire::CompressionTypes::").append(compExt
),"");
1277 if(decompProg
.empty() == false);
1278 else if(compExt
== "uncompressed")
1279 decompProg
= "copy";
1281 _error
->Error("Unsupported extension: %s", compExt
.c_str());
1285 Decompression
= true;
1286 DestFile
+= ".decomp";
1287 Desc
.URI
= decompProg
+ ":" + FileName
;
1290 ActiveSubprocess
= decompProg
;
1292 #pragma GCC diagnostic push
1293 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
1295 Mode
= ActiveSubprocess
.c_str();
1297 #pragma GCC diagnostic pop
1301 // AcqIndexTrans::pkgAcqIndexTrans - Constructor /*{{{*/
1302 // ---------------------------------------------------------------------
1303 /* The Translation file is added to the queue */
1304 pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire
*Owner
,
1305 string URI
,string URIDesc
,string ShortDesc
)
1306 : pkgAcqIndex(Owner
, URI
, URIDesc
, ShortDesc
, HashStringList())
1310 pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire
*Owner
,
1311 pkgAcqMetaBase
*TransactionManager
,
1312 IndexTarget
const * const Target
,
1313 HashStringList
const &ExpectedHashes
,
1314 indexRecords
*MetaIndexParser
)
1315 : pkgAcqIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
)
1317 // load the filesize
1318 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(string(Target
->MetaKey
));
1320 FileSize
= Record
->Size
;
1323 // AcqIndexTrans::Custom600Headers - Insert custom request headers /*{{{*/
1324 // ---------------------------------------------------------------------
1325 string
pkgAcqIndexTrans::Custom600Headers() const
1327 string Final
= GetFinalFilename();
1330 if (stat(Final
.c_str(),&Buf
) != 0)
1331 return "\nFail-Ignore: true\nIndex-File: true";
1332 return "\nFail-Ignore: true\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1335 // AcqIndexTrans::Failed - Silence failure messages for missing files /*{{{*/
1336 // ---------------------------------------------------------------------
1338 void pkgAcqIndexTrans::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1340 size_t const nextExt
= CompressionExtension
.find(' ');
1341 if (nextExt
!= std::string::npos
)
1343 CompressionExtension
= CompressionExtension
.substr(nextExt
+1);
1344 Init(RealURI
, Desc
.Description
, Desc
.ShortDesc
);
1349 // FIXME: this is used often (e.g. in pkgAcqIndexTrans) so refactor
1350 if (Cnf
->LocalOnly
== true ||
1351 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1360 Item::Failed(Message
,Cnf
);
1364 void pkgAcqMetaBase::Add(Item
*I
)
1366 Transaction
.push_back(I
);
1369 void pkgAcqMetaBase::AbortTransaction()
1371 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1372 std::clog
<< "AbortTransaction: " << TransactionManager
<< std::endl
;
1374 // ensure the toplevel is in error state too
1375 for (std::vector
<Item
*>::iterator I
= Transaction
.begin();
1376 I
!= Transaction
.end(); ++I
)
1378 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1379 std::clog
<< " Cancel: " << (*I
)->DestFile
<< std::endl
;
1380 // the transaction will abort, so stop anything that is idle
1381 if ((*I
)->Status
== pkgAcquire::Item::StatIdle
)
1382 (*I
)->Status
= pkgAcquire::Item::StatDone
;
1386 bool pkgAcqMetaBase::TransactionHasError()
1388 for (pkgAcquire::ItemIterator I
= Transaction
.begin();
1389 I
!= Transaction
.end(); ++I
)
1390 if((*I
)->Status
!= pkgAcquire::Item::StatDone
&&
1391 (*I
)->Status
!= pkgAcquire::Item::StatIdle
)
1396 // Acquire::CommitTransaction - Commit a transaction /*{{{*/
1397 void pkgAcqMetaBase::CommitTransaction()
1399 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1400 std::clog
<< "CommitTransaction: " << this << std::endl
;
1402 // move new files into place *and* remove files that are not
1403 // part of the transaction but are still on disk
1404 for (std::vector
<Item
*>::iterator I
= Transaction
.begin();
1405 I
!= Transaction
.end(); ++I
)
1407 if((*I
)->PartialFile
!= "")
1409 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1411 << (*I
)->PartialFile
<< " -> "
1412 << (*I
)->DestFile
<< " "
1415 Rename((*I
)->PartialFile
, (*I
)->DestFile
);
1416 chmod((*I
)->DestFile
.c_str(),0644);
1418 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1424 unlink((*I
)->DestFile
.c_str());
1426 // mark that this transaction is finished
1427 (*I
)->TransactionManager
= 0;
1432 bool pkgAcqMetaBase::GenerateAuthWarning(const std::string
&RealURI
,
1433 const std::string
&Message
)
1435 string Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1437 if(FileExists(Final
))
1439 Status
= StatTransientNetworkError
;
1440 _error
->Warning(_("An error occurred during the signature "
1441 "verification. The repository is not updated "
1442 "and the previous index files will be used. "
1443 "GPG error: %s: %s\n"),
1444 Desc
.Description
.c_str(),
1445 LookupTag(Message
,"Message").c_str());
1446 RunScripts("APT::Update::Auth-Failure");
1448 } else if (LookupTag(Message
,"Message").find("NODATA") != string::npos
) {
1449 /* Invalid signature file, reject (LP: #346386) (Closes: #627642) */
1450 _error
->Error(_("GPG error: %s: %s"),
1451 Desc
.Description
.c_str(),
1452 LookupTag(Message
,"Message").c_str());
1456 _error
->Warning(_("GPG error: %s: %s"),
1457 Desc
.Description
.c_str(),
1458 LookupTag(Message
,"Message").c_str());
1460 // gpgv method failed
1461 ReportMirrorFailure("GPGFailure");
1467 pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire
*Owner
, /*{{{*/
1468 pkgAcqMetaBase
*TransactionManager
,
1469 string URI
,string URIDesc
,string ShortDesc
,
1470 string MetaIndexFile
,
1471 const vector
<IndexTarget
*>* IndexTargets
,
1472 indexRecords
* MetaIndexParser
) :
1473 pkgAcqMetaBase(Owner
, IndexTargets
, MetaIndexParser
,
1474 HashStringList(), TransactionManager
),
1475 RealURI(URI
), MetaIndexFile(MetaIndexFile
), URIDesc(URIDesc
),
1476 ShortDesc(ShortDesc
), AuthPass(false), IMSHit(false)
1478 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1479 DestFile
+= URItoFileName(URI
);
1481 // remove any partial downloaded sig-file in partial/.
1482 // it may confuse proxies and is too small to warrant a
1483 // partial download anyway
1484 unlink(DestFile
.c_str());
1486 // set the TransactionManager
1487 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1488 std::clog
<< "New pkgAcqMetaSig with TransactionManager "
1489 << TransactionManager
<< std::endl
;
1492 Desc
.Description
= URIDesc
;
1494 Desc
.ShortDesc
= ShortDesc
;
1500 pkgAcqMetaSig::~pkgAcqMetaSig() /*{{{*/
1504 // pkgAcqMetaSig::Custom600Headers - Insert custom request headers /*{{{*/
1505 // ---------------------------------------------------------------------
1506 /* The only header we use is the last-modified header. */
1507 string
pkgAcqMetaSig::Custom600Headers() const
1509 string FinalFile
= _config
->FindDir("Dir::State::lists");
1510 FinalFile
+= URItoFileName(RealURI
);
1513 if (stat(FinalFile
.c_str(),&Buf
) != 0)
1514 return "\nIndex-File: true";
1516 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1519 void pkgAcqMetaSig::Done(string Message
,unsigned long long Size
, HashStringList
const &Hashes
,
1520 pkgAcquire::MethodConfig
*Cfg
)
1522 Item::Done(Message
, Size
, Hashes
, Cfg
);
1524 string FileName
= LookupTag(Message
,"Filename");
1525 if (FileName
.empty() == true)
1528 ErrorText
= "Method gave a blank filename";
1532 if (FileName
!= DestFile
)
1534 // We have to copy it into place
1536 Desc
.URI
= "copy:" + FileName
;
1541 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
1544 // adjust paths if its a ims-hit
1547 string FinalFile
= _config
->FindDir("Dir::State::lists");
1548 FinalFile
+= URItoFileName(RealURI
);
1550 DestFile
= PartialFile
= FinalFile
;
1554 if(AuthPass
== false)
1557 Desc
.URI
= "gpgv:" + DestFile
;
1558 DestFile
= MetaIndexFile
;
1563 // queue to copy the file in place if it was not a ims hit, on ims
1564 // hit the file is already at the right place
1567 PartialFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1568 PartialFile
+= URItoFileName(RealURI
);
1570 DestFile
= _config
->FindDir("Dir::State::lists");
1571 DestFile
+= URItoFileName(RealURI
);
1574 // we parse the MetaIndexFile here because at this point we can
1576 if(AuthPass
== true)
1578 // load indexes and queue further downloads
1579 MetaIndexParser
->Load(MetaIndexFile
);
1586 void pkgAcqMetaSig::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)/*{{{*/
1588 string Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1590 // FIXME: meh, this is not really elegant
1591 string InReleaseURI
= RealURI
.replace(RealURI
.rfind("Release.gpg"), 12,
1593 string FinalInRelease
= _config
->FindDir("Dir::State::lists") + URItoFileName(InReleaseURI
);
1595 if(RealFileExists(Final
) || RealFileExists(FinalInRelease
))
1597 _error
->Error("The repository '%s' is no longer signed.",
1599 Rename(MetaIndexFile
, MetaIndexFile
+".FAILED");
1600 Status
= pkgAcquire::Item::StatError
;
1601 TransactionManager
->AbortTransaction();
1605 // this ensures that any file in the lists/ dir is removed by the
1607 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1608 DestFile
+= URItoFileName(RealURI
);
1611 // FIXME: duplicated code from pkgAcqMetaIndex
1612 if (AuthPass
== true)
1614 bool Stop
= GenerateAuthWarning(RealURI
, Message
);
1619 // only allow going further if the users explicitely wants it
1620 if(_config
->FindB("APT::Get::AllowUnauthenticated", false) == true)
1622 // we parse the indexes here because at this point the user wanted
1623 // a repository that may potentially harm him
1624 MetaIndexParser
->Load(MetaIndexFile
);
1629 _error
->Warning("Use --allow-unauthenticated to force the update");
1632 // FIXME: this is used often (e.g. in pkgAcqIndexTrans) so refactor
1633 if (Cnf
->LocalOnly
== true ||
1634 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1642 Item::Failed(Message
,Cnf
);
1645 pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire
*Owner
, /*{{{*/
1646 pkgAcqMetaBase
*TransactionManager
,
1647 string URI
,string URIDesc
,string ShortDesc
,
1648 string MetaIndexSigURI
,string MetaIndexSigURIDesc
, string MetaIndexSigShortDesc
,
1649 const vector
<IndexTarget
*>* IndexTargets
,
1650 indexRecords
* MetaIndexParser
) :
1651 pkgAcqMetaBase(Owner
, IndexTargets
, MetaIndexParser
, HashStringList(),
1652 TransactionManager
),
1653 RealURI(URI
), URIDesc(URIDesc
), ShortDesc(ShortDesc
),
1654 AuthPass(false), IMSHit(false),
1655 MetaIndexSigURI(MetaIndexSigURI
), MetaIndexSigURIDesc(MetaIndexSigURIDesc
),
1656 MetaIndexSigShortDesc(MetaIndexSigShortDesc
)
1658 if(TransactionManager
== NULL
)
1660 this->TransactionManager
= this;
1661 this->TransactionManager
->Add(this);
1664 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1665 std::clog
<< "New pkgAcqMetaIndex with TransactionManager "
1666 << this->TransactionManager
<< std::endl
;
1669 Init(URIDesc
, ShortDesc
);
1672 // pkgAcqMetaIndex::Init - Delayed constructor /*{{{*/
1673 void pkgAcqMetaIndex::Init(std::string URIDesc
, std::string ShortDesc
)
1675 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1676 DestFile
+= URItoFileName(RealURI
);
1679 Desc
.Description
= URIDesc
;
1681 Desc
.ShortDesc
= ShortDesc
;
1684 // we expect more item
1685 ExpectedAdditionalItems
= IndexTargets
->size();
1688 // pkgAcqMetaIndex::Custom600Headers - Insert custom request headers /*{{{*/
1689 // ---------------------------------------------------------------------
1690 /* The only header we use is the last-modified header. */
1691 string
pkgAcqMetaIndex::Custom600Headers() const
1693 string Final
= _config
->FindDir("Dir::State::lists");
1694 Final
+= URItoFileName(RealURI
);
1697 if (stat(Final
.c_str(),&Buf
) != 0)
1698 return "\nIndex-File: true";
1700 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1703 void pkgAcqMetaIndex::Done(string Message
,unsigned long long Size
,HashStringList
const &Hashes
, /*{{{*/
1704 pkgAcquire::MethodConfig
*Cfg
)
1706 Item::Done(Message
,Size
,Hashes
,Cfg
);
1708 // MetaIndexes are done in two passes: one to download the
1709 // metaindex with an appropriate method, and a second to verify it
1710 // with the gpgv method
1712 if (AuthPass
== true)
1716 // all cool, move Release file into place
1721 RetrievalDone(Message
);
1723 // Still more retrieving to do
1728 // There was a signature file, so pass it to gpgv for
1730 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1731 std::cerr
<< "Metaindex acquired, queueing gpg verification ("
1732 << SigFile
<< "," << DestFile
<< ")\n";
1734 Desc
.URI
= "gpgv:" + SigFile
;
1736 ActiveSubprocess
= "gpgv";
1738 #pragma GCC diagnostic push
1739 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
1743 #pragma GCC diagnostic pop
1749 if (Complete
== true)
1751 string FinalFile
= _config
->FindDir("Dir::State::lists");
1752 FinalFile
+= URItoFileName(RealURI
);
1753 if (SigFile
== DestFile
)
1754 SigFile
= FinalFile
;
1755 // queue for copy in place
1756 PartialFile
= DestFile
;
1757 DestFile
= FinalFile
;
1761 void pkgAcqMetaIndex::RetrievalDone(string Message
) /*{{{*/
1763 // We have just finished downloading a Release file (it is not
1766 string FileName
= LookupTag(Message
,"Filename");
1767 if (FileName
.empty() == true)
1770 ErrorText
= "Method gave a blank filename";
1774 if (FileName
!= DestFile
)
1777 Desc
.URI
= "copy:" + FileName
;
1782 // make sure to verify against the right file on I-M-S hit
1783 IMSHit
= StringToBool(LookupTag(Message
,"IMS-Hit"),false);
1786 string FinalFile
= _config
->FindDir("Dir::State::lists");
1787 FinalFile
+= URItoFileName(RealURI
);
1788 if (SigFile
== DestFile
)
1790 SigFile
= FinalFile
;
1792 // constructor of pkgAcqMetaClearSig moved it out of the way,
1793 // now move it back in on IMS hit for the 'old' file
1794 string
const OldClearSig
= DestFile
+ ".reverify";
1795 if (RealFileExists(OldClearSig
) == true)
1796 Rename(OldClearSig
, FinalFile
);
1799 DestFile
= FinalFile
;
1802 // queue a signature
1803 if(SigFile
!= DestFile
)
1804 new pkgAcqMetaSig(Owner
, TransactionManager
,
1805 MetaIndexSigURI
, MetaIndexSigURIDesc
,
1806 MetaIndexSigShortDesc
, DestFile
, IndexTargets
,
1812 void pkgAcqMetaIndex::AuthDone(string Message
) /*{{{*/
1814 // At this point, the gpgv method has succeeded, so there is a
1815 // valid signature from a key in the trusted keyring. We
1816 // perform additional verification of its contents, and use them
1817 // to verify the indexes we are about to download
1819 if (!MetaIndexParser
->Load(DestFile
))
1821 Status
= StatAuthError
;
1822 ErrorText
= MetaIndexParser
->ErrorText
;
1826 if (!VerifyVendor(Message
))
1831 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1832 std::cerr
<< "Signature verification succeeded: "
1833 << DestFile
<< std::endl
;
1835 // we ensure this by other means
1837 // do not trust any previously unverified content that we may have
1838 string LastGoodSigFile
= _config
->FindDir("Dir::State::lists").append("partial/").append(URItoFileName(RealURI
));
1839 if (DestFile
!= SigFile
)
1840 LastGoodSigFile
.append(".gpg");
1841 LastGoodSigFile
.append(".reverify");
1842 if(IMSHit
== false && RealFileExists(LastGoodSigFile
) == false)
1844 for (vector
<struct IndexTarget
*>::const_iterator Target
= IndexTargets
->begin();
1845 Target
!= IndexTargets
->end();
1848 // remove old indexes
1849 std::string index
= _config
->FindDir("Dir::State::lists") +
1850 URItoFileName((*Target
)->URI
);
1851 unlink(index
.c_str());
1852 // and also old gzipindexes
1853 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
1854 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
1856 index
+= '.' + (*t
);
1857 unlink(index
.c_str());
1863 // Download further indexes with verification
1865 // it would be really nice if we could simply do
1866 // if (IMSHit == false) QueueIndexes(true)
1867 // and skip the download if the Release file has not changed
1868 // - but right now the list cleaner will needs to be tricked
1869 // to not delete all our packages/source indexes in this case
1873 // is it a clearsigned MetaIndex file?
1874 if (DestFile
== SigFile
)
1877 // Done, move signature file into position
1878 string VerifiedSigFile
= _config
->FindDir("Dir::State::lists") +
1879 URItoFileName(RealURI
) + ".gpg";
1880 Rename(SigFile
,VerifiedSigFile
);
1881 chmod(VerifiedSigFile
.c_str(),0644);
1885 void pkgAcqMetaBase::QueueIndexes(bool verify
) /*{{{*/
1887 bool transInRelease
= false;
1889 std::vector
<std::string
> const keys
= MetaIndexParser
->MetaKeys();
1890 for (std::vector
<std::string
>::const_iterator k
= keys
.begin(); k
!= keys
.end(); ++k
)
1891 // FIXME: Feels wrong to check for hardcoded string here, but what should we do else…
1892 if (k
->find("Translation-") != std::string::npos
)
1894 transInRelease
= true;
1899 // at this point the real Items are loaded in the fetcher
1900 ExpectedAdditionalItems
= 0;
1901 for (vector
<IndexTarget
*>::const_iterator Target
= IndexTargets
->begin();
1902 Target
!= IndexTargets
->end();
1905 HashStringList ExpectedIndexHashes
;
1906 const indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup((*Target
)->MetaKey
);
1907 bool compressedAvailable
= false;
1910 if ((*Target
)->IsOptional() == true)
1912 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
1913 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
1914 if (MetaIndexParser
->Exists((*Target
)->MetaKey
+ "." + *t
) == true)
1916 compressedAvailable
= true;
1920 else if (verify
== true)
1922 Status
= StatAuthError
;
1923 strprintf(ErrorText
, _("Unable to find expected entry '%s' in Release file (Wrong sources.list entry or malformed file)"), (*Target
)->MetaKey
.c_str());
1929 ExpectedIndexHashes
= Record
->Hashes
;
1930 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1932 std::cerr
<< "Queueing: " << (*Target
)->URI
<< std::endl
1933 << "Expected Hash:" << std::endl
;
1934 for (HashStringList::const_iterator hs
= ExpectedIndexHashes
.begin(); hs
!= ExpectedIndexHashes
.end(); ++hs
)
1935 std::cerr
<< "\t- " << hs
->toStr() << std::endl
;
1936 std::cerr
<< "For: " << Record
->MetaKeyFilename
<< std::endl
;
1938 if (verify
== true && ExpectedIndexHashes
.empty() == true && (*Target
)->IsOptional() == false)
1940 Status
= StatAuthError
;
1941 strprintf(ErrorText
, _("Unable to find hash sum for '%s' in Release file"), (*Target
)->MetaKey
.c_str());
1946 if ((*Target
)->IsOptional() == true)
1948 if (transInRelease
== false || Record
!= NULL
|| compressedAvailable
== true)
1950 if (_config
->FindB("Acquire::PDiffs",true) == true && transInRelease
== true &&
1951 MetaIndexParser
->Exists((*Target
)->MetaKey
+ ".diff/Index") == true)
1952 new pkgAcqDiffIndex(Owner
, TransactionManager
, *Target
, ExpectedIndexHashes
, MetaIndexParser
);
1954 new pkgAcqIndexTrans(Owner
, TransactionManager
, *Target
, ExpectedIndexHashes
, MetaIndexParser
);
1959 /* Queue Packages file (either diff or full packages files, depending
1960 on the users option) - we also check if the PDiff Index file is listed
1961 in the Meta-Index file. Ideal would be if pkgAcqDiffIndex would test this
1962 instead, but passing the required info to it is to much hassle */
1963 if(_config
->FindB("Acquire::PDiffs",true) == true && (verify
== false ||
1964 MetaIndexParser
->Exists((*Target
)->MetaKey
+ ".diff/Index") == true))
1965 new pkgAcqDiffIndex(Owner
, TransactionManager
, *Target
, ExpectedIndexHashes
, MetaIndexParser
);
1967 new pkgAcqIndex(Owner
, TransactionManager
, *Target
, ExpectedIndexHashes
, MetaIndexParser
);
1971 bool pkgAcqMetaIndex::VerifyVendor(string Message
) /*{{{*/
1973 string::size_type pos
;
1975 // check for missing sigs (that where not fatal because otherwise we had
1978 string msg
= _("There is no public key available for the "
1979 "following key IDs:\n");
1980 pos
= Message
.find("NO_PUBKEY ");
1981 if (pos
!= std::string::npos
)
1983 string::size_type start
= pos
+strlen("NO_PUBKEY ");
1984 string Fingerprint
= Message
.substr(start
, Message
.find("\n")-start
);
1985 missingkeys
+= (Fingerprint
);
1987 if(!missingkeys
.empty())
1988 _error
->Warning("%s", (msg
+ missingkeys
).c_str());
1990 string Transformed
= MetaIndexParser
->GetExpectedDist();
1992 if (Transformed
== "../project/experimental")
1994 Transformed
= "experimental";
1997 pos
= Transformed
.rfind('/');
1998 if (pos
!= string::npos
)
2000 Transformed
= Transformed
.substr(0, pos
);
2003 if (Transformed
== ".")
2008 if (_config
->FindB("Acquire::Check-Valid-Until", true) == true &&
2009 MetaIndexParser
->GetValidUntil() > 0) {
2010 time_t const invalid_since
= time(NULL
) - MetaIndexParser
->GetValidUntil();
2011 if (invalid_since
> 0)
2012 // TRANSLATOR: The first %s is the URL of the bad Release file, the second is
2013 // the time since then the file is invalid - formated in the same way as in
2014 // the download progress display (e.g. 7d 3h 42min 1s)
2015 return _error
->Error(
2016 _("Release file for %s is expired (invalid since %s). "
2017 "Updates for this repository will not be applied."),
2018 RealURI
.c_str(), TimeToStr(invalid_since
).c_str());
2021 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
2023 std::cerr
<< "Got Codename: " << MetaIndexParser
->GetDist() << std::endl
;
2024 std::cerr
<< "Expecting Dist: " << MetaIndexParser
->GetExpectedDist() << std::endl
;
2025 std::cerr
<< "Transformed Dist: " << Transformed
<< std::endl
;
2028 if (MetaIndexParser
->CheckDist(Transformed
) == false)
2030 // This might become fatal one day
2031 // Status = StatAuthError;
2032 // ErrorText = "Conflicting distribution; expected "
2033 // + MetaIndexParser->GetExpectedDist() + " but got "
2034 // + MetaIndexParser->GetDist();
2036 if (!Transformed
.empty())
2038 _error
->Warning(_("Conflicting distribution: %s (expected %s but got %s)"),
2039 Desc
.Description
.c_str(),
2040 Transformed
.c_str(),
2041 MetaIndexParser
->GetDist().c_str());
2048 // pkgAcqMetaIndex::Failed - no Release file present or no signature file present /*{{{*/
2049 // ---------------------------------------------------------------------
2051 void pkgAcqMetaIndex::Failed(string Message
,
2052 pkgAcquire::MethodConfig
* /*Cnf*/)
2054 string Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
2056 if (AuthPass
== true)
2058 bool Stop
= GenerateAuthWarning(RealURI
, Message
);
2063 /* Always move the meta index, even if gpgv failed. This ensures
2064 * that PackageFile objects are correctly filled in */
2065 if (FileExists(DestFile
))
2067 string FinalFile
= _config
->FindDir("Dir::State::lists");
2068 FinalFile
+= URItoFileName(RealURI
);
2069 /* InRelease files become Release files, otherwise
2070 * they would be considered as trusted later on */
2071 if (SigFile
== DestFile
) {
2072 RealURI
= RealURI
.replace(RealURI
.rfind("InRelease"), 9,
2074 FinalFile
= FinalFile
.replace(FinalFile
.rfind("InRelease"), 9,
2076 SigFile
= FinalFile
;
2079 // Done, queue for rename on transaction finished
2080 PartialFile
= DestFile
;
2081 DestFile
= FinalFile
;
2084 _error
->Warning(_("The data from '%s' is not signed. Packages "
2085 "from that repository can not be authenticated."),
2088 // No Release file was present, or verification failed, so fall
2089 // back to queueing Packages files without verification
2090 // only allow going further if the users explicitely wants it
2091 if(_config
->FindB("APT::Get::AllowUnauthenticated", false) == true)
2093 QueueIndexes(false);
2095 // warn if the repository is unsinged
2096 _error
->Warning("Use --allow-unauthenticated to force the update");
2101 void pkgAcqMetaIndex::Finished()
2103 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
2104 std::clog
<< "Finished: " << DestFile
<<std::endl
;
2105 if(TransactionManager
!= NULL
&&
2106 TransactionManager
->TransactionHasError() == false)
2107 TransactionManager
->CommitTransaction();
2111 pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire
*Owner
, /*{{{*/
2112 string
const &URI
, string
const &URIDesc
, string
const &ShortDesc
,
2113 string
const &MetaIndexURI
, string
const &MetaIndexURIDesc
, string
const &MetaIndexShortDesc
,
2114 string
const &MetaSigURI
, string
const &MetaSigURIDesc
, string
const &MetaSigShortDesc
,
2115 const vector
<IndexTarget
*>* IndexTargets
,
2116 indexRecords
* MetaIndexParser
) :
2117 pkgAcqMetaIndex(Owner
, NULL
, URI
, URIDesc
, ShortDesc
, MetaSigURI
, MetaSigURIDesc
,MetaSigShortDesc
, IndexTargets
, MetaIndexParser
),
2118 MetaIndexURI(MetaIndexURI
), MetaIndexURIDesc(MetaIndexURIDesc
), MetaIndexShortDesc(MetaIndexShortDesc
),
2119 MetaSigURI(MetaSigURI
), MetaSigURIDesc(MetaSigURIDesc
), MetaSigShortDesc(MetaSigShortDesc
)
2123 // index targets + (worst case:) Release/Release.gpg
2124 ExpectedAdditionalItems
= IndexTargets
->size() + 2;
2127 // keep the old InRelease around in case of transistent network errors
2128 string
const Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
2129 if (RealFileExists(Final
) == true)
2131 string
const LastGoodSig
= DestFile
+ ".reverify";
2132 Rename(Final
,LastGoodSig
);
2137 pkgAcqMetaClearSig::~pkgAcqMetaClearSig() /*{{{*/
2140 // if the file was never queued undo file-changes done in the constructor
2141 if (QueueCounter
== 1 && Status
== StatIdle
&& FileSize
== 0 && Complete
== false)
2143 string
const Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
2144 string
const LastGoodSig
= DestFile
+ ".reverify";
2145 if (RealFileExists(Final
) == false && RealFileExists(LastGoodSig
) == true)
2146 Rename(LastGoodSig
, Final
);
2151 // pkgAcqMetaClearSig::Custom600Headers - Insert custom request headers /*{{{*/
2152 // ---------------------------------------------------------------------
2153 // FIXME: this can go away once the InRelease file is used widely
2154 string
pkgAcqMetaClearSig::Custom600Headers() const
2156 string Final
= _config
->FindDir("Dir::State::lists");
2157 Final
+= URItoFileName(RealURI
);
2160 if (stat(Final
.c_str(),&Buf
) != 0)
2162 if (stat(Final
.c_str(),&Buf
) != 0)
2163 return "\nIndex-File: true\nFail-Ignore: true\n";
2166 return "\nIndex-File: true\nFail-Ignore: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
2169 // pkgAcqMetaClearSig::Done - We got a file /*{{{*/
2170 // ---------------------------------------------------------------------
2171 void pkgAcqMetaClearSig::Done(std::string Message
,unsigned long long Size
,
2172 HashStringList
const &Hashes
,
2173 pkgAcquire::MethodConfig
*Cnf
)
2175 // if we expect a ClearTextSignature (InRelase), ensure that
2176 // this is what we get and if not fail to queue a
2177 // Release/Release.gpg, see #346386
2178 if (FileExists(DestFile
) && !StartsWithGPGClearTextSignature(DestFile
))
2180 pkgAcquire::Item::Failed(Message
, Cnf
);
2181 RenameOnError(NotClearsigned
);
2182 TransactionManager
->AbortTransaction();
2185 pkgAcqMetaIndex::Done(Message
, Size
, Hashes
, Cnf
);
2188 void pkgAcqMetaClearSig::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
2190 // we failed, we will not get additional items from this method
2191 ExpectedAdditionalItems
= 0;
2193 if (AuthPass
== false)
2195 // Queue the 'old' InRelease file for removal if we try Release.gpg
2196 // as otherwise the file will stay around and gives a false-auth
2197 // impression (CVE-2012-0214)
2198 string FinalFile
= _config
->FindDir("Dir::State::lists");
2199 FinalFile
.append(URItoFileName(RealURI
));
2201 DestFile
= FinalFile
;
2203 new pkgAcqMetaIndex(Owner
, TransactionManager
,
2204 MetaIndexURI
, MetaIndexURIDesc
, MetaIndexShortDesc
,
2205 MetaSigURI
, MetaSigURIDesc
, MetaSigShortDesc
,
2206 IndexTargets
, MetaIndexParser
);
2207 if (Cnf
->LocalOnly
== true ||
2208 StringToBool(LookupTag(Message
, "Transient-Failure"), false) == false)
2212 pkgAcqMetaIndex::Failed(Message
, Cnf
);
2215 // AcqArchive::AcqArchive - Constructor /*{{{*/
2216 // ---------------------------------------------------------------------
2217 /* This just sets up the initial fetch environment and queues the first
2219 pkgAcqArchive::pkgAcqArchive(pkgAcquire
*Owner
,pkgSourceList
*Sources
,
2220 pkgRecords
*Recs
,pkgCache::VerIterator
const &Version
,
2221 string
&StoreFilename
) :
2222 Item(Owner
, HashStringList()), Version(Version
), Sources(Sources
), Recs(Recs
),
2223 StoreFilename(StoreFilename
), Vf(Version
.FileList()),
2226 Retries
= _config
->FindI("Acquire::Retries",0);
2228 if (Version
.Arch() == 0)
2230 _error
->Error(_("I wasn't able to locate a file for the %s package. "
2231 "This might mean you need to manually fix this package. "
2232 "(due to missing arch)"),
2233 Version
.ParentPkg().FullName().c_str());
2237 /* We need to find a filename to determine the extension. We make the
2238 assumption here that all the available sources for this version share
2239 the same extension.. */
2240 // Skip not source sources, they do not have file fields.
2241 for (; Vf
.end() == false; ++Vf
)
2243 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
2248 // Does not really matter here.. we are going to fail out below
2249 if (Vf
.end() != true)
2251 // If this fails to get a file name we will bomb out below.
2252 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2253 if (_error
->PendingError() == true)
2256 // Generate the final file name as: package_version_arch.foo
2257 StoreFilename
= QuoteString(Version
.ParentPkg().Name(),"_:") + '_' +
2258 QuoteString(Version
.VerStr(),"_:") + '_' +
2259 QuoteString(Version
.Arch(),"_:.") +
2260 "." + flExtension(Parse
.FileName());
2263 // check if we have one trusted source for the package. if so, switch
2264 // to "TrustedOnly" mode - but only if not in AllowUnauthenticated mode
2265 bool const allowUnauth
= _config
->FindB("APT::Get::AllowUnauthenticated", false);
2266 bool const debugAuth
= _config
->FindB("Debug::pkgAcquire::Auth", false);
2267 bool seenUntrusted
= false;
2268 for (pkgCache::VerFileIterator i
= Version
.FileList(); i
.end() == false; ++i
)
2270 pkgIndexFile
*Index
;
2271 if (Sources
->FindIndex(i
.File(),Index
) == false)
2274 if (debugAuth
== true)
2275 std::cerr
<< "Checking index: " << Index
->Describe()
2276 << "(Trusted=" << Index
->IsTrusted() << ")" << std::endl
;
2278 if (Index
->IsTrusted() == true)
2281 if (allowUnauth
== false)
2285 seenUntrusted
= true;
2288 // "allow-unauthenticated" restores apts old fetching behaviour
2289 // that means that e.g. unauthenticated file:// uris are higher
2290 // priority than authenticated http:// uris
2291 if (allowUnauth
== true && seenUntrusted
== true)
2295 if (QueueNext() == false && _error
->PendingError() == false)
2296 _error
->Error(_("Can't find a source to download version '%s' of '%s'"),
2297 Version
.VerStr(), Version
.ParentPkg().FullName(false).c_str());
2300 // AcqArchive::QueueNext - Queue the next file source /*{{{*/
2301 // ---------------------------------------------------------------------
2302 /* This queues the next available file version for download. It checks if
2303 the archive is already available in the cache and stashs the MD5 for
2305 bool pkgAcqArchive::QueueNext()
2307 for (; Vf
.end() == false; ++Vf
)
2309 // Ignore not source sources
2310 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
2313 // Try to cross match against the source list
2314 pkgIndexFile
*Index
;
2315 if (Sources
->FindIndex(Vf
.File(),Index
) == false)
2318 // only try to get a trusted package from another source if that source
2320 if(Trusted
&& !Index
->IsTrusted())
2323 // Grab the text package record
2324 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2325 if (_error
->PendingError() == true)
2328 string PkgFile
= Parse
.FileName();
2329 ExpectedHashes
= Parse
.Hashes();
2331 if (PkgFile
.empty() == true)
2332 return _error
->Error(_("The package index files are corrupted. No Filename: "
2333 "field for package %s."),
2334 Version
.ParentPkg().Name());
2336 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
2337 Desc
.Description
= Index
->ArchiveInfo(Version
);
2339 Desc
.ShortDesc
= Version
.ParentPkg().FullName(true);
2341 // See if we already have the file. (Legacy filenames)
2342 FileSize
= Version
->Size
;
2343 string FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile
);
2345 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2347 // Make sure the size matches
2348 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2353 StoreFilename
= DestFile
= FinalFile
;
2357 /* Hmm, we have a file and its size does not match, this means it is
2358 an old style mismatched arch */
2359 unlink(FinalFile
.c_str());
2362 // Check it again using the new style output filenames
2363 FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
2364 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2366 // Make sure the size matches
2367 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2372 StoreFilename
= DestFile
= FinalFile
;
2376 /* Hmm, we have a file and its size does not match, this shouldn't
2378 unlink(FinalFile
.c_str());
2381 DestFile
= _config
->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename
);
2383 // Check the destination file
2384 if (stat(DestFile
.c_str(),&Buf
) == 0)
2386 // Hmm, the partial file is too big, erase it
2387 if ((unsigned long long)Buf
.st_size
> Version
->Size
)
2388 unlink(DestFile
.c_str());
2390 PartialSize
= Buf
.st_size
;
2393 // Disables download of archives - useful if no real installation follows,
2394 // e.g. if we are just interested in proposed installation order
2395 if (_config
->FindB("Debug::pkgAcqArchive::NoQueue", false) == true)
2400 StoreFilename
= DestFile
= FinalFile
;
2414 // AcqArchive::Done - Finished fetching /*{{{*/
2415 // ---------------------------------------------------------------------
2417 void pkgAcqArchive::Done(string Message
,unsigned long long Size
, HashStringList
const &CalcHashes
,
2418 pkgAcquire::MethodConfig
*Cfg
)
2420 Item::Done(Message
, Size
, CalcHashes
, Cfg
);
2423 if (Size
!= Version
->Size
)
2425 RenameOnError(SizeMismatch
);
2429 // FIXME: could this empty() check impose *any* sort of security issue?
2430 if(ExpectedHashes
.usable() && ExpectedHashes
!= CalcHashes
)
2432 RenameOnError(HashSumMismatch
);
2433 printHashSumComparision(DestFile
, ExpectedHashes
, CalcHashes
);
2437 // Grab the output filename
2438 string FileName
= LookupTag(Message
,"Filename");
2439 if (FileName
.empty() == true)
2442 ErrorText
= "Method gave a blank filename";
2448 // Reference filename
2449 if (FileName
!= DestFile
)
2451 StoreFilename
= DestFile
= FileName
;
2456 // Done, move it into position
2457 string FinalFile
= _config
->FindDir("Dir::Cache::Archives");
2458 FinalFile
+= flNotDir(StoreFilename
);
2459 Rename(DestFile
,FinalFile
);
2461 StoreFilename
= DestFile
= FinalFile
;
2465 // AcqArchive::Failed - Failure handler /*{{{*/
2466 // ---------------------------------------------------------------------
2467 /* Here we try other sources */
2468 void pkgAcqArchive::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
2470 ErrorText
= LookupTag(Message
,"Message");
2472 /* We don't really want to retry on failed media swaps, this prevents
2473 that. An interesting observation is that permanent failures are not
2475 if (Cnf
->Removable
== true &&
2476 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2478 // Vf = Version.FileList();
2479 while (Vf
.end() == false) ++Vf
;
2480 StoreFilename
= string();
2481 Item::Failed(Message
,Cnf
);
2485 if (QueueNext() == false)
2487 // This is the retry counter
2489 Cnf
->LocalOnly
== false &&
2490 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2493 Vf
= Version
.FileList();
2494 if (QueueNext() == true)
2498 StoreFilename
= string();
2499 Item::Failed(Message
,Cnf
);
2503 // AcqArchive::IsTrusted - Determine whether this archive comes from a trusted source /*{{{*/
2504 // ---------------------------------------------------------------------
2505 APT_PURE
bool pkgAcqArchive::IsTrusted() const
2510 // AcqArchive::Finished - Fetching has finished, tidy up /*{{{*/
2511 // ---------------------------------------------------------------------
2513 void pkgAcqArchive::Finished()
2515 if (Status
== pkgAcquire::Item::StatDone
&&
2518 StoreFilename
= string();
2521 // AcqFile::pkgAcqFile - Constructor /*{{{*/
2522 // ---------------------------------------------------------------------
2523 /* The file is added to the queue */
2524 pkgAcqFile::pkgAcqFile(pkgAcquire
*Owner
,string URI
, HashStringList
const &Hashes
,
2525 unsigned long long Size
,string Dsc
,string ShortDesc
,
2526 const string
&DestDir
, const string
&DestFilename
,
2528 Item(Owner
, Hashes
), IsIndexFile(IsIndexFile
)
2530 Retries
= _config
->FindI("Acquire::Retries",0);
2532 if(!DestFilename
.empty())
2533 DestFile
= DestFilename
;
2534 else if(!DestDir
.empty())
2535 DestFile
= DestDir
+ "/" + flNotDir(URI
);
2537 DestFile
= flNotDir(URI
);
2541 Desc
.Description
= Dsc
;
2544 // Set the short description to the archive component
2545 Desc
.ShortDesc
= ShortDesc
;
2547 // Get the transfer sizes
2550 if (stat(DestFile
.c_str(),&Buf
) == 0)
2552 // Hmm, the partial file is too big, erase it
2553 if ((Size
> 0) && (unsigned long long)Buf
.st_size
> Size
)
2554 unlink(DestFile
.c_str());
2556 PartialSize
= Buf
.st_size
;
2562 // AcqFile::Done - Item downloaded OK /*{{{*/
2563 // ---------------------------------------------------------------------
2565 void pkgAcqFile::Done(string Message
,unsigned long long Size
,HashStringList
const &CalcHashes
,
2566 pkgAcquire::MethodConfig
*Cnf
)
2568 Item::Done(Message
,Size
,CalcHashes
,Cnf
);
2571 if(ExpectedHashes
.usable() && ExpectedHashes
!= CalcHashes
)
2573 RenameOnError(HashSumMismatch
);
2574 printHashSumComparision(DestFile
, ExpectedHashes
, CalcHashes
);
2578 string FileName
= LookupTag(Message
,"Filename");
2579 if (FileName
.empty() == true)
2582 ErrorText
= "Method gave a blank filename";
2588 // The files timestamp matches
2589 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
2592 // We have to copy it into place
2593 if (FileName
!= DestFile
)
2596 if (_config
->FindB("Acquire::Source-Symlinks",true) == false ||
2597 Cnf
->Removable
== true)
2599 Desc
.URI
= "copy:" + FileName
;
2604 // Erase the file if it is a symlink so we can overwrite it
2606 if (lstat(DestFile
.c_str(),&St
) == 0)
2608 if (S_ISLNK(St
.st_mode
) != 0)
2609 unlink(DestFile
.c_str());
2613 if (symlink(FileName
.c_str(),DestFile
.c_str()) != 0)
2615 ErrorText
= "Link to " + DestFile
+ " failure ";
2622 // AcqFile::Failed - Failure handler /*{{{*/
2623 // ---------------------------------------------------------------------
2624 /* Here we try other sources */
2625 void pkgAcqFile::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
2627 ErrorText
= LookupTag(Message
,"Message");
2629 // This is the retry counter
2631 Cnf
->LocalOnly
== false &&
2632 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2639 Item::Failed(Message
,Cnf
);
2642 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
2643 // ---------------------------------------------------------------------
2644 /* The only header we use is the last-modified header. */
2645 string
pkgAcqFile::Custom600Headers() const
2648 return "\nIndex-File: true";