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 /*{{{*/
67 pkgAcquire::Item::Item(pkgAcquire
*Owner
, HashStringList
const &ExpectedHashes
) :
68 Owner(Owner
), FileSize(0), PartialSize(0), Mode(0), ID(0), Complete(false),
69 Local(false), QueueCounter(0), TransactionID(0), ExpectedAdditionalItems(0),
70 ExpectedHashes(ExpectedHashes
)
76 // Acquire::Item::~Item - Destructor /*{{{*/
77 // ---------------------------------------------------------------------
79 pkgAcquire::Item::~Item()
84 // Acquire::Item::Failed - Item failed to download /*{{{*/
85 // ---------------------------------------------------------------------
86 /* We return to an idle state if there are still other queues that could
88 void pkgAcquire::Item::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
92 ErrorText
= LookupTag(Message
,"Message");
93 UsedMirror
= LookupTag(Message
,"UsedMirror");
94 if (QueueCounter
<= 1)
96 /* This indicates that the file is not available right now but might
97 be sometime later. If we do a retry cycle then this should be
99 if (Cnf
->LocalOnly
== true &&
100 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
111 // report mirror failure back to LP if we actually use a mirror
112 string FailReason
= LookupTag(Message
, "FailReason");
113 if(FailReason
.size() != 0)
114 ReportMirrorFailure(FailReason
);
116 ReportMirrorFailure(ErrorText
);
119 // Acquire::Item::Start - Item has begun to download /*{{{*/
120 // ---------------------------------------------------------------------
121 /* Stash status and the file size. Note that setting Complete means
122 sub-phases of the acquire process such as decompresion are operating */
123 void pkgAcquire::Item::Start(string
/*Message*/,unsigned long long Size
)
125 Status
= StatFetching
;
126 if (FileSize
== 0 && Complete
== false)
130 // Acquire::Item::Done - Item downloaded OK /*{{{*/
131 // ---------------------------------------------------------------------
133 void pkgAcquire::Item::Done(string Message
,unsigned long long Size
,HashStringList
const &/*Hash*/,
134 pkgAcquire::MethodConfig
* /*Cnf*/)
136 // We just downloaded something..
137 string FileName
= LookupTag(Message
,"Filename");
138 UsedMirror
= LookupTag(Message
,"UsedMirror");
139 if (Complete
== false && !Local
&& FileName
== DestFile
)
142 Owner
->Log
->Fetched(Size
,atoi(LookupTag(Message
,"Resume-Point","0").c_str()));
148 ErrorText
= string();
149 Owner
->Dequeue(this);
152 // Acquire::Item::Rename - Rename a file /*{{{*/
153 // ---------------------------------------------------------------------
154 /* This helper function is used by a lot of item methods as their final
156 void pkgAcquire::Item::Rename(string From
,string To
)
158 if (rename(From
.c_str(),To
.c_str()) != 0)
161 snprintf(S
,sizeof(S
),_("rename failed, %s (%s -> %s)."),strerror(errno
),
162 From
.c_str(),To
.c_str());
168 bool pkgAcquire::Item::RenameOnError(pkgAcquire::Item::RenameOnErrorState
const error
)/*{{{*/
170 if(FileExists(DestFile
))
171 Rename(DestFile
, DestFile
+ ".FAILED");
175 case HashSumMismatch
:
176 ErrorText
= _("Hash Sum mismatch");
177 Status
= StatAuthError
;
178 ReportMirrorFailure("HashChecksumFailure");
181 ErrorText
= _("Size mismatch");
182 Status
= StatAuthError
;
183 ReportMirrorFailure("SizeFailure");
186 ErrorText
= _("Invalid file format");
188 // do not report as usually its not the mirrors fault, but Portal/Proxy
194 // Acquire::Item::ReportMirrorFailure /*{{{*/
195 // ---------------------------------------------------------------------
196 void pkgAcquire::Item::ReportMirrorFailure(string FailCode
)
198 // we only act if a mirror was used at all
199 if(UsedMirror
.empty())
202 std::cerr
<< "\nReportMirrorFailure: "
204 << " Uri: " << DescURI()
206 << FailCode
<< std::endl
;
208 const char *Args
[40];
210 string report
= _config
->Find("Methods::Mirror::ProblemReporting",
211 "/usr/lib/apt/apt-report-mirror-failure");
212 if(!FileExists(report
))
214 Args
[i
++] = report
.c_str();
215 Args
[i
++] = UsedMirror
.c_str();
216 Args
[i
++] = DescURI().c_str();
217 Args
[i
++] = FailCode
.c_str();
219 pid_t pid
= ExecFork();
222 _error
->Error("ReportMirrorFailure Fork failed");
227 execvp(Args
[0], (char**)Args
);
228 std::cerr
<< "Could not exec " << Args
[0] << std::endl
;
231 if(!ExecWait(pid
, "report-mirror-failure"))
233 _error
->Warning("Couldn't report problem to '%s'",
234 _config
->Find("Methods::Mirror::ProblemReporting").c_str());
238 // AcqSubIndex::AcqSubIndex - Constructor /*{{{*/
239 // ---------------------------------------------------------------------
240 /* Get a sub-index file based on checksums from a 'master' file and
241 possibly query additional files */
242 pkgAcqSubIndex::pkgAcqSubIndex(pkgAcquire
*Owner
, string
const &URI
,
243 string
const &URIDesc
, string
const &ShortDesc
,
244 HashStringList
const &ExpectedHashes
)
245 : Item(Owner
, ExpectedHashes
)
247 /* XXX: Beware: Currently this class does nothing (of value) anymore ! */
248 Debug
= _config
->FindB("Debug::pkgAcquire::SubIndex",false);
250 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
251 DestFile
+= URItoFileName(URI
);
254 Desc
.Description
= URIDesc
;
256 Desc
.ShortDesc
= ShortDesc
;
261 std::clog
<< "pkgAcqSubIndex: " << Desc
.URI
<< std::endl
;
264 // AcqSubIndex::Custom600Headers - Insert custom request headers /*{{{*/
265 // ---------------------------------------------------------------------
266 /* The only header we use is the last-modified header. */
267 string
pkgAcqSubIndex::Custom600Headers() const
269 string Final
= _config
->FindDir("Dir::State::lists");
270 Final
+= URItoFileName(Desc
.URI
);
273 if (stat(Final
.c_str(),&Buf
) != 0)
274 return "\nIndex-File: true\nFail-Ignore: true\n";
275 return "\nIndex-File: true\nFail-Ignore: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
278 void pkgAcqSubIndex::Failed(string Message
,pkgAcquire::MethodConfig
* /*Cnf*/)/*{{{*/
281 std::clog
<< "pkgAcqSubIndex failed: " << Desc
.URI
<< " with " << Message
<< std::endl
;
287 // No good Index is provided
290 void pkgAcqSubIndex::Done(string Message
,unsigned long long Size
,HashStringList
const &Hashes
, /*{{{*/
291 pkgAcquire::MethodConfig
*Cnf
)
294 std::clog
<< "pkgAcqSubIndex::Done(): " << Desc
.URI
<< std::endl
;
296 string FileName
= LookupTag(Message
,"Filename");
297 if (FileName
.empty() == true)
300 ErrorText
= "Method gave a blank filename";
304 if (FileName
!= DestFile
)
307 Desc
.URI
= "copy:" + FileName
;
312 Item::Done(Message
, Size
, Hashes
, Cnf
);
314 string FinalFile
= _config
->FindDir("Dir::State::lists")+URItoFileName(Desc
.URI
);
316 /* Downloaded invalid transindex => Error (LP: #346386) (Closes: #627642) */
317 indexRecords SubIndexParser
;
318 if (FileExists(DestFile
) == true && !SubIndexParser
.Load(DestFile
)) {
320 ErrorText
= SubIndexParser
.ErrorText
;
324 // success in downloading the index
327 std::clog
<< "Renaming: " << DestFile
<< " -> " << FinalFile
<< std::endl
;
328 Rename(DestFile
,FinalFile
);
329 chmod(FinalFile
.c_str(),0644);
330 DestFile
= FinalFile
;
332 if(ParseIndex(DestFile
) == false)
333 return Failed("", NULL
);
341 bool pkgAcqSubIndex::ParseIndex(string
const &IndexFile
) /*{{{*/
343 indexRecords SubIndexParser
;
344 if (FileExists(IndexFile
) == false || SubIndexParser
.Load(IndexFile
) == false)
346 // so something with the downloaded index
350 // AcqDiffIndex::AcqDiffIndex - Constructor /*{{{*/
351 // ---------------------------------------------------------------------
352 /* Get the DiffIndex file first and see if there are patches available
353 * If so, create a pkgAcqIndexDiffs fetcher that will get and apply the
354 * patches. If anything goes wrong in that process, it will fall back to
355 * the original packages file
357 pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcqMetaIndex
*MetaOwner
,
358 IndexTarget
const * const Target
,
359 HashStringList
const &ExpectedHashes
,
360 indexRecords
*MetaIndexParser
)
361 : pkgAcqBaseIndex(MetaOwner
, Target
, ExpectedHashes
,
365 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
367 RealURI
= Target
->URI
;
369 Desc
.Description
= Target
->Description
+ "/DiffIndex";
370 Desc
.ShortDesc
= Target
->ShortDesc
;
371 Desc
.URI
= Target
->URI
+ ".diff/Index";
373 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
374 DestFile
+= URItoFileName(Target
->URI
) + string(".DiffIndex");
377 std::clog
<< "pkgAcqDiffIndex: " << Desc
.URI
<< std::endl
;
379 // look for the current package file
380 CurrentPackagesFile
= _config
->FindDir("Dir::State::lists");
381 CurrentPackagesFile
+= URItoFileName(RealURI
);
383 // FIXME: this file:/ check is a hack to prevent fetching
384 // from local sources. this is really silly, and
385 // should be fixed cleanly as soon as possible
386 if(!FileExists(CurrentPackagesFile
) ||
387 Desc
.URI
.substr(0,strlen("file:/")) == "file:/")
389 // we don't have a pkg file or we don't want to queue
391 std::clog
<< "No index file, local or canceld by user" << std::endl
;
397 std::clog
<< "pkgAcqDiffIndex::pkgAcqDiffIndex(): "
398 << CurrentPackagesFile
<< std::endl
;
404 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
405 // ---------------------------------------------------------------------
406 /* The only header we use is the last-modified header. */
407 string
pkgAcqDiffIndex::Custom600Headers() const
409 string Final
= _config
->FindDir("Dir::State::lists");
410 Final
+= URItoFileName(RealURI
) + string(".IndexDiff");
413 std::clog
<< "Custom600Header-IMS: " << Final
<< std::endl
;
416 if (stat(Final
.c_str(),&Buf
) != 0)
417 return "\nIndex-File: true";
419 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
422 bool pkgAcqDiffIndex::ParseDiffIndex(string IndexDiffFile
) /*{{{*/
425 std::clog
<< "pkgAcqDiffIndex::ParseIndexDiff() " << IndexDiffFile
430 vector
<DiffInfo
> available_patches
;
432 FileFd
Fd(IndexDiffFile
,FileFd::ReadOnly
);
434 if (_error
->PendingError() == true)
437 if(TF
.Step(Tags
) == true)
443 string
const tmp
= Tags
.FindS("SHA1-Current");
444 std::stringstream
ss(tmp
);
445 ss
>> ServerSha1
>> size
;
446 unsigned long const ServerSize
= atol(size
.c_str());
448 FileFd
fd(CurrentPackagesFile
, FileFd::ReadOnly
);
451 string
const local_sha1
= SHA1
.Result();
453 if(local_sha1
== ServerSha1
)
455 // we have the same sha1 as the server so we are done here
457 std::clog
<< "Package file is up-to-date" << std::endl
;
458 // list cleanup needs to know that this file as well as the already
459 // present index is ours, so we create an empty diff to save it for us
460 new pkgAcqIndexDiffs(MetaOwner
, Target
, ExpectedHashes
, MetaIndexParser
,
461 ServerSha1
, available_patches
);
467 std::clog
<< "SHA1-Current: " << ServerSha1
<< " and we start at "<< fd
.Name() << " " << fd
.Size() << " " << local_sha1
<< std::endl
;
469 // check the historie and see what patches we need
470 string
const history
= Tags
.FindS("SHA1-History");
471 std::stringstream
hist(history
);
472 while(hist
>> d
.sha1
>> size
>> d
.file
)
474 // read until the first match is found
475 // from that point on, we probably need all diffs
476 if(d
.sha1
== local_sha1
)
478 else if (found
== false)
482 std::clog
<< "Need to get diff: " << d
.file
<< std::endl
;
483 available_patches
.push_back(d
);
486 if (available_patches
.empty() == false)
488 // patching with too many files is rather slow compared to a fast download
489 unsigned long const fileLimit
= _config
->FindI("Acquire::PDiffs::FileLimit", 0);
490 if (fileLimit
!= 0 && fileLimit
< available_patches
.size())
493 std::clog
<< "Need " << available_patches
.size() << " diffs (Limit is " << fileLimit
494 << ") so fallback to complete download" << std::endl
;
498 // see if the patches are too big
499 found
= false; // it was true and it will be true again at the end
500 d
= *available_patches
.begin();
501 string
const firstPatch
= d
.file
;
502 unsigned long patchesSize
= 0;
503 std::stringstream
patches(Tags
.FindS("SHA1-Patches"));
504 while(patches
>> d
.sha1
>> size
>> d
.file
)
506 if (firstPatch
== d
.file
)
508 else if (found
== false)
511 patchesSize
+= atol(size
.c_str());
513 unsigned long const sizeLimit
= ServerSize
* _config
->FindI("Acquire::PDiffs::SizeLimit", 100);
514 if (sizeLimit
> 0 && (sizeLimit
/100) < patchesSize
)
517 std::clog
<< "Need " << patchesSize
<< " bytes (Limit is " << sizeLimit
/100
518 << ") so fallback to complete download" << std::endl
;
524 // we have something, queue the next diff
528 string::size_type
const last_space
= Description
.rfind(" ");
529 if(last_space
!= string::npos
)
530 Description
.erase(last_space
, Description
.size()-last_space
);
532 /* decide if we should download patches one by one or in one go:
533 The first is good if the server merges patches, but many don't so client
534 based merging can be attempt in which case the second is better.
535 "bad things" will happen if patches are merged on the server,
536 but client side merging is attempt as well */
537 bool pdiff_merge
= _config
->FindB("Acquire::PDiffs::Merge", true);
538 if (pdiff_merge
== true)
540 // reprepro adds this flag if it has merged patches on the server
541 std::string
const precedence
= Tags
.FindS("X-Patch-Precedence");
542 pdiff_merge
= (precedence
!= "merged");
545 if (pdiff_merge
== false)
547 new pkgAcqIndexDiffs(MetaOwner
, Target
, ExpectedHashes
, MetaIndexParser
,
548 ServerSha1
, available_patches
);
552 std::vector
<pkgAcqIndexMergeDiffs
*> *diffs
= new std::vector
<pkgAcqIndexMergeDiffs
*>(available_patches
.size());
553 for(size_t i
= 0; i
< available_patches
.size(); ++i
)
554 (*diffs
)[i
] = new pkgAcqIndexMergeDiffs(MetaOwner
, Target
,
557 available_patches
[i
],
568 // Nothing found, report and return false
569 // Failing here is ok, if we return false later, the full
570 // IndexFile is queued
572 std::clog
<< "Can't find a patch in the index file" << std::endl
;
576 void pkgAcqDiffIndex::Failed(string Message
,pkgAcquire::MethodConfig
* /*Cnf*/)/*{{{*/
579 std::clog
<< "pkgAcqDiffIndex failed: " << Desc
.URI
<< " with " << Message
<< std::endl
580 << "Falling back to normal index file acquire" << std::endl
;
582 new pkgAcqIndex(MetaOwner
, Target
, ExpectedHashes
, MetaIndexParser
);
589 void pkgAcqDiffIndex::Done(string Message
,unsigned long long Size
,HashStringList
const &Hashes
, /*{{{*/
590 pkgAcquire::MethodConfig
*Cnf
)
593 std::clog
<< "pkgAcqDiffIndex::Done(): " << Desc
.URI
<< std::endl
;
595 Item::Done(Message
, Size
, Hashes
, Cnf
);
598 FinalFile
= _config
->FindDir("Dir::State::lists")+URItoFileName(RealURI
);
600 // success in downloading the index
602 FinalFile
+= string(".IndexDiff");
604 std::clog
<< "Renaming: " << DestFile
<< " -> " << FinalFile
606 Rename(DestFile
,FinalFile
);
607 chmod(FinalFile
.c_str(),0644);
608 DestFile
= FinalFile
;
610 if(!ParseDiffIndex(DestFile
))
611 return Failed("", NULL
);
619 // AcqIndexDiffs::AcqIndexDiffs - Constructor /*{{{*/
620 // ---------------------------------------------------------------------
621 /* The package diff is added to the queue. one object is constructed
622 * for each diff and the index
624 pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcqMetaIndex
*MetaOwner
,
625 struct IndexTarget
const * const Target
,
626 HashStringList
const &ExpectedHashes
,
627 indexRecords
*MetaIndexParser
,
629 vector
<DiffInfo
> diffs
)
630 : pkgAcqBaseIndex(MetaOwner
, Target
, ExpectedHashes
, MetaIndexParser
),
631 available_patches(diffs
), ServerSha1(ServerSha1
)
634 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
635 DestFile
+= URItoFileName(Target
->URI
);
637 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
639 RealURI
= Target
->URI
;
641 Description
= Target
->Description
;
642 Desc
.ShortDesc
= Target
->ShortDesc
;
644 if(available_patches
.empty() == true)
646 // we are done (yeah!)
652 State
= StateFetchDiff
;
657 void pkgAcqIndexDiffs::Failed(string Message
,pkgAcquire::MethodConfig
* /*Cnf*/)/*{{{*/
660 std::clog
<< "pkgAcqIndexDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
661 << "Falling back to normal index file acquire" << std::endl
;
662 new pkgAcqIndex(MetaOwner
, Target
, ExpectedHashes
, MetaIndexParser
);
666 // Finish - helper that cleans the item out of the fetcher queue /*{{{*/
667 void pkgAcqIndexDiffs::Finish(bool allDone
)
669 // we restore the original name, this is required, otherwise
670 // the file will be cleaned
673 DestFile
= _config
->FindDir("Dir::State::lists");
674 DestFile
+= URItoFileName(RealURI
);
676 if(HashSums().usable() && !HashSums().VerifyFile(DestFile
))
678 RenameOnError(HashSumMismatch
);
683 // this is for the "real" finish
688 std::clog
<< "\n\nallDone: " << DestFile
<< "\n" << std::endl
;
693 std::clog
<< "Finishing: " << Desc
.URI
<< std::endl
;
700 bool pkgAcqIndexDiffs::QueueNextDiff() /*{{{*/
703 // calc sha1 of the just patched file
704 string FinalFile
= _config
->FindDir("Dir::State::lists");
705 FinalFile
+= URItoFileName(RealURI
);
707 FileFd
fd(FinalFile
, FileFd::ReadOnly
);
710 string local_sha1
= string(SHA1
.Result());
712 std::clog
<< "QueueNextDiff: "
713 << FinalFile
<< " (" << local_sha1
<< ")"<<std::endl
;
715 // final file reached before all patches are applied
716 if(local_sha1
== ServerSha1
)
722 // remove all patches until the next matching patch is found
723 // this requires the Index file to be ordered
724 for(vector
<DiffInfo
>::iterator I
=available_patches
.begin();
725 available_patches
.empty() == false &&
726 I
!= available_patches
.end() &&
727 I
->sha1
!= local_sha1
;
730 available_patches
.erase(I
);
733 // error checking and falling back if no patch was found
734 if(available_patches
.empty() == true)
740 // queue the right diff
741 Desc
.URI
= RealURI
+ ".diff/" + available_patches
[0].file
+ ".gz";
742 Desc
.Description
= Description
+ " " + available_patches
[0].file
+ string(".pdiff");
743 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
744 DestFile
+= URItoFileName(RealURI
+ ".diff/" + available_patches
[0].file
);
747 std::clog
<< "pkgAcqIndexDiffs::QueueNextDiff(): " << Desc
.URI
<< std::endl
;
754 void pkgAcqIndexDiffs::Done(string Message
,unsigned long long Size
, HashStringList
const &Hashes
, /*{{{*/
755 pkgAcquire::MethodConfig
*Cnf
)
758 std::clog
<< "pkgAcqIndexDiffs::Done(): " << Desc
.URI
<< std::endl
;
760 Item::Done(Message
, Size
, Hashes
, Cnf
);
763 FinalFile
= _config
->FindDir("Dir::State::lists")+URItoFileName(RealURI
);
765 // success in downloading a diff, enter ApplyDiff state
766 if(State
== StateFetchDiff
)
769 // rred excepts the patch as $FinalFile.ed
770 Rename(DestFile
,FinalFile
+".ed");
773 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
775 State
= StateApplyDiff
;
777 Desc
.URI
= "rred:" + FinalFile
;
784 // success in download/apply a diff, queue next (if needed)
785 if(State
== StateApplyDiff
)
787 // remove the just applied patch
788 available_patches
.erase(available_patches
.begin());
789 unlink((FinalFile
+ ".ed").c_str());
794 std::clog
<< "Moving patched file in place: " << std::endl
795 << DestFile
<< " -> " << FinalFile
<< std::endl
;
797 Rename(DestFile
,FinalFile
);
798 chmod(FinalFile
.c_str(),0644);
800 // see if there is more to download
801 if(available_patches
.empty() == false) {
802 new pkgAcqIndexDiffs(MetaOwner
, Target
,
803 ExpectedHashes
, MetaIndexParser
,
804 ServerSha1
, available_patches
);
811 // AcqIndexMergeDiffs::AcqIndexMergeDiffs - Constructor /*{{{*/
812 pkgAcqIndexMergeDiffs::pkgAcqIndexMergeDiffs(pkgAcqMetaIndex
*MetaOwner
,
813 struct IndexTarget
const * const Target
,
814 HashStringList
const &ExpectedHashes
,
815 indexRecords
*MetaIndexParser
,
816 DiffInfo
const &patch
,
817 std::vector
<pkgAcqIndexMergeDiffs
*> const * const allPatches
)
818 : pkgAcqBaseIndex(MetaOwner
, Target
, ExpectedHashes
, MetaIndexParser
),
819 patch(patch
), allPatches(allPatches
), State(StateFetchDiff
)
822 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
823 DestFile
+= URItoFileName(Target
->URI
);
825 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
827 RealURI
= Target
->URI
;
829 Description
= Target
->Description
;
830 Desc
.ShortDesc
= Target
->ShortDesc
;
832 Desc
.URI
= RealURI
+ ".diff/" + patch
.file
+ ".gz";
833 Desc
.Description
= Description
+ " " + patch
.file
+ string(".pdiff");
834 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
835 DestFile
+= URItoFileName(RealURI
+ ".diff/" + patch
.file
);
838 std::clog
<< "pkgAcqIndexMergeDiffs: " << Desc
.URI
<< std::endl
;
843 void pkgAcqIndexMergeDiffs::Failed(string Message
,pkgAcquire::MethodConfig
* /*Cnf*/)/*{{{*/
846 std::clog
<< "pkgAcqIndexMergeDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
;
851 // check if we are the first to fail, otherwise we are done here
852 State
= StateDoneDiff
;
853 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
854 I
!= allPatches
->end(); ++I
)
855 if ((*I
)->State
== StateErrorDiff
)
858 // first failure means we should fallback
859 State
= StateErrorDiff
;
860 std::clog
<< "Falling back to normal index file acquire" << std::endl
;
861 new pkgAcqIndex(MetaOwner
, Target
, ExpectedHashes
, MetaIndexParser
);
864 void pkgAcqIndexMergeDiffs::Done(string Message
,unsigned long long Size
,HashStringList
const &Hashes
, /*{{{*/
865 pkgAcquire::MethodConfig
*Cnf
)
868 std::clog
<< "pkgAcqIndexMergeDiffs::Done(): " << Desc
.URI
<< std::endl
;
870 Item::Done(Message
,Size
,Hashes
,Cnf
);
872 string
const FinalFile
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
874 if (State
== StateFetchDiff
)
876 // rred expects the patch as $FinalFile.ed.$patchname.gz
877 Rename(DestFile
, FinalFile
+ ".ed." + patch
.file
+ ".gz");
879 // check if this is the last completed diff
880 State
= StateDoneDiff
;
881 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
882 I
!= allPatches
->end(); ++I
)
883 if ((*I
)->State
!= StateDoneDiff
)
886 std::clog
<< "Not the last done diff in the batch: " << Desc
.URI
<< std::endl
;
890 // this is the last completed diff, so we are ready to apply now
891 State
= StateApplyDiff
;
894 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
897 Desc
.URI
= "rred:" + FinalFile
;
902 // success in download/apply all diffs, clean up
903 else if (State
== StateApplyDiff
)
905 // see if we really got the expected file
906 if(ExpectedHashes
.usable() && !ExpectedHashes
.VerifyFile(DestFile
))
908 RenameOnError(HashSumMismatch
);
912 // move the result into place
914 std::clog
<< "Moving patched file in place: " << std::endl
915 << DestFile
<< " -> " << FinalFile
<< std::endl
;
916 Rename(DestFile
, FinalFile
);
917 chmod(FinalFile
.c_str(), 0644);
919 // otherwise lists cleanup will eat the file
920 DestFile
= FinalFile
;
922 // ensure the ed's are gone regardless of list-cleanup
923 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
924 I
!= allPatches
->end(); ++I
)
926 std::string patch
= FinalFile
+ ".ed." + (*I
)->patch
.file
+ ".gz";
927 unlink(patch
.c_str());
933 std::clog
<< "allDone: " << DestFile
<< "\n" << std::endl
;
937 // AcqIndex::AcqIndex - Constructor /*{{{*/
938 // ---------------------------------------------------------------------
939 /* The package file is added to the queue and a second class is
940 instantiated to fetch the revision file */
941 pkgAcqIndex::pkgAcqIndex(pkgAcquire
*Owner
,
942 string URI
,string URIDesc
,string ShortDesc
,
943 HashStringList
const &ExpectedHash
, string comprExt
)
944 : pkgAcqBaseIndex(Owner
, NULL
, ExpectedHash
, NULL
), RealURI(URI
)
946 if(comprExt
.empty() == true)
948 // autoselect the compression method
949 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
950 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
951 comprExt
.append(*t
).append(" ");
952 if (comprExt
.empty() == false)
953 comprExt
.erase(comprExt
.end()-1);
955 CompressionExtension
= comprExt
;
957 Init(URI
, URIDesc
, ShortDesc
);
960 pkgAcqIndex::pkgAcqIndex(pkgAcquire
*Owner
, IndexTarget
const *Target
,
961 HashStringList
const &ExpectedHash
,
962 indexRecords
*MetaIndexParser
)
963 : pkgAcqBaseIndex(Owner
, Target
, ExpectedHash
, MetaIndexParser
),
966 // autoselect the compression method
967 AutoSelectCompression();
968 Init(Target
->URI
, Target
->Description
, Target
->ShortDesc
);
972 pkgAcqIndex::pkgAcqIndex(pkgAcqMetaIndex
*MetaOwner
,
973 IndexTarget
const *Target
,
974 HashStringList
const &ExpectedHash
,
975 indexRecords
*MetaIndexParser
)
976 : pkgAcqBaseIndex(MetaOwner
->GetOwner(), Target
, ExpectedHash
,
977 MetaIndexParser
), RealURI(Target
->URI
)
979 // autoselect the compression method
980 AutoSelectCompression();
981 Init(Target
->URI
, Target
->Description
, Target
->ShortDesc
);
983 TransactionID
= (unsigned long)MetaOwner
;
986 void pkgAcqIndex::AutoSelectCompression()
988 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
989 CompressionExtension
= "";
990 if (ExpectedHashes
.usable())
992 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
993 if (*t
== "uncompressed" || MetaIndexParser
->Exists(string(Target
->MetaKey
).append(".").append(*t
)) == true)
994 CompressionExtension
.append(*t
).append(" ");
998 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
999 CompressionExtension
.append(*t
).append(" ");
1001 if (CompressionExtension
.empty() == false)
1002 CompressionExtension
.erase(CompressionExtension
.end()-1);
1004 // AcqIndex::Init - defered Constructor /*{{{*/
1005 void pkgAcqIndex::Init(string
const &URI
, string
const &URIDesc
, string
const &ShortDesc
) {
1006 Decompression
= false;
1009 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1010 DestFile
+= URItoFileName(URI
);
1012 std::string
const comprExt
= CompressionExtension
.substr(0, CompressionExtension
.find(' '));
1013 std::string MetaKey
;
1014 if (comprExt
== "uncompressed")
1018 MetaKey
= string(Target
->MetaKey
);
1022 Desc
.URI
= URI
+ '.' + comprExt
;
1024 MetaKey
= string(Target
->MetaKey
) + '.' + comprExt
;
1027 // load the filesize
1030 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(MetaKey
);
1032 FileSize
= Record
->Size
;
1034 InitByHashIfNeeded(MetaKey
);
1037 Desc
.Description
= URIDesc
;
1039 Desc
.ShortDesc
= ShortDesc
;
1044 // AcqIndex::AdjustForByHash - modify URI for by-hash support /*{{{*/
1045 // ---------------------------------------------------------------------
1047 void pkgAcqIndex::InitByHashIfNeeded(const std::string MetaKey
)
1050 // - (maybe?) add support for by-hash into the sources.list as flag
1051 // - make apt-ftparchive generate the hashes (and expire?)
1052 std::string HostKnob
= "APT::Acquire::" + ::URI(Desc
.URI
).Host
+ "::By-Hash";
1053 if(_config
->FindB("APT::Acquire::By-Hash", false) == true ||
1054 _config
->FindB(HostKnob
, false) == true ||
1055 MetaIndexParser
->GetSupportsAcquireByHash())
1057 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(MetaKey
);
1060 // FIXME: should we really use the best hash here? or a fixed one?
1061 const HashString
*TargetHash
= Record
->Hashes
.find("");
1062 std::string ByHash
= "/by-hash/" + TargetHash
->HashType() + "/" + TargetHash
->HashValue();
1063 size_t trailing_slash
= Desc
.URI
.find_last_of("/");
1064 Desc
.URI
= Desc
.URI
.replace(
1066 Desc
.URI
.substr(trailing_slash
+1).size()+1,
1070 "Fetching ByHash requested but can not find record for %s",
1076 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
1077 // ---------------------------------------------------------------------
1078 /* The only header we use is the last-modified header. */
1079 string
pkgAcqIndex::Custom600Headers() const
1081 string Final
= _config
->FindDir("Dir::State::lists");
1082 Final
+= URItoFileName(RealURI
);
1083 if (_config
->FindB("Acquire::GzipIndexes",false))
1086 string msg
= "\nIndex-File: true";
1087 // FIXME: this really should use "IndexTarget::IsOptional()" but that
1088 // seems to be difficult without breaking ABI
1089 if (ShortDesc().find("Translation") != 0)
1090 msg
+= "\nFail-Ignore: true";
1092 if (stat(Final
.c_str(),&Buf
) == 0)
1093 msg
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1098 void pkgAcqIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
1100 size_t const nextExt
= CompressionExtension
.find(' ');
1101 if (nextExt
!= std::string::npos
)
1103 CompressionExtension
= CompressionExtension
.substr(nextExt
+1);
1104 Init(RealURI
, Desc
.Description
, Desc
.ShortDesc
);
1108 // on decompression failure, remove bad versions in partial/
1109 if (Decompression
&& Erase
) {
1110 string s
= _config
->FindDir("Dir::State::lists") + "partial/";
1111 s
.append(URItoFileName(RealURI
));
1115 Item::Failed(Message
,Cnf
);
1117 /// cancel the entire transaction
1118 Owner
->AbortTransaction(TransactionID
);
1121 // AcqIndex::Done - Finished a fetch /*{{{*/
1122 // ---------------------------------------------------------------------
1123 /* This goes through a number of states.. On the initial fetch the
1124 method could possibly return an alternate filename which points
1125 to the uncompressed version of the file. If this is so the file
1126 is copied into the partial directory. In all other cases the file
1127 is decompressed with a gzip uri. */
1128 void pkgAcqIndex::Done(string Message
,unsigned long long Size
,HashStringList
const &Hashes
,
1129 pkgAcquire::MethodConfig
*Cfg
)
1131 Item::Done(Message
,Size
,Hashes
,Cfg
);
1133 if (Decompression
== true)
1135 if (ExpectedHashes
.usable() && ExpectedHashes
!= Hashes
)
1137 RenameOnError(HashSumMismatch
);
1138 printHashSumComparision(RealURI
, ExpectedHashes
, Hashes
);
1139 Failed(Message
, Cfg
);
1143 // FIXME: this can go away once we only ever download stuff that
1144 // has a valid hash and we never do GET based probing
1146 /* Always verify the index file for correctness (all indexes must
1147 * have a Package field) (LP: #346386) (Closes: #627642)
1149 FileFd
fd(DestFile
, FileFd::ReadOnly
);
1150 // Only test for correctness if the file is not empty (empty is ok)
1151 if (fd
.FileSize() > 0)
1154 pkgTagFile
tag(&fd
);
1156 // all our current indexes have a field 'Package' in each section
1157 if (_error
->PendingError() == true || tag
.Step(sec
) == false || sec
.Exists("Package") == false)
1159 RenameOnError(InvalidFormat
);
1160 Failed(Message
, Cfg
);
1165 // Done, queue for rename on transaction finished
1166 PartialFile
= DestFile
;
1168 string FinalFile
= _config
->FindDir("Dir::State::lists");
1169 FinalFile
+= URItoFileName(RealURI
);
1170 DestFile
= FinalFile
;
1172 /* We restore the original name to DestFile so that the clean operation
1174 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1175 DestFile
+= URItoFileName(RealURI
);
1177 // Remove the compressed version.
1179 unlink(DestFile
.c_str());
1187 // Handle the unzipd case
1188 string FileName
= LookupTag(Message
,"Alt-Filename");
1189 if (FileName
.empty() == false)
1191 // The files timestamp matches
1192 if (StringToBool(LookupTag(Message
,"Alt-IMS-Hit"),false) == true)
1194 Decompression
= true;
1196 DestFile
+= ".decomp";
1197 Desc
.URI
= "copy:" + FileName
;
1203 FileName
= LookupTag(Message
,"Filename");
1204 if (FileName
.empty() == true)
1207 ErrorText
= "Method gave a blank filename";
1210 std::string
const compExt
= CompressionExtension
.substr(0, CompressionExtension
.find(' '));
1212 // The files timestamp matches
1213 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true) {
1214 if (_config
->FindB("Acquire::GzipIndexes",false) && compExt
== "gz")
1215 // Update DestFile for .gz suffix so that the clean operation keeps it
1220 if (FileName
== DestFile
)
1227 // If we enable compressed indexes and already have gzip, keep it
1228 if (_config
->FindB("Acquire::GzipIndexes",false) && compExt
== "gz" && !Local
) {
1229 string FinalFile
= _config
->FindDir("Dir::State::lists");
1230 FinalFile
+= URItoFileName(RealURI
) + ".gz";
1231 Rename(DestFile
,FinalFile
);
1232 chmod(FinalFile
.c_str(),0644);
1234 // Update DestFile for .gz suffix so that the clean operation keeps it
1235 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1236 DestFile
+= URItoFileName(RealURI
) + ".gz";
1240 // get the binary name for your used compression type
1241 decompProg
= _config
->Find(string("Acquire::CompressionTypes::").append(compExt
),"");
1242 if(decompProg
.empty() == false);
1243 else if(compExt
== "uncompressed")
1244 decompProg
= "copy";
1246 _error
->Error("Unsupported extension: %s", compExt
.c_str());
1250 Decompression
= true;
1251 DestFile
+= ".decomp";
1252 Desc
.URI
= decompProg
+ ":" + FileName
;
1255 // FIXME: this points to a c++ string that goes out of scope
1256 Mode
= decompProg
.c_str();
1259 // AcqIndexTrans::pkgAcqIndexTrans - Constructor /*{{{*/
1260 // ---------------------------------------------------------------------
1261 /* The Translation file is added to the queue */
1262 pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire
*Owner
,
1263 string URI
,string URIDesc
,string ShortDesc
)
1264 : pkgAcqIndex(Owner
, URI
, URIDesc
, ShortDesc
, HashStringList(), "")
1268 pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcqMetaIndex
*MetaOwner
, IndexTarget
const * const Target
,
1269 HashStringList
const &ExpectedHashes
, indexRecords
*MetaIndexParser
)
1270 : pkgAcqIndex(MetaOwner
, Target
, ExpectedHashes
, MetaIndexParser
)
1272 // load the filesize
1273 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(string(Target
->MetaKey
));
1275 FileSize
= Record
->Size
;
1278 // AcqIndexTrans::Custom600Headers - Insert custom request headers /*{{{*/
1279 // ---------------------------------------------------------------------
1280 string
pkgAcqIndexTrans::Custom600Headers() const
1282 string Final
= _config
->FindDir("Dir::State::lists");
1283 Final
+= URItoFileName(RealURI
);
1286 if (stat(Final
.c_str(),&Buf
) != 0)
1287 return "\nFail-Ignore: true\nIndex-File: true";
1288 return "\nFail-Ignore: true\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1291 // AcqIndexTrans::Failed - Silence failure messages for missing files /*{{{*/
1292 // ---------------------------------------------------------------------
1294 void pkgAcqIndexTrans::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1296 size_t const nextExt
= CompressionExtension
.find(' ');
1297 if (nextExt
!= std::string::npos
)
1299 CompressionExtension
= CompressionExtension
.substr(nextExt
+1);
1300 Init(RealURI
, Desc
.Description
, Desc
.ShortDesc
);
1305 if (Cnf
->LocalOnly
== true ||
1306 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1315 Item::Failed(Message
,Cnf
);
1318 pkgAcqMetaSig::pkgAcqMetaSig(pkgAcqMetaIndex
*MetaOwner
, /*{{{*/
1319 string URI
,string URIDesc
,string ShortDesc
,
1320 string MetaIndexFile
,
1321 const vector
<IndexTarget
*>* IndexTargets
,
1322 indexRecords
* MetaIndexParser
) :
1323 Item(MetaOwner
->GetOwner(), HashStringList()), RealURI(URI
),
1324 MetaIndexParser(MetaIndexParser
), MetaIndexFile(MetaIndexFile
),
1325 IndexTargets(IndexTargets
), AuthPass(false)
1327 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1328 DestFile
+= URItoFileName(URI
);
1330 TransactionID
= (unsigned long)MetaOwner
;
1332 // remove any partial downloaded sig-file in partial/.
1333 // it may confuse proxies and is too small to warrant a
1334 // partial download anyway
1335 unlink(DestFile
.c_str());
1338 Desc
.Description
= URIDesc
;
1340 Desc
.ShortDesc
= ShortDesc
;
1344 string Final
= _config
->FindDir("Dir::State::lists");
1345 Final
+= URItoFileName(RealURI
);
1346 if (RealFileExists(Final
) == true)
1348 // File was already in place. It needs to be re-downloaded/verified
1349 // because Release might have changed, we do give it a different
1350 // name than DestFile because otherwise the http method will
1351 // send If-Range requests and there are too many broken servers
1352 // out there that do not understand them
1353 LastGoodSig
= DestFile
+".reverify";
1354 Rename(Final
,LastGoodSig
);
1357 // we expect the indextargets + one additional Release file
1358 //ExpectedAdditionalItems = IndexTargets->size() + 1;
1363 pkgAcqMetaSig::~pkgAcqMetaSig() /*{{{*/
1365 // if the file was never queued undo file-changes done in the constructor
1366 if (QueueCounter
== 1 && Status
== StatIdle
&& FileSize
== 0 && Complete
== false &&
1367 LastGoodSig
.empty() == false)
1369 string
const Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1370 if (RealFileExists(Final
) == false && RealFileExists(LastGoodSig
) == true)
1371 Rename(LastGoodSig
, Final
);
1376 // pkgAcqMetaSig::Custom600Headers - Insert custom request headers /*{{{*/
1377 // ---------------------------------------------------------------------
1378 /* The only header we use is the last-modified header. */
1379 string
pkgAcqMetaSig::Custom600Headers() const
1382 if (stat(LastGoodSig
.c_str(),&Buf
) != 0)
1383 return "\nIndex-File: true";
1385 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1388 void pkgAcqMetaSig::Done(string Message
,unsigned long long Size
, HashStringList
const &Hashes
,
1389 pkgAcquire::MethodConfig
*Cfg
)
1391 Item::Done(Message
, Size
, Hashes
, Cfg
);
1393 string FileName
= LookupTag(Message
,"Filename");
1394 if (FileName
.empty() == true)
1397 ErrorText
= "Method gave a blank filename";
1401 if (FileName
!= DestFile
)
1403 // We have to copy it into place
1405 Desc
.URI
= "copy:" + FileName
;
1411 if(AuthPass
== false)
1414 Desc
.URI
= "gpgv:" + DestFile
;
1415 DestFile
= MetaIndexFile
;
1422 // put the last known good file back on i-m-s hit (it will
1423 // be re-verified again)
1424 // Else do nothing, we have the new file in DestFile then
1425 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
1426 Rename(LastGoodSig
, DestFile
);
1429 PartialFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1430 PartialFile
+= URItoFileName(RealURI
);
1432 DestFile
= _config
->FindDir("Dir::State::lists");
1433 DestFile
+= URItoFileName(RealURI
);
1436 // queue a pkgAcqMetaIndex to be verified against the sig we just retrieved
1437 pkgAcqMetaIndex
*metaindex
= new pkgAcqMetaIndex(
1438 Owner
, MetaIndexURI
, MetaIndexURIDesc
,
1439 MetaIndexShortDesc
, DestFile
, IndexTargets
,
1442 TransactionID
= (unsigned long)metaindex
;
1446 void pkgAcqMetaSig::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)/*{{{*/
1448 string Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1449 // if we get a network error we fail gracefully
1450 if(Status
== StatTransientNetworkError
)
1452 Item::Failed(Message
,Cnf
);
1453 // move the sigfile back on transient network failures
1454 if(FileExists(LastGoodSig
))
1455 Rename(LastGoodSig
,Final
);
1457 // set the status back to , Item::Failed likes to reset it
1458 Status
= pkgAcquire::Item::StatTransientNetworkError
;
1462 // Delete any existing sigfile when the acquire failed
1463 unlink(Final
.c_str());
1465 // queue a pkgAcqMetaIndex with no sigfile
1466 new pkgAcqMetaIndex(Owner
, MetaIndexURI
, MetaIndexURIDesc
, MetaIndexShortDesc
,
1467 "", IndexTargets
, MetaIndexParser
);
1469 if (Cnf
->LocalOnly
== true ||
1470 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1479 Item::Failed(Message
,Cnf
);
1482 pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire
*Owner
, /*{{{*/
1483 string URI
,string URIDesc
,string ShortDesc
,
1484 string MetaIndexSigURI
,string MetaIndexSigURIDesc
, string MetaIndexSigShortDesc
,
1485 const vector
<IndexTarget
*>* IndexTargets
,
1486 indexRecords
* MetaIndexParser
) :
1487 Item(Owner
, HashStringList()), RealURI(URI
), IndexTargets(IndexTargets
),
1488 MetaIndexParser(MetaIndexParser
), AuthPass(false), IMSHit(false),
1489 MetaIndexSigURI(MetaIndexSigURI
), MetaIndexSigURIDesc(MetaIndexSigURIDesc
),
1490 MetaIndexSigShortDesc(MetaIndexSigShortDesc
)
1492 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1493 DestFile
+= URItoFileName(URI
);
1495 TransactionID
= (unsigned long)this;
1498 Desc
.Description
= URIDesc
;
1500 Desc
.ShortDesc
= ShortDesc
;
1503 // we expect more item
1504 ExpectedAdditionalItems
= IndexTargets
->size();
1508 // pkgAcqMetaIndex::Custom600Headers - Insert custom request headers /*{{{*/
1509 // ---------------------------------------------------------------------
1510 /* The only header we use is the last-modified header. */
1511 string
pkgAcqMetaIndex::Custom600Headers() const
1513 string Final
= _config
->FindDir("Dir::State::lists");
1514 Final
+= URItoFileName(RealURI
);
1517 if (stat(Final
.c_str(),&Buf
) != 0)
1518 return "\nIndex-File: true";
1520 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1523 void pkgAcqMetaIndex::Done(string Message
,unsigned long long Size
,HashStringList
const &Hashes
, /*{{{*/
1524 pkgAcquire::MethodConfig
*Cfg
)
1526 Item::Done(Message
,Size
,Hashes
,Cfg
);
1528 // MetaIndexes are done in two passes: one to download the
1529 // metaindex with an appropriate method, and a second to verify it
1530 // with the gpgv method
1532 if (AuthPass
== true)
1536 // all cool, move Release file into place
1541 RetrievalDone(Message
);
1543 // Still more retrieving to do
1548 // load indexes, the signature will downloaded afterwards
1549 MetaIndexParser
->Load(DestFile
);
1554 // FIXME: move this into pkgAcqMetaClearSig::Done on the next
1557 // if we expect a ClearTextSignature (InRelase), ensure that
1558 // this is what we get and if not fail to queue a
1559 // Release/Release.gpg, see #346386
1560 if (SigFile
== DestFile
&& !StartsWithGPGClearTextSignature(DestFile
))
1562 Failed(Message
, Cfg
);
1566 // There was a signature file, so pass it to gpgv for
1568 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1569 std::cerr
<< "Metaindex acquired, queueing gpg verification ("
1570 << SigFile
<< "," << DestFile
<< ")\n";
1572 Desc
.URI
= "gpgv:" + SigFile
;
1579 if (Complete
== true)
1581 string FinalFile
= _config
->FindDir("Dir::State::lists");
1582 FinalFile
+= URItoFileName(RealURI
);
1583 if (SigFile
== DestFile
)
1584 SigFile
= FinalFile
;
1585 PartialFile
= DestFile
;
1586 DestFile
= FinalFile
;
1590 void pkgAcqMetaIndex::RetrievalDone(string Message
) /*{{{*/
1592 // We have just finished downloading a Release file (it is not
1595 string FileName
= LookupTag(Message
,"Filename");
1596 if (FileName
.empty() == true)
1599 ErrorText
= "Method gave a blank filename";
1603 if (FileName
!= DestFile
)
1606 Desc
.URI
= "copy:" + FileName
;
1611 // make sure to verify against the right file on I-M-S hit
1612 IMSHit
= StringToBool(LookupTag(Message
,"IMS-Hit"),false);
1615 string FinalFile
= _config
->FindDir("Dir::State::lists");
1616 FinalFile
+= URItoFileName(RealURI
);
1617 if (SigFile
== DestFile
)
1619 SigFile
= FinalFile
;
1620 // constructor of pkgAcqMetaClearSig moved it out of the way,
1621 // now move it back in on IMS hit for the 'old' file
1622 string
const OldClearSig
= DestFile
+ ".reverify";
1623 if (RealFileExists(OldClearSig
) == true)
1624 Rename(OldClearSig
, FinalFile
);
1626 DestFile
= FinalFile
;
1629 // queue a signature
1630 if(SigFile
!= DestFile
)
1631 new pkgAcqMetaSig(this, MetaIndexSigURI
, MetaIndexSigURIDesc
,
1632 MetaIndexSigShortDesc
, DestFile
, IndexTargets
,
1638 void pkgAcqMetaIndex::AuthDone(string Message
) /*{{{*/
1640 // At this point, the gpgv method has succeeded, so there is a
1641 // valid signature from a key in the trusted keyring. We
1642 // perform additional verification of its contents, and use them
1643 // to verify the indexes we are about to download
1645 if (!MetaIndexParser
->Load(DestFile
))
1647 Status
= StatAuthError
;
1648 ErrorText
= MetaIndexParser
->ErrorText
;
1652 if (!VerifyVendor(Message
))
1657 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1658 std::cerr
<< "Signature verification succeeded: "
1659 << DestFile
<< std::endl
;
1661 // Download further indexes with verification
1665 // is it a clearsigned MetaIndex file?
1666 if (DestFile
== SigFile
)
1669 // Done, move signature file into position
1670 string VerifiedSigFile
= _config
->FindDir("Dir::State::lists") +
1671 URItoFileName(RealURI
) + ".gpg";
1672 Rename(SigFile
,VerifiedSigFile
);
1673 chmod(VerifiedSigFile
.c_str(),0644);
1677 void pkgAcqMetaIndex::QueueIndexes(bool verify
) /*{{{*/
1679 bool transInRelease
= false;
1681 std::vector
<std::string
> const keys
= MetaIndexParser
->MetaKeys();
1682 for (std::vector
<std::string
>::const_iterator k
= keys
.begin(); k
!= keys
.end(); ++k
)
1683 // FIXME: Feels wrong to check for hardcoded string here, but what should we do else…
1684 if (k
->find("Translation-") != std::string::npos
)
1686 transInRelease
= true;
1691 // at this point the real Items are loaded in the fetcher
1692 ExpectedAdditionalItems
= 0;
1693 for (vector
<IndexTarget
*>::const_iterator Target
= IndexTargets
->begin();
1694 Target
!= IndexTargets
->end();
1697 HashStringList ExpectedIndexHashes
;
1698 const indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup((*Target
)->MetaKey
);
1699 bool compressedAvailable
= false;
1702 if ((*Target
)->IsOptional() == true)
1704 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
1705 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
1706 if (MetaIndexParser
->Exists((*Target
)->MetaKey
+ "." + *t
) == true)
1708 compressedAvailable
= true;
1712 else if (verify
== true)
1714 Status
= StatAuthError
;
1715 strprintf(ErrorText
, _("Unable to find expected entry '%s' in Release file (Wrong sources.list entry or malformed file)"), (*Target
)->MetaKey
.c_str());
1721 ExpectedIndexHashes
= Record
->Hashes
;
1722 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1724 std::cerr
<< "Queueing: " << (*Target
)->URI
<< std::endl
1725 << "Expected Hash:" << std::endl
;
1726 for (HashStringList::const_iterator hs
= ExpectedIndexHashes
.begin(); hs
!= ExpectedIndexHashes
.end(); ++hs
)
1727 std::cerr
<< "\t- " << hs
->toStr() << std::endl
;
1728 std::cerr
<< "For: " << Record
->MetaKeyFilename
<< std::endl
;
1730 if (verify
== true && ExpectedIndexHashes
.empty() == true && (*Target
)->IsOptional() == false)
1732 Status
= StatAuthError
;
1733 strprintf(ErrorText
, _("Unable to find hash sum for '%s' in Release file"), (*Target
)->MetaKey
.c_str());
1738 if ((*Target
)->IsOptional() == true)
1740 if ((*Target
)->IsSubIndex() == true)
1741 new pkgAcqSubIndex(Owner
, (*Target
)->URI
, (*Target
)->Description
,
1742 (*Target
)->ShortDesc
, ExpectedIndexHashes
);
1743 else if (transInRelease
== false || Record
!= NULL
|| compressedAvailable
== true)
1745 if (_config
->FindB("Acquire::PDiffs",true) == true && transInRelease
== true &&
1746 MetaIndexParser
->Exists((*Target
)->MetaKey
+ ".diff/Index") == true)
1747 new pkgAcqDiffIndex(this, *Target
, ExpectedIndexHashes
, MetaIndexParser
);
1749 new pkgAcqIndexTrans(this, *Target
, ExpectedIndexHashes
, MetaIndexParser
);
1754 /* Queue Packages file (either diff or full packages files, depending
1755 on the users option) - we also check if the PDiff Index file is listed
1756 in the Meta-Index file. Ideal would be if pkgAcqDiffIndex would test this
1757 instead, but passing the required info to it is to much hassle */
1758 if(_config
->FindB("Acquire::PDiffs",true) == true && (verify
== false ||
1759 MetaIndexParser
->Exists((*Target
)->MetaKey
+ ".diff/Index") == true))
1760 new pkgAcqDiffIndex(this, *Target
, ExpectedIndexHashes
, MetaIndexParser
);
1762 new pkgAcqIndex(this, *Target
, ExpectedIndexHashes
, MetaIndexParser
);
1766 bool pkgAcqMetaIndex::VerifyVendor(string Message
) /*{{{*/
1768 string::size_type pos
;
1770 // check for missing sigs (that where not fatal because otherwise we had
1773 string msg
= _("There is no public key available for the "
1774 "following key IDs:\n");
1775 pos
= Message
.find("NO_PUBKEY ");
1776 if (pos
!= std::string::npos
)
1778 string::size_type start
= pos
+strlen("NO_PUBKEY ");
1779 string Fingerprint
= Message
.substr(start
, Message
.find("\n")-start
);
1780 missingkeys
+= (Fingerprint
);
1782 if(!missingkeys
.empty())
1783 _error
->Warning("%s", (msg
+ missingkeys
).c_str());
1785 string Transformed
= MetaIndexParser
->GetExpectedDist();
1787 if (Transformed
== "../project/experimental")
1789 Transformed
= "experimental";
1792 pos
= Transformed
.rfind('/');
1793 if (pos
!= string::npos
)
1795 Transformed
= Transformed
.substr(0, pos
);
1798 if (Transformed
== ".")
1803 if (_config
->FindB("Acquire::Check-Valid-Until", true) == true &&
1804 MetaIndexParser
->GetValidUntil() > 0) {
1805 time_t const invalid_since
= time(NULL
) - MetaIndexParser
->GetValidUntil();
1806 if (invalid_since
> 0)
1807 // TRANSLATOR: The first %s is the URL of the bad Release file, the second is
1808 // the time since then the file is invalid - formated in the same way as in
1809 // the download progress display (e.g. 7d 3h 42min 1s)
1810 return _error
->Error(
1811 _("Release file for %s is expired (invalid since %s). "
1812 "Updates for this repository will not be applied."),
1813 RealURI
.c_str(), TimeToStr(invalid_since
).c_str());
1816 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1818 std::cerr
<< "Got Codename: " << MetaIndexParser
->GetDist() << std::endl
;
1819 std::cerr
<< "Expecting Dist: " << MetaIndexParser
->GetExpectedDist() << std::endl
;
1820 std::cerr
<< "Transformed Dist: " << Transformed
<< std::endl
;
1823 if (MetaIndexParser
->CheckDist(Transformed
) == false)
1825 // This might become fatal one day
1826 // Status = StatAuthError;
1827 // ErrorText = "Conflicting distribution; expected "
1828 // + MetaIndexParser->GetExpectedDist() + " but got "
1829 // + MetaIndexParser->GetDist();
1831 if (!Transformed
.empty())
1833 _error
->Warning(_("Conflicting distribution: %s (expected %s but got %s)"),
1834 Desc
.Description
.c_str(),
1835 Transformed
.c_str(),
1836 MetaIndexParser
->GetDist().c_str());
1843 // pkgAcqMetaIndex::Failed - no Release file present or no signature file present /*{{{*/
1844 // ---------------------------------------------------------------------
1846 void pkgAcqMetaIndex::Failed(string
/*Message*/,
1847 pkgAcquire::MethodConfig
* /*Cnf*/)
1850 if (AuthPass
== true)
1852 // gpgv method failed, if we have a good signature
1853 string LastGoodSigFile
= _config
->FindDir("Dir::State::lists").append("partial/").append(URItoFileName(RealURI
));
1854 if (DestFile
!= SigFile
)
1855 LastGoodSigFile
.append(".gpg");
1856 LastGoodSigFile
.append(".reverify");
1858 if(FileExists(LastGoodSigFile
))
1860 string VerifiedSigFile
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1861 if (DestFile
!= SigFile
)
1862 VerifiedSigFile
.append(".gpg");
1863 Rename(LastGoodSigFile
, VerifiedSigFile
);
1864 Status
= StatTransientNetworkError
;
1865 _error
->Warning(_("An error occurred during the signature "
1866 "verification. The repository is not updated "
1867 "and the previous index files will be used. "
1868 "GPG error: %s: %s\n"),
1869 Desc
.Description
.c_str(),
1870 LookupTag(Message
,"Message").c_str());
1871 RunScripts("APT::Update::Auth-Failure");
1873 } else if (LookupTag(Message
,"Message").find("NODATA") != string::npos
) {
1874 /* Invalid signature file, reject (LP: #346386) (Closes: #627642) */
1875 _error
->Error(_("GPG error: %s: %s"),
1876 Desc
.Description
.c_str(),
1877 LookupTag(Message
,"Message").c_str());
1880 _error
->Warning(_("GPG error: %s: %s"),
1881 Desc
.Description
.c_str(),
1882 LookupTag(Message
,"Message").c_str());
1884 // gpgv method failed
1885 ReportMirrorFailure("GPGFailure");
1888 /* Always move the meta index, even if gpgv failed. This ensures
1889 * that PackageFile objects are correctly filled in */
1890 if (FileExists(DestFile
)) {
1891 string FinalFile
= _config
->FindDir("Dir::State::lists");
1892 FinalFile
+= URItoFileName(RealURI
);
1893 /* InRelease files become Release files, otherwise
1894 * they would be considered as trusted later on */
1895 if (SigFile
== DestFile
) {
1896 RealURI
= RealURI
.replace(RealURI
.rfind("InRelease"), 9,
1898 FinalFile
= FinalFile
.replace(FinalFile
.rfind("InRelease"), 9,
1900 SigFile
= FinalFile
;
1902 Rename(DestFile
,FinalFile
);
1903 chmod(FinalFile
.c_str(),0644);
1905 DestFile
= FinalFile
;
1908 // No Release file was present, or verification failed, so fall
1909 // back to queueing Packages files without verification
1910 QueueIndexes(false);
1914 void pkgAcqMetaIndex::Finished()
1916 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1917 std::clog
<< "Finished: " << DestFile
<<std::endl
;
1918 if(Owner
->TransactionHasError((unsigned long)this) == false)
1919 Owner
->CommitTransaction((unsigned long)this);
1923 pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire
*Owner
, /*{{{*/
1924 string
const &URI
, string
const &URIDesc
, string
const &ShortDesc
,
1925 string
const &MetaIndexURI
, string
const &MetaIndexURIDesc
, string
const &MetaIndexShortDesc
,
1926 string
const &MetaSigURI
, string
const &MetaSigURIDesc
, string
const &MetaSigShortDesc
,
1927 const vector
<IndexTarget
*>* IndexTargets
,
1928 indexRecords
* MetaIndexParser
) :
1929 pkgAcqMetaIndex(Owner
, URI
, URIDesc
, ShortDesc
, MetaSigURI
, MetaSigURIDesc
,MetaSigShortDesc
, IndexTargets
, MetaIndexParser
),
1930 MetaIndexURI(MetaIndexURI
), MetaIndexURIDesc(MetaIndexURIDesc
), MetaIndexShortDesc(MetaIndexShortDesc
),
1931 MetaSigURI(MetaSigURI
), MetaSigURIDesc(MetaSigURIDesc
), MetaSigShortDesc(MetaSigShortDesc
)
1935 // index targets + (worst case:) Release/Release.gpg
1936 ExpectedAdditionalItems
= IndexTargets
->size() + 2;
1939 // keep the old InRelease around in case of transistent network errors
1940 string
const Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1941 if (RealFileExists(Final
) == true)
1943 string
const LastGoodSig
= DestFile
+ ".reverify";
1944 Rename(Final
,LastGoodSig
);
1948 pkgAcqMetaClearSig::~pkgAcqMetaClearSig() /*{{{*/
1950 // if the file was never queued undo file-changes done in the constructor
1951 if (QueueCounter
== 1 && Status
== StatIdle
&& FileSize
== 0 && Complete
== false)
1953 string
const Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1954 string
const LastGoodSig
= DestFile
+ ".reverify";
1955 if (RealFileExists(Final
) == false && RealFileExists(LastGoodSig
) == true)
1956 Rename(LastGoodSig
, Final
);
1960 // pkgAcqMetaClearSig::Custom600Headers - Insert custom request headers /*{{{*/
1961 // ---------------------------------------------------------------------
1962 // FIXME: this can go away once the InRelease file is used widely
1963 string
pkgAcqMetaClearSig::Custom600Headers() const
1965 string Final
= _config
->FindDir("Dir::State::lists");
1966 Final
+= URItoFileName(RealURI
);
1969 if (stat(Final
.c_str(),&Buf
) != 0)
1971 Final
= DestFile
+ ".reverify";
1972 if (stat(Final
.c_str(),&Buf
) != 0)
1973 return "\nIndex-File: true\nFail-Ignore: true\n";
1976 return "\nIndex-File: true\nFail-Ignore: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1979 void pkgAcqMetaClearSig::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
1981 // we failed, we will not get additional items from this method
1982 ExpectedAdditionalItems
= 0;
1984 if (AuthPass
== false)
1986 // Remove the 'old' InRelease file if we try Release.gpg now as otherwise
1987 // the file will stay around and gives a false-auth impression (CVE-2012-0214)
1988 string FinalFile
= _config
->FindDir("Dir::State::lists");
1989 FinalFile
.append(URItoFileName(RealURI
));
1990 if (FileExists(FinalFile
))
1991 unlink(FinalFile
.c_str());
1993 new pkgAcqMetaIndex(Owner
,
1994 MetaIndexURI
, MetaIndexURIDesc
, MetaIndexShortDesc
,
1995 MetaSigURI
, MetaSigURIDesc
, MetaSigShortDesc
,
1996 IndexTargets
, MetaIndexParser
);
1997 if (Cnf
->LocalOnly
== true ||
1998 StringToBool(LookupTag(Message
, "Transient-Failure"), false) == false)
2002 pkgAcqMetaIndex::Failed(Message
, Cnf
);
2005 // AcqArchive::AcqArchive - Constructor /*{{{*/
2006 // ---------------------------------------------------------------------
2007 /* This just sets up the initial fetch environment and queues the first
2009 pkgAcqArchive::pkgAcqArchive(pkgAcquire
*Owner
,pkgSourceList
*Sources
,
2010 pkgRecords
*Recs
,pkgCache::VerIterator
const &Version
,
2011 string
&StoreFilename
) :
2012 Item(Owner
, HashStringList()), Version(Version
), Sources(Sources
), Recs(Recs
),
2013 StoreFilename(StoreFilename
), Vf(Version
.FileList()),
2016 Retries
= _config
->FindI("Acquire::Retries",0);
2018 if (Version
.Arch() == 0)
2020 _error
->Error(_("I wasn't able to locate a file for the %s package. "
2021 "This might mean you need to manually fix this package. "
2022 "(due to missing arch)"),
2023 Version
.ParentPkg().FullName().c_str());
2027 /* We need to find a filename to determine the extension. We make the
2028 assumption here that all the available sources for this version share
2029 the same extension.. */
2030 // Skip not source sources, they do not have file fields.
2031 for (; Vf
.end() == false; ++Vf
)
2033 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
2038 // Does not really matter here.. we are going to fail out below
2039 if (Vf
.end() != true)
2041 // If this fails to get a file name we will bomb out below.
2042 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2043 if (_error
->PendingError() == true)
2046 // Generate the final file name as: package_version_arch.foo
2047 StoreFilename
= QuoteString(Version
.ParentPkg().Name(),"_:") + '_' +
2048 QuoteString(Version
.VerStr(),"_:") + '_' +
2049 QuoteString(Version
.Arch(),"_:.") +
2050 "." + flExtension(Parse
.FileName());
2053 // check if we have one trusted source for the package. if so, switch
2054 // to "TrustedOnly" mode - but only if not in AllowUnauthenticated mode
2055 bool const allowUnauth
= _config
->FindB("APT::Get::AllowUnauthenticated", false);
2056 bool const debugAuth
= _config
->FindB("Debug::pkgAcquire::Auth", false);
2057 bool seenUntrusted
= false;
2058 for (pkgCache::VerFileIterator i
= Version
.FileList(); i
.end() == false; ++i
)
2060 pkgIndexFile
*Index
;
2061 if (Sources
->FindIndex(i
.File(),Index
) == false)
2064 if (debugAuth
== true)
2065 std::cerr
<< "Checking index: " << Index
->Describe()
2066 << "(Trusted=" << Index
->IsTrusted() << ")" << std::endl
;
2068 if (Index
->IsTrusted() == true)
2071 if (allowUnauth
== false)
2075 seenUntrusted
= true;
2078 // "allow-unauthenticated" restores apts old fetching behaviour
2079 // that means that e.g. unauthenticated file:// uris are higher
2080 // priority than authenticated http:// uris
2081 if (allowUnauth
== true && seenUntrusted
== true)
2085 if (QueueNext() == false && _error
->PendingError() == false)
2086 _error
->Error(_("Can't find a source to download version '%s' of '%s'"),
2087 Version
.VerStr(), Version
.ParentPkg().FullName(false).c_str());
2090 // AcqArchive::QueueNext - Queue the next file source /*{{{*/
2091 // ---------------------------------------------------------------------
2092 /* This queues the next available file version for download. It checks if
2093 the archive is already available in the cache and stashs the MD5 for
2095 bool pkgAcqArchive::QueueNext()
2097 for (; Vf
.end() == false; ++Vf
)
2099 // Ignore not source sources
2100 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
2103 // Try to cross match against the source list
2104 pkgIndexFile
*Index
;
2105 if (Sources
->FindIndex(Vf
.File(),Index
) == false)
2108 // only try to get a trusted package from another source if that source
2110 if(Trusted
&& !Index
->IsTrusted())
2113 // Grab the text package record
2114 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2115 if (_error
->PendingError() == true)
2118 string PkgFile
= Parse
.FileName();
2119 ExpectedHashes
= Parse
.Hashes();
2121 if (PkgFile
.empty() == true)
2122 return _error
->Error(_("The package index files are corrupted. No Filename: "
2123 "field for package %s."),
2124 Version
.ParentPkg().Name());
2126 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
2127 Desc
.Description
= Index
->ArchiveInfo(Version
);
2129 Desc
.ShortDesc
= Version
.ParentPkg().FullName(true);
2131 // See if we already have the file. (Legacy filenames)
2132 FileSize
= Version
->Size
;
2133 string FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile
);
2135 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2137 // Make sure the size matches
2138 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2143 StoreFilename
= DestFile
= FinalFile
;
2147 /* Hmm, we have a file and its size does not match, this means it is
2148 an old style mismatched arch */
2149 unlink(FinalFile
.c_str());
2152 // Check it again using the new style output filenames
2153 FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
2154 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2156 // Make sure the size matches
2157 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2162 StoreFilename
= DestFile
= FinalFile
;
2166 /* Hmm, we have a file and its size does not match, this shouldn't
2168 unlink(FinalFile
.c_str());
2171 DestFile
= _config
->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename
);
2173 // Check the destination file
2174 if (stat(DestFile
.c_str(),&Buf
) == 0)
2176 // Hmm, the partial file is too big, erase it
2177 if ((unsigned long long)Buf
.st_size
> Version
->Size
)
2178 unlink(DestFile
.c_str());
2180 PartialSize
= Buf
.st_size
;
2183 // Disables download of archives - useful if no real installation follows,
2184 // e.g. if we are just interested in proposed installation order
2185 if (_config
->FindB("Debug::pkgAcqArchive::NoQueue", false) == true)
2190 StoreFilename
= DestFile
= FinalFile
;
2204 // AcqArchive::Done - Finished fetching /*{{{*/
2205 // ---------------------------------------------------------------------
2207 void pkgAcqArchive::Done(string Message
,unsigned long long Size
, HashStringList
const &CalcHashes
,
2208 pkgAcquire::MethodConfig
*Cfg
)
2210 Item::Done(Message
, Size
, CalcHashes
, Cfg
);
2213 if (Size
!= Version
->Size
)
2215 RenameOnError(SizeMismatch
);
2219 // FIXME: could this empty() check impose *any* sort of security issue?
2220 if(ExpectedHashes
.usable() && ExpectedHashes
!= CalcHashes
)
2222 RenameOnError(HashSumMismatch
);
2223 printHashSumComparision(DestFile
, ExpectedHashes
, CalcHashes
);
2227 // Grab the output filename
2228 string FileName
= LookupTag(Message
,"Filename");
2229 if (FileName
.empty() == true)
2232 ErrorText
= "Method gave a blank filename";
2238 // Reference filename
2239 if (FileName
!= DestFile
)
2241 StoreFilename
= DestFile
= FileName
;
2246 // Done, move it into position
2247 string FinalFile
= _config
->FindDir("Dir::Cache::Archives");
2248 FinalFile
+= flNotDir(StoreFilename
);
2249 Rename(DestFile
,FinalFile
);
2251 StoreFilename
= DestFile
= FinalFile
;
2255 // AcqArchive::Failed - Failure handler /*{{{*/
2256 // ---------------------------------------------------------------------
2257 /* Here we try other sources */
2258 void pkgAcqArchive::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
2260 ErrorText
= LookupTag(Message
,"Message");
2262 /* We don't really want to retry on failed media swaps, this prevents
2263 that. An interesting observation is that permanent failures are not
2265 if (Cnf
->Removable
== true &&
2266 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2268 // Vf = Version.FileList();
2269 while (Vf
.end() == false) ++Vf
;
2270 StoreFilename
= string();
2271 Item::Failed(Message
,Cnf
);
2275 if (QueueNext() == false)
2277 // This is the retry counter
2279 Cnf
->LocalOnly
== false &&
2280 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2283 Vf
= Version
.FileList();
2284 if (QueueNext() == true)
2288 StoreFilename
= string();
2289 Item::Failed(Message
,Cnf
);
2293 // AcqArchive::IsTrusted - Determine whether this archive comes from a trusted source /*{{{*/
2294 // ---------------------------------------------------------------------
2295 APT_PURE
bool pkgAcqArchive::IsTrusted() const
2300 // AcqArchive::Finished - Fetching has finished, tidy up /*{{{*/
2301 // ---------------------------------------------------------------------
2303 void pkgAcqArchive::Finished()
2305 if (Status
== pkgAcquire::Item::StatDone
&&
2308 StoreFilename
= string();
2311 // AcqFile::pkgAcqFile - Constructor /*{{{*/
2312 // ---------------------------------------------------------------------
2313 /* The file is added to the queue */
2314 pkgAcqFile::pkgAcqFile(pkgAcquire
*Owner
,string URI
, HashStringList
const &Hashes
,
2315 unsigned long long Size
,string Dsc
,string ShortDesc
,
2316 const string
&DestDir
, const string
&DestFilename
,
2318 Item(Owner
, Hashes
), IsIndexFile(IsIndexFile
)
2320 Retries
= _config
->FindI("Acquire::Retries",0);
2322 if(!DestFilename
.empty())
2323 DestFile
= DestFilename
;
2324 else if(!DestDir
.empty())
2325 DestFile
= DestDir
+ "/" + flNotDir(URI
);
2327 DestFile
= flNotDir(URI
);
2331 Desc
.Description
= Dsc
;
2334 // Set the short description to the archive component
2335 Desc
.ShortDesc
= ShortDesc
;
2337 // Get the transfer sizes
2340 if (stat(DestFile
.c_str(),&Buf
) == 0)
2342 // Hmm, the partial file is too big, erase it
2343 if ((Size
> 0) && (unsigned long long)Buf
.st_size
> Size
)
2344 unlink(DestFile
.c_str());
2346 PartialSize
= Buf
.st_size
;
2352 // AcqFile::Done - Item downloaded OK /*{{{*/
2353 // ---------------------------------------------------------------------
2355 void pkgAcqFile::Done(string Message
,unsigned long long Size
,HashStringList
const &CalcHashes
,
2356 pkgAcquire::MethodConfig
*Cnf
)
2358 Item::Done(Message
,Size
,CalcHashes
,Cnf
);
2361 if(ExpectedHashes
.usable() && ExpectedHashes
!= CalcHashes
)
2363 RenameOnError(HashSumMismatch
);
2364 printHashSumComparision(DestFile
, ExpectedHashes
, CalcHashes
);
2368 string FileName
= LookupTag(Message
,"Filename");
2369 if (FileName
.empty() == true)
2372 ErrorText
= "Method gave a blank filename";
2378 // The files timestamp matches
2379 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
2382 // We have to copy it into place
2383 if (FileName
!= DestFile
)
2386 if (_config
->FindB("Acquire::Source-Symlinks",true) == false ||
2387 Cnf
->Removable
== true)
2389 Desc
.URI
= "copy:" + FileName
;
2394 // Erase the file if it is a symlink so we can overwrite it
2396 if (lstat(DestFile
.c_str(),&St
) == 0)
2398 if (S_ISLNK(St
.st_mode
) != 0)
2399 unlink(DestFile
.c_str());
2403 if (symlink(FileName
.c_str(),DestFile
.c_str()) != 0)
2405 ErrorText
= "Link to " + DestFile
+ " failure ";
2412 // AcqFile::Failed - Failure handler /*{{{*/
2413 // ---------------------------------------------------------------------
2414 /* Here we try other sources */
2415 void pkgAcqFile::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
2417 ErrorText
= LookupTag(Message
,"Message");
2419 // This is the retry counter
2421 Cnf
->LocalOnly
== false &&
2422 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2429 Item::Failed(Message
,Cnf
);
2432 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
2433 // ---------------------------------------------------------------------
2434 /* The only header we use is the last-modified header. */
2435 string
pkgAcqFile::Custom600Headers() const
2438 return "\nIndex-File: true";