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
);
530 // verify the index target
531 if(Target
&& Target
->MetaKey
!= "" && MetaIndexParser
&& Hashes
.usable())
533 std::string IndexMetaKey
= Target
->MetaKey
+ ".diff/Index";
534 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(IndexMetaKey
);
535 if(Record
&& Record
->Hashes
.usable() && Hashes
!= Record
->Hashes
)
537 RenameOnError(HashSumMismatch
);
538 printHashSumComparision(RealURI
, Record
->Hashes
, Hashes
);
539 Failed(Message
, Cnf
);
546 FinalFile
= _config
->FindDir("Dir::State::lists")+URItoFileName(RealURI
);
548 // success in downloading the index
550 FinalFile
+= string(".IndexDiff");
552 std::clog
<< "Renaming: " << DestFile
<< " -> " << FinalFile
554 Rename(DestFile
,FinalFile
);
555 chmod(FinalFile
.c_str(),0644);
556 DestFile
= FinalFile
;
558 if(!ParseDiffIndex(DestFile
))
559 return Failed("", NULL
);
567 // AcqIndexDiffs::AcqIndexDiffs - Constructor /*{{{*/
568 // ---------------------------------------------------------------------
569 /* The package diff is added to the queue. one object is constructed
570 * for each diff and the index
572 pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire
*Owner
,
573 pkgAcqMetaBase
*TransactionManager
,
574 struct IndexTarget
const * const Target
,
575 HashStringList
const &ExpectedHashes
,
576 indexRecords
*MetaIndexParser
,
578 vector
<DiffInfo
> diffs
)
579 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
),
580 available_patches(diffs
), ServerSha1(ServerSha1
)
583 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
584 DestFile
+= URItoFileName(Target
->URI
);
586 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
588 RealURI
= Target
->URI
;
590 Description
= Target
->Description
;
591 Desc
.ShortDesc
= Target
->ShortDesc
;
593 if(available_patches
.empty() == true)
595 // we are done (yeah!), check hashes against the final file
596 DestFile
= _config
->FindDir("Dir::State::lists");
597 DestFile
+= URItoFileName(Target
->URI
);
603 State
= StateFetchDiff
;
608 void pkgAcqIndexDiffs::Failed(string Message
,pkgAcquire::MethodConfig
* /*Cnf*/)/*{{{*/
611 std::clog
<< "pkgAcqIndexDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
612 << "Falling back to normal index file acquire" << std::endl
;
613 new pkgAcqIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
);
617 // Finish - helper that cleans the item out of the fetcher queue /*{{{*/
618 void pkgAcqIndexDiffs::Finish(bool allDone
)
621 std::clog
<< "pkgAcqIndexDiffs::Finish(): "
623 << Desc
.URI
<< std::endl
;
625 // we restore the original name, this is required, otherwise
626 // the file will be cleaned
629 if(HashSums().usable() && !HashSums().VerifyFile(DestFile
))
631 RenameOnError(HashSumMismatch
);
637 PartialFile
= _config
->FindDir("Dir::State::lists")+"partial/"+URItoFileName(RealURI
);
639 DestFile
= _config
->FindDir("Dir::State::lists");
640 DestFile
+= URItoFileName(RealURI
);
642 // this happens if we have a up-to-date indexfile
643 if(!FileExists(PartialFile
))
644 PartialFile
= DestFile
;
646 TransactionManager
->TransactionStageCopy(this, PartialFile
, DestFile
);
648 // this is for the "real" finish
653 std::clog
<< "\n\nallDone: " << DestFile
<< "\n" << std::endl
;
658 std::clog
<< "Finishing: " << Desc
.URI
<< std::endl
;
665 bool pkgAcqIndexDiffs::QueueNextDiff() /*{{{*/
667 // calc sha1 of the just patched file
668 string FinalFile
= _config
->FindDir("Dir::State::lists");
669 FinalFile
+= "partial/" + URItoFileName(RealURI
);
671 if(!FileExists(FinalFile
))
673 Failed("No FinalFile " + FinalFile
+ " available", NULL
);
677 FileFd
fd(FinalFile
, FileFd::ReadOnly
);
680 string local_sha1
= string(SHA1
.Result());
682 std::clog
<< "QueueNextDiff: "
683 << FinalFile
<< " (" << local_sha1
<< ")"<<std::endl
;
686 // final file reached before all patches are applied
687 if(local_sha1
== ServerSha1
)
693 // remove all patches until the next matching patch is found
694 // this requires the Index file to be ordered
695 for(vector
<DiffInfo
>::iterator I
=available_patches
.begin();
696 available_patches
.empty() == false &&
697 I
!= available_patches
.end() &&
698 I
->sha1
!= local_sha1
;
701 available_patches
.erase(I
);
704 // error checking and falling back if no patch was found
705 if(available_patches
.empty() == true)
707 Failed("No patches available", NULL
);
711 // queue the right diff
712 Desc
.URI
= RealURI
+ ".diff/" + available_patches
[0].file
+ ".gz";
713 Desc
.Description
= Description
+ " " + available_patches
[0].file
+ string(".pdiff");
714 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
715 DestFile
+= URItoFileName(RealURI
+ ".diff/" + available_patches
[0].file
);
718 std::clog
<< "pkgAcqIndexDiffs::QueueNextDiff(): " << Desc
.URI
<< std::endl
;
725 void pkgAcqIndexDiffs::Done(string Message
,unsigned long long Size
, HashStringList
const &Hashes
, /*{{{*/
726 pkgAcquire::MethodConfig
*Cnf
)
729 std::clog
<< "pkgAcqIndexDiffs::Done(): " << Desc
.URI
<< std::endl
;
731 Item::Done(Message
, Size
, Hashes
, Cnf
);
733 // FIXME: verify this download too before feeding it to rred
736 FinalFile
= _config
->FindDir("Dir::State::lists")+"partial/"+URItoFileName(RealURI
);
738 // success in downloading a diff, enter ApplyDiff state
739 if(State
== StateFetchDiff
)
742 // rred excepts the patch as $FinalFile.ed
743 Rename(DestFile
,FinalFile
+".ed");
746 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
748 State
= StateApplyDiff
;
750 Desc
.URI
= "rred:" + FinalFile
;
752 ActiveSubprocess
= "rred";
754 #pragma GCC diagnostic push
755 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
759 #pragma GCC diagnostic pop
765 // success in download/apply a diff, queue next (if needed)
766 if(State
== StateApplyDiff
)
768 // remove the just applied patch
769 available_patches
.erase(available_patches
.begin());
770 unlink((FinalFile
+ ".ed").c_str());
775 std::clog
<< "Moving patched file in place: " << std::endl
776 << DestFile
<< " -> " << FinalFile
<< std::endl
;
778 Rename(DestFile
,FinalFile
);
779 chmod(FinalFile
.c_str(),0644);
781 // see if there is more to download
782 if(available_patches
.empty() == false) {
783 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
,
784 ExpectedHashes
, MetaIndexParser
,
785 ServerSha1
, available_patches
);
789 DestFile
= FinalFile
;
794 // AcqIndexMergeDiffs::AcqIndexMergeDiffs - Constructor /*{{{*/
795 pkgAcqIndexMergeDiffs::pkgAcqIndexMergeDiffs(pkgAcquire
*Owner
,
796 pkgAcqMetaBase
*TransactionManager
,
797 struct IndexTarget
const * const Target
,
798 HashStringList
const &ExpectedHashes
,
799 indexRecords
*MetaIndexParser
,
800 DiffInfo
const &patch
,
801 std::vector
<pkgAcqIndexMergeDiffs
*> const * const allPatches
)
802 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
),
803 patch(patch
), allPatches(allPatches
), State(StateFetchDiff
)
806 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
807 DestFile
+= URItoFileName(Target
->URI
);
809 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
811 RealURI
= Target
->URI
;
813 Description
= Target
->Description
;
814 Desc
.ShortDesc
= Target
->ShortDesc
;
816 Desc
.URI
= RealURI
+ ".diff/" + patch
.file
+ ".gz";
817 Desc
.Description
= Description
+ " " + patch
.file
+ string(".pdiff");
818 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
819 DestFile
+= URItoFileName(RealURI
+ ".diff/" + patch
.file
);
822 std::clog
<< "pkgAcqIndexMergeDiffs: " << Desc
.URI
<< std::endl
;
827 void pkgAcqIndexMergeDiffs::Failed(string Message
,pkgAcquire::MethodConfig
* /*Cnf*/)/*{{{*/
830 std::clog
<< "pkgAcqIndexMergeDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
;
835 // check if we are the first to fail, otherwise we are done here
836 State
= StateDoneDiff
;
837 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
838 I
!= allPatches
->end(); ++I
)
839 if ((*I
)->State
== StateErrorDiff
)
842 // first failure means we should fallback
843 State
= StateErrorDiff
;
844 std::clog
<< "Falling back to normal index file acquire" << std::endl
;
845 new pkgAcqIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
);
848 void pkgAcqIndexMergeDiffs::Done(string Message
,unsigned long long Size
,HashStringList
const &Hashes
, /*{{{*/
849 pkgAcquire::MethodConfig
*Cnf
)
852 std::clog
<< "pkgAcqIndexMergeDiffs::Done(): " << Desc
.URI
<< std::endl
;
854 Item::Done(Message
,Size
,Hashes
,Cnf
);
856 // FIXME: verify download before feeding it to rred
858 string
const FinalFile
= _config
->FindDir("Dir::State::lists") + "partial/" + URItoFileName(RealURI
);
860 if (State
== StateFetchDiff
)
862 // rred expects the patch as $FinalFile.ed.$patchname.gz
863 Rename(DestFile
, FinalFile
+ ".ed." + patch
.file
+ ".gz");
865 // check if this is the last completed diff
866 State
= StateDoneDiff
;
867 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
868 I
!= allPatches
->end(); ++I
)
869 if ((*I
)->State
!= StateDoneDiff
)
872 std::clog
<< "Not the last done diff in the batch: " << Desc
.URI
<< std::endl
;
876 // this is the last completed diff, so we are ready to apply now
877 State
= StateApplyDiff
;
880 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
883 Desc
.URI
= "rred:" + FinalFile
;
885 ActiveSubprocess
= "rred";
887 #pragma GCC diagnostic push
888 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
892 #pragma GCC diagnostic pop
896 // success in download/apply all diffs, clean up
897 else if (State
== StateApplyDiff
)
899 // see if we really got the expected file
900 if(ExpectedHashes
.usable() && !ExpectedHashes
.VerifyFile(DestFile
))
902 RenameOnError(HashSumMismatch
);
907 std::string FinalFile
= _config
->FindDir("Dir::State::lists");
908 FinalFile
+= URItoFileName(RealURI
);
910 // move the result into place
912 std::clog
<< "Queue patched file in place: " << std::endl
913 << DestFile
<< " -> " << FinalFile
<< std::endl
;
915 // queue for copy by the transaction manager
916 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
918 // ensure the ed's are gone regardless of list-cleanup
919 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
920 I
!= allPatches
->end(); ++I
)
922 std::string PartialFile
= _config
->FindDir("Dir::State::lists");
923 PartialFile
+= "partial/" + URItoFileName(RealURI
);
924 std::string patch
= PartialFile
+ ".ed." + (*I
)->patch
.file
+ ".gz";
925 std::cerr
<< patch
<< std::endl
;
926 unlink(patch
.c_str());
932 std::clog
<< "allDone: " << DestFile
<< "\n" << std::endl
;
937 // AcqBaseIndex::VerifyHashByMetaKey - verify hash for the given metakey /*{{{*/
938 bool pkgAcqBaseIndex::VerifyHashByMetaKey(HashStringList
const &Hashes
)
940 if(MetaKey
!= "" && Hashes
.usable())
942 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(MetaKey
);
943 if(Record
&& Record
->Hashes
.usable() && Hashes
!= Record
->Hashes
)
945 printHashSumComparision(RealURI
, Record
->Hashes
, Hashes
);
953 // AcqIndex::AcqIndex - Constructor /*{{{*/
954 // ---------------------------------------------------------------------
955 /* The package file is added to the queue and a second class is
956 instantiated to fetch the revision file */
957 pkgAcqIndex::pkgAcqIndex(pkgAcquire
*Owner
,
958 string URI
,string URIDesc
,string ShortDesc
,
959 HashStringList
const &ExpectedHash
)
960 : pkgAcqBaseIndex(Owner
, 0, NULL
, ExpectedHash
, NULL
)
964 AutoSelectCompression();
965 Init(URI
, URIDesc
, ShortDesc
);
967 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
968 std::clog
<< "New pkgIndex with TransactionManager "
969 << TransactionManager
<< std::endl
;
972 // AcqIndex::AcqIndex - Constructor /*{{{*/
973 // ---------------------------------------------------------------------
974 pkgAcqIndex::pkgAcqIndex(pkgAcquire
*Owner
,
975 pkgAcqMetaBase
*TransactionManager
,
976 IndexTarget
const *Target
,
977 HashStringList
const &ExpectedHash
,
978 indexRecords
*MetaIndexParser
)
979 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
, ExpectedHash
,
982 RealURI
= Target
->URI
;
984 // autoselect the compression method
985 AutoSelectCompression();
986 Init(Target
->URI
, Target
->Description
, Target
->ShortDesc
);
988 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
989 std::clog
<< "New pkgIndex with TransactionManager "
990 << TransactionManager
<< std::endl
;
993 // AcqIndex::AutoSelectCompression - Select compression /*{{{*/
994 // ---------------------------------------------------------------------
995 void pkgAcqIndex::AutoSelectCompression()
997 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
998 CompressionExtensions
= "";
999 if (ExpectedHashes
.usable())
1001 for (std::vector
<std::string
>::const_iterator t
= types
.begin();
1002 t
!= types
.end(); ++t
)
1004 std::string CompressedMetaKey
= string(Target
->MetaKey
).append(".").append(*t
);
1005 if (*t
== "uncompressed" ||
1006 MetaIndexParser
->Exists(CompressedMetaKey
) == true)
1007 CompressionExtensions
.append(*t
).append(" ");
1012 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
1013 CompressionExtensions
.append(*t
).append(" ");
1015 if (CompressionExtensions
.empty() == false)
1016 CompressionExtensions
.erase(CompressionExtensions
.end()-1);
1018 // AcqIndex::Init - defered Constructor /*{{{*/
1019 // ---------------------------------------------------------------------
1020 void pkgAcqIndex::Init(string
const &URI
, string
const &URIDesc
,
1021 string
const &ShortDesc
)
1023 Stage
= STAGE_DOWNLOAD
;
1025 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1026 DestFile
+= URItoFileName(URI
);
1028 CurrentCompressionExtension
= CompressionExtensions
.substr(0, CompressionExtensions
.find(' '));
1029 if (CurrentCompressionExtension
== "uncompressed")
1033 MetaKey
= string(Target
->MetaKey
);
1037 Desc
.URI
= URI
+ '.' + CurrentCompressionExtension
;
1038 DestFile
= DestFile
+ '.' + CurrentCompressionExtension
;
1040 MetaKey
= string(Target
->MetaKey
) + '.' + CurrentCompressionExtension
;
1043 // load the filesize
1046 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(MetaKey
);
1048 FileSize
= Record
->Size
;
1050 InitByHashIfNeeded(MetaKey
);
1053 Desc
.Description
= URIDesc
;
1055 Desc
.ShortDesc
= ShortDesc
;
1060 // AcqIndex::AdjustForByHash - modify URI for by-hash support /*{{{*/
1061 // ---------------------------------------------------------------------
1063 void pkgAcqIndex::InitByHashIfNeeded(const std::string MetaKey
)
1066 // - (maybe?) add support for by-hash into the sources.list as flag
1067 // - make apt-ftparchive generate the hashes (and expire?)
1068 std::string HostKnob
= "APT::Acquire::" + ::URI(Desc
.URI
).Host
+ "::By-Hash";
1069 if(_config
->FindB("APT::Acquire::By-Hash", false) == true ||
1070 _config
->FindB(HostKnob
, false) == true ||
1071 MetaIndexParser
->GetSupportsAcquireByHash())
1073 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(MetaKey
);
1076 // FIXME: should we really use the best hash here? or a fixed one?
1077 const HashString
*TargetHash
= Record
->Hashes
.find("");
1078 std::string ByHash
= "/by-hash/" + TargetHash
->HashType() + "/" + TargetHash
->HashValue();
1079 size_t trailing_slash
= Desc
.URI
.find_last_of("/");
1080 Desc
.URI
= Desc
.URI
.replace(
1082 Desc
.URI
.substr(trailing_slash
+1).size()+1,
1086 "Fetching ByHash requested but can not find record for %s",
1092 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
1093 // ---------------------------------------------------------------------
1094 /* The only header we use is the last-modified header. */
1095 string
pkgAcqIndex::Custom600Headers() const
1097 string Final
= GetFinalFilename();
1099 string msg
= "\nIndex-File: true";
1101 if (stat(Final
.c_str(),&Buf
) == 0)
1102 msg
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1107 // pkgAcqIndex::Failed - getting the indexfile failed /*{{{*/
1108 // ---------------------------------------------------------------------
1110 void pkgAcqIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
1112 size_t const nextExt
= CompressionExtensions
.find(' ');
1113 if (nextExt
!= std::string::npos
)
1115 CompressionExtensions
= CompressionExtensions
.substr(nextExt
+1);
1116 Init(RealURI
, Desc
.Description
, Desc
.ShortDesc
);
1120 // on decompression failure, remove bad versions in partial/
1121 if (Stage
== STAGE_DECOMPRESS_AND_VERIFY
)
1123 unlink(EraseFileName
.c_str());
1126 Item::Failed(Message
,Cnf
);
1128 /// cancel the entire transaction
1129 TransactionManager
->AbortTransaction();
1132 // pkgAcqIndex::GetFinalFilename - Return the full final file path /*{{{*/
1133 // ---------------------------------------------------------------------
1135 std::string
pkgAcqIndex::GetFinalFilename() const
1137 std::string FinalFile
= _config
->FindDir("Dir::State::lists");
1138 FinalFile
+= URItoFileName(RealURI
);
1139 if (_config
->FindB("Acquire::GzipIndexes",false) == true)
1140 FinalFile
+= '.' + CurrentCompressionExtension
;
1144 // AcqIndex::ReverifyAfterIMS - Reverify index after an ims-hit /*{{{*/
1145 // ---------------------------------------------------------------------
1147 void pkgAcqIndex::ReverifyAfterIMS()
1149 // update destfile to *not* include the compression extension when doing
1150 // a reverify (as its uncompressed on disk already)
1151 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1152 DestFile
+= URItoFileName(RealURI
);
1154 // adjust DestFile if its compressed on disk
1155 if (_config
->FindB("Acquire::GzipIndexes",false) == true)
1156 DestFile
+= '.' + CurrentCompressionExtension
;
1158 // copy FinalFile into partial/ so that we check the hash again
1159 string FinalFile
= GetFinalFilename();
1160 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
1161 Desc
.URI
= "copy:" + FinalFile
;
1166 // AcqIndex::ValidateFile - Validate the content of the downloaded file /*{{{*/
1167 // --------------------------------------------------------------------------
1168 bool pkgAcqIndex::ValidateFile(const std::string
&FileName
)
1170 // FIXME: this can go away once we only ever download stuff that
1171 // has a valid hash and we never do GET based probing
1172 // FIXME2: this also leaks debian-isms into the code and should go therefore
1174 /* Always validate the index file for correctness (all indexes must
1175 * have a Package field) (LP: #346386) (Closes: #627642)
1177 FileFd
fd(FileName
, FileFd::ReadOnly
, FileFd::Extension
);
1178 // Only test for correctness if the content of the file is not empty
1183 pkgTagFile
tag(&fd
);
1185 // all our current indexes have a field 'Package' in each section
1186 if (_error
->PendingError() == true ||
1187 tag
.Step(sec
) == false ||
1188 sec
.Exists("Package") == false)
1194 // AcqIndex::Done - Finished a fetch /*{{{*/
1195 // ---------------------------------------------------------------------
1196 /* This goes through a number of states.. On the initial fetch the
1197 method could possibly return an alternate filename which points
1198 to the uncompressed version of the file. If this is so the file
1199 is copied into the partial directory. In all other cases the file
1200 is decompressed with a compressed uri. */
1201 void pkgAcqIndex::Done(string Message
,
1202 unsigned long long Size
,
1203 HashStringList
const &Hashes
,
1204 pkgAcquire::MethodConfig
*Cfg
)
1206 Item::Done(Message
,Size
,Hashes
,Cfg
);
1210 case STAGE_DOWNLOAD
:
1211 StageDownloadDone(Message
, Hashes
, Cfg
);
1213 case STAGE_DECOMPRESS_AND_VERIFY
:
1214 StageDecompressDone(Message
, Hashes
, Cfg
);
1219 // AcqIndex::StageDownloadDone - Queue for decompress and verify /*{{{*/
1220 void pkgAcqIndex::StageDownloadDone(string Message
,
1221 HashStringList
const &Hashes
,
1222 pkgAcquire::MethodConfig
*Cfg
)
1224 // First check if the calculcated Hash of the (compressed) downloaded
1225 // file matches the hash we have in the MetaIndexRecords for this file
1226 if(VerifyHashByMetaKey(Hashes
) == false)
1228 RenameOnError(HashSumMismatch
);
1229 Failed(Message
, Cfg
);
1235 // Handle the unzipd case
1236 string FileName
= LookupTag(Message
,"Alt-Filename");
1237 if (FileName
.empty() == false)
1239 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
1241 DestFile
+= ".decomp";
1242 Desc
.URI
= "copy:" + FileName
;
1244 ActiveSubprocess
= "copy";
1246 #pragma GCC diagnostic push
1247 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
1251 #pragma GCC diagnostic pop
1256 FileName
= LookupTag(Message
,"Filename");
1257 if (FileName
.empty() == true)
1260 ErrorText
= "Method gave a blank filename";
1263 // Methods like e.g. "file:" will give us a (compressed) FileName that is
1264 // not the "DestFile" we set, in this case we uncompress from the local file
1265 if (FileName
!= DestFile
)
1268 EraseFileName
= FileName
;
1270 // we need to verify the file against the current Release file again
1271 // on if-modfied-since hit to avoid a stale attack against us
1272 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
1274 // do not reverify cdrom sources as apt-cdrom may rewrite the Packages
1275 // file when its doing the indexcopy
1276 if (RealURI
.substr(0,6) == "cdrom:")
1279 // The files timestamp matches, reverify by copy into partial/
1285 // If we have compressed indexes enabled, queue for hash verification
1286 if (_config
->FindB("Acquire::GzipIndexes",false))
1288 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1289 DestFile
+= URItoFileName(RealURI
) + '.' + CurrentCompressionExtension
;
1291 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
1292 Desc
.URI
= "copy:" + FileName
;
1298 // get the binary name for your used compression type
1300 if(CurrentCompressionExtension
== "uncompressed")
1301 decompProg
= "copy";
1303 decompProg
= _config
->Find(string("Acquire::CompressionTypes::").append(CurrentCompressionExtension
),"");
1304 if(decompProg
.empty() == true)
1306 _error
->Error("Unsupported extension: %s", CurrentCompressionExtension
.c_str());
1310 // queue uri for the next stage
1311 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
1312 DestFile
+= ".decomp";
1313 Desc
.URI
= decompProg
+ ":" + FileName
;
1316 ActiveSubprocess
= decompProg
;
1318 #pragma GCC diagnostic push
1319 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
1321 Mode
= ActiveSubprocess
.c_str();
1323 #pragma GCC diagnostic pop
1327 // pkgAcqIndex::StageDecompressDone - Final verification /*{{{*/
1328 void pkgAcqIndex::StageDecompressDone(string Message
,
1329 HashStringList
const &Hashes
,
1330 pkgAcquire::MethodConfig
*Cfg
)
1332 if (ExpectedHashes
.usable() && ExpectedHashes
!= Hashes
)
1335 RenameOnError(HashSumMismatch
);
1336 printHashSumComparision(RealURI
, ExpectedHashes
, Hashes
);
1337 Failed(Message
, Cfg
);
1341 if(!ValidateFile(DestFile
))
1343 RenameOnError(InvalidFormat
);
1344 Failed(Message
, Cfg
);
1348 // remove the compressed version of the file
1349 unlink(EraseFileName
.c_str());
1351 // Done, queue for rename on transaction finished
1352 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
1358 // AcqIndexTrans::pkgAcqIndexTrans - Constructor /*{{{*/
1359 // ---------------------------------------------------------------------
1360 /* The Translation file is added to the queue */
1361 pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire
*Owner
,
1362 string URI
,string URIDesc
,string ShortDesc
)
1363 : pkgAcqIndex(Owner
, URI
, URIDesc
, ShortDesc
, HashStringList())
1367 pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire
*Owner
,
1368 pkgAcqMetaBase
*TransactionManager
,
1369 IndexTarget
const * const Target
,
1370 HashStringList
const &ExpectedHashes
,
1371 indexRecords
*MetaIndexParser
)
1372 : pkgAcqIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
)
1374 // load the filesize
1375 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(string(Target
->MetaKey
));
1377 FileSize
= Record
->Size
;
1380 // AcqIndexTrans::Custom600Headers - Insert custom request headers /*{{{*/
1381 // ---------------------------------------------------------------------
1382 string
pkgAcqIndexTrans::Custom600Headers() const
1384 string Final
= GetFinalFilename();
1387 if (stat(Final
.c_str(),&Buf
) != 0)
1388 return "\nFail-Ignore: true\nIndex-File: true";
1389 return "\nFail-Ignore: true\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1392 // AcqIndexTrans::Failed - Silence failure messages for missing files /*{{{*/
1393 // ---------------------------------------------------------------------
1395 void pkgAcqIndexTrans::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1397 size_t const nextExt
= CompressionExtensions
.find(' ');
1398 if (nextExt
!= std::string::npos
)
1400 CompressionExtensions
= CompressionExtensions
.substr(nextExt
+1);
1401 Init(RealURI
, Desc
.Description
, Desc
.ShortDesc
);
1406 // FIXME: this is used often (e.g. in pkgAcqIndexTrans) so refactor
1407 if (Cnf
->LocalOnly
== true ||
1408 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1417 Item::Failed(Message
,Cnf
);
1420 // AcqMetaBase::Add - Add a item to the current Transaction /*{{{*/
1421 // ---------------------------------------------------------------------
1423 void pkgAcqMetaBase::Add(Item
*I
)
1425 Transaction
.push_back(I
);
1428 // AcqMetaBase::AbortTransaction - Abort the current Transaction /*{{{*/
1429 // ---------------------------------------------------------------------
1431 void pkgAcqMetaBase::AbortTransaction()
1433 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1434 std::clog
<< "AbortTransaction: " << TransactionManager
<< std::endl
;
1436 // ensure the toplevel is in error state too
1437 for (std::vector
<Item
*>::iterator I
= Transaction
.begin();
1438 I
!= Transaction
.end(); ++I
)
1440 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1441 std::clog
<< " Cancel: " << (*I
)->DestFile
<< std::endl
;
1442 // the transaction will abort, so stop anything that is idle
1443 if ((*I
)->Status
== pkgAcquire::Item::StatIdle
)
1444 (*I
)->Status
= pkgAcquire::Item::StatDone
;
1446 // kill files in partial
1447 string PartialFile
= _config
->FindDir("Dir::State::lists");
1448 PartialFile
+= "partial/";
1449 PartialFile
+= flNotDir((*I
)->DestFile
);
1450 if(FileExists(PartialFile
))
1451 Rename(PartialFile
, PartialFile
+ ".FAILED");
1455 // AcqMetaBase::TransactionHasError - Check for errors in Transaction /*{{{*/
1456 // ---------------------------------------------------------------------
1458 bool pkgAcqMetaBase::TransactionHasError()
1460 for (pkgAcquire::ItemIterator I
= Transaction
.begin();
1461 I
!= Transaction
.end(); ++I
)
1462 if((*I
)->Status
!= pkgAcquire::Item::StatDone
&&
1463 (*I
)->Status
!= pkgAcquire::Item::StatIdle
)
1469 // AcqMetaBase::CommitTransaction - Commit a transaction /*{{{*/
1470 // ---------------------------------------------------------------------
1472 void pkgAcqMetaBase::CommitTransaction()
1474 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1475 std::clog
<< "CommitTransaction: " << this << std::endl
;
1477 // move new files into place *and* remove files that are not
1478 // part of the transaction but are still on disk
1479 for (std::vector
<Item
*>::iterator I
= Transaction
.begin();
1480 I
!= Transaction
.end(); ++I
)
1482 if((*I
)->PartialFile
!= "")
1484 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1486 << (*I
)->PartialFile
<< " -> "
1487 << (*I
)->DestFile
<< " "
1490 Rename((*I
)->PartialFile
, (*I
)->DestFile
);
1491 chmod((*I
)->DestFile
.c_str(),0644);
1493 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1499 unlink((*I
)->DestFile
.c_str());
1501 // mark that this transaction is finished
1502 (*I
)->TransactionManager
= 0;
1506 // AcqMetaBase::CommitTransaction - Commit a transaction /*{{{*/
1507 // ---------------------------------------------------------------------
1509 void pkgAcqMetaBase::TransactionStageCopy(Item
*I
,
1510 const std::string
&From
,
1511 const std::string
&To
)
1513 I
->PartialFile
= From
;
1517 // AcqMetaBase::CommitTransaction - Commit a transaction /*{{{*/
1518 // ---------------------------------------------------------------------
1520 void pkgAcqMetaBase::TransactionStageRemoval(Item
*I
,
1521 const std::string
&FinalFile
)
1523 I
->PartialFile
= "";
1524 I
->DestFile
= FinalFile
;
1528 // AcqMetaBase::GenerateAuthWarning - Check gpg authentication error /*{{{*/
1529 // ---------------------------------------------------------------------
1531 bool pkgAcqMetaBase::GenerateAuthWarning(const std::string
&RealURI
,
1532 const std::string
&Message
)
1534 string Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1536 if(FileExists(Final
))
1538 Status
= StatTransientNetworkError
;
1539 _error
->Warning(_("An error occurred during the signature "
1540 "verification. The repository is not updated "
1541 "and the previous index files will be used. "
1542 "GPG error: %s: %s\n"),
1543 Desc
.Description
.c_str(),
1544 LookupTag(Message
,"Message").c_str());
1545 RunScripts("APT::Update::Auth-Failure");
1547 } else if (LookupTag(Message
,"Message").find("NODATA") != string::npos
) {
1548 /* Invalid signature file, reject (LP: #346386) (Closes: #627642) */
1549 _error
->Error(_("GPG error: %s: %s"),
1550 Desc
.Description
.c_str(),
1551 LookupTag(Message
,"Message").c_str());
1555 _error
->Warning(_("GPG error: %s: %s"),
1556 Desc
.Description
.c_str(),
1557 LookupTag(Message
,"Message").c_str());
1559 // gpgv method failed
1560 ReportMirrorFailure("GPGFailure");
1564 // AcqMetaSig::AcqMetaSig - Constructor /*{{{*/
1565 // ---------------------------------------------------------------------
1567 pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire
*Owner
,
1568 pkgAcqMetaBase
*TransactionManager
,
1569 string URI
,string URIDesc
,string ShortDesc
,
1570 string MetaIndexFile
,
1571 const vector
<IndexTarget
*>* IndexTargets
,
1572 indexRecords
* MetaIndexParser
) :
1573 pkgAcqMetaBase(Owner
, IndexTargets
, MetaIndexParser
,
1574 HashStringList(), TransactionManager
),
1575 RealURI(URI
), MetaIndexFile(MetaIndexFile
), URIDesc(URIDesc
),
1576 ShortDesc(ShortDesc
)
1578 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1579 DestFile
+= URItoFileName(URI
);
1581 // remove any partial downloaded sig-file in partial/.
1582 // it may confuse proxies and is too small to warrant a
1583 // partial download anyway
1584 unlink(DestFile
.c_str());
1586 // set the TransactionManager
1587 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1588 std::clog
<< "New pkgAcqMetaSig with TransactionManager "
1589 << TransactionManager
<< std::endl
;
1592 Desc
.Description
= URIDesc
;
1594 Desc
.ShortDesc
= ShortDesc
;
1600 pkgAcqMetaSig::~pkgAcqMetaSig() /*{{{*/
1604 // pkgAcqMetaSig::Custom600Headers - Insert custom request headers /*{{{*/
1605 // ---------------------------------------------------------------------
1606 /* The only header we use is the last-modified header. */
1607 string
pkgAcqMetaSig::Custom600Headers() const
1609 string FinalFile
= _config
->FindDir("Dir::State::lists");
1610 FinalFile
+= URItoFileName(RealURI
);
1613 if (stat(FinalFile
.c_str(),&Buf
) != 0)
1614 return "\nIndex-File: true";
1616 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1619 // pkgAcqMetaSig::Done - The signature was downloaded/verified /*{{{*/
1620 // ---------------------------------------------------------------------
1621 /* The only header we use is the last-modified header. */
1622 void pkgAcqMetaSig::Done(string Message
,unsigned long long Size
,
1623 HashStringList
const &Hashes
,
1624 pkgAcquire::MethodConfig
*Cfg
)
1626 Item::Done(Message
, Size
, Hashes
, Cfg
);
1628 string FileName
= LookupTag(Message
,"Filename");
1629 if (FileName
.empty() == true)
1632 ErrorText
= "Method gave a blank filename";
1636 if (FileName
!= DestFile
)
1638 // We have to copy it into place
1640 Desc
.URI
= "copy:" + FileName
;
1645 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
1648 // adjust paths if its a ims-hit
1651 string FinalFile
= _config
->FindDir("Dir::State::lists");
1652 FinalFile
+= URItoFileName(RealURI
);
1654 TransactionManager
->TransactionStageCopy(this, FinalFile
, FinalFile
);
1658 if(AuthPass
== false)
1661 Desc
.URI
= "gpgv:" + DestFile
;
1662 DestFile
= MetaIndexFile
;
1667 // queue to copy the file in place if it was not a ims hit, on ims
1668 // hit the file is already at the right place
1671 PartialFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1672 PartialFile
+= URItoFileName(RealURI
);
1674 std::string FinalFile
= _config
->FindDir("Dir::State::lists");
1675 FinalFile
+= URItoFileName(RealURI
);
1677 TransactionManager
->TransactionStageCopy(this, PartialFile
, FinalFile
);
1680 // we parse the MetaIndexFile here because at this point we can
1682 if(AuthPass
== true)
1684 // load indexes and queue further downloads
1685 MetaIndexParser
->Load(MetaIndexFile
);
1692 void pkgAcqMetaSig::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)/*{{{*/
1694 string Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1696 // FIXME: duplicated code from pkgAcqMetaIndex
1697 if (AuthPass
== true)
1699 bool Stop
= GenerateAuthWarning(RealURI
, Message
);
1704 // FIXME: meh, this is not really elegant
1705 string InReleaseURI
= RealURI
.replace(RealURI
.rfind("Release.gpg"), 12,
1707 string FinalInRelease
= _config
->FindDir("Dir::State::lists") + URItoFileName(InReleaseURI
);
1709 if (RealFileExists(Final
) || RealFileExists(FinalInRelease
))
1711 std::string downgrade_msg
;
1712 strprintf(downgrade_msg
, _("The repository '%s' is no longer signed."),
1714 if(_config
->FindB("Acquire::AllowDowngradeToInsecureRepositories"))
1716 // meh, the users wants to take risks (we still mark the packages
1717 // from this repository as unauthenticated)
1718 _error
->Warning("%s", downgrade_msg
.c_str());
1719 _error
->Warning(_("This is normally not allowed, but the option "
1720 "Acquire::AllowDowngradeToInsecureRepositories was "
1721 "given to override it."));
1724 _error
->Error("%s", downgrade_msg
.c_str());
1725 Rename(MetaIndexFile
, MetaIndexFile
+".FAILED");
1726 Status
= pkgAcquire::Item::StatError
;
1727 TransactionManager
->AbortTransaction();
1732 // this ensures that any file in the lists/ dir is removed by the
1734 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1735 DestFile
+= URItoFileName(RealURI
);
1736 TransactionManager
->TransactionStageRemoval(this, DestFile
);
1738 // only allow going further if the users explicitely wants it
1739 if(_config
->FindB("Acquire::AllowInsecureRepositories") == true)
1741 // we parse the indexes here because at this point the user wanted
1742 // a repository that may potentially harm him
1743 MetaIndexParser
->Load(MetaIndexFile
);
1748 _error
->Warning("Use --allow-insecure-repositories to force the update");
1751 // FIXME: this is used often (e.g. in pkgAcqIndexTrans) so refactor
1752 if (Cnf
->LocalOnly
== true ||
1753 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1761 Item::Failed(Message
,Cnf
);
1764 pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire
*Owner
, /*{{{*/
1765 pkgAcqMetaBase
*TransactionManager
,
1766 string URI
,string URIDesc
,string ShortDesc
,
1767 string MetaIndexSigURI
,string MetaIndexSigURIDesc
, string MetaIndexSigShortDesc
,
1768 const vector
<IndexTarget
*>* IndexTargets
,
1769 indexRecords
* MetaIndexParser
) :
1770 pkgAcqMetaBase(Owner
, IndexTargets
, MetaIndexParser
, HashStringList(),
1771 TransactionManager
),
1772 RealURI(URI
), URIDesc(URIDesc
), ShortDesc(ShortDesc
),
1773 MetaIndexSigURI(MetaIndexSigURI
), MetaIndexSigURIDesc(MetaIndexSigURIDesc
),
1774 MetaIndexSigShortDesc(MetaIndexSigShortDesc
)
1776 if(TransactionManager
== NULL
)
1778 this->TransactionManager
= this;
1779 this->TransactionManager
->Add(this);
1782 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1783 std::clog
<< "New pkgAcqMetaIndex with TransactionManager "
1784 << this->TransactionManager
<< std::endl
;
1787 Init(URIDesc
, ShortDesc
);
1790 // pkgAcqMetaIndex::Init - Delayed constructor /*{{{*/
1791 void pkgAcqMetaIndex::Init(std::string URIDesc
, std::string ShortDesc
)
1793 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1794 DestFile
+= URItoFileName(RealURI
);
1797 Desc
.Description
= URIDesc
;
1799 Desc
.ShortDesc
= ShortDesc
;
1802 // we expect more item
1803 ExpectedAdditionalItems
= IndexTargets
->size();
1806 // pkgAcqMetaIndex::Custom600Headers - Insert custom request headers /*{{{*/
1807 // ---------------------------------------------------------------------
1808 /* The only header we use is the last-modified header. */
1809 string
pkgAcqMetaIndex::Custom600Headers() const
1811 string Final
= _config
->FindDir("Dir::State::lists");
1812 Final
+= URItoFileName(RealURI
);
1815 if (stat(Final
.c_str(),&Buf
) != 0)
1816 return "\nIndex-File: true";
1818 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1821 void pkgAcqMetaIndex::Done(string Message
,unsigned long long Size
,HashStringList
const &Hashes
, /*{{{*/
1822 pkgAcquire::MethodConfig
*Cfg
)
1824 Item::Done(Message
,Size
,Hashes
,Cfg
);
1826 // MetaIndexes are done in two passes: one to download the
1827 // metaindex with an appropriate method, and a second to verify it
1828 // with the gpgv method
1830 if (AuthPass
== true)
1834 // all cool, move Release file into place
1839 RetrievalDone(Message
);
1841 // Still more retrieving to do
1846 // There was a signature file, so pass it to gpgv for
1848 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1849 std::cerr
<< "Metaindex acquired, queueing gpg verification ("
1850 << SigFile
<< "," << DestFile
<< ")\n";
1852 Desc
.URI
= "gpgv:" + SigFile
;
1854 ActiveSubprocess
= "gpgv";
1856 #pragma GCC diagnostic push
1857 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
1861 #pragma GCC diagnostic pop
1867 if (Complete
== true)
1869 string FinalFile
= _config
->FindDir("Dir::State::lists");
1870 FinalFile
+= URItoFileName(RealURI
);
1871 if (SigFile
== DestFile
)
1872 SigFile
= FinalFile
;
1874 // queue for copy in place
1875 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
1879 void pkgAcqMetaIndex::RetrievalDone(string Message
) /*{{{*/
1881 // We have just finished downloading a Release file (it is not
1884 string FileName
= LookupTag(Message
,"Filename");
1885 if (FileName
.empty() == true)
1888 ErrorText
= "Method gave a blank filename";
1892 if (FileName
!= DestFile
)
1895 Desc
.URI
= "copy:" + FileName
;
1900 // make sure to verify against the right file on I-M-S hit
1901 IMSHit
= StringToBool(LookupTag(Message
,"IMS-Hit"),false);
1904 string FinalFile
= _config
->FindDir("Dir::State::lists");
1905 FinalFile
+= URItoFileName(RealURI
);
1906 if (SigFile
== DestFile
)
1908 SigFile
= FinalFile
;
1910 // constructor of pkgAcqMetaClearSig moved it out of the way,
1911 // now move it back in on IMS hit for the 'old' file
1912 string
const OldClearSig
= DestFile
+ ".reverify";
1913 if (RealFileExists(OldClearSig
) == true)
1914 Rename(OldClearSig
, FinalFile
);
1917 DestFile
= FinalFile
;
1920 // queue a signature
1921 if(SigFile
!= DestFile
)
1922 new pkgAcqMetaSig(Owner
, TransactionManager
,
1923 MetaIndexSigURI
, MetaIndexSigURIDesc
,
1924 MetaIndexSigShortDesc
, DestFile
, IndexTargets
,
1930 void pkgAcqMetaIndex::AuthDone(string Message
) /*{{{*/
1932 // At this point, the gpgv method has succeeded, so there is a
1933 // valid signature from a key in the trusted keyring. We
1934 // perform additional verification of its contents, and use them
1935 // to verify the indexes we are about to download
1937 if (!MetaIndexParser
->Load(DestFile
))
1939 Status
= StatAuthError
;
1940 ErrorText
= MetaIndexParser
->ErrorText
;
1944 if (!VerifyVendor(Message
))
1949 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1950 std::cerr
<< "Signature verification succeeded: "
1951 << DestFile
<< std::endl
;
1953 // we ensure this by other means
1955 // do not trust any previously unverified content that we may have
1956 string LastGoodSigFile
= _config
->FindDir("Dir::State::lists").append("partial/").append(URItoFileName(RealURI
));
1957 if (DestFile
!= SigFile
)
1958 LastGoodSigFile
.append(".gpg");
1959 LastGoodSigFile
.append(".reverify");
1960 if(IMSHit
== false && RealFileExists(LastGoodSigFile
) == false)
1962 for (vector
<struct IndexTarget
*>::const_iterator Target
= IndexTargets
->begin();
1963 Target
!= IndexTargets
->end();
1966 // remove old indexes
1967 std::string index
= _config
->FindDir("Dir::State::lists") +
1968 URItoFileName((*Target
)->URI
);
1969 unlink(index
.c_str());
1970 // and also old gzipindexes
1971 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
1972 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
1974 index
+= '.' + (*t
);
1975 unlink(index
.c_str());
1981 // Download further indexes with verification
1983 // it would be really nice if we could simply do
1984 // if (IMSHit == false) QueueIndexes(true)
1985 // and skip the download if the Release file has not changed
1986 // - but right now the list cleaner will needs to be tricked
1987 // to not delete all our packages/source indexes in this case
1991 // is it a clearsigned MetaIndex file?
1992 if (DestFile
== SigFile
)
1995 // Done, move signature file into position
1996 string VerifiedSigFile
= _config
->FindDir("Dir::State::lists") +
1997 URItoFileName(RealURI
) + ".gpg";
1998 Rename(SigFile
,VerifiedSigFile
);
1999 chmod(VerifiedSigFile
.c_str(),0644);
2003 void pkgAcqMetaBase::QueueIndexes(bool verify
) /*{{{*/
2005 bool transInRelease
= false;
2007 std::vector
<std::string
> const keys
= MetaIndexParser
->MetaKeys();
2008 for (std::vector
<std::string
>::const_iterator k
= keys
.begin(); k
!= keys
.end(); ++k
)
2009 // FIXME: Feels wrong to check for hardcoded string here, but what should we do else…
2010 if (k
->find("Translation-") != std::string::npos
)
2012 transInRelease
= true;
2017 // at this point the real Items are loaded in the fetcher
2018 ExpectedAdditionalItems
= 0;
2019 for (vector
<IndexTarget
*>::const_iterator Target
= IndexTargets
->begin();
2020 Target
!= IndexTargets
->end();
2023 HashStringList ExpectedIndexHashes
;
2024 const indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup((*Target
)->MetaKey
);
2025 bool compressedAvailable
= false;
2028 if ((*Target
)->IsOptional() == true)
2030 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
2031 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
2032 if (MetaIndexParser
->Exists((*Target
)->MetaKey
+ "." + *t
) == true)
2034 compressedAvailable
= true;
2038 else if (verify
== true)
2040 Status
= StatAuthError
;
2041 strprintf(ErrorText
, _("Unable to find expected entry '%s' in Release file (Wrong sources.list entry or malformed file)"), (*Target
)->MetaKey
.c_str());
2047 ExpectedIndexHashes
= Record
->Hashes
;
2048 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
2050 std::cerr
<< "Queueing: " << (*Target
)->URI
<< std::endl
2051 << "Expected Hash:" << std::endl
;
2052 for (HashStringList::const_iterator hs
= ExpectedIndexHashes
.begin(); hs
!= ExpectedIndexHashes
.end(); ++hs
)
2053 std::cerr
<< "\t- " << hs
->toStr() << std::endl
;
2054 std::cerr
<< "For: " << Record
->MetaKeyFilename
<< std::endl
;
2056 if (verify
== true && ExpectedIndexHashes
.empty() == true && (*Target
)->IsOptional() == false)
2058 Status
= StatAuthError
;
2059 strprintf(ErrorText
, _("Unable to find hash sum for '%s' in Release file"), (*Target
)->MetaKey
.c_str());
2064 if ((*Target
)->IsOptional() == true)
2066 if (transInRelease
== false || Record
!= NULL
|| compressedAvailable
== true)
2068 if (_config
->FindB("Acquire::PDiffs",true) == true && transInRelease
== true &&
2069 MetaIndexParser
->Exists((*Target
)->MetaKey
+ ".diff/Index") == true)
2070 new pkgAcqDiffIndex(Owner
, TransactionManager
, *Target
, ExpectedIndexHashes
, MetaIndexParser
);
2072 new pkgAcqIndexTrans(Owner
, TransactionManager
, *Target
, ExpectedIndexHashes
, MetaIndexParser
);
2077 /* Queue Packages file (either diff or full packages files, depending
2078 on the users option) - we also check if the PDiff Index file is listed
2079 in the Meta-Index file. Ideal would be if pkgAcqDiffIndex would test this
2080 instead, but passing the required info to it is to much hassle */
2081 if(_config
->FindB("Acquire::PDiffs",true) == true && (verify
== false ||
2082 MetaIndexParser
->Exists((*Target
)->MetaKey
+ ".diff/Index") == true))
2083 new pkgAcqDiffIndex(Owner
, TransactionManager
, *Target
, ExpectedIndexHashes
, MetaIndexParser
);
2085 new pkgAcqIndex(Owner
, TransactionManager
, *Target
, ExpectedIndexHashes
, MetaIndexParser
);
2089 bool pkgAcqMetaIndex::VerifyVendor(string Message
) /*{{{*/
2091 string::size_type pos
;
2093 // check for missing sigs (that where not fatal because otherwise we had
2096 string msg
= _("There is no public key available for the "
2097 "following key IDs:\n");
2098 pos
= Message
.find("NO_PUBKEY ");
2099 if (pos
!= std::string::npos
)
2101 string::size_type start
= pos
+strlen("NO_PUBKEY ");
2102 string Fingerprint
= Message
.substr(start
, Message
.find("\n")-start
);
2103 missingkeys
+= (Fingerprint
);
2105 if(!missingkeys
.empty())
2106 _error
->Warning("%s", (msg
+ missingkeys
).c_str());
2108 string Transformed
= MetaIndexParser
->GetExpectedDist();
2110 if (Transformed
== "../project/experimental")
2112 Transformed
= "experimental";
2115 pos
= Transformed
.rfind('/');
2116 if (pos
!= string::npos
)
2118 Transformed
= Transformed
.substr(0, pos
);
2121 if (Transformed
== ".")
2126 if (_config
->FindB("Acquire::Check-Valid-Until", true) == true &&
2127 MetaIndexParser
->GetValidUntil() > 0) {
2128 time_t const invalid_since
= time(NULL
) - MetaIndexParser
->GetValidUntil();
2129 if (invalid_since
> 0)
2130 // TRANSLATOR: The first %s is the URL of the bad Release file, the second is
2131 // the time since then the file is invalid - formated in the same way as in
2132 // the download progress display (e.g. 7d 3h 42min 1s)
2133 return _error
->Error(
2134 _("Release file for %s is expired (invalid since %s). "
2135 "Updates for this repository will not be applied."),
2136 RealURI
.c_str(), TimeToStr(invalid_since
).c_str());
2139 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
2141 std::cerr
<< "Got Codename: " << MetaIndexParser
->GetDist() << std::endl
;
2142 std::cerr
<< "Expecting Dist: " << MetaIndexParser
->GetExpectedDist() << std::endl
;
2143 std::cerr
<< "Transformed Dist: " << Transformed
<< std::endl
;
2146 if (MetaIndexParser
->CheckDist(Transformed
) == false)
2148 // This might become fatal one day
2149 // Status = StatAuthError;
2150 // ErrorText = "Conflicting distribution; expected "
2151 // + MetaIndexParser->GetExpectedDist() + " but got "
2152 // + MetaIndexParser->GetDist();
2154 if (!Transformed
.empty())
2156 _error
->Warning(_("Conflicting distribution: %s (expected %s but got %s)"),
2157 Desc
.Description
.c_str(),
2158 Transformed
.c_str(),
2159 MetaIndexParser
->GetDist().c_str());
2166 // pkgAcqMetaIndex::Failed - no Release file present or no signature file present /*{{{*/
2167 // ---------------------------------------------------------------------
2169 void pkgAcqMetaIndex::Failed(string Message
,
2170 pkgAcquire::MethodConfig
* /*Cnf*/)
2172 string Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
2174 if (AuthPass
== true)
2176 bool Stop
= GenerateAuthWarning(RealURI
, Message
);
2181 /* Always move the meta index, even if gpgv failed. This ensures
2182 * that PackageFile objects are correctly filled in */
2183 if (FileExists(DestFile
))
2185 string FinalFile
= _config
->FindDir("Dir::State::lists");
2186 FinalFile
+= URItoFileName(RealURI
);
2187 /* InRelease files become Release files, otherwise
2188 * they would be considered as trusted later on */
2189 if (SigFile
== DestFile
) {
2190 RealURI
= RealURI
.replace(RealURI
.rfind("InRelease"), 9,
2192 FinalFile
= FinalFile
.replace(FinalFile
.rfind("InRelease"), 9,
2194 SigFile
= FinalFile
;
2197 // Done, queue for rename on transaction finished
2198 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
2201 _error
->Warning(_("The data from '%s' is not signed. Packages "
2202 "from that repository can not be authenticated."),
2205 // No Release file was present, or verification failed, so fall
2206 // back to queueing Packages files without verification
2207 // only allow going further if the users explicitely wants it
2208 if(_config
->FindB("Acquire::AllowInsecureRepositories") == true)
2210 QueueIndexes(false);
2212 // warn if the repository is unsinged
2213 _error
->Warning("Use --allow-insecure-repositories to force the update");
2218 void pkgAcqMetaIndex::Finished()
2220 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
2221 std::clog
<< "Finished: " << DestFile
<<std::endl
;
2222 if(TransactionManager
!= NULL
&&
2223 TransactionManager
->TransactionHasError() == false)
2224 TransactionManager
->CommitTransaction();
2228 pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire
*Owner
, /*{{{*/
2229 string
const &URI
, string
const &URIDesc
, string
const &ShortDesc
,
2230 string
const &MetaIndexURI
, string
const &MetaIndexURIDesc
, string
const &MetaIndexShortDesc
,
2231 string
const &MetaSigURI
, string
const &MetaSigURIDesc
, string
const &MetaSigShortDesc
,
2232 const vector
<IndexTarget
*>* IndexTargets
,
2233 indexRecords
* MetaIndexParser
) :
2234 pkgAcqMetaIndex(Owner
, NULL
, URI
, URIDesc
, ShortDesc
, MetaSigURI
, MetaSigURIDesc
,MetaSigShortDesc
, IndexTargets
, MetaIndexParser
),
2235 MetaIndexURI(MetaIndexURI
), MetaIndexURIDesc(MetaIndexURIDesc
), MetaIndexShortDesc(MetaIndexShortDesc
),
2236 MetaSigURI(MetaSigURI
), MetaSigURIDesc(MetaSigURIDesc
), MetaSigShortDesc(MetaSigShortDesc
)
2240 // index targets + (worst case:) Release/Release.gpg
2241 ExpectedAdditionalItems
= IndexTargets
->size() + 2;
2244 // keep the old InRelease around in case of transistent network errors
2245 string
const Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
2246 if (RealFileExists(Final
) == true)
2248 string
const LastGoodSig
= DestFile
+ ".reverify";
2249 Rename(Final
,LastGoodSig
);
2254 pkgAcqMetaClearSig::~pkgAcqMetaClearSig() /*{{{*/
2257 // if the file was never queued undo file-changes done in the constructor
2258 if (QueueCounter
== 1 && Status
== StatIdle
&& FileSize
== 0 && Complete
== false)
2260 string
const Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
2261 string
const LastGoodSig
= DestFile
+ ".reverify";
2262 if (RealFileExists(Final
) == false && RealFileExists(LastGoodSig
) == true)
2263 Rename(LastGoodSig
, Final
);
2268 // pkgAcqMetaClearSig::Custom600Headers - Insert custom request headers /*{{{*/
2269 // ---------------------------------------------------------------------
2270 // FIXME: this can go away once the InRelease file is used widely
2271 string
pkgAcqMetaClearSig::Custom600Headers() const
2273 string Final
= _config
->FindDir("Dir::State::lists");
2274 Final
+= URItoFileName(RealURI
);
2277 if (stat(Final
.c_str(),&Buf
) != 0)
2279 if (stat(Final
.c_str(),&Buf
) != 0)
2280 return "\nIndex-File: true\nFail-Ignore: true\n";
2283 return "\nIndex-File: true\nFail-Ignore: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
2286 // pkgAcqMetaClearSig::Done - We got a file /*{{{*/
2287 // ---------------------------------------------------------------------
2288 void pkgAcqMetaClearSig::Done(std::string Message
,unsigned long long Size
,
2289 HashStringList
const &Hashes
,
2290 pkgAcquire::MethodConfig
*Cnf
)
2292 // if we expect a ClearTextSignature (InRelase), ensure that
2293 // this is what we get and if not fail to queue a
2294 // Release/Release.gpg, see #346386
2295 if (FileExists(DestFile
) && !StartsWithGPGClearTextSignature(DestFile
))
2297 pkgAcquire::Item::Failed(Message
, Cnf
);
2298 RenameOnError(NotClearsigned
);
2299 TransactionManager
->AbortTransaction();
2302 pkgAcqMetaIndex::Done(Message
, Size
, Hashes
, Cnf
);
2305 void pkgAcqMetaClearSig::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
2307 // we failed, we will not get additional items from this method
2308 ExpectedAdditionalItems
= 0;
2310 if (AuthPass
== false)
2312 // Queue the 'old' InRelease file for removal if we try Release.gpg
2313 // as otherwise the file will stay around and gives a false-auth
2314 // impression (CVE-2012-0214)
2315 string FinalFile
= _config
->FindDir("Dir::State::lists");
2316 FinalFile
.append(URItoFileName(RealURI
));
2317 TransactionManager
->TransactionStageRemoval(this, FinalFile
);
2319 new pkgAcqMetaIndex(Owner
, TransactionManager
,
2320 MetaIndexURI
, MetaIndexURIDesc
, MetaIndexShortDesc
,
2321 MetaSigURI
, MetaSigURIDesc
, MetaSigShortDesc
,
2322 IndexTargets
, MetaIndexParser
);
2323 if (Cnf
->LocalOnly
== true ||
2324 StringToBool(LookupTag(Message
, "Transient-Failure"), false) == false)
2328 pkgAcqMetaIndex::Failed(Message
, Cnf
);
2331 // AcqArchive::AcqArchive - Constructor /*{{{*/
2332 // ---------------------------------------------------------------------
2333 /* This just sets up the initial fetch environment and queues the first
2335 pkgAcqArchive::pkgAcqArchive(pkgAcquire
*Owner
,pkgSourceList
*Sources
,
2336 pkgRecords
*Recs
,pkgCache::VerIterator
const &Version
,
2337 string
&StoreFilename
) :
2338 Item(Owner
, HashStringList()), Version(Version
), Sources(Sources
), Recs(Recs
),
2339 StoreFilename(StoreFilename
), Vf(Version
.FileList()),
2342 Retries
= _config
->FindI("Acquire::Retries",0);
2344 if (Version
.Arch() == 0)
2346 _error
->Error(_("I wasn't able to locate a file for the %s package. "
2347 "This might mean you need to manually fix this package. "
2348 "(due to missing arch)"),
2349 Version
.ParentPkg().FullName().c_str());
2353 /* We need to find a filename to determine the extension. We make the
2354 assumption here that all the available sources for this version share
2355 the same extension.. */
2356 // Skip not source sources, they do not have file fields.
2357 for (; Vf
.end() == false; ++Vf
)
2359 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
2364 // Does not really matter here.. we are going to fail out below
2365 if (Vf
.end() != true)
2367 // If this fails to get a file name we will bomb out below.
2368 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2369 if (_error
->PendingError() == true)
2372 // Generate the final file name as: package_version_arch.foo
2373 StoreFilename
= QuoteString(Version
.ParentPkg().Name(),"_:") + '_' +
2374 QuoteString(Version
.VerStr(),"_:") + '_' +
2375 QuoteString(Version
.Arch(),"_:.") +
2376 "." + flExtension(Parse
.FileName());
2379 // check if we have one trusted source for the package. if so, switch
2380 // to "TrustedOnly" mode - but only if not in AllowUnauthenticated mode
2381 bool const allowUnauth
= _config
->FindB("APT::Get::AllowUnauthenticated", false);
2382 bool const debugAuth
= _config
->FindB("Debug::pkgAcquire::Auth", false);
2383 bool seenUntrusted
= false;
2384 for (pkgCache::VerFileIterator i
= Version
.FileList(); i
.end() == false; ++i
)
2386 pkgIndexFile
*Index
;
2387 if (Sources
->FindIndex(i
.File(),Index
) == false)
2390 if (debugAuth
== true)
2391 std::cerr
<< "Checking index: " << Index
->Describe()
2392 << "(Trusted=" << Index
->IsTrusted() << ")" << std::endl
;
2394 if (Index
->IsTrusted() == true)
2397 if (allowUnauth
== false)
2401 seenUntrusted
= true;
2404 // "allow-unauthenticated" restores apts old fetching behaviour
2405 // that means that e.g. unauthenticated file:// uris are higher
2406 // priority than authenticated http:// uris
2407 if (allowUnauth
== true && seenUntrusted
== true)
2411 if (QueueNext() == false && _error
->PendingError() == false)
2412 _error
->Error(_("Can't find a source to download version '%s' of '%s'"),
2413 Version
.VerStr(), Version
.ParentPkg().FullName(false).c_str());
2416 // AcqArchive::QueueNext - Queue the next file source /*{{{*/
2417 // ---------------------------------------------------------------------
2418 /* This queues the next available file version for download. It checks if
2419 the archive is already available in the cache and stashs the MD5 for
2421 bool pkgAcqArchive::QueueNext()
2423 for (; Vf
.end() == false; ++Vf
)
2425 // Ignore not source sources
2426 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
2429 // Try to cross match against the source list
2430 pkgIndexFile
*Index
;
2431 if (Sources
->FindIndex(Vf
.File(),Index
) == false)
2434 // only try to get a trusted package from another source if that source
2436 if(Trusted
&& !Index
->IsTrusted())
2439 // Grab the text package record
2440 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2441 if (_error
->PendingError() == true)
2444 string PkgFile
= Parse
.FileName();
2445 ExpectedHashes
= Parse
.Hashes();
2447 if (PkgFile
.empty() == true)
2448 return _error
->Error(_("The package index files are corrupted. No Filename: "
2449 "field for package %s."),
2450 Version
.ParentPkg().Name());
2452 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
2453 Desc
.Description
= Index
->ArchiveInfo(Version
);
2455 Desc
.ShortDesc
= Version
.ParentPkg().FullName(true);
2457 // See if we already have the file. (Legacy filenames)
2458 FileSize
= Version
->Size
;
2459 string FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile
);
2461 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2463 // Make sure the size matches
2464 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2469 StoreFilename
= DestFile
= FinalFile
;
2473 /* Hmm, we have a file and its size does not match, this means it is
2474 an old style mismatched arch */
2475 unlink(FinalFile
.c_str());
2478 // Check it again using the new style output filenames
2479 FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
2480 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2482 // Make sure the size matches
2483 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2488 StoreFilename
= DestFile
= FinalFile
;
2492 /* Hmm, we have a file and its size does not match, this shouldn't
2494 unlink(FinalFile
.c_str());
2497 DestFile
= _config
->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename
);
2499 // Check the destination file
2500 if (stat(DestFile
.c_str(),&Buf
) == 0)
2502 // Hmm, the partial file is too big, erase it
2503 if ((unsigned long long)Buf
.st_size
> Version
->Size
)
2504 unlink(DestFile
.c_str());
2506 PartialSize
= Buf
.st_size
;
2509 // Disables download of archives - useful if no real installation follows,
2510 // e.g. if we are just interested in proposed installation order
2511 if (_config
->FindB("Debug::pkgAcqArchive::NoQueue", false) == true)
2516 StoreFilename
= DestFile
= FinalFile
;
2530 // AcqArchive::Done - Finished fetching /*{{{*/
2531 // ---------------------------------------------------------------------
2533 void pkgAcqArchive::Done(string Message
,unsigned long long Size
, HashStringList
const &CalcHashes
,
2534 pkgAcquire::MethodConfig
*Cfg
)
2536 Item::Done(Message
, Size
, CalcHashes
, Cfg
);
2539 if (Size
!= Version
->Size
)
2541 RenameOnError(SizeMismatch
);
2545 // FIXME: could this empty() check impose *any* sort of security issue?
2546 if(ExpectedHashes
.usable() && ExpectedHashes
!= CalcHashes
)
2548 RenameOnError(HashSumMismatch
);
2549 printHashSumComparision(DestFile
, ExpectedHashes
, CalcHashes
);
2553 // Grab the output filename
2554 string FileName
= LookupTag(Message
,"Filename");
2555 if (FileName
.empty() == true)
2558 ErrorText
= "Method gave a blank filename";
2564 // Reference filename
2565 if (FileName
!= DestFile
)
2567 StoreFilename
= DestFile
= FileName
;
2572 // Done, move it into position
2573 string FinalFile
= _config
->FindDir("Dir::Cache::Archives");
2574 FinalFile
+= flNotDir(StoreFilename
);
2575 Rename(DestFile
,FinalFile
);
2577 StoreFilename
= DestFile
= FinalFile
;
2581 // AcqArchive::Failed - Failure handler /*{{{*/
2582 // ---------------------------------------------------------------------
2583 /* Here we try other sources */
2584 void pkgAcqArchive::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
2586 ErrorText
= LookupTag(Message
,"Message");
2588 /* We don't really want to retry on failed media swaps, this prevents
2589 that. An interesting observation is that permanent failures are not
2591 if (Cnf
->Removable
== true &&
2592 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2594 // Vf = Version.FileList();
2595 while (Vf
.end() == false) ++Vf
;
2596 StoreFilename
= string();
2597 Item::Failed(Message
,Cnf
);
2601 if (QueueNext() == false)
2603 // This is the retry counter
2605 Cnf
->LocalOnly
== false &&
2606 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2609 Vf
= Version
.FileList();
2610 if (QueueNext() == true)
2614 StoreFilename
= string();
2615 Item::Failed(Message
,Cnf
);
2619 // AcqArchive::IsTrusted - Determine whether this archive comes from a trusted source /*{{{*/
2620 // ---------------------------------------------------------------------
2621 APT_PURE
bool pkgAcqArchive::IsTrusted() const
2626 // AcqArchive::Finished - Fetching has finished, tidy up /*{{{*/
2627 // ---------------------------------------------------------------------
2629 void pkgAcqArchive::Finished()
2631 if (Status
== pkgAcquire::Item::StatDone
&&
2634 StoreFilename
= string();
2637 // AcqFile::pkgAcqFile - Constructor /*{{{*/
2638 // ---------------------------------------------------------------------
2639 /* The file is added to the queue */
2640 pkgAcqFile::pkgAcqFile(pkgAcquire
*Owner
,string URI
, HashStringList
const &Hashes
,
2641 unsigned long long Size
,string Dsc
,string ShortDesc
,
2642 const string
&DestDir
, const string
&DestFilename
,
2644 Item(Owner
, Hashes
), IsIndexFile(IsIndexFile
)
2646 Retries
= _config
->FindI("Acquire::Retries",0);
2648 if(!DestFilename
.empty())
2649 DestFile
= DestFilename
;
2650 else if(!DestDir
.empty())
2651 DestFile
= DestDir
+ "/" + flNotDir(URI
);
2653 DestFile
= flNotDir(URI
);
2657 Desc
.Description
= Dsc
;
2660 // Set the short description to the archive component
2661 Desc
.ShortDesc
= ShortDesc
;
2663 // Get the transfer sizes
2666 if (stat(DestFile
.c_str(),&Buf
) == 0)
2668 // Hmm, the partial file is too big, erase it
2669 if ((Size
> 0) && (unsigned long long)Buf
.st_size
> Size
)
2670 unlink(DestFile
.c_str());
2672 PartialSize
= Buf
.st_size
;
2678 // AcqFile::Done - Item downloaded OK /*{{{*/
2679 // ---------------------------------------------------------------------
2681 void pkgAcqFile::Done(string Message
,unsigned long long Size
,HashStringList
const &CalcHashes
,
2682 pkgAcquire::MethodConfig
*Cnf
)
2684 Item::Done(Message
,Size
,CalcHashes
,Cnf
);
2687 if(ExpectedHashes
.usable() && ExpectedHashes
!= CalcHashes
)
2689 RenameOnError(HashSumMismatch
);
2690 printHashSumComparision(DestFile
, ExpectedHashes
, CalcHashes
);
2694 string FileName
= LookupTag(Message
,"Filename");
2695 if (FileName
.empty() == true)
2698 ErrorText
= "Method gave a blank filename";
2704 // The files timestamp matches
2705 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
2708 // We have to copy it into place
2709 if (FileName
!= DestFile
)
2712 if (_config
->FindB("Acquire::Source-Symlinks",true) == false ||
2713 Cnf
->Removable
== true)
2715 Desc
.URI
= "copy:" + FileName
;
2720 // Erase the file if it is a symlink so we can overwrite it
2722 if (lstat(DestFile
.c_str(),&St
) == 0)
2724 if (S_ISLNK(St
.st_mode
) != 0)
2725 unlink(DestFile
.c_str());
2729 if (symlink(FileName
.c_str(),DestFile
.c_str()) != 0)
2731 ErrorText
= "Link to " + DestFile
+ " failure ";
2738 // AcqFile::Failed - Failure handler /*{{{*/
2739 // ---------------------------------------------------------------------
2740 /* Here we try other sources */
2741 void pkgAcqFile::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
2743 ErrorText
= LookupTag(Message
,"Message");
2745 // This is the retry counter
2747 Cnf
->LocalOnly
== false &&
2748 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2755 Item::Failed(Message
,Cnf
);
2758 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
2759 // ---------------------------------------------------------------------
2760 /* The only header we use is the last-modified header. */
2761 string
pkgAcqFile::Custom600Headers() const
2764 return "\nIndex-File: true";