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
;
1026 MetaKey
= string(Target
->MetaKey
) + '.' + comprExt
;
1029 // load the filesize
1032 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(MetaKey
);
1034 FileSize
= Record
->Size
;
1036 InitByHashIfNeeded(MetaKey
);
1039 Desc
.Description
= URIDesc
;
1041 Desc
.ShortDesc
= ShortDesc
;
1046 // AcqIndex::AdjustForByHash - modify URI for by-hash support /*{{{*/
1047 // ---------------------------------------------------------------------
1049 void pkgAcqIndex::InitByHashIfNeeded(const std::string MetaKey
)
1052 // - (maybe?) add support for by-hash into the sources.list as flag
1053 // - make apt-ftparchive generate the hashes (and expire?)
1054 std::string HostKnob
= "APT::Acquire::" + ::URI(Desc
.URI
).Host
+ "::By-Hash";
1055 if(_config
->FindB("APT::Acquire::By-Hash", false) == true ||
1056 _config
->FindB(HostKnob
, false) == true ||
1057 MetaIndexParser
->GetSupportsAcquireByHash())
1059 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(MetaKey
);
1062 // FIXME: should we really use the best hash here? or a fixed one?
1063 const HashString
*TargetHash
= Record
->Hashes
.find("");
1064 std::string ByHash
= "/by-hash/" + TargetHash
->HashType() + "/" + TargetHash
->HashValue();
1065 size_t trailing_slash
= Desc
.URI
.find_last_of("/");
1066 Desc
.URI
= Desc
.URI
.replace(
1068 Desc
.URI
.substr(trailing_slash
+1).size()+1,
1072 "Fetching ByHash requested but can not find record for %s",
1078 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
1079 // ---------------------------------------------------------------------
1080 /* The only header we use is the last-modified header. */
1081 string
pkgAcqIndex::Custom600Headers() const
1083 string Final
= _config
->FindDir("Dir::State::lists");
1084 Final
+= URItoFileName(RealURI
);
1085 if (_config
->FindB("Acquire::GzipIndexes",false))
1088 string msg
= "\nIndex-File: true";
1091 if (stat(Final
.c_str(),&Buf
) == 0)
1092 msg
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1097 void pkgAcqIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
1099 size_t const nextExt
= CompressionExtension
.find(' ');
1100 if (nextExt
!= std::string::npos
)
1102 CompressionExtension
= CompressionExtension
.substr(nextExt
+1);
1103 Init(RealURI
, Desc
.Description
, Desc
.ShortDesc
);
1107 // on decompression failure, remove bad versions in partial/
1108 if (Decompression
&& Erase
) {
1109 string s
= _config
->FindDir("Dir::State::lists") + "partial/";
1110 s
.append(URItoFileName(RealURI
));
1114 Item::Failed(Message
,Cnf
);
1117 // pkgAcqIndex::GetFinalFilename - Return the full final file path /*{{{*/
1118 std::string
pkgAcqIndex::GetFinalFilename(std::string
const &URI
,
1119 std::string
const &compExt
)
1121 std::string FinalFile
= _config
->FindDir("Dir::State::lists");
1122 FinalFile
+= URItoFileName(URI
);
1123 if (_config
->FindB("Acquire::GzipIndexes",false) && compExt
== "gz")
1128 // AcqIndex::ReverifyAfterIMS - Reverify index after an ims-hit /*{{{*/
1129 void pkgAcqIndex::ReverifyAfterIMS(std::string
const &FileName
)
1131 std::string
const compExt
= CompressionExtension
.substr(0, CompressionExtension
.find(' '));
1132 if (_config
->FindB("Acquire::GzipIndexes",false) && compExt
== "gz")
1135 string FinalFile
= GetFinalFilename(RealURI
, compExt
);
1136 Rename(FinalFile
, FileName
);
1137 Decompression
= true;
1138 Desc
.URI
= "copy:" + FileName
;
1142 // AcqIndex::Done - Finished a fetch /*{{{*/
1143 // ---------------------------------------------------------------------
1144 /* This goes through a number of states.. On the initial fetch the
1145 method could possibly return an alternate filename which points
1146 to the uncompressed version of the file. If this is so the file
1147 is copied into the partial directory. In all other cases the file
1148 is decompressed with a gzip uri. */
1149 void pkgAcqIndex::Done(string Message
,unsigned long long Size
,HashStringList
const &Hashes
,
1150 pkgAcquire::MethodConfig
*Cfg
)
1152 Item::Done(Message
,Size
,Hashes
,Cfg
);
1153 std::string
const compExt
= CompressionExtension
.substr(0, CompressionExtension
.find(' '));
1155 if (Decompression
== true)
1157 if (ExpectedHashes
.usable() && ExpectedHashes
!= Hashes
)
1160 RenameOnError(HashSumMismatch
);
1161 printHashSumComparision(RealURI
, ExpectedHashes
, Hashes
);
1165 // FIXME: this can go away once we only ever download stuff that
1166 // has a valid hash and we never do GET based probing
1168 /* Always verify the index file for correctness (all indexes must
1169 * have a Package field) (LP: #346386) (Closes: #627642)
1171 FileFd
fd(DestFile
, FileFd::ReadOnlyGzip
);
1172 // Only test for correctness if the file is not empty (empty is ok)
1176 pkgTagFile
tag(&fd
);
1178 // all our current indexes have a field 'Package' in each section
1179 if (_error
->PendingError() == true || tag
.Step(sec
) == false || sec
.Exists("Package") == false)
1181 RenameOnError(InvalidFormat
);
1186 // Done, move it into position
1187 string FinalFile
= GetFinalFilename(RealURI
, compExt
);
1188 Rename(DestFile
,FinalFile
);
1189 chmod(FinalFile
.c_str(),0644);
1191 /* We restore the original name to DestFile so that the clean operation
1193 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1194 DestFile
+= URItoFileName(RealURI
);
1195 if (_config
->FindB("Acquire::GzipIndexes",false) && compExt
== "gz")
1198 // Remove the compressed version.
1200 unlink(DestFile
.c_str());
1208 // Handle the unzipd case
1209 string FileName
= LookupTag(Message
,"Alt-Filename");
1210 if (FileName
.empty() == false)
1212 Decompression
= true;
1214 DestFile
+= ".decomp";
1215 Desc
.URI
= "copy:" + FileName
;
1217 ActiveSubprocess
= "copy";
1219 #pragma GCC diagnostic push
1220 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
1224 #pragma GCC diagnostic pop
1229 FileName
= LookupTag(Message
,"Filename");
1230 if (FileName
.empty() == true)
1233 ErrorText
= "Method gave a blank filename";
1236 if (FileName
== DestFile
)
1241 // do not reverify cdrom sources as apt-cdrom may rewrite the Packages
1242 // file when its doing the indexcopy
1243 if (RealURI
.substr(0,6) == "cdrom:" &&
1244 StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
1247 // The files timestamp matches, for non-local URLs reverify the local
1248 // file, for local file, uncompress again to ensure the hashsum is still
1249 // matching the Release file
1250 if (!Local
&& StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
1252 ReverifyAfterIMS(FileName
);
1257 // If we enable compressed indexes, queue for hash verification
1258 if (_config
->FindB("Acquire::GzipIndexes",false) && compExt
== "gz" && !Local
)
1260 DestFile
= _config
->FindDir("Dir::State::lists");
1261 DestFile
+= URItoFileName(RealURI
) + ".gz";
1263 Decompression
= true;
1264 Desc
.URI
= "copy:" + FileName
;
1270 // get the binary name for your used compression type
1271 decompProg
= _config
->Find(string("Acquire::CompressionTypes::").append(compExt
),"");
1272 if(decompProg
.empty() == false);
1273 else if(compExt
== "uncompressed")
1274 decompProg
= "copy";
1276 _error
->Error("Unsupported extension: %s", compExt
.c_str());
1280 Decompression
= true;
1281 DestFile
+= ".decomp";
1282 Desc
.URI
= decompProg
+ ":" + FileName
;
1285 ActiveSubprocess
= decompProg
;
1287 #pragma GCC diagnostic push
1288 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
1290 Mode
= ActiveSubprocess
.c_str();
1292 #pragma GCC diagnostic pop
1296 // AcqIndexTrans::pkgAcqIndexTrans - Constructor /*{{{*/
1297 // ---------------------------------------------------------------------
1298 /* The Translation file is added to the queue */
1299 pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire
*Owner
,
1300 string URI
,string URIDesc
,string ShortDesc
)
1301 : pkgAcqIndex(Owner
, URI
, URIDesc
, ShortDesc
, HashStringList(), "")
1304 pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire
*Owner
, IndexTarget
const * const Target
,
1305 HashStringList
const &ExpectedHashes
, indexRecords
*MetaIndexParser
)
1306 : pkgAcqIndex(Owner
, Target
, ExpectedHashes
, MetaIndexParser
)
1308 // load the filesize
1309 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(string(Target
->MetaKey
));
1311 FileSize
= Record
->Size
;
1314 // AcqIndexTrans::Custom600Headers - Insert custom request headers /*{{{*/
1315 // ---------------------------------------------------------------------
1316 string
pkgAcqIndexTrans::Custom600Headers() const
1318 string Final
= _config
->FindDir("Dir::State::lists");
1319 Final
+= URItoFileName(RealURI
);
1321 if (_config
->FindB("Acquire::GzipIndexes",false))
1325 if (stat(Final
.c_str(),&Buf
) != 0)
1326 return "\nFail-Ignore: true\nIndex-File: true";
1327 return "\nFail-Ignore: true\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1330 // AcqIndexTrans::Failed - Silence failure messages for missing files /*{{{*/
1331 // ---------------------------------------------------------------------
1333 void pkgAcqIndexTrans::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1335 size_t const nextExt
= CompressionExtension
.find(' ');
1336 if (nextExt
!= std::string::npos
)
1338 CompressionExtension
= CompressionExtension
.substr(nextExt
+1);
1339 Init(RealURI
, Desc
.Description
, Desc
.ShortDesc
);
1344 if (Cnf
->LocalOnly
== true ||
1345 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1354 Item::Failed(Message
,Cnf
);
1357 pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire
*Owner
, /*{{{*/
1358 string URI
,string URIDesc
,string ShortDesc
,
1359 string MetaIndexURI
, string MetaIndexURIDesc
,
1360 string MetaIndexShortDesc
,
1361 const vector
<IndexTarget
*>* IndexTargets
,
1362 indexRecords
* MetaIndexParser
) :
1363 Item(Owner
, HashStringList()), RealURI(URI
), MetaIndexURI(MetaIndexURI
),
1364 MetaIndexURIDesc(MetaIndexURIDesc
), MetaIndexShortDesc(MetaIndexShortDesc
),
1365 MetaIndexParser(MetaIndexParser
), IndexTargets(IndexTargets
)
1367 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1368 DestFile
+= URItoFileName(URI
);
1370 // remove any partial downloaded sig-file in partial/.
1371 // it may confuse proxies and is too small to warrant a
1372 // partial download anyway
1373 unlink(DestFile
.c_str());
1376 Desc
.Description
= URIDesc
;
1378 Desc
.ShortDesc
= ShortDesc
;
1381 string Final
= _config
->FindDir("Dir::State::lists");
1382 Final
+= URItoFileName(RealURI
);
1383 if (RealFileExists(Final
) == true)
1385 // File was already in place. It needs to be re-downloaded/verified
1386 // because Release might have changed, we do give it a different
1387 // name than DestFile because otherwise the http method will
1388 // send If-Range requests and there are too many broken servers
1389 // out there that do not understand them
1390 LastGoodSig
= DestFile
+".reverify";
1391 Rename(Final
,LastGoodSig
);
1394 // we expect the indextargets + one additional Release file
1395 ExpectedAdditionalItems
= IndexTargets
->size() + 1;
1400 pkgAcqMetaSig::~pkgAcqMetaSig() /*{{{*/
1402 // if the file was never queued undo file-changes done in the constructor
1403 if (QueueCounter
== 1 && Status
== StatIdle
&& FileSize
== 0 && Complete
== false &&
1404 LastGoodSig
.empty() == false)
1406 string
const Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1407 if (RealFileExists(Final
) == false && RealFileExists(LastGoodSig
) == true)
1408 Rename(LastGoodSig
, Final
);
1413 // pkgAcqMetaSig::Custom600Headers - Insert custom request headers /*{{{*/
1414 // ---------------------------------------------------------------------
1415 /* The only header we use is the last-modified header. */
1416 string
pkgAcqMetaSig::Custom600Headers() const
1419 if (stat(LastGoodSig
.c_str(),&Buf
) != 0)
1420 return "\nIndex-File: true";
1422 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1425 void pkgAcqMetaSig::Done(string Message
,unsigned long long Size
, HashStringList
const &Hashes
,
1426 pkgAcquire::MethodConfig
*Cfg
)
1428 Item::Done(Message
, Size
, Hashes
, Cfg
);
1430 string FileName
= LookupTag(Message
,"Filename");
1431 if (FileName
.empty() == true)
1434 ErrorText
= "Method gave a blank filename";
1438 if (FileName
!= DestFile
)
1440 // We have to copy it into place
1442 Desc
.URI
= "copy:" + FileName
;
1449 // at this point pkgAcqMetaIndex takes over
1450 ExpectedAdditionalItems
= 0;
1452 // put the last known good file back on i-m-s hit (it will
1453 // be re-verified again)
1454 // Else do nothing, we have the new file in DestFile then
1455 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
1456 Rename(LastGoodSig
, DestFile
);
1458 // queue a pkgAcqMetaIndex to be verified against the sig we just retrieved
1459 new pkgAcqMetaIndex(Owner
, MetaIndexURI
, MetaIndexURIDesc
,
1460 MetaIndexShortDesc
, DestFile
, IndexTargets
,
1465 void pkgAcqMetaSig::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)/*{{{*/
1467 string Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1469 // at this point pkgAcqMetaIndex takes over
1470 ExpectedAdditionalItems
= 0;
1472 // if we get a network error we fail gracefully
1473 if(Status
== StatTransientNetworkError
)
1475 Item::Failed(Message
,Cnf
);
1476 // move the sigfile back on transient network failures
1477 if(FileExists(LastGoodSig
))
1478 Rename(LastGoodSig
,Final
);
1480 // set the status back to , Item::Failed likes to reset it
1481 Status
= pkgAcquire::Item::StatTransientNetworkError
;
1485 // Delete any existing sigfile when the acquire failed
1486 unlink(Final
.c_str());
1488 // queue a pkgAcqMetaIndex with no sigfile
1489 new pkgAcqMetaIndex(Owner
, MetaIndexURI
, MetaIndexURIDesc
, MetaIndexShortDesc
,
1490 "", IndexTargets
, MetaIndexParser
);
1492 if (Cnf
->LocalOnly
== true ||
1493 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1502 Item::Failed(Message
,Cnf
);
1505 pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire
*Owner
, /*{{{*/
1506 string URI
,string URIDesc
,string ShortDesc
,
1508 const vector
<IndexTarget
*>* IndexTargets
,
1509 indexRecords
* MetaIndexParser
) :
1510 Item(Owner
, HashStringList()), RealURI(URI
), SigFile(SigFile
), IndexTargets(IndexTargets
),
1511 MetaIndexParser(MetaIndexParser
), AuthPass(false), IMSHit(false)
1513 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1514 DestFile
+= URItoFileName(URI
);
1517 Desc
.Description
= URIDesc
;
1519 Desc
.ShortDesc
= ShortDesc
;
1522 // we expect more item
1523 ExpectedAdditionalItems
= IndexTargets
->size();
1528 // pkgAcqMetaIndex::Custom600Headers - Insert custom request headers /*{{{*/
1529 // ---------------------------------------------------------------------
1530 /* The only header we use is the last-modified header. */
1531 string
pkgAcqMetaIndex::Custom600Headers() const
1533 string Final
= _config
->FindDir("Dir::State::lists");
1534 Final
+= URItoFileName(RealURI
);
1537 if (stat(Final
.c_str(),&Buf
) != 0)
1538 return "\nIndex-File: true";
1540 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1543 void pkgAcqMetaIndex::Done(string Message
,unsigned long long Size
,HashStringList
const &Hashes
, /*{{{*/
1544 pkgAcquire::MethodConfig
*Cfg
)
1546 Item::Done(Message
,Size
,Hashes
,Cfg
);
1548 // MetaIndexes are done in two passes: one to download the
1549 // metaindex with an appropriate method, and a second to verify it
1550 // with the gpgv method
1552 if (AuthPass
== true)
1556 // all cool, move Release file into place
1561 RetrievalDone(Message
);
1563 // Still more retrieving to do
1568 // There was no signature file, so we are finished. Download
1569 // the indexes and do only hashsum verification if possible
1570 MetaIndexParser
->Load(DestFile
);
1571 QueueIndexes(false);
1575 // FIXME: move this into pkgAcqMetaClearSig::Done on the next
1578 // if we expect a ClearTextSignature (InRelase), ensure that
1579 // this is what we get and if not fail to queue a
1580 // Release/Release.gpg, see #346386
1581 if (SigFile
== DestFile
&& !StartsWithGPGClearTextSignature(DestFile
))
1583 Failed(Message
, Cfg
);
1587 // There was a signature file, so pass it to gpgv for
1589 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1590 std::cerr
<< "Metaindex acquired, queueing gpg verification ("
1591 << SigFile
<< "," << DestFile
<< ")\n";
1593 Desc
.URI
= "gpgv:" + SigFile
;
1595 ActiveSubprocess
= "gpgv";
1597 #pragma GCC diagnostic push
1598 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
1602 #pragma GCC diagnostic pop
1608 if (Complete
== true)
1610 string FinalFile
= _config
->FindDir("Dir::State::lists");
1611 FinalFile
+= URItoFileName(RealURI
);
1612 if (SigFile
== DestFile
)
1613 SigFile
= FinalFile
;
1614 Rename(DestFile
,FinalFile
);
1615 chmod(FinalFile
.c_str(),0644);
1616 DestFile
= FinalFile
;
1620 void pkgAcqMetaIndex::RetrievalDone(string Message
) /*{{{*/
1622 // We have just finished downloading a Release file (it is not
1625 string FileName
= LookupTag(Message
,"Filename");
1626 if (FileName
.empty() == true)
1629 ErrorText
= "Method gave a blank filename";
1633 if (FileName
!= DestFile
)
1636 Desc
.URI
= "copy:" + FileName
;
1641 // make sure to verify against the right file on I-M-S hit
1642 IMSHit
= StringToBool(LookupTag(Message
,"IMS-Hit"),false);
1645 string FinalFile
= _config
->FindDir("Dir::State::lists");
1646 FinalFile
+= URItoFileName(RealURI
);
1647 if (SigFile
== DestFile
)
1649 SigFile
= FinalFile
;
1650 // constructor of pkgAcqMetaClearSig moved it out of the way,
1651 // now move it back in on IMS hit for the 'old' file
1652 string
const OldClearSig
= DestFile
+ ".reverify";
1653 if (RealFileExists(OldClearSig
) == true)
1654 Rename(OldClearSig
, FinalFile
);
1656 DestFile
= FinalFile
;
1661 void pkgAcqMetaIndex::AuthDone(string Message
) /*{{{*/
1663 // At this point, the gpgv method has succeeded, so there is a
1664 // valid signature from a key in the trusted keyring. We
1665 // perform additional verification of its contents, and use them
1666 // to verify the indexes we are about to download
1668 if (!MetaIndexParser
->Load(DestFile
))
1670 Status
= StatAuthError
;
1671 ErrorText
= MetaIndexParser
->ErrorText
;
1675 if (!VerifyVendor(Message
))
1680 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1681 std::cerr
<< "Signature verification succeeded: "
1682 << DestFile
<< std::endl
;
1684 // do not trust any previously unverified content that we may have
1685 string LastGoodSigFile
= _config
->FindDir("Dir::State::lists").append("partial/").append(URItoFileName(RealURI
));
1686 if (DestFile
!= SigFile
)
1687 LastGoodSigFile
.append(".gpg");
1688 LastGoodSigFile
.append(".reverify");
1689 if(IMSHit
== false && RealFileExists(LastGoodSigFile
) == false)
1691 for (vector
<struct IndexTarget
*>::const_iterator Target
= IndexTargets
->begin();
1692 Target
!= IndexTargets
->end();
1695 // remove old indexes
1696 std::string index
= _config
->FindDir("Dir::State::lists") +
1697 URItoFileName((*Target
)->URI
);
1698 unlink(index
.c_str());
1699 // and also old gzipindexes
1701 unlink(index
.c_str());
1706 // Download further indexes with verification
1709 // is it a clearsigned MetaIndex file?
1710 if (DestFile
== SigFile
)
1713 // Done, move signature file into position
1714 string VerifiedSigFile
= _config
->FindDir("Dir::State::lists") +
1715 URItoFileName(RealURI
) + ".gpg";
1716 Rename(SigFile
,VerifiedSigFile
);
1717 chmod(VerifiedSigFile
.c_str(),0644);
1720 void pkgAcqMetaIndex::QueueIndexes(bool verify
) /*{{{*/
1723 /* Reject invalid, existing Release files (LP: #346386) (Closes: #627642)
1724 * FIXME: Disabled; it breaks unsigned repositories without hashes */
1725 if (!verify
&& FileExists(DestFile
) && !MetaIndexParser
->Load(DestFile
))
1728 ErrorText
= MetaIndexParser
->ErrorText
;
1732 bool transInRelease
= false;
1734 std::vector
<std::string
> const keys
= MetaIndexParser
->MetaKeys();
1735 for (std::vector
<std::string
>::const_iterator k
= keys
.begin(); k
!= keys
.end(); ++k
)
1736 // FIXME: Feels wrong to check for hardcoded string here, but what should we do else…
1737 if (k
->find("Translation-") != std::string::npos
)
1739 transInRelease
= true;
1744 // at this point the real Items are loaded in the fetcher
1745 ExpectedAdditionalItems
= 0;
1746 for (vector
<IndexTarget
*>::const_iterator Target
= IndexTargets
->begin();
1747 Target
!= IndexTargets
->end();
1750 HashStringList ExpectedIndexHashes
;
1751 const indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup((*Target
)->MetaKey
);
1752 bool compressedAvailable
= false;
1755 if ((*Target
)->IsOptional() == true)
1757 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
1758 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
1759 if (MetaIndexParser
->Exists((*Target
)->MetaKey
+ "." + *t
) == true)
1761 compressedAvailable
= true;
1765 else if (verify
== true)
1767 Status
= StatAuthError
;
1768 strprintf(ErrorText
, _("Unable to find expected entry '%s' in Release file (Wrong sources.list entry or malformed file)"), (*Target
)->MetaKey
.c_str());
1774 ExpectedIndexHashes
= Record
->Hashes
;
1775 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1777 std::cerr
<< "Queueing: " << (*Target
)->URI
<< std::endl
1778 << "Expected Hash:" << std::endl
;
1779 for (HashStringList::const_iterator hs
= ExpectedIndexHashes
.begin(); hs
!= ExpectedIndexHashes
.end(); ++hs
)
1780 std::cerr
<< "\t- " << hs
->toStr() << std::endl
;
1781 std::cerr
<< "For: " << Record
->MetaKeyFilename
<< std::endl
;
1783 if (verify
== true && ExpectedIndexHashes
.empty() == true && (*Target
)->IsOptional() == false)
1785 Status
= StatAuthError
;
1786 strprintf(ErrorText
, _("Unable to find hash sum for '%s' in Release file"), (*Target
)->MetaKey
.c_str());
1791 if ((*Target
)->IsOptional() == true)
1793 if ((*Target
)->IsSubIndex() == true)
1794 new pkgAcqSubIndex(Owner
, (*Target
)->URI
, (*Target
)->Description
,
1795 (*Target
)->ShortDesc
, ExpectedIndexHashes
);
1796 else if (transInRelease
== false || Record
!= NULL
|| compressedAvailable
== true)
1798 if (_config
->FindB("Acquire::PDiffs",true) == true && transInRelease
== true &&
1799 MetaIndexParser
->Exists((*Target
)->MetaKey
+ ".diff/Index") == true)
1800 new pkgAcqDiffIndex(Owner
, *Target
, ExpectedIndexHashes
, MetaIndexParser
);
1802 new pkgAcqIndexTrans(Owner
, *Target
, ExpectedIndexHashes
, MetaIndexParser
);
1807 /* Queue Packages file (either diff or full packages files, depending
1808 on the users option) - we also check if the PDiff Index file is listed
1809 in the Meta-Index file. Ideal would be if pkgAcqDiffIndex would test this
1810 instead, but passing the required info to it is to much hassle */
1811 if(_config
->FindB("Acquire::PDiffs",true) == true && (verify
== false ||
1812 MetaIndexParser
->Exists((*Target
)->MetaKey
+ ".diff/Index") == true))
1813 new pkgAcqDiffIndex(Owner
, *Target
, ExpectedIndexHashes
, MetaIndexParser
);
1815 new pkgAcqIndex(Owner
, *Target
, ExpectedIndexHashes
, MetaIndexParser
);
1819 bool pkgAcqMetaIndex::VerifyVendor(string Message
) /*{{{*/
1821 string::size_type pos
;
1823 // check for missing sigs (that where not fatal because otherwise we had
1826 string msg
= _("There is no public key available for the "
1827 "following key IDs:\n");
1828 pos
= Message
.find("NO_PUBKEY ");
1829 if (pos
!= std::string::npos
)
1831 string::size_type start
= pos
+strlen("NO_PUBKEY ");
1832 string Fingerprint
= Message
.substr(start
, Message
.find("\n")-start
);
1833 missingkeys
+= (Fingerprint
);
1835 if(!missingkeys
.empty())
1836 _error
->Warning("%s", (msg
+ missingkeys
).c_str());
1838 string Transformed
= MetaIndexParser
->GetExpectedDist();
1840 if (Transformed
== "../project/experimental")
1842 Transformed
= "experimental";
1845 pos
= Transformed
.rfind('/');
1846 if (pos
!= string::npos
)
1848 Transformed
= Transformed
.substr(0, pos
);
1851 if (Transformed
== ".")
1856 if (_config
->FindB("Acquire::Check-Valid-Until", true) == true &&
1857 MetaIndexParser
->GetValidUntil() > 0) {
1858 time_t const invalid_since
= time(NULL
) - MetaIndexParser
->GetValidUntil();
1859 if (invalid_since
> 0)
1860 // TRANSLATOR: The first %s is the URL of the bad Release file, the second is
1861 // the time since then the file is invalid - formated in the same way as in
1862 // the download progress display (e.g. 7d 3h 42min 1s)
1863 return _error
->Error(
1864 _("Release file for %s is expired (invalid since %s). "
1865 "Updates for this repository will not be applied."),
1866 RealURI
.c_str(), TimeToStr(invalid_since
).c_str());
1869 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1871 std::cerr
<< "Got Codename: " << MetaIndexParser
->GetDist() << std::endl
;
1872 std::cerr
<< "Expecting Dist: " << MetaIndexParser
->GetExpectedDist() << std::endl
;
1873 std::cerr
<< "Transformed Dist: " << Transformed
<< std::endl
;
1876 if (MetaIndexParser
->CheckDist(Transformed
) == false)
1878 // This might become fatal one day
1879 // Status = StatAuthError;
1880 // ErrorText = "Conflicting distribution; expected "
1881 // + MetaIndexParser->GetExpectedDist() + " but got "
1882 // + MetaIndexParser->GetDist();
1884 if (!Transformed
.empty())
1886 _error
->Warning(_("Conflicting distribution: %s (expected %s but got %s)"),
1887 Desc
.Description
.c_str(),
1888 Transformed
.c_str(),
1889 MetaIndexParser
->GetDist().c_str());
1896 // pkgAcqMetaIndex::Failed - no Release file present or no signature file present /*{{{*/
1897 // ---------------------------------------------------------------------
1899 void pkgAcqMetaIndex::Failed(string Message
,pkgAcquire::MethodConfig
* /*Cnf*/)
1901 if (AuthPass
== true)
1903 // gpgv method failed, if we have a good signature
1904 string LastGoodSigFile
= _config
->FindDir("Dir::State::lists").append("partial/").append(URItoFileName(RealURI
));
1905 if (DestFile
!= SigFile
)
1906 LastGoodSigFile
.append(".gpg");
1907 LastGoodSigFile
.append(".reverify");
1909 if(FileExists(LastGoodSigFile
))
1911 string VerifiedSigFile
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1912 if (DestFile
!= SigFile
)
1913 VerifiedSigFile
.append(".gpg");
1914 Rename(LastGoodSigFile
, VerifiedSigFile
);
1915 Status
= StatTransientNetworkError
;
1916 _error
->Warning(_("An error occurred during the signature "
1917 "verification. The repository is not updated "
1918 "and the previous index files will be used. "
1919 "GPG error: %s: %s\n"),
1920 Desc
.Description
.c_str(),
1921 LookupTag(Message
,"Message").c_str());
1922 RunScripts("APT::Update::Auth-Failure");
1924 } else if (LookupTag(Message
,"Message").find("NODATA") != string::npos
) {
1925 /* Invalid signature file, reject (LP: #346386) (Closes: #627642) */
1926 _error
->Error(_("GPG error: %s: %s"),
1927 Desc
.Description
.c_str(),
1928 LookupTag(Message
,"Message").c_str());
1931 _error
->Warning(_("GPG error: %s: %s"),
1932 Desc
.Description
.c_str(),
1933 LookupTag(Message
,"Message").c_str());
1935 // gpgv method failed
1936 ReportMirrorFailure("GPGFailure");
1939 /* Always move the meta index, even if gpgv failed. This ensures
1940 * that PackageFile objects are correctly filled in */
1941 if (FileExists(DestFile
)) {
1942 string FinalFile
= _config
->FindDir("Dir::State::lists");
1943 FinalFile
+= URItoFileName(RealURI
);
1944 /* InRelease files become Release files, otherwise
1945 * they would be considered as trusted later on */
1946 if (SigFile
== DestFile
) {
1947 RealURI
= RealURI
.replace(RealURI
.rfind("InRelease"), 9,
1949 FinalFile
= FinalFile
.replace(FinalFile
.rfind("InRelease"), 9,
1951 SigFile
= FinalFile
;
1953 Rename(DestFile
,FinalFile
);
1954 chmod(FinalFile
.c_str(),0644);
1956 DestFile
= FinalFile
;
1959 // No Release file was present, or verification failed, so fall
1960 // back to queueing Packages files without verification
1961 QueueIndexes(false);
1964 pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire
*Owner
, /*{{{*/
1965 string
const &URI
, string
const &URIDesc
, string
const &ShortDesc
,
1966 string
const &MetaIndexURI
, string
const &MetaIndexURIDesc
, string
const &MetaIndexShortDesc
,
1967 string
const &MetaSigURI
, string
const &MetaSigURIDesc
, string
const &MetaSigShortDesc
,
1968 const vector
<IndexTarget
*>* IndexTargets
,
1969 indexRecords
* MetaIndexParser
) :
1970 pkgAcqMetaIndex(Owner
, URI
, URIDesc
, ShortDesc
, "", IndexTargets
, MetaIndexParser
),
1971 MetaIndexURI(MetaIndexURI
), MetaIndexURIDesc(MetaIndexURIDesc
), MetaIndexShortDesc(MetaIndexShortDesc
),
1972 MetaSigURI(MetaSigURI
), MetaSigURIDesc(MetaSigURIDesc
), MetaSigShortDesc(MetaSigShortDesc
)
1976 // index targets + (worst case:) Release/Release.gpg
1977 ExpectedAdditionalItems
= IndexTargets
->size() + 2;
1980 // keep the old InRelease around in case of transistent network errors
1981 string
const Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1982 if (RealFileExists(Final
) == true)
1984 string
const LastGoodSig
= DestFile
+ ".reverify";
1985 Rename(Final
,LastGoodSig
);
1989 pkgAcqMetaClearSig::~pkgAcqMetaClearSig() /*{{{*/
1991 // if the file was never queued undo file-changes done in the constructor
1992 if (QueueCounter
== 1 && Status
== StatIdle
&& FileSize
== 0 && Complete
== false)
1994 string
const Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1995 string
const LastGoodSig
= DestFile
+ ".reverify";
1996 if (RealFileExists(Final
) == false && RealFileExists(LastGoodSig
) == true)
1997 Rename(LastGoodSig
, Final
);
2001 // pkgAcqMetaClearSig::Custom600Headers - Insert custom request headers /*{{{*/
2002 // ---------------------------------------------------------------------
2003 // FIXME: this can go away once the InRelease file is used widely
2004 string
pkgAcqMetaClearSig::Custom600Headers() const
2006 string Final
= _config
->FindDir("Dir::State::lists");
2007 Final
+= URItoFileName(RealURI
);
2010 if (stat(Final
.c_str(),&Buf
) != 0)
2012 Final
= DestFile
+ ".reverify";
2013 if (stat(Final
.c_str(),&Buf
) != 0)
2014 return "\nIndex-File: true\nFail-Ignore: true\n";
2017 return "\nIndex-File: true\nFail-Ignore: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
2020 void pkgAcqMetaClearSig::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
2022 // we failed, we will not get additional items from this method
2023 ExpectedAdditionalItems
= 0;
2025 if (AuthPass
== false)
2027 // Remove the 'old' InRelease file if we try Release.gpg now as otherwise
2028 // the file will stay around and gives a false-auth impression (CVE-2012-0214)
2029 string FinalFile
= _config
->FindDir("Dir::State::lists");
2030 FinalFile
.append(URItoFileName(RealURI
));
2031 if (FileExists(FinalFile
))
2032 unlink(FinalFile
.c_str());
2034 new pkgAcqMetaSig(Owner
,
2035 MetaSigURI
, MetaSigURIDesc
, MetaSigShortDesc
,
2036 MetaIndexURI
, MetaIndexURIDesc
, MetaIndexShortDesc
,
2037 IndexTargets
, MetaIndexParser
);
2038 if (Cnf
->LocalOnly
== true ||
2039 StringToBool(LookupTag(Message
, "Transient-Failure"), false) == false)
2043 pkgAcqMetaIndex::Failed(Message
, Cnf
);
2046 // AcqArchive::AcqArchive - Constructor /*{{{*/
2047 // ---------------------------------------------------------------------
2048 /* This just sets up the initial fetch environment and queues the first
2050 pkgAcqArchive::pkgAcqArchive(pkgAcquire
*Owner
,pkgSourceList
*Sources
,
2051 pkgRecords
*Recs
,pkgCache::VerIterator
const &Version
,
2052 string
&StoreFilename
) :
2053 Item(Owner
, HashStringList()), Version(Version
), Sources(Sources
), Recs(Recs
),
2054 StoreFilename(StoreFilename
), Vf(Version
.FileList()),
2057 Retries
= _config
->FindI("Acquire::Retries",0);
2059 if (Version
.Arch() == 0)
2061 _error
->Error(_("I wasn't able to locate a file for the %s package. "
2062 "This might mean you need to manually fix this package. "
2063 "(due to missing arch)"),
2064 Version
.ParentPkg().FullName().c_str());
2068 /* We need to find a filename to determine the extension. We make the
2069 assumption here that all the available sources for this version share
2070 the same extension.. */
2071 // Skip not source sources, they do not have file fields.
2072 for (; Vf
.end() == false; ++Vf
)
2074 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
2079 // Does not really matter here.. we are going to fail out below
2080 if (Vf
.end() != true)
2082 // If this fails to get a file name we will bomb out below.
2083 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2084 if (_error
->PendingError() == true)
2087 // Generate the final file name as: package_version_arch.foo
2088 StoreFilename
= QuoteString(Version
.ParentPkg().Name(),"_:") + '_' +
2089 QuoteString(Version
.VerStr(),"_:") + '_' +
2090 QuoteString(Version
.Arch(),"_:.") +
2091 "." + flExtension(Parse
.FileName());
2094 // check if we have one trusted source for the package. if so, switch
2095 // to "TrustedOnly" mode - but only if not in AllowUnauthenticated mode
2096 bool const allowUnauth
= _config
->FindB("APT::Get::AllowUnauthenticated", false);
2097 bool const debugAuth
= _config
->FindB("Debug::pkgAcquire::Auth", false);
2098 bool seenUntrusted
= false;
2099 for (pkgCache::VerFileIterator i
= Version
.FileList(); i
.end() == false; ++i
)
2101 pkgIndexFile
*Index
;
2102 if (Sources
->FindIndex(i
.File(),Index
) == false)
2105 if (debugAuth
== true)
2106 std::cerr
<< "Checking index: " << Index
->Describe()
2107 << "(Trusted=" << Index
->IsTrusted() << ")" << std::endl
;
2109 if (Index
->IsTrusted() == true)
2112 if (allowUnauth
== false)
2116 seenUntrusted
= true;
2119 // "allow-unauthenticated" restores apts old fetching behaviour
2120 // that means that e.g. unauthenticated file:// uris are higher
2121 // priority than authenticated http:// uris
2122 if (allowUnauth
== true && seenUntrusted
== true)
2126 if (QueueNext() == false && _error
->PendingError() == false)
2127 _error
->Error(_("Can't find a source to download version '%s' of '%s'"),
2128 Version
.VerStr(), Version
.ParentPkg().FullName(false).c_str());
2131 // AcqArchive::QueueNext - Queue the next file source /*{{{*/
2132 // ---------------------------------------------------------------------
2133 /* This queues the next available file version for download. It checks if
2134 the archive is already available in the cache and stashs the MD5 for
2136 bool pkgAcqArchive::QueueNext()
2138 for (; Vf
.end() == false; ++Vf
)
2140 // Ignore not source sources
2141 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
2144 // Try to cross match against the source list
2145 pkgIndexFile
*Index
;
2146 if (Sources
->FindIndex(Vf
.File(),Index
) == false)
2149 // only try to get a trusted package from another source if that source
2151 if(Trusted
&& !Index
->IsTrusted())
2154 // Grab the text package record
2155 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2156 if (_error
->PendingError() == true)
2159 string PkgFile
= Parse
.FileName();
2160 ExpectedHashes
= Parse
.Hashes();
2162 if (PkgFile
.empty() == true)
2163 return _error
->Error(_("The package index files are corrupted. No Filename: "
2164 "field for package %s."),
2165 Version
.ParentPkg().Name());
2167 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
2168 Desc
.Description
= Index
->ArchiveInfo(Version
);
2170 Desc
.ShortDesc
= Version
.ParentPkg().FullName(true);
2172 // See if we already have the file. (Legacy filenames)
2173 FileSize
= Version
->Size
;
2174 string FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile
);
2176 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2178 // Make sure the size matches
2179 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2184 StoreFilename
= DestFile
= FinalFile
;
2188 /* Hmm, we have a file and its size does not match, this means it is
2189 an old style mismatched arch */
2190 unlink(FinalFile
.c_str());
2193 // Check it again using the new style output filenames
2194 FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
2195 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2197 // Make sure the size matches
2198 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2203 StoreFilename
= DestFile
= FinalFile
;
2207 /* Hmm, we have a file and its size does not match, this shouldn't
2209 unlink(FinalFile
.c_str());
2212 DestFile
= _config
->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename
);
2214 // Check the destination file
2215 if (stat(DestFile
.c_str(),&Buf
) == 0)
2217 // Hmm, the partial file is too big, erase it
2218 if ((unsigned long long)Buf
.st_size
> Version
->Size
)
2219 unlink(DestFile
.c_str());
2221 PartialSize
= Buf
.st_size
;
2224 // Disables download of archives - useful if no real installation follows,
2225 // e.g. if we are just interested in proposed installation order
2226 if (_config
->FindB("Debug::pkgAcqArchive::NoQueue", false) == true)
2231 StoreFilename
= DestFile
= FinalFile
;
2245 // AcqArchive::Done - Finished fetching /*{{{*/
2246 // ---------------------------------------------------------------------
2248 void pkgAcqArchive::Done(string Message
,unsigned long long Size
, HashStringList
const &CalcHashes
,
2249 pkgAcquire::MethodConfig
*Cfg
)
2251 Item::Done(Message
, Size
, CalcHashes
, Cfg
);
2254 if (Size
!= Version
->Size
)
2256 RenameOnError(SizeMismatch
);
2260 // FIXME: could this empty() check impose *any* sort of security issue?
2261 if(ExpectedHashes
.usable() && ExpectedHashes
!= CalcHashes
)
2263 RenameOnError(HashSumMismatch
);
2264 printHashSumComparision(DestFile
, ExpectedHashes
, CalcHashes
);
2268 // Grab the output filename
2269 string FileName
= LookupTag(Message
,"Filename");
2270 if (FileName
.empty() == true)
2273 ErrorText
= "Method gave a blank filename";
2279 // Reference filename
2280 if (FileName
!= DestFile
)
2282 StoreFilename
= DestFile
= FileName
;
2287 // Done, move it into position
2288 string FinalFile
= _config
->FindDir("Dir::Cache::Archives");
2289 FinalFile
+= flNotDir(StoreFilename
);
2290 Rename(DestFile
,FinalFile
);
2292 StoreFilename
= DestFile
= FinalFile
;
2296 // AcqArchive::Failed - Failure handler /*{{{*/
2297 // ---------------------------------------------------------------------
2298 /* Here we try other sources */
2299 void pkgAcqArchive::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
2301 ErrorText
= LookupTag(Message
,"Message");
2303 /* We don't really want to retry on failed media swaps, this prevents
2304 that. An interesting observation is that permanent failures are not
2306 if (Cnf
->Removable
== true &&
2307 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2309 // Vf = Version.FileList();
2310 while (Vf
.end() == false) ++Vf
;
2311 StoreFilename
= string();
2312 Item::Failed(Message
,Cnf
);
2316 if (QueueNext() == false)
2318 // This is the retry counter
2320 Cnf
->LocalOnly
== false &&
2321 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2324 Vf
= Version
.FileList();
2325 if (QueueNext() == true)
2329 StoreFilename
= string();
2330 Item::Failed(Message
,Cnf
);
2334 // AcqArchive::IsTrusted - Determine whether this archive comes from a trusted source /*{{{*/
2335 // ---------------------------------------------------------------------
2336 APT_PURE
bool pkgAcqArchive::IsTrusted() const
2341 // AcqArchive::Finished - Fetching has finished, tidy up /*{{{*/
2342 // ---------------------------------------------------------------------
2344 void pkgAcqArchive::Finished()
2346 if (Status
== pkgAcquire::Item::StatDone
&&
2349 StoreFilename
= string();
2352 // AcqFile::pkgAcqFile - Constructor /*{{{*/
2353 // ---------------------------------------------------------------------
2354 /* The file is added to the queue */
2355 pkgAcqFile::pkgAcqFile(pkgAcquire
*Owner
,string URI
, HashStringList
const &Hashes
,
2356 unsigned long long Size
,string Dsc
,string ShortDesc
,
2357 const string
&DestDir
, const string
&DestFilename
,
2359 Item(Owner
, Hashes
), IsIndexFile(IsIndexFile
)
2361 Retries
= _config
->FindI("Acquire::Retries",0);
2363 if(!DestFilename
.empty())
2364 DestFile
= DestFilename
;
2365 else if(!DestDir
.empty())
2366 DestFile
= DestDir
+ "/" + flNotDir(URI
);
2368 DestFile
= flNotDir(URI
);
2372 Desc
.Description
= Dsc
;
2375 // Set the short description to the archive component
2376 Desc
.ShortDesc
= ShortDesc
;
2378 // Get the transfer sizes
2381 if (stat(DestFile
.c_str(),&Buf
) == 0)
2383 // Hmm, the partial file is too big, erase it
2384 if ((Size
> 0) && (unsigned long long)Buf
.st_size
> Size
)
2385 unlink(DestFile
.c_str());
2387 PartialSize
= Buf
.st_size
;
2393 // AcqFile::Done - Item downloaded OK /*{{{*/
2394 // ---------------------------------------------------------------------
2396 void pkgAcqFile::Done(string Message
,unsigned long long Size
,HashStringList
const &CalcHashes
,
2397 pkgAcquire::MethodConfig
*Cnf
)
2399 Item::Done(Message
,Size
,CalcHashes
,Cnf
);
2402 if(ExpectedHashes
.usable() && ExpectedHashes
!= CalcHashes
)
2404 RenameOnError(HashSumMismatch
);
2405 printHashSumComparision(DestFile
, ExpectedHashes
, CalcHashes
);
2409 string FileName
= LookupTag(Message
,"Filename");
2410 if (FileName
.empty() == true)
2413 ErrorText
= "Method gave a blank filename";
2419 // The files timestamp matches
2420 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
2423 // We have to copy it into place
2424 if (FileName
!= DestFile
)
2427 if (_config
->FindB("Acquire::Source-Symlinks",true) == false ||
2428 Cnf
->Removable
== true)
2430 Desc
.URI
= "copy:" + FileName
;
2435 // Erase the file if it is a symlink so we can overwrite it
2437 if (lstat(DestFile
.c_str(),&St
) == 0)
2439 if (S_ISLNK(St
.st_mode
) != 0)
2440 unlink(DestFile
.c_str());
2444 if (symlink(FileName
.c_str(),DestFile
.c_str()) != 0)
2446 ErrorText
= "Link to " + DestFile
+ " failure ";
2453 // AcqFile::Failed - Failure handler /*{{{*/
2454 // ---------------------------------------------------------------------
2455 /* Here we try other sources */
2456 void pkgAcqFile::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
2458 ErrorText
= LookupTag(Message
,"Message");
2460 // This is the retry counter
2462 Cnf
->LocalOnly
== false &&
2463 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2470 Item::Failed(Message
,Cnf
);
2473 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
2474 // ---------------------------------------------------------------------
2475 /* The only header we use is the last-modified header. */
2476 string
pkgAcqFile::Custom600Headers() const
2479 return "\nIndex-File: true";