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
, HashStringList
const &ExpectedHashes
) :
72 Owner(Owner
), FileSize(0), PartialSize(0), Mode(0), ID(0), Complete(false),
73 Local(false), QueueCounter(0), ExpectedAdditionalItems(0),
74 ExpectedHashes(ExpectedHashes
)
80 #pragma GCC diagnostic pop
83 // Acquire::Item::~Item - Destructor /*{{{*/
84 // ---------------------------------------------------------------------
86 pkgAcquire::Item::~Item()
91 // Acquire::Item::Failed - Item failed to download /*{{{*/
92 // ---------------------------------------------------------------------
93 /* We return to an idle state if there are still other queues that could
95 void pkgAcquire::Item::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
98 ErrorText
= LookupTag(Message
,"Message");
99 UsedMirror
= LookupTag(Message
,"UsedMirror");
100 if (QueueCounter
<= 1)
102 /* This indicates that the file is not available right now but might
103 be sometime later. If we do a retry cycle then this should be
105 if (Cnf
->LocalOnly
== true &&
106 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
117 // report mirror failure back to LP if we actually use a mirror
118 string FailReason
= LookupTag(Message
, "FailReason");
119 if(FailReason
.size() != 0)
120 ReportMirrorFailure(FailReason
);
122 ReportMirrorFailure(ErrorText
);
125 // Acquire::Item::Start - Item has begun to download /*{{{*/
126 // ---------------------------------------------------------------------
127 /* Stash status and the file size. Note that setting Complete means
128 sub-phases of the acquire process such as decompresion are operating */
129 void pkgAcquire::Item::Start(string
/*Message*/,unsigned long long Size
)
131 Status
= StatFetching
;
132 if (FileSize
== 0 && Complete
== false)
136 // Acquire::Item::Done - Item downloaded OK /*{{{*/
137 // ---------------------------------------------------------------------
139 void pkgAcquire::Item::Done(string Message
,unsigned long long Size
,HashStringList
const &/*Hash*/,
140 pkgAcquire::MethodConfig
* /*Cnf*/)
142 // We just downloaded something..
143 string FileName
= LookupTag(Message
,"Filename");
144 UsedMirror
= LookupTag(Message
,"UsedMirror");
145 if (Complete
== false && !Local
&& FileName
== DestFile
)
148 Owner
->Log
->Fetched(Size
,atoi(LookupTag(Message
,"Resume-Point","0").c_str()));
154 ErrorText
= string();
155 Owner
->Dequeue(this);
158 // Acquire::Item::Rename - Rename a file /*{{{*/
159 // ---------------------------------------------------------------------
160 /* This helper function is used by a lot of item methods as their final
162 void pkgAcquire::Item::Rename(string From
,string To
)
164 if (rename(From
.c_str(),To
.c_str()) != 0)
167 snprintf(S
,sizeof(S
),_("rename failed, %s (%s -> %s)."),strerror(errno
),
168 From
.c_str(),To
.c_str());
174 bool pkgAcquire::Item::RenameOnError(pkgAcquire::Item::RenameOnErrorState
const error
)/*{{{*/
176 if(FileExists(DestFile
))
177 Rename(DestFile
, DestFile
+ ".FAILED");
181 case HashSumMismatch
:
182 ErrorText
= _("Hash Sum mismatch");
183 Status
= StatAuthError
;
184 ReportMirrorFailure("HashChecksumFailure");
187 ErrorText
= _("Size mismatch");
188 Status
= StatAuthError
;
189 ReportMirrorFailure("SizeFailure");
192 ErrorText
= _("Invalid file format");
194 // do not report as usually its not the mirrors fault, but Portal/Proxy
200 // Acquire::Item::ReportMirrorFailure /*{{{*/
201 // ---------------------------------------------------------------------
202 void pkgAcquire::Item::ReportMirrorFailure(string FailCode
)
204 // we only act if a mirror was used at all
205 if(UsedMirror
.empty())
208 std::cerr
<< "\nReportMirrorFailure: "
210 << " Uri: " << DescURI()
212 << FailCode
<< std::endl
;
214 const char *Args
[40];
216 string report
= _config
->Find("Methods::Mirror::ProblemReporting",
217 "/usr/lib/apt/apt-report-mirror-failure");
218 if(!FileExists(report
))
220 Args
[i
++] = report
.c_str();
221 Args
[i
++] = UsedMirror
.c_str();
222 Args
[i
++] = DescURI().c_str();
223 Args
[i
++] = FailCode
.c_str();
225 pid_t pid
= ExecFork();
228 _error
->Error("ReportMirrorFailure Fork failed");
233 execvp(Args
[0], (char**)Args
);
234 std::cerr
<< "Could not exec " << Args
[0] << std::endl
;
237 if(!ExecWait(pid
, "report-mirror-failure"))
239 _error
->Warning("Couldn't report problem to '%s'",
240 _config
->Find("Methods::Mirror::ProblemReporting").c_str());
244 // AcqSubIndex::AcqSubIndex - Constructor /*{{{*/
245 // ---------------------------------------------------------------------
246 /* Get a sub-index file based on checksums from a 'master' file and
247 possibly query additional files */
248 pkgAcqSubIndex::pkgAcqSubIndex(pkgAcquire
*Owner
, string
const &URI
,
249 string
const &URIDesc
, string
const &ShortDesc
,
250 HashStringList
const &ExpectedHashes
)
251 : Item(Owner
, ExpectedHashes
)
253 /* XXX: Beware: Currently this class does nothing (of value) anymore ! */
254 Debug
= _config
->FindB("Debug::pkgAcquire::SubIndex",false);
256 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
257 DestFile
+= URItoFileName(URI
);
260 Desc
.Description
= URIDesc
;
262 Desc
.ShortDesc
= ShortDesc
;
267 std::clog
<< "pkgAcqSubIndex: " << Desc
.URI
<< std::endl
;
270 // AcqSubIndex::Custom600Headers - Insert custom request headers /*{{{*/
271 // ---------------------------------------------------------------------
272 /* The only header we use is the last-modified header. */
273 string
pkgAcqSubIndex::Custom600Headers() const
275 string Final
= _config
->FindDir("Dir::State::lists");
276 Final
+= URItoFileName(Desc
.URI
);
279 if (stat(Final
.c_str(),&Buf
) != 0)
280 return "\nIndex-File: true\nFail-Ignore: true\n";
281 return "\nIndex-File: true\nFail-Ignore: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
284 void pkgAcqSubIndex::Failed(string Message
,pkgAcquire::MethodConfig
* /*Cnf*/)/*{{{*/
287 std::clog
<< "pkgAcqSubIndex failed: " << Desc
.URI
<< " with " << Message
<< std::endl
;
293 // No good Index is provided
296 void pkgAcqSubIndex::Done(string Message
,unsigned long long Size
,HashStringList
const &Hashes
, /*{{{*/
297 pkgAcquire::MethodConfig
*Cnf
)
300 std::clog
<< "pkgAcqSubIndex::Done(): " << Desc
.URI
<< std::endl
;
302 string FileName
= LookupTag(Message
,"Filename");
303 if (FileName
.empty() == true)
306 ErrorText
= "Method gave a blank filename";
310 if (FileName
!= DestFile
)
313 Desc
.URI
= "copy:" + FileName
;
318 Item::Done(Message
, Size
, Hashes
, Cnf
);
320 string FinalFile
= _config
->FindDir("Dir::State::lists")+URItoFileName(Desc
.URI
);
322 /* Downloaded invalid transindex => Error (LP: #346386) (Closes: #627642) */
323 indexRecords SubIndexParser
;
324 if (FileExists(DestFile
) == true && !SubIndexParser
.Load(DestFile
)) {
326 ErrorText
= SubIndexParser
.ErrorText
;
330 // success in downloading the index
333 std::clog
<< "Renaming: " << DestFile
<< " -> " << FinalFile
<< std::endl
;
334 Rename(DestFile
,FinalFile
);
335 chmod(FinalFile
.c_str(),0644);
336 DestFile
= FinalFile
;
338 if(ParseIndex(DestFile
) == false)
339 return Failed("", NULL
);
347 bool pkgAcqSubIndex::ParseIndex(string
const &IndexFile
) /*{{{*/
349 indexRecords SubIndexParser
;
350 if (FileExists(IndexFile
) == false || SubIndexParser
.Load(IndexFile
) == false)
352 // so something with the downloaded index
356 // AcqDiffIndex::AcqDiffIndex - Constructor /*{{{*/
357 // ---------------------------------------------------------------------
358 /* Get the DiffIndex file first and see if there are patches available
359 * If so, create a pkgAcqIndexDiffs fetcher that will get and apply the
360 * patches. If anything goes wrong in that process, it will fall back to
361 * the original packages file
363 pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire
*Owner
,
364 IndexTarget
const * const Target
,
365 HashStringList
const &ExpectedHashes
,
366 indexRecords
*MetaIndexParser
)
367 : pkgAcqBaseIndex(Owner
, Target
, ExpectedHashes
, MetaIndexParser
)
370 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
372 RealURI
= Target
->URI
;
374 Desc
.Description
= Target
->Description
+ "/DiffIndex";
375 Desc
.ShortDesc
= Target
->ShortDesc
;
376 Desc
.URI
= Target
->URI
+ ".diff/Index";
378 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
379 DestFile
+= URItoFileName(Desc
.URI
);
382 std::clog
<< "pkgAcqDiffIndex: " << Desc
.URI
<< std::endl
;
384 // look for the current package file
385 CurrentPackagesFile
= _config
->FindDir("Dir::State::lists");
386 CurrentPackagesFile
+= URItoFileName(RealURI
);
388 // FIXME: this file:/ check is a hack to prevent fetching
389 // from local sources. this is really silly, and
390 // should be fixed cleanly as soon as possible
391 if(!FileExists(CurrentPackagesFile
) ||
392 Desc
.URI
.substr(0,strlen("file:/")) == "file:/")
394 // we don't have a pkg file or we don't want to queue
396 std::clog
<< "No index file, local or canceld by user" << std::endl
;
402 std::clog
<< "pkgAcqDiffIndex::pkgAcqDiffIndex(): "
403 << CurrentPackagesFile
<< std::endl
;
409 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
410 // ---------------------------------------------------------------------
411 /* The only header we use is the last-modified header. */
412 string
pkgAcqDiffIndex::Custom600Headers() const
414 string Final
= _config
->FindDir("Dir::State::lists");
415 Final
+= URItoFileName(Desc
.URI
);
418 std::clog
<< "Custom600Header-IMS: " << Final
<< std::endl
;
421 if (stat(Final
.c_str(),&Buf
) != 0)
422 return "\nIndex-File: true";
424 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
427 bool pkgAcqDiffIndex::ParseDiffIndex(string IndexDiffFile
) /*{{{*/
430 std::clog
<< "pkgAcqDiffIndex::ParseIndexDiff() " << IndexDiffFile
435 vector
<DiffInfo
> available_patches
;
437 FileFd
Fd(IndexDiffFile
,FileFd::ReadOnly
);
439 if (_error
->PendingError() == true)
442 if(TF
.Step(Tags
) == true)
448 string
const tmp
= Tags
.FindS("SHA1-Current");
449 std::stringstream
ss(tmp
);
450 ss
>> ServerSha1
>> size
;
451 unsigned long const ServerSize
= atol(size
.c_str());
453 FileFd
fd(CurrentPackagesFile
, FileFd::ReadOnly
);
456 string
const local_sha1
= SHA1
.Result();
458 if(local_sha1
== ServerSha1
)
460 // we have the same sha1 as the server so we are done here
462 std::clog
<< "Package file is up-to-date" << std::endl
;
463 // list cleanup needs to know that this file as well as the already
464 // present index is ours, so we create an empty diff to save it for us
465 new pkgAcqIndexDiffs(Owner
, Target
, ExpectedHashes
, MetaIndexParser
,
466 ServerSha1
, available_patches
);
472 std::clog
<< "SHA1-Current: " << ServerSha1
<< " and we start at "<< fd
.Name() << " " << fd
.Size() << " " << local_sha1
<< std::endl
;
474 // check the historie and see what patches we need
475 string
const history
= Tags
.FindS("SHA1-History");
476 std::stringstream
hist(history
);
477 while(hist
>> d
.sha1
>> size
>> d
.file
)
479 // read until the first match is found
480 // from that point on, we probably need all diffs
481 if(d
.sha1
== local_sha1
)
483 else if (found
== false)
487 std::clog
<< "Need to get diff: " << d
.file
<< std::endl
;
488 available_patches
.push_back(d
);
491 if (available_patches
.empty() == false)
493 // patching with too many files is rather slow compared to a fast download
494 unsigned long const fileLimit
= _config
->FindI("Acquire::PDiffs::FileLimit", 0);
495 if (fileLimit
!= 0 && fileLimit
< available_patches
.size())
498 std::clog
<< "Need " << available_patches
.size() << " diffs (Limit is " << fileLimit
499 << ") so fallback to complete download" << std::endl
;
503 // see if the patches are too big
504 found
= false; // it was true and it will be true again at the end
505 d
= *available_patches
.begin();
506 string
const firstPatch
= d
.file
;
507 unsigned long patchesSize
= 0;
508 std::stringstream
patches(Tags
.FindS("SHA1-Patches"));
509 while(patches
>> d
.sha1
>> size
>> d
.file
)
511 if (firstPatch
== d
.file
)
513 else if (found
== false)
516 patchesSize
+= atol(size
.c_str());
518 unsigned long const sizeLimit
= ServerSize
* _config
->FindI("Acquire::PDiffs::SizeLimit", 100);
519 if (sizeLimit
> 0 && (sizeLimit
/100) < patchesSize
)
522 std::clog
<< "Need " << patchesSize
<< " bytes (Limit is " << sizeLimit
/100
523 << ") so fallback to complete download" << std::endl
;
529 // we have something, queue the next diff
533 string::size_type
const last_space
= Description
.rfind(" ");
534 if(last_space
!= string::npos
)
535 Description
.erase(last_space
, Description
.size()-last_space
);
537 /* decide if we should download patches one by one or in one go:
538 The first is good if the server merges patches, but many don't so client
539 based merging can be attempt in which case the second is better.
540 "bad things" will happen if patches are merged on the server,
541 but client side merging is attempt as well */
542 bool pdiff_merge
= _config
->FindB("Acquire::PDiffs::Merge", true);
543 if (pdiff_merge
== true)
545 // reprepro adds this flag if it has merged patches on the server
546 std::string
const precedence
= Tags
.FindS("X-Patch-Precedence");
547 pdiff_merge
= (precedence
!= "merged");
550 if (pdiff_merge
== false)
552 new pkgAcqIndexDiffs(Owner
, Target
, ExpectedHashes
, MetaIndexParser
,
553 ServerSha1
, available_patches
);
557 std::vector
<pkgAcqIndexMergeDiffs
*> *diffs
= new std::vector
<pkgAcqIndexMergeDiffs
*>(available_patches
.size());
558 for(size_t i
= 0; i
< available_patches
.size(); ++i
)
559 (*diffs
)[i
] = new pkgAcqIndexMergeDiffs(Owner
, Target
,
562 available_patches
[i
],
573 // Nothing found, report and return false
574 // Failing here is ok, if we return false later, the full
575 // IndexFile is queued
577 std::clog
<< "Can't find a patch in the index file" << std::endl
;
581 void pkgAcqDiffIndex::Failed(string Message
,pkgAcquire::MethodConfig
* /*Cnf*/)/*{{{*/
584 std::clog
<< "pkgAcqDiffIndex failed: " << Desc
.URI
<< " with " << Message
<< std::endl
585 << "Falling back to normal index file acquire" << std::endl
;
587 new pkgAcqIndex(Owner
, Target
, ExpectedHashes
, MetaIndexParser
);
594 void pkgAcqDiffIndex::Done(string Message
,unsigned long long Size
,HashStringList
const &Hashes
, /*{{{*/
595 pkgAcquire::MethodConfig
*Cnf
)
598 std::clog
<< "pkgAcqDiffIndex::Done(): " << Desc
.URI
<< std::endl
;
600 Item::Done(Message
, Size
, Hashes
, Cnf
);
603 FinalFile
= _config
->FindDir("Dir::State::lists")+URItoFileName(RealURI
);
605 // success in downloading the index
607 FinalFile
+= string(".IndexDiff");
609 std::clog
<< "Renaming: " << DestFile
<< " -> " << FinalFile
611 Rename(DestFile
,FinalFile
);
612 chmod(FinalFile
.c_str(),0644);
613 DestFile
= FinalFile
;
615 if(!ParseDiffIndex(DestFile
))
616 return Failed("", NULL
);
624 // AcqIndexDiffs::AcqIndexDiffs - Constructor /*{{{*/
625 // ---------------------------------------------------------------------
626 /* The package diff is added to the queue. one object is constructed
627 * for each diff and the index
629 pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire
*Owner
,
630 struct IndexTarget
const * const Target
,
631 HashStringList
const &ExpectedHashes
,
632 indexRecords
*MetaIndexParser
,
634 vector
<DiffInfo
> diffs
)
635 : pkgAcqBaseIndex(Owner
, Target
, ExpectedHashes
, MetaIndexParser
),
636 available_patches(diffs
), ServerSha1(ServerSha1
)
639 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
640 DestFile
+= URItoFileName(Target
->URI
);
642 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
644 RealURI
= Target
->URI
;
646 Description
= Target
->Description
;
647 Desc
.ShortDesc
= Target
->ShortDesc
;
649 if(available_patches
.empty() == true)
651 // we are done (yeah!)
657 State
= StateFetchDiff
;
662 void pkgAcqIndexDiffs::Failed(string Message
,pkgAcquire::MethodConfig
* /*Cnf*/)/*{{{*/
665 std::clog
<< "pkgAcqIndexDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
666 << "Falling back to normal index file acquire" << std::endl
;
667 new pkgAcqIndex(Owner
, Target
, ExpectedHashes
, MetaIndexParser
);
671 // Finish - helper that cleans the item out of the fetcher queue /*{{{*/
672 void pkgAcqIndexDiffs::Finish(bool allDone
)
674 // we restore the original name, this is required, otherwise
675 // the file will be cleaned
678 DestFile
= _config
->FindDir("Dir::State::lists");
679 DestFile
+= URItoFileName(RealURI
);
681 if(HashSums().usable() && !HashSums().VerifyFile(DestFile
))
683 RenameOnError(HashSumMismatch
);
688 // this is for the "real" finish
693 std::clog
<< "\n\nallDone: " << DestFile
<< "\n" << std::endl
;
698 std::clog
<< "Finishing: " << Desc
.URI
<< std::endl
;
705 bool pkgAcqIndexDiffs::QueueNextDiff() /*{{{*/
708 // calc sha1 of the just patched file
709 string FinalFile
= _config
->FindDir("Dir::State::lists");
710 FinalFile
+= URItoFileName(RealURI
);
712 FileFd
fd(FinalFile
, FileFd::ReadOnly
);
715 string local_sha1
= string(SHA1
.Result());
717 std::clog
<< "QueueNextDiff: "
718 << FinalFile
<< " (" << local_sha1
<< ")"<<std::endl
;
720 // final file reached before all patches are applied
721 if(local_sha1
== ServerSha1
)
727 // remove all patches until the next matching patch is found
728 // this requires the Index file to be ordered
729 for(vector
<DiffInfo
>::iterator I
=available_patches
.begin();
730 available_patches
.empty() == false &&
731 I
!= available_patches
.end() &&
732 I
->sha1
!= local_sha1
;
735 available_patches
.erase(I
);
738 // error checking and falling back if no patch was found
739 if(available_patches
.empty() == true)
745 // queue the right diff
746 Desc
.URI
= RealURI
+ ".diff/" + available_patches
[0].file
+ ".gz";
747 Desc
.Description
= Description
+ " " + available_patches
[0].file
+ string(".pdiff");
748 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
749 DestFile
+= URItoFileName(RealURI
+ ".diff/" + available_patches
[0].file
);
752 std::clog
<< "pkgAcqIndexDiffs::QueueNextDiff(): " << Desc
.URI
<< std::endl
;
759 void pkgAcqIndexDiffs::Done(string Message
,unsigned long long Size
, HashStringList
const &Hashes
, /*{{{*/
760 pkgAcquire::MethodConfig
*Cnf
)
763 std::clog
<< "pkgAcqIndexDiffs::Done(): " << Desc
.URI
<< std::endl
;
765 Item::Done(Message
, Size
, Hashes
, Cnf
);
768 FinalFile
= _config
->FindDir("Dir::State::lists")+URItoFileName(RealURI
);
770 // success in downloading a diff, enter ApplyDiff state
771 if(State
== StateFetchDiff
)
774 // rred excepts the patch as $FinalFile.ed
775 Rename(DestFile
,FinalFile
+".ed");
778 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
780 State
= StateApplyDiff
;
782 Desc
.URI
= "rred:" + FinalFile
;
784 ActiveSubprocess
= "rred";
786 #pragma GCC diagnostic push
787 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
791 #pragma GCC diagnostic pop
797 // success in download/apply a diff, queue next (if needed)
798 if(State
== StateApplyDiff
)
800 // remove the just applied patch
801 available_patches
.erase(available_patches
.begin());
802 unlink((FinalFile
+ ".ed").c_str());
807 std::clog
<< "Moving patched file in place: " << std::endl
808 << DestFile
<< " -> " << FinalFile
<< std::endl
;
810 Rename(DestFile
,FinalFile
);
811 chmod(FinalFile
.c_str(),0644);
813 // see if there is more to download
814 if(available_patches
.empty() == false) {
815 new pkgAcqIndexDiffs(Owner
, Target
,
816 ExpectedHashes
, MetaIndexParser
,
817 ServerSha1
, available_patches
);
824 // AcqIndexMergeDiffs::AcqIndexMergeDiffs - Constructor /*{{{*/
825 pkgAcqIndexMergeDiffs::pkgAcqIndexMergeDiffs(pkgAcquire
*Owner
,
826 struct IndexTarget
const * const Target
,
827 HashStringList
const &ExpectedHashes
,
828 indexRecords
*MetaIndexParser
,
829 DiffInfo
const &patch
,
830 std::vector
<pkgAcqIndexMergeDiffs
*> const * const allPatches
)
831 : pkgAcqBaseIndex(Owner
, Target
, ExpectedHashes
, MetaIndexParser
),
832 patch(patch
), allPatches(allPatches
), State(StateFetchDiff
)
835 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
836 DestFile
+= URItoFileName(Target
->URI
);
838 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
840 RealURI
= Target
->URI
;
842 Description
= Target
->Description
;
843 Desc
.ShortDesc
= Target
->ShortDesc
;
845 Desc
.URI
= RealURI
+ ".diff/" + patch
.file
+ ".gz";
846 Desc
.Description
= Description
+ " " + patch
.file
+ string(".pdiff");
847 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
848 DestFile
+= URItoFileName(RealURI
+ ".diff/" + patch
.file
);
851 std::clog
<< "pkgAcqIndexMergeDiffs: " << Desc
.URI
<< std::endl
;
856 void pkgAcqIndexMergeDiffs::Failed(string Message
,pkgAcquire::MethodConfig
* /*Cnf*/)/*{{{*/
859 std::clog
<< "pkgAcqIndexMergeDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
;
864 // check if we are the first to fail, otherwise we are done here
865 State
= StateDoneDiff
;
866 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
867 I
!= allPatches
->end(); ++I
)
868 if ((*I
)->State
== StateErrorDiff
)
871 // first failure means we should fallback
872 State
= StateErrorDiff
;
873 std::clog
<< "Falling back to normal index file acquire" << std::endl
;
874 new pkgAcqIndex(Owner
, Target
, ExpectedHashes
, MetaIndexParser
);
877 void pkgAcqIndexMergeDiffs::Done(string Message
,unsigned long long Size
,HashStringList
const &Hashes
, /*{{{*/
878 pkgAcquire::MethodConfig
*Cnf
)
881 std::clog
<< "pkgAcqIndexMergeDiffs::Done(): " << Desc
.URI
<< std::endl
;
883 Item::Done(Message
,Size
,Hashes
,Cnf
);
885 string
const FinalFile
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
887 if (State
== StateFetchDiff
)
889 // rred expects the patch as $FinalFile.ed.$patchname.gz
890 Rename(DestFile
, FinalFile
+ ".ed." + patch
.file
+ ".gz");
892 // check if this is the last completed diff
893 State
= StateDoneDiff
;
894 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
895 I
!= allPatches
->end(); ++I
)
896 if ((*I
)->State
!= StateDoneDiff
)
899 std::clog
<< "Not the last done diff in the batch: " << Desc
.URI
<< std::endl
;
903 // this is the last completed diff, so we are ready to apply now
904 State
= StateApplyDiff
;
907 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
910 Desc
.URI
= "rred:" + FinalFile
;
912 ActiveSubprocess
= "rred";
914 #pragma GCC diagnostic push
915 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
919 #pragma GCC diagnostic pop
923 // success in download/apply all diffs, clean up
924 else if (State
== StateApplyDiff
)
926 // see if we really got the expected file
927 if(ExpectedHashes
.usable() && !ExpectedHashes
.VerifyFile(DestFile
))
929 RenameOnError(HashSumMismatch
);
933 // move the result into place
935 std::clog
<< "Moving patched file in place: " << std::endl
936 << DestFile
<< " -> " << FinalFile
<< std::endl
;
937 Rename(DestFile
, FinalFile
);
938 chmod(FinalFile
.c_str(), 0644);
940 // otherwise lists cleanup will eat the file
941 DestFile
= FinalFile
;
943 // ensure the ed's are gone regardless of list-cleanup
944 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
945 I
!= allPatches
->end(); ++I
)
947 std::string patch
= FinalFile
+ ".ed." + (*I
)->patch
.file
+ ".gz";
948 unlink(patch
.c_str());
954 std::clog
<< "allDone: " << DestFile
<< "\n" << std::endl
;
958 // AcqIndex::AcqIndex - Constructor /*{{{*/
959 // ---------------------------------------------------------------------
960 /* The package file is added to the queue and a second class is
961 instantiated to fetch the revision file */
962 pkgAcqIndex::pkgAcqIndex(pkgAcquire
*Owner
,
963 string URI
,string URIDesc
,string ShortDesc
,
964 HashStringList
const &ExpectedHash
, string comprExt
)
965 : pkgAcqBaseIndex(Owner
, NULL
, ExpectedHash
, NULL
), RealURI(URI
)
967 if(comprExt
.empty() == true)
969 // autoselect the compression method
970 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
971 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
972 comprExt
.append(*t
).append(" ");
973 if (comprExt
.empty() == false)
974 comprExt
.erase(comprExt
.end()-1);
976 CompressionExtension
= comprExt
;
978 Init(URI
, URIDesc
, ShortDesc
);
980 pkgAcqIndex::pkgAcqIndex(pkgAcquire
*Owner
, IndexTarget
const *Target
,
981 HashStringList
const &ExpectedHash
,
982 indexRecords
*MetaIndexParser
)
983 : pkgAcqBaseIndex(Owner
, Target
, ExpectedHash
, MetaIndexParser
),
986 // autoselect the compression method
987 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
988 CompressionExtension
= "";
989 if (ExpectedHashes
.usable())
991 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
992 if (*t
== "uncompressed" || MetaIndexParser
->Exists(string(Target
->MetaKey
).append(".").append(*t
)) == true)
993 CompressionExtension
.append(*t
).append(" ");
997 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
998 CompressionExtension
.append(*t
).append(" ");
1000 if (CompressionExtension
.empty() == false)
1001 CompressionExtension
.erase(CompressionExtension
.end()-1);
1003 Init(Target
->URI
, Target
->Description
, Target
->ShortDesc
);
1006 // AcqIndex::Init - defered Constructor /*{{{*/
1007 void pkgAcqIndex::Init(string
const &URI
, string
const &URIDesc
, string
const &ShortDesc
) {
1008 Decompression
= false;
1011 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1012 DestFile
+= URItoFileName(URI
);
1014 std::string
const comprExt
= CompressionExtension
.substr(0, CompressionExtension
.find(' '));
1015 std::string MetaKey
;
1016 if (comprExt
== "uncompressed")
1020 MetaKey
= string(Target
->MetaKey
);
1024 Desc
.URI
= URI
+ '.' + comprExt
;
1025 DestFile
= DestFile
+ '.' + comprExt
;
1027 MetaKey
= string(Target
->MetaKey
) + '.' + comprExt
;
1030 // load the filesize
1033 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(MetaKey
);
1035 FileSize
= Record
->Size
;
1037 InitByHashIfNeeded(MetaKey
);
1040 Desc
.Description
= URIDesc
;
1042 Desc
.ShortDesc
= ShortDesc
;
1047 // AcqIndex::AdjustForByHash - modify URI for by-hash support /*{{{*/
1048 // ---------------------------------------------------------------------
1050 void pkgAcqIndex::InitByHashIfNeeded(const std::string MetaKey
)
1053 // - (maybe?) add support for by-hash into the sources.list as flag
1054 // - make apt-ftparchive generate the hashes (and expire?)
1055 std::string HostKnob
= "APT::Acquire::" + ::URI(Desc
.URI
).Host
+ "::By-Hash";
1056 if(_config
->FindB("APT::Acquire::By-Hash", false) == true ||
1057 _config
->FindB(HostKnob
, false) == true ||
1058 MetaIndexParser
->GetSupportsAcquireByHash())
1060 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(MetaKey
);
1063 // FIXME: should we really use the best hash here? or a fixed one?
1064 const HashString
*TargetHash
= Record
->Hashes
.find("");
1065 std::string ByHash
= "/by-hash/" + TargetHash
->HashType() + "/" + TargetHash
->HashValue();
1066 size_t trailing_slash
= Desc
.URI
.find_last_of("/");
1067 Desc
.URI
= Desc
.URI
.replace(
1069 Desc
.URI
.substr(trailing_slash
+1).size()+1,
1073 "Fetching ByHash requested but can not find record for %s",
1079 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
1080 // ---------------------------------------------------------------------
1081 /* The only header we use is the last-modified header. */
1082 string
pkgAcqIndex::Custom600Headers() const
1084 std::string
const compExt
= CompressionExtension
.substr(0, CompressionExtension
.find(' '));
1085 string Final
= _config
->FindDir("Dir::State::lists");
1086 Final
+= URItoFileName(RealURI
);
1087 if (_config
->FindB("Acquire::GzipIndexes",false))
1090 string msg
= "\nIndex-File: true";
1093 if (stat(Final
.c_str(),&Buf
) == 0)
1094 msg
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1099 void pkgAcqIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
1101 size_t const nextExt
= CompressionExtension
.find(' ');
1102 if (nextExt
!= std::string::npos
)
1104 CompressionExtension
= CompressionExtension
.substr(nextExt
+1);
1105 Init(RealURI
, Desc
.Description
, Desc
.ShortDesc
);
1109 // on decompression failure, remove bad versions in partial/
1110 if (Decompression
&& Erase
) {
1111 string s
= _config
->FindDir("Dir::State::lists") + "partial/";
1112 s
.append(URItoFileName(RealURI
));
1116 Item::Failed(Message
,Cnf
);
1119 // pkgAcqIndex::GetFinalFilename - Return the full final file path /*{{{*/
1120 std::string
pkgAcqIndex::GetFinalFilename(std::string
const &URI
,
1121 std::string
const &compExt
)
1123 std::string FinalFile
= _config
->FindDir("Dir::State::lists");
1124 FinalFile
+= URItoFileName(URI
);
1125 if (_config
->FindB("Acquire::GzipIndexes",false) == true)
1126 FinalFile
+= '.' + compExt
;
1130 // AcqIndex::ReverifyAfterIMS - Reverify index after an ims-hit /*{{{*/
1131 void pkgAcqIndex::ReverifyAfterIMS(std::string
const &FileName
)
1133 std::string
const compExt
= CompressionExtension
.substr(0, CompressionExtension
.find(' '));
1134 if (_config
->FindB("Acquire::GzipIndexes",false) == true)
1135 DestFile
+= compExt
;
1137 string FinalFile
= GetFinalFilename(RealURI
, compExt
);
1138 Rename(FinalFile
, FileName
);
1139 Decompression
= true;
1140 Desc
.URI
= "copy:" + FileName
;
1144 // AcqIndex::Done - Finished a fetch /*{{{*/
1145 // ---------------------------------------------------------------------
1146 /* This goes through a number of states.. On the initial fetch the
1147 method could possibly return an alternate filename which points
1148 to the uncompressed version of the file. If this is so the file
1149 is copied into the partial directory. In all other cases the file
1150 is decompressed with a gzip uri. */
1151 void pkgAcqIndex::Done(string Message
,unsigned long long Size
,HashStringList
const &Hashes
,
1152 pkgAcquire::MethodConfig
*Cfg
)
1154 Item::Done(Message
,Size
,Hashes
,Cfg
);
1155 std::string
const compExt
= CompressionExtension
.substr(0, CompressionExtension
.find(' '));
1157 if (Decompression
== true)
1159 if (ExpectedHashes
.usable() && ExpectedHashes
!= Hashes
)
1162 RenameOnError(HashSumMismatch
);
1163 printHashSumComparision(RealURI
, ExpectedHashes
, Hashes
);
1167 // FIXME: this can go away once we only ever download stuff that
1168 // has a valid hash and we never do GET based probing
1170 /* Always verify the index file for correctness (all indexes must
1171 * have a Package field) (LP: #346386) (Closes: #627642)
1173 FileFd
fd(DestFile
, FileFd::ReadOnly
, FileFd::Extension
);
1174 // Only test for correctness if the file is not empty (empty is ok)
1178 pkgTagFile
tag(&fd
);
1180 // all our current indexes have a field 'Package' in each section
1181 if (_error
->PendingError() == true || tag
.Step(sec
) == false || sec
.Exists("Package") == false)
1183 RenameOnError(InvalidFormat
);
1188 // Done, move it into position
1189 string FinalFile
= GetFinalFilename(RealURI
, compExt
);
1190 Rename(DestFile
,FinalFile
);
1191 chmod(FinalFile
.c_str(),0644);
1193 /* We restore the original name to DestFile so that the clean operation
1195 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1196 DestFile
+= URItoFileName(RealURI
);
1197 if (_config
->FindB("Acquire::GzipIndexes",false))
1198 DestFile
+= '.' + compExt
;
1200 // Remove the compressed version.
1202 unlink(DestFile
.c_str());
1210 // Handle the unzipd case
1211 string FileName
= LookupTag(Message
,"Alt-Filename");
1212 if (FileName
.empty() == false)
1214 Decompression
= true;
1216 DestFile
+= ".decomp";
1217 Desc
.URI
= "copy:" + FileName
;
1219 ActiveSubprocess
= "copy";
1221 #pragma GCC diagnostic push
1222 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
1226 #pragma GCC diagnostic pop
1231 FileName
= LookupTag(Message
,"Filename");
1232 if (FileName
.empty() == true)
1235 ErrorText
= "Method gave a blank filename";
1238 if (FileName
== DestFile
)
1243 // do not reverify cdrom sources as apt-cdrom may rewrite the Packages
1244 // file when its doing the indexcopy
1245 if (RealURI
.substr(0,6) == "cdrom:" &&
1246 StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
1249 // The files timestamp matches, for non-local URLs reverify the local
1250 // file, for local file, uncompress again to ensure the hashsum is still
1251 // matching the Release file
1252 if (!Local
&& StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
1254 // set destfile to the final destfile
1255 if(_config
->FindB("Acquire::GzipIndexes",false) == false)
1257 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1258 DestFile
+= URItoFileName(RealURI
);
1261 ReverifyAfterIMS(FileName
);
1266 // If we enable compressed indexes, queue for hash verification
1267 if (_config
->FindB("Acquire::GzipIndexes",false))
1269 DestFile
= _config
->FindDir("Dir::State::lists");
1270 DestFile
+= URItoFileName(RealURI
) + '.' + compExt
;
1272 Decompression
= true;
1273 Desc
.URI
= "copy:" + FileName
;
1279 // get the binary name for your used compression type
1280 decompProg
= _config
->Find(string("Acquire::CompressionTypes::").append(compExt
),"");
1281 if(decompProg
.empty() == false);
1282 else if(compExt
== "uncompressed")
1283 decompProg
= "copy";
1285 _error
->Error("Unsupported extension: %s", compExt
.c_str());
1289 Decompression
= true;
1290 DestFile
+= ".decomp";
1291 Desc
.URI
= decompProg
+ ":" + FileName
;
1294 ActiveSubprocess
= decompProg
;
1296 #pragma GCC diagnostic push
1297 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
1299 Mode
= ActiveSubprocess
.c_str();
1301 #pragma GCC diagnostic pop
1305 // AcqIndexTrans::pkgAcqIndexTrans - Constructor /*{{{*/
1306 // ---------------------------------------------------------------------
1307 /* The Translation file is added to the queue */
1308 pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire
*Owner
,
1309 string URI
,string URIDesc
,string ShortDesc
)
1310 : pkgAcqIndex(Owner
, URI
, URIDesc
, ShortDesc
, HashStringList(), "")
1313 pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire
*Owner
, IndexTarget
const * const Target
,
1314 HashStringList
const &ExpectedHashes
, indexRecords
*MetaIndexParser
)
1315 : pkgAcqIndex(Owner
, 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 std::string
const compExt
= CompressionExtension
.substr(0, CompressionExtension
.find(' '));
1328 string Final
= _config
->FindDir("Dir::State::lists");
1329 Final
+= URItoFileName(RealURI
);
1330 if (_config
->FindB("Acquire::GzipIndexes",false))
1334 if (stat(Final
.c_str(),&Buf
) != 0)
1335 return "\nFail-Ignore: true\nIndex-File: true";
1336 return "\nFail-Ignore: true\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1339 // AcqIndexTrans::Failed - Silence failure messages for missing files /*{{{*/
1340 // ---------------------------------------------------------------------
1342 void pkgAcqIndexTrans::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1344 size_t const nextExt
= CompressionExtension
.find(' ');
1345 if (nextExt
!= std::string::npos
)
1347 CompressionExtension
= CompressionExtension
.substr(nextExt
+1);
1348 Init(RealURI
, Desc
.Description
, Desc
.ShortDesc
);
1353 if (Cnf
->LocalOnly
== true ||
1354 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1363 Item::Failed(Message
,Cnf
);
1366 pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire
*Owner
, /*{{{*/
1367 string URI
,string URIDesc
,string ShortDesc
,
1368 string MetaIndexURI
, string MetaIndexURIDesc
,
1369 string MetaIndexShortDesc
,
1370 const vector
<IndexTarget
*>* IndexTargets
,
1371 indexRecords
* MetaIndexParser
) :
1372 Item(Owner
, HashStringList()), RealURI(URI
), MetaIndexURI(MetaIndexURI
),
1373 MetaIndexURIDesc(MetaIndexURIDesc
), MetaIndexShortDesc(MetaIndexShortDesc
),
1374 MetaIndexParser(MetaIndexParser
), IndexTargets(IndexTargets
)
1376 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1377 DestFile
+= URItoFileName(URI
);
1379 // remove any partial downloaded sig-file in partial/.
1380 // it may confuse proxies and is too small to warrant a
1381 // partial download anyway
1382 unlink(DestFile
.c_str());
1385 Desc
.Description
= URIDesc
;
1387 Desc
.ShortDesc
= ShortDesc
;
1390 string Final
= _config
->FindDir("Dir::State::lists");
1391 Final
+= URItoFileName(RealURI
);
1392 if (RealFileExists(Final
) == true)
1394 // File was already in place. It needs to be re-downloaded/verified
1395 // because Release might have changed, we do give it a different
1396 // name than DestFile because otherwise the http method will
1397 // send If-Range requests and there are too many broken servers
1398 // out there that do not understand them
1399 LastGoodSig
= DestFile
+".reverify";
1400 Rename(Final
,LastGoodSig
);
1403 // we expect the indextargets + one additional Release file
1404 ExpectedAdditionalItems
= IndexTargets
->size() + 1;
1409 pkgAcqMetaSig::~pkgAcqMetaSig() /*{{{*/
1411 // if the file was never queued undo file-changes done in the constructor
1412 if (QueueCounter
== 1 && Status
== StatIdle
&& FileSize
== 0 && Complete
== false &&
1413 LastGoodSig
.empty() == false)
1415 string
const Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1416 if (RealFileExists(Final
) == false && RealFileExists(LastGoodSig
) == true)
1417 Rename(LastGoodSig
, Final
);
1422 // pkgAcqMetaSig::Custom600Headers - Insert custom request headers /*{{{*/
1423 // ---------------------------------------------------------------------
1424 /* The only header we use is the last-modified header. */
1425 string
pkgAcqMetaSig::Custom600Headers() const
1428 if (stat(LastGoodSig
.c_str(),&Buf
) != 0)
1429 return "\nIndex-File: true";
1431 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1434 void pkgAcqMetaSig::Done(string Message
,unsigned long long Size
, HashStringList
const &Hashes
,
1435 pkgAcquire::MethodConfig
*Cfg
)
1437 Item::Done(Message
, Size
, Hashes
, Cfg
);
1439 string FileName
= LookupTag(Message
,"Filename");
1440 if (FileName
.empty() == true)
1443 ErrorText
= "Method gave a blank filename";
1447 if (FileName
!= DestFile
)
1449 // We have to copy it into place
1451 Desc
.URI
= "copy:" + FileName
;
1458 // at this point pkgAcqMetaIndex takes over
1459 ExpectedAdditionalItems
= 0;
1461 // put the last known good file back on i-m-s hit (it will
1462 // be re-verified again)
1463 // Else do nothing, we have the new file in DestFile then
1464 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
1465 Rename(LastGoodSig
, DestFile
);
1467 // queue a pkgAcqMetaIndex to be verified against the sig we just retrieved
1468 new pkgAcqMetaIndex(Owner
, MetaIndexURI
, MetaIndexURIDesc
,
1469 MetaIndexShortDesc
, DestFile
, IndexTargets
,
1474 void pkgAcqMetaSig::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)/*{{{*/
1476 string Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1478 // at this point pkgAcqMetaIndex takes over
1479 ExpectedAdditionalItems
= 0;
1481 // if we get a network error we fail gracefully
1482 if(Status
== StatTransientNetworkError
)
1484 Item::Failed(Message
,Cnf
);
1485 // move the sigfile back on transient network failures
1486 if(FileExists(LastGoodSig
))
1487 Rename(LastGoodSig
,Final
);
1489 // set the status back to , Item::Failed likes to reset it
1490 Status
= pkgAcquire::Item::StatTransientNetworkError
;
1494 // Delete any existing sigfile when the acquire failed
1495 unlink(Final
.c_str());
1497 // queue a pkgAcqMetaIndex with no sigfile
1498 new pkgAcqMetaIndex(Owner
, MetaIndexURI
, MetaIndexURIDesc
, MetaIndexShortDesc
,
1499 "", IndexTargets
, MetaIndexParser
);
1501 if (Cnf
->LocalOnly
== true ||
1502 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1511 Item::Failed(Message
,Cnf
);
1514 pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire
*Owner
, /*{{{*/
1515 string URI
,string URIDesc
,string ShortDesc
,
1517 const vector
<IndexTarget
*>* IndexTargets
,
1518 indexRecords
* MetaIndexParser
) :
1519 Item(Owner
, HashStringList()), RealURI(URI
), SigFile(SigFile
), IndexTargets(IndexTargets
),
1520 MetaIndexParser(MetaIndexParser
), AuthPass(false), IMSHit(false)
1522 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1523 DestFile
+= URItoFileName(URI
);
1526 Desc
.Description
= URIDesc
;
1528 Desc
.ShortDesc
= ShortDesc
;
1531 // we expect more item
1532 ExpectedAdditionalItems
= IndexTargets
->size();
1537 // pkgAcqMetaIndex::Custom600Headers - Insert custom request headers /*{{{*/
1538 // ---------------------------------------------------------------------
1539 /* The only header we use is the last-modified header. */
1540 string
pkgAcqMetaIndex::Custom600Headers() const
1542 string Final
= _config
->FindDir("Dir::State::lists");
1543 Final
+= URItoFileName(RealURI
);
1546 if (stat(Final
.c_str(),&Buf
) != 0)
1547 return "\nIndex-File: true";
1549 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1552 void pkgAcqMetaIndex::Done(string Message
,unsigned long long Size
,HashStringList
const &Hashes
, /*{{{*/
1553 pkgAcquire::MethodConfig
*Cfg
)
1555 Item::Done(Message
,Size
,Hashes
,Cfg
);
1557 // MetaIndexes are done in two passes: one to download the
1558 // metaindex with an appropriate method, and a second to verify it
1559 // with the gpgv method
1561 if (AuthPass
== true)
1565 // all cool, move Release file into place
1570 RetrievalDone(Message
);
1572 // Still more retrieving to do
1577 // There was no signature file, so we are finished. Download
1578 // the indexes and do only hashsum verification if possible
1579 MetaIndexParser
->Load(DestFile
);
1580 QueueIndexes(false);
1584 // FIXME: move this into pkgAcqMetaClearSig::Done on the next
1587 // if we expect a ClearTextSignature (InRelase), ensure that
1588 // this is what we get and if not fail to queue a
1589 // Release/Release.gpg, see #346386
1590 if (SigFile
== DestFile
&& !StartsWithGPGClearTextSignature(DestFile
))
1592 Failed(Message
, Cfg
);
1596 // There was a signature file, so pass it to gpgv for
1598 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1599 std::cerr
<< "Metaindex acquired, queueing gpg verification ("
1600 << SigFile
<< "," << DestFile
<< ")\n";
1602 Desc
.URI
= "gpgv:" + SigFile
;
1604 ActiveSubprocess
= "gpgv";
1606 #pragma GCC diagnostic push
1607 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
1611 #pragma GCC diagnostic pop
1617 if (Complete
== true)
1619 string FinalFile
= _config
->FindDir("Dir::State::lists");
1620 FinalFile
+= URItoFileName(RealURI
);
1621 if (SigFile
== DestFile
)
1622 SigFile
= FinalFile
;
1623 Rename(DestFile
,FinalFile
);
1624 chmod(FinalFile
.c_str(),0644);
1625 DestFile
= FinalFile
;
1629 void pkgAcqMetaIndex::RetrievalDone(string Message
) /*{{{*/
1631 // We have just finished downloading a Release file (it is not
1634 string FileName
= LookupTag(Message
,"Filename");
1635 if (FileName
.empty() == true)
1638 ErrorText
= "Method gave a blank filename";
1642 if (FileName
!= DestFile
)
1645 Desc
.URI
= "copy:" + FileName
;
1650 // make sure to verify against the right file on I-M-S hit
1651 IMSHit
= StringToBool(LookupTag(Message
,"IMS-Hit"),false);
1654 string FinalFile
= _config
->FindDir("Dir::State::lists");
1655 FinalFile
+= URItoFileName(RealURI
);
1656 if (SigFile
== DestFile
)
1658 SigFile
= FinalFile
;
1659 // constructor of pkgAcqMetaClearSig moved it out of the way,
1660 // now move it back in on IMS hit for the 'old' file
1661 string
const OldClearSig
= DestFile
+ ".reverify";
1662 if (RealFileExists(OldClearSig
) == true)
1663 Rename(OldClearSig
, FinalFile
);
1665 DestFile
= FinalFile
;
1670 void pkgAcqMetaIndex::AuthDone(string Message
) /*{{{*/
1672 // At this point, the gpgv method has succeeded, so there is a
1673 // valid signature from a key in the trusted keyring. We
1674 // perform additional verification of its contents, and use them
1675 // to verify the indexes we are about to download
1677 if (!MetaIndexParser
->Load(DestFile
))
1679 Status
= StatAuthError
;
1680 ErrorText
= MetaIndexParser
->ErrorText
;
1684 if (!VerifyVendor(Message
))
1689 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1690 std::cerr
<< "Signature verification succeeded: "
1691 << DestFile
<< std::endl
;
1693 // do not trust any previously unverified content that we may have
1694 string LastGoodSigFile
= _config
->FindDir("Dir::State::lists").append("partial/").append(URItoFileName(RealURI
));
1695 if (DestFile
!= SigFile
)
1696 LastGoodSigFile
.append(".gpg");
1697 LastGoodSigFile
.append(".reverify");
1698 if(IMSHit
== false && RealFileExists(LastGoodSigFile
) == false)
1700 for (vector
<struct IndexTarget
*>::const_iterator Target
= IndexTargets
->begin();
1701 Target
!= IndexTargets
->end();
1704 // remove old indexes
1705 std::string index
= _config
->FindDir("Dir::State::lists") +
1706 URItoFileName((*Target
)->URI
);
1707 unlink(index
.c_str());
1708 // and also old gzipindexes
1709 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
1710 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
1712 index
+= '.' + (*t
);
1713 unlink(index
.c_str());
1719 // Download further indexes with verification
1722 // is it a clearsigned MetaIndex file?
1723 if (DestFile
== SigFile
)
1726 // Done, move signature file into position
1727 string VerifiedSigFile
= _config
->FindDir("Dir::State::lists") +
1728 URItoFileName(RealURI
) + ".gpg";
1729 Rename(SigFile
,VerifiedSigFile
);
1730 chmod(VerifiedSigFile
.c_str(),0644);
1733 void pkgAcqMetaIndex::QueueIndexes(bool verify
) /*{{{*/
1736 /* Reject invalid, existing Release files (LP: #346386) (Closes: #627642)
1737 * FIXME: Disabled; it breaks unsigned repositories without hashes */
1738 if (!verify
&& FileExists(DestFile
) && !MetaIndexParser
->Load(DestFile
))
1741 ErrorText
= MetaIndexParser
->ErrorText
;
1745 bool transInRelease
= false;
1747 std::vector
<std::string
> const keys
= MetaIndexParser
->MetaKeys();
1748 for (std::vector
<std::string
>::const_iterator k
= keys
.begin(); k
!= keys
.end(); ++k
)
1749 // FIXME: Feels wrong to check for hardcoded string here, but what should we do else…
1750 if (k
->find("Translation-") != std::string::npos
)
1752 transInRelease
= true;
1757 // at this point the real Items are loaded in the fetcher
1758 ExpectedAdditionalItems
= 0;
1759 for (vector
<IndexTarget
*>::const_iterator Target
= IndexTargets
->begin();
1760 Target
!= IndexTargets
->end();
1763 HashStringList ExpectedIndexHashes
;
1764 const indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup((*Target
)->MetaKey
);
1765 bool compressedAvailable
= false;
1768 if ((*Target
)->IsOptional() == true)
1770 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
1771 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
1772 if (MetaIndexParser
->Exists((*Target
)->MetaKey
+ "." + *t
) == true)
1774 compressedAvailable
= true;
1778 else if (verify
== true)
1780 Status
= StatAuthError
;
1781 strprintf(ErrorText
, _("Unable to find expected entry '%s' in Release file (Wrong sources.list entry or malformed file)"), (*Target
)->MetaKey
.c_str());
1787 ExpectedIndexHashes
= Record
->Hashes
;
1788 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1790 std::cerr
<< "Queueing: " << (*Target
)->URI
<< std::endl
1791 << "Expected Hash:" << std::endl
;
1792 for (HashStringList::const_iterator hs
= ExpectedIndexHashes
.begin(); hs
!= ExpectedIndexHashes
.end(); ++hs
)
1793 std::cerr
<< "\t- " << hs
->toStr() << std::endl
;
1794 std::cerr
<< "For: " << Record
->MetaKeyFilename
<< std::endl
;
1796 if (verify
== true && ExpectedIndexHashes
.empty() == true && (*Target
)->IsOptional() == false)
1798 Status
= StatAuthError
;
1799 strprintf(ErrorText
, _("Unable to find hash sum for '%s' in Release file"), (*Target
)->MetaKey
.c_str());
1804 if ((*Target
)->IsOptional() == true)
1806 if ((*Target
)->IsSubIndex() == true)
1807 new pkgAcqSubIndex(Owner
, (*Target
)->URI
, (*Target
)->Description
,
1808 (*Target
)->ShortDesc
, ExpectedIndexHashes
);
1809 else if (transInRelease
== false || Record
!= NULL
|| compressedAvailable
== true)
1811 if (_config
->FindB("Acquire::PDiffs",true) == true && transInRelease
== true &&
1812 MetaIndexParser
->Exists((*Target
)->MetaKey
+ ".diff/Index") == true)
1813 new pkgAcqDiffIndex(Owner
, *Target
, ExpectedIndexHashes
, MetaIndexParser
);
1815 new pkgAcqIndexTrans(Owner
, *Target
, ExpectedIndexHashes
, MetaIndexParser
);
1820 /* Queue Packages file (either diff or full packages files, depending
1821 on the users option) - we also check if the PDiff Index file is listed
1822 in the Meta-Index file. Ideal would be if pkgAcqDiffIndex would test this
1823 instead, but passing the required info to it is to much hassle */
1824 if(_config
->FindB("Acquire::PDiffs",true) == true && (verify
== false ||
1825 MetaIndexParser
->Exists((*Target
)->MetaKey
+ ".diff/Index") == true))
1826 new pkgAcqDiffIndex(Owner
, *Target
, ExpectedIndexHashes
, MetaIndexParser
);
1828 new pkgAcqIndex(Owner
, *Target
, ExpectedIndexHashes
, MetaIndexParser
);
1832 bool pkgAcqMetaIndex::VerifyVendor(string Message
) /*{{{*/
1834 string::size_type pos
;
1836 // check for missing sigs (that where not fatal because otherwise we had
1839 string msg
= _("There is no public key available for the "
1840 "following key IDs:\n");
1841 pos
= Message
.find("NO_PUBKEY ");
1842 if (pos
!= std::string::npos
)
1844 string::size_type start
= pos
+strlen("NO_PUBKEY ");
1845 string Fingerprint
= Message
.substr(start
, Message
.find("\n")-start
);
1846 missingkeys
+= (Fingerprint
);
1848 if(!missingkeys
.empty())
1849 _error
->Warning("%s", (msg
+ missingkeys
).c_str());
1851 string Transformed
= MetaIndexParser
->GetExpectedDist();
1853 if (Transformed
== "../project/experimental")
1855 Transformed
= "experimental";
1858 pos
= Transformed
.rfind('/');
1859 if (pos
!= string::npos
)
1861 Transformed
= Transformed
.substr(0, pos
);
1864 if (Transformed
== ".")
1869 if (_config
->FindB("Acquire::Check-Valid-Until", true) == true &&
1870 MetaIndexParser
->GetValidUntil() > 0) {
1871 time_t const invalid_since
= time(NULL
) - MetaIndexParser
->GetValidUntil();
1872 if (invalid_since
> 0)
1873 // TRANSLATOR: The first %s is the URL of the bad Release file, the second is
1874 // the time since then the file is invalid - formated in the same way as in
1875 // the download progress display (e.g. 7d 3h 42min 1s)
1876 return _error
->Error(
1877 _("Release file for %s is expired (invalid since %s). "
1878 "Updates for this repository will not be applied."),
1879 RealURI
.c_str(), TimeToStr(invalid_since
).c_str());
1882 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1884 std::cerr
<< "Got Codename: " << MetaIndexParser
->GetDist() << std::endl
;
1885 std::cerr
<< "Expecting Dist: " << MetaIndexParser
->GetExpectedDist() << std::endl
;
1886 std::cerr
<< "Transformed Dist: " << Transformed
<< std::endl
;
1889 if (MetaIndexParser
->CheckDist(Transformed
) == false)
1891 // This might become fatal one day
1892 // Status = StatAuthError;
1893 // ErrorText = "Conflicting distribution; expected "
1894 // + MetaIndexParser->GetExpectedDist() + " but got "
1895 // + MetaIndexParser->GetDist();
1897 if (!Transformed
.empty())
1899 _error
->Warning(_("Conflicting distribution: %s (expected %s but got %s)"),
1900 Desc
.Description
.c_str(),
1901 Transformed
.c_str(),
1902 MetaIndexParser
->GetDist().c_str());
1909 // pkgAcqMetaIndex::Failed - no Release file present or no signature file present /*{{{*/
1910 // ---------------------------------------------------------------------
1912 void pkgAcqMetaIndex::Failed(string Message
,pkgAcquire::MethodConfig
* /*Cnf*/)
1914 if (AuthPass
== true)
1916 // gpgv method failed, if we have a good signature
1917 string LastGoodSigFile
= _config
->FindDir("Dir::State::lists").append("partial/").append(URItoFileName(RealURI
));
1918 if (DestFile
!= SigFile
)
1919 LastGoodSigFile
.append(".gpg");
1920 LastGoodSigFile
.append(".reverify");
1922 if(FileExists(LastGoodSigFile
))
1924 string VerifiedSigFile
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1925 if (DestFile
!= SigFile
)
1926 VerifiedSigFile
.append(".gpg");
1927 Rename(LastGoodSigFile
, VerifiedSigFile
);
1928 Status
= StatTransientNetworkError
;
1929 _error
->Warning(_("An error occurred during the signature "
1930 "verification. The repository is not updated "
1931 "and the previous index files will be used. "
1932 "GPG error: %s: %s\n"),
1933 Desc
.Description
.c_str(),
1934 LookupTag(Message
,"Message").c_str());
1935 RunScripts("APT::Update::Auth-Failure");
1937 } else if (LookupTag(Message
,"Message").find("NODATA") != string::npos
) {
1938 /* Invalid signature file, reject (LP: #346386) (Closes: #627642) */
1939 _error
->Error(_("GPG error: %s: %s"),
1940 Desc
.Description
.c_str(),
1941 LookupTag(Message
,"Message").c_str());
1944 _error
->Warning(_("GPG error: %s: %s"),
1945 Desc
.Description
.c_str(),
1946 LookupTag(Message
,"Message").c_str());
1948 // gpgv method failed
1949 ReportMirrorFailure("GPGFailure");
1952 /* Always move the meta index, even if gpgv failed. This ensures
1953 * that PackageFile objects are correctly filled in */
1954 if (FileExists(DestFile
)) {
1955 string FinalFile
= _config
->FindDir("Dir::State::lists");
1956 FinalFile
+= URItoFileName(RealURI
);
1957 /* InRelease files become Release files, otherwise
1958 * they would be considered as trusted later on */
1959 if (SigFile
== DestFile
) {
1960 RealURI
= RealURI
.replace(RealURI
.rfind("InRelease"), 9,
1962 FinalFile
= FinalFile
.replace(FinalFile
.rfind("InRelease"), 9,
1964 SigFile
= FinalFile
;
1966 Rename(DestFile
,FinalFile
);
1967 chmod(FinalFile
.c_str(),0644);
1969 DestFile
= FinalFile
;
1972 // No Release file was present, or verification failed, so fall
1973 // back to queueing Packages files without verification
1974 QueueIndexes(false);
1977 pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire
*Owner
, /*{{{*/
1978 string
const &URI
, string
const &URIDesc
, string
const &ShortDesc
,
1979 string
const &MetaIndexURI
, string
const &MetaIndexURIDesc
, string
const &MetaIndexShortDesc
,
1980 string
const &MetaSigURI
, string
const &MetaSigURIDesc
, string
const &MetaSigShortDesc
,
1981 const vector
<IndexTarget
*>* IndexTargets
,
1982 indexRecords
* MetaIndexParser
) :
1983 pkgAcqMetaIndex(Owner
, URI
, URIDesc
, ShortDesc
, "", IndexTargets
, MetaIndexParser
),
1984 MetaIndexURI(MetaIndexURI
), MetaIndexURIDesc(MetaIndexURIDesc
), MetaIndexShortDesc(MetaIndexShortDesc
),
1985 MetaSigURI(MetaSigURI
), MetaSigURIDesc(MetaSigURIDesc
), MetaSigShortDesc(MetaSigShortDesc
)
1989 // index targets + (worst case:) Release/Release.gpg
1990 ExpectedAdditionalItems
= IndexTargets
->size() + 2;
1993 // keep the old InRelease around in case of transistent network errors
1994 string
const Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1995 if (RealFileExists(Final
) == true)
1997 string
const LastGoodSig
= DestFile
+ ".reverify";
1998 Rename(Final
,LastGoodSig
);
2002 pkgAcqMetaClearSig::~pkgAcqMetaClearSig() /*{{{*/
2004 // if the file was never queued undo file-changes done in the constructor
2005 if (QueueCounter
== 1 && Status
== StatIdle
&& FileSize
== 0 && Complete
== false)
2007 string
const Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
2008 string
const LastGoodSig
= DestFile
+ ".reverify";
2009 if (RealFileExists(Final
) == false && RealFileExists(LastGoodSig
) == true)
2010 Rename(LastGoodSig
, Final
);
2014 // pkgAcqMetaClearSig::Custom600Headers - Insert custom request headers /*{{{*/
2015 // ---------------------------------------------------------------------
2016 // FIXME: this can go away once the InRelease file is used widely
2017 string
pkgAcqMetaClearSig::Custom600Headers() const
2019 string Final
= _config
->FindDir("Dir::State::lists");
2020 Final
+= URItoFileName(RealURI
);
2023 if (stat(Final
.c_str(),&Buf
) != 0)
2025 Final
= DestFile
+ ".reverify";
2026 if (stat(Final
.c_str(),&Buf
) != 0)
2027 return "\nIndex-File: true\nFail-Ignore: true\n";
2030 return "\nIndex-File: true\nFail-Ignore: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
2033 void pkgAcqMetaClearSig::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
2035 // we failed, we will not get additional items from this method
2036 ExpectedAdditionalItems
= 0;
2038 if (AuthPass
== false)
2040 // Remove the 'old' InRelease file if we try Release.gpg now as otherwise
2041 // the file will stay around and gives a false-auth impression (CVE-2012-0214)
2042 string FinalFile
= _config
->FindDir("Dir::State::lists");
2043 FinalFile
.append(URItoFileName(RealURI
));
2044 if (FileExists(FinalFile
))
2045 unlink(FinalFile
.c_str());
2047 new pkgAcqMetaSig(Owner
,
2048 MetaSigURI
, MetaSigURIDesc
, MetaSigShortDesc
,
2049 MetaIndexURI
, MetaIndexURIDesc
, MetaIndexShortDesc
,
2050 IndexTargets
, MetaIndexParser
);
2051 if (Cnf
->LocalOnly
== true ||
2052 StringToBool(LookupTag(Message
, "Transient-Failure"), false) == false)
2056 pkgAcqMetaIndex::Failed(Message
, Cnf
);
2059 // AcqArchive::AcqArchive - Constructor /*{{{*/
2060 // ---------------------------------------------------------------------
2061 /* This just sets up the initial fetch environment and queues the first
2063 pkgAcqArchive::pkgAcqArchive(pkgAcquire
*Owner
,pkgSourceList
*Sources
,
2064 pkgRecords
*Recs
,pkgCache::VerIterator
const &Version
,
2065 string
&StoreFilename
) :
2066 Item(Owner
, HashStringList()), Version(Version
), Sources(Sources
), Recs(Recs
),
2067 StoreFilename(StoreFilename
), Vf(Version
.FileList()),
2070 Retries
= _config
->FindI("Acquire::Retries",0);
2072 if (Version
.Arch() == 0)
2074 _error
->Error(_("I wasn't able to locate a file for the %s package. "
2075 "This might mean you need to manually fix this package. "
2076 "(due to missing arch)"),
2077 Version
.ParentPkg().FullName().c_str());
2081 /* We need to find a filename to determine the extension. We make the
2082 assumption here that all the available sources for this version share
2083 the same extension.. */
2084 // Skip not source sources, they do not have file fields.
2085 for (; Vf
.end() == false; ++Vf
)
2087 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
2092 // Does not really matter here.. we are going to fail out below
2093 if (Vf
.end() != true)
2095 // If this fails to get a file name we will bomb out below.
2096 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2097 if (_error
->PendingError() == true)
2100 // Generate the final file name as: package_version_arch.foo
2101 StoreFilename
= QuoteString(Version
.ParentPkg().Name(),"_:") + '_' +
2102 QuoteString(Version
.VerStr(),"_:") + '_' +
2103 QuoteString(Version
.Arch(),"_:.") +
2104 "." + flExtension(Parse
.FileName());
2107 // check if we have one trusted source for the package. if so, switch
2108 // to "TrustedOnly" mode - but only if not in AllowUnauthenticated mode
2109 bool const allowUnauth
= _config
->FindB("APT::Get::AllowUnauthenticated", false);
2110 bool const debugAuth
= _config
->FindB("Debug::pkgAcquire::Auth", false);
2111 bool seenUntrusted
= false;
2112 for (pkgCache::VerFileIterator i
= Version
.FileList(); i
.end() == false; ++i
)
2114 pkgIndexFile
*Index
;
2115 if (Sources
->FindIndex(i
.File(),Index
) == false)
2118 if (debugAuth
== true)
2119 std::cerr
<< "Checking index: " << Index
->Describe()
2120 << "(Trusted=" << Index
->IsTrusted() << ")" << std::endl
;
2122 if (Index
->IsTrusted() == true)
2125 if (allowUnauth
== false)
2129 seenUntrusted
= true;
2132 // "allow-unauthenticated" restores apts old fetching behaviour
2133 // that means that e.g. unauthenticated file:// uris are higher
2134 // priority than authenticated http:// uris
2135 if (allowUnauth
== true && seenUntrusted
== true)
2139 if (QueueNext() == false && _error
->PendingError() == false)
2140 _error
->Error(_("Can't find a source to download version '%s' of '%s'"),
2141 Version
.VerStr(), Version
.ParentPkg().FullName(false).c_str());
2144 // AcqArchive::QueueNext - Queue the next file source /*{{{*/
2145 // ---------------------------------------------------------------------
2146 /* This queues the next available file version for download. It checks if
2147 the archive is already available in the cache and stashs the MD5 for
2149 bool pkgAcqArchive::QueueNext()
2151 for (; Vf
.end() == false; ++Vf
)
2153 // Ignore not source sources
2154 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
2157 // Try to cross match against the source list
2158 pkgIndexFile
*Index
;
2159 if (Sources
->FindIndex(Vf
.File(),Index
) == false)
2162 // only try to get a trusted package from another source if that source
2164 if(Trusted
&& !Index
->IsTrusted())
2167 // Grab the text package record
2168 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2169 if (_error
->PendingError() == true)
2172 string PkgFile
= Parse
.FileName();
2173 ExpectedHashes
= Parse
.Hashes();
2175 if (PkgFile
.empty() == true)
2176 return _error
->Error(_("The package index files are corrupted. No Filename: "
2177 "field for package %s."),
2178 Version
.ParentPkg().Name());
2180 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
2181 Desc
.Description
= Index
->ArchiveInfo(Version
);
2183 Desc
.ShortDesc
= Version
.ParentPkg().FullName(true);
2185 // See if we already have the file. (Legacy filenames)
2186 FileSize
= Version
->Size
;
2187 string FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile
);
2189 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2191 // Make sure the size matches
2192 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2197 StoreFilename
= DestFile
= FinalFile
;
2201 /* Hmm, we have a file and its size does not match, this means it is
2202 an old style mismatched arch */
2203 unlink(FinalFile
.c_str());
2206 // Check it again using the new style output filenames
2207 FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
2208 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2210 // Make sure the size matches
2211 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2216 StoreFilename
= DestFile
= FinalFile
;
2220 /* Hmm, we have a file and its size does not match, this shouldn't
2222 unlink(FinalFile
.c_str());
2225 DestFile
= _config
->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename
);
2227 // Check the destination file
2228 if (stat(DestFile
.c_str(),&Buf
) == 0)
2230 // Hmm, the partial file is too big, erase it
2231 if ((unsigned long long)Buf
.st_size
> Version
->Size
)
2232 unlink(DestFile
.c_str());
2234 PartialSize
= Buf
.st_size
;
2237 // Disables download of archives - useful if no real installation follows,
2238 // e.g. if we are just interested in proposed installation order
2239 if (_config
->FindB("Debug::pkgAcqArchive::NoQueue", false) == true)
2244 StoreFilename
= DestFile
= FinalFile
;
2258 // AcqArchive::Done - Finished fetching /*{{{*/
2259 // ---------------------------------------------------------------------
2261 void pkgAcqArchive::Done(string Message
,unsigned long long Size
, HashStringList
const &CalcHashes
,
2262 pkgAcquire::MethodConfig
*Cfg
)
2264 Item::Done(Message
, Size
, CalcHashes
, Cfg
);
2267 if (Size
!= Version
->Size
)
2269 RenameOnError(SizeMismatch
);
2273 // FIXME: could this empty() check impose *any* sort of security issue?
2274 if(ExpectedHashes
.usable() && ExpectedHashes
!= CalcHashes
)
2276 RenameOnError(HashSumMismatch
);
2277 printHashSumComparision(DestFile
, ExpectedHashes
, CalcHashes
);
2281 // Grab the output filename
2282 string FileName
= LookupTag(Message
,"Filename");
2283 if (FileName
.empty() == true)
2286 ErrorText
= "Method gave a blank filename";
2292 // Reference filename
2293 if (FileName
!= DestFile
)
2295 StoreFilename
= DestFile
= FileName
;
2300 // Done, move it into position
2301 string FinalFile
= _config
->FindDir("Dir::Cache::Archives");
2302 FinalFile
+= flNotDir(StoreFilename
);
2303 Rename(DestFile
,FinalFile
);
2305 StoreFilename
= DestFile
= FinalFile
;
2309 // AcqArchive::Failed - Failure handler /*{{{*/
2310 // ---------------------------------------------------------------------
2311 /* Here we try other sources */
2312 void pkgAcqArchive::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
2314 ErrorText
= LookupTag(Message
,"Message");
2316 /* We don't really want to retry on failed media swaps, this prevents
2317 that. An interesting observation is that permanent failures are not
2319 if (Cnf
->Removable
== true &&
2320 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2322 // Vf = Version.FileList();
2323 while (Vf
.end() == false) ++Vf
;
2324 StoreFilename
= string();
2325 Item::Failed(Message
,Cnf
);
2329 if (QueueNext() == false)
2331 // This is the retry counter
2333 Cnf
->LocalOnly
== false &&
2334 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2337 Vf
= Version
.FileList();
2338 if (QueueNext() == true)
2342 StoreFilename
= string();
2343 Item::Failed(Message
,Cnf
);
2347 // AcqArchive::IsTrusted - Determine whether this archive comes from a trusted source /*{{{*/
2348 // ---------------------------------------------------------------------
2349 APT_PURE
bool pkgAcqArchive::IsTrusted() const
2354 // AcqArchive::Finished - Fetching has finished, tidy up /*{{{*/
2355 // ---------------------------------------------------------------------
2357 void pkgAcqArchive::Finished()
2359 if (Status
== pkgAcquire::Item::StatDone
&&
2362 StoreFilename
= string();
2365 // AcqFile::pkgAcqFile - Constructor /*{{{*/
2366 // ---------------------------------------------------------------------
2367 /* The file is added to the queue */
2368 pkgAcqFile::pkgAcqFile(pkgAcquire
*Owner
,string URI
, HashStringList
const &Hashes
,
2369 unsigned long long Size
,string Dsc
,string ShortDesc
,
2370 const string
&DestDir
, const string
&DestFilename
,
2372 Item(Owner
, Hashes
), IsIndexFile(IsIndexFile
)
2374 Retries
= _config
->FindI("Acquire::Retries",0);
2376 if(!DestFilename
.empty())
2377 DestFile
= DestFilename
;
2378 else if(!DestDir
.empty())
2379 DestFile
= DestDir
+ "/" + flNotDir(URI
);
2381 DestFile
= flNotDir(URI
);
2385 Desc
.Description
= Dsc
;
2388 // Set the short description to the archive component
2389 Desc
.ShortDesc
= ShortDesc
;
2391 // Get the transfer sizes
2394 if (stat(DestFile
.c_str(),&Buf
) == 0)
2396 // Hmm, the partial file is too big, erase it
2397 if ((Size
> 0) && (unsigned long long)Buf
.st_size
> Size
)
2398 unlink(DestFile
.c_str());
2400 PartialSize
= Buf
.st_size
;
2406 // AcqFile::Done - Item downloaded OK /*{{{*/
2407 // ---------------------------------------------------------------------
2409 void pkgAcqFile::Done(string Message
,unsigned long long Size
,HashStringList
const &CalcHashes
,
2410 pkgAcquire::MethodConfig
*Cnf
)
2412 Item::Done(Message
,Size
,CalcHashes
,Cnf
);
2415 if(ExpectedHashes
.usable() && ExpectedHashes
!= CalcHashes
)
2417 RenameOnError(HashSumMismatch
);
2418 printHashSumComparision(DestFile
, ExpectedHashes
, CalcHashes
);
2422 string FileName
= LookupTag(Message
,"Filename");
2423 if (FileName
.empty() == true)
2426 ErrorText
= "Method gave a blank filename";
2432 // The files timestamp matches
2433 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
2436 // We have to copy it into place
2437 if (FileName
!= DestFile
)
2440 if (_config
->FindB("Acquire::Source-Symlinks",true) == false ||
2441 Cnf
->Removable
== true)
2443 Desc
.URI
= "copy:" + FileName
;
2448 // Erase the file if it is a symlink so we can overwrite it
2450 if (lstat(DestFile
.c_str(),&St
) == 0)
2452 if (S_ISLNK(St
.st_mode
) != 0)
2453 unlink(DestFile
.c_str());
2457 if (symlink(FileName
.c_str(),DestFile
.c_str()) != 0)
2459 ErrorText
= "Link to " + DestFile
+ " failure ";
2466 // AcqFile::Failed - Failure handler /*{{{*/
2467 // ---------------------------------------------------------------------
2468 /* Here we try other sources */
2469 void pkgAcqFile::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
2471 ErrorText
= LookupTag(Message
,"Message");
2473 // This is the retry counter
2475 Cnf
->LocalOnly
== false &&
2476 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2483 Item::Failed(Message
,Cnf
);
2486 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
2487 // ---------------------------------------------------------------------
2488 /* The only header we use is the last-modified header. */
2489 string
pkgAcqFile::Custom600Headers() const
2492 return "\nIndex-File: true";