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), 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
)
91 ErrorText
= LookupTag(Message
,"Message");
92 UsedMirror
= LookupTag(Message
,"UsedMirror");
93 if (QueueCounter
<= 1)
95 /* This indicates that the file is not available right now but might
96 be sometime later. If we do a retry cycle then this should be
98 if (Cnf
->LocalOnly
== true &&
99 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
110 // report mirror failure back to LP if we actually use a mirror
111 string FailReason
= LookupTag(Message
, "FailReason");
112 if(FailReason
.size() != 0)
113 ReportMirrorFailure(FailReason
);
115 ReportMirrorFailure(ErrorText
);
118 // Acquire::Item::Start - Item has begun to download /*{{{*/
119 // ---------------------------------------------------------------------
120 /* Stash status and the file size. Note that setting Complete means
121 sub-phases of the acquire process such as decompresion are operating */
122 void pkgAcquire::Item::Start(string
/*Message*/,unsigned long long Size
)
124 Status
= StatFetching
;
125 if (FileSize
== 0 && Complete
== false)
129 // Acquire::Item::Done - Item downloaded OK /*{{{*/
130 // ---------------------------------------------------------------------
132 void pkgAcquire::Item::Done(string Message
,unsigned long long Size
,HashStringList
const &/*Hash*/,
133 pkgAcquire::MethodConfig
* /*Cnf*/)
135 // We just downloaded something..
136 string FileName
= LookupTag(Message
,"Filename");
137 UsedMirror
= LookupTag(Message
,"UsedMirror");
138 if (Complete
== false && !Local
&& FileName
== DestFile
)
141 Owner
->Log
->Fetched(Size
,atoi(LookupTag(Message
,"Resume-Point","0").c_str()));
147 ErrorText
= string();
148 Owner
->Dequeue(this);
151 // Acquire::Item::Rename - Rename a file /*{{{*/
152 // ---------------------------------------------------------------------
153 /* This helper function is used by a lot of item methods as their final
155 void pkgAcquire::Item::Rename(string From
,string To
)
157 if (rename(From
.c_str(),To
.c_str()) != 0)
160 snprintf(S
,sizeof(S
),_("rename failed, %s (%s -> %s)."),strerror(errno
),
161 From
.c_str(),To
.c_str());
167 bool pkgAcquire::Item::RenameOnError(pkgAcquire::Item::RenameOnErrorState
const error
)/*{{{*/
169 if(FileExists(DestFile
))
170 Rename(DestFile
, DestFile
+ ".FAILED");
174 case HashSumMismatch
:
175 ErrorText
= _("Hash Sum mismatch");
176 Status
= StatAuthError
;
177 ReportMirrorFailure("HashChecksumFailure");
180 ErrorText
= _("Size mismatch");
181 Status
= StatAuthError
;
182 ReportMirrorFailure("SizeFailure");
185 ErrorText
= _("Invalid file format");
187 // do not report as usually its not the mirrors fault, but Portal/Proxy
193 // Acquire::Item::ReportMirrorFailure /*{{{*/
194 // ---------------------------------------------------------------------
195 void pkgAcquire::Item::ReportMirrorFailure(string FailCode
)
197 // we only act if a mirror was used at all
198 if(UsedMirror
.empty())
201 std::cerr
<< "\nReportMirrorFailure: "
203 << " Uri: " << DescURI()
205 << FailCode
<< std::endl
;
207 const char *Args
[40];
209 string report
= _config
->Find("Methods::Mirror::ProblemReporting",
210 "/usr/lib/apt/apt-report-mirror-failure");
211 if(!FileExists(report
))
213 Args
[i
++] = report
.c_str();
214 Args
[i
++] = UsedMirror
.c_str();
215 Args
[i
++] = DescURI().c_str();
216 Args
[i
++] = FailCode
.c_str();
218 pid_t pid
= ExecFork();
221 _error
->Error("ReportMirrorFailure Fork failed");
226 execvp(Args
[0], (char**)Args
);
227 std::cerr
<< "Could not exec " << Args
[0] << std::endl
;
230 if(!ExecWait(pid
, "report-mirror-failure"))
232 _error
->Warning("Couldn't report problem to '%s'",
233 _config
->Find("Methods::Mirror::ProblemReporting").c_str());
237 // AcqSubIndex::AcqSubIndex - Constructor /*{{{*/
238 // ---------------------------------------------------------------------
239 /* Get a sub-index file based on checksums from a 'master' file and
240 possibly query additional files */
241 pkgAcqSubIndex::pkgAcqSubIndex(pkgAcquire
*Owner
, string
const &URI
,
242 string
const &URIDesc
, string
const &ShortDesc
,
243 HashStringList
const &ExpectedHashes
)
244 : Item(Owner
, ExpectedHashes
)
246 /* XXX: Beware: Currently this class does nothing (of value) anymore ! */
247 Debug
= _config
->FindB("Debug::pkgAcquire::SubIndex",false);
249 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
250 DestFile
+= URItoFileName(URI
);
253 Desc
.Description
= URIDesc
;
255 Desc
.ShortDesc
= ShortDesc
;
260 std::clog
<< "pkgAcqSubIndex: " << Desc
.URI
<< std::endl
;
263 // AcqSubIndex::Custom600Headers - Insert custom request headers /*{{{*/
264 // ---------------------------------------------------------------------
265 /* The only header we use is the last-modified header. */
266 string
pkgAcqSubIndex::Custom600Headers() const
268 string Final
= _config
->FindDir("Dir::State::lists");
269 Final
+= URItoFileName(Desc
.URI
);
272 if (stat(Final
.c_str(),&Buf
) != 0)
273 return "\nIndex-File: true\nFail-Ignore: true\n";
274 return "\nIndex-File: true\nFail-Ignore: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
277 void pkgAcqSubIndex::Failed(string Message
,pkgAcquire::MethodConfig
* /*Cnf*/)/*{{{*/
280 std::clog
<< "pkgAcqSubIndex failed: " << Desc
.URI
<< " with " << Message
<< std::endl
;
286 // No good Index is provided
289 void pkgAcqSubIndex::Done(string Message
,unsigned long long Size
,HashStringList
const &Hashes
, /*{{{*/
290 pkgAcquire::MethodConfig
*Cnf
)
293 std::clog
<< "pkgAcqSubIndex::Done(): " << Desc
.URI
<< std::endl
;
295 string FileName
= LookupTag(Message
,"Filename");
296 if (FileName
.empty() == true)
299 ErrorText
= "Method gave a blank filename";
303 if (FileName
!= DestFile
)
306 Desc
.URI
= "copy:" + FileName
;
311 Item::Done(Message
, Size
, Hashes
, Cnf
);
313 string FinalFile
= _config
->FindDir("Dir::State::lists")+URItoFileName(Desc
.URI
);
315 /* Downloaded invalid transindex => Error (LP: #346386) (Closes: #627642) */
316 indexRecords SubIndexParser
;
317 if (FileExists(DestFile
) == true && !SubIndexParser
.Load(DestFile
)) {
319 ErrorText
= SubIndexParser
.ErrorText
;
323 // success in downloading the index
326 std::clog
<< "Renaming: " << DestFile
<< " -> " << FinalFile
<< std::endl
;
327 Rename(DestFile
,FinalFile
);
328 chmod(FinalFile
.c_str(),0644);
329 DestFile
= FinalFile
;
331 if(ParseIndex(DestFile
) == false)
332 return Failed("", NULL
);
340 bool pkgAcqSubIndex::ParseIndex(string
const &IndexFile
) /*{{{*/
342 indexRecords SubIndexParser
;
343 if (FileExists(IndexFile
) == false || SubIndexParser
.Load(IndexFile
) == false)
345 // so something with the downloaded index
349 // AcqDiffIndex::AcqDiffIndex - Constructor /*{{{*/
350 // ---------------------------------------------------------------------
351 /* Get the DiffIndex file first and see if there are patches available
352 * If so, create a pkgAcqIndexDiffs fetcher that will get and apply the
353 * patches. If anything goes wrong in that process, it will fall back to
354 * the original packages file
356 pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire
*Owner
,
357 IndexTarget
const * const Target
,
358 HashStringList
const &ExpectedHashes
,
359 indexRecords
*MetaIndexParser
)
360 : Item(Owner
, ExpectedHashes
), Target(Target
),
361 MetaIndexParser(MetaIndexParser
)
364 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
366 RealURI
= Target
->URI
;
368 Desc
.Description
= Target
->Description
+ "/DiffIndex";
369 Desc
.ShortDesc
= Target
->ShortDesc
;
370 Desc
.URI
= Target
->URI
+ ".diff/Index";
372 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
373 DestFile
+= URItoFileName(Target
->URI
) + string(".DiffIndex");
376 std::clog
<< "pkgAcqDiffIndex: " << Desc
.URI
<< std::endl
;
378 // look for the current package file
379 CurrentPackagesFile
= _config
->FindDir("Dir::State::lists");
380 CurrentPackagesFile
+= URItoFileName(RealURI
);
382 // FIXME: this file:/ check is a hack to prevent fetching
383 // from local sources. this is really silly, and
384 // should be fixed cleanly as soon as possible
385 if(!FileExists(CurrentPackagesFile
) ||
386 Desc
.URI
.substr(0,strlen("file:/")) == "file:/")
388 // we don't have a pkg file or we don't want to queue
390 std::clog
<< "No index file, local or canceld by user" << std::endl
;
396 std::clog
<< "pkgAcqDiffIndex::pkgAcqDiffIndex(): "
397 << CurrentPackagesFile
<< std::endl
;
403 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
404 // ---------------------------------------------------------------------
405 /* The only header we use is the last-modified header. */
406 string
pkgAcqDiffIndex::Custom600Headers() const
408 string Final
= _config
->FindDir("Dir::State::lists");
409 Final
+= URItoFileName(RealURI
) + string(".IndexDiff");
412 std::clog
<< "Custom600Header-IMS: " << Final
<< std::endl
;
415 if (stat(Final
.c_str(),&Buf
) != 0)
416 return "\nIndex-File: true";
418 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
421 bool pkgAcqDiffIndex::ParseDiffIndex(string IndexDiffFile
) /*{{{*/
424 std::clog
<< "pkgAcqDiffIndex::ParseIndexDiff() " << IndexDiffFile
429 vector
<DiffInfo
> available_patches
;
431 FileFd
Fd(IndexDiffFile
,FileFd::ReadOnly
);
433 if (_error
->PendingError() == true)
436 if(TF
.Step(Tags
) == true)
442 string
const tmp
= Tags
.FindS("SHA1-Current");
443 std::stringstream
ss(tmp
);
444 ss
>> ServerSha1
>> size
;
445 unsigned long const ServerSize
= atol(size
.c_str());
447 FileFd
fd(CurrentPackagesFile
, FileFd::ReadOnly
);
450 string
const local_sha1
= SHA1
.Result();
452 if(local_sha1
== ServerSha1
)
454 // we have the same sha1 as the server so we are done here
456 std::clog
<< "Package file is up-to-date" << std::endl
;
457 // list cleanup needs to know that this file as well as the already
458 // present index is ours, so we create an empty diff to save it for us
459 new pkgAcqIndexDiffs(Owner
, RealURI
, Description
, Desc
.ShortDesc
,
460 ExpectedHashes
, ServerSha1
, available_patches
);
466 std::clog
<< "SHA1-Current: " << ServerSha1
<< " and we start at "<< fd
.Name() << " " << fd
.Size() << " " << local_sha1
<< std::endl
;
468 // check the historie and see what patches we need
469 string
const history
= Tags
.FindS("SHA1-History");
470 std::stringstream
hist(history
);
471 while(hist
>> d
.sha1
>> size
>> d
.file
)
473 // read until the first match is found
474 // from that point on, we probably need all diffs
475 if(d
.sha1
== local_sha1
)
477 else if (found
== false)
481 std::clog
<< "Need to get diff: " << d
.file
<< std::endl
;
482 available_patches
.push_back(d
);
485 if (available_patches
.empty() == false)
487 // patching with too many files is rather slow compared to a fast download
488 unsigned long const fileLimit
= _config
->FindI("Acquire::PDiffs::FileLimit", 0);
489 if (fileLimit
!= 0 && fileLimit
< available_patches
.size())
492 std::clog
<< "Need " << available_patches
.size() << " diffs (Limit is " << fileLimit
493 << ") so fallback to complete download" << std::endl
;
497 // see if the patches are too big
498 found
= false; // it was true and it will be true again at the end
499 d
= *available_patches
.begin();
500 string
const firstPatch
= d
.file
;
501 unsigned long patchesSize
= 0;
502 std::stringstream
patches(Tags
.FindS("SHA1-Patches"));
503 while(patches
>> d
.sha1
>> size
>> d
.file
)
505 if (firstPatch
== d
.file
)
507 else if (found
== false)
510 patchesSize
+= atol(size
.c_str());
512 unsigned long const sizeLimit
= ServerSize
* _config
->FindI("Acquire::PDiffs::SizeLimit", 100);
513 if (sizeLimit
> 0 && (sizeLimit
/100) < patchesSize
)
516 std::clog
<< "Need " << patchesSize
<< " bytes (Limit is " << sizeLimit
/100
517 << ") so fallback to complete download" << std::endl
;
523 // we have something, queue the next diff
527 string::size_type
const last_space
= Description
.rfind(" ");
528 if(last_space
!= string::npos
)
529 Description
.erase(last_space
, Description
.size()-last_space
);
531 /* decide if we should download patches one by one or in one go:
532 The first is good if the server merges patches, but many don't so client
533 based merging can be attempt in which case the second is better.
534 "bad things" will happen if patches are merged on the server,
535 but client side merging is attempt as well */
536 bool pdiff_merge
= _config
->FindB("Acquire::PDiffs::Merge", true);
537 if (pdiff_merge
== true)
539 // reprepro adds this flag if it has merged patches on the server
540 std::string
const precedence
= Tags
.FindS("X-Patch-Precedence");
541 pdiff_merge
= (precedence
!= "merged");
544 if (pdiff_merge
== false)
545 new pkgAcqIndexDiffs(Owner
, RealURI
, Description
, Desc
.ShortDesc
,
546 ExpectedHashes
, ServerSha1
, available_patches
);
549 std::vector
<pkgAcqIndexMergeDiffs
*> *diffs
= new std::vector
<pkgAcqIndexMergeDiffs
*>(available_patches
.size());
550 for(size_t i
= 0; i
< available_patches
.size(); ++i
)
551 (*diffs
)[i
] = new pkgAcqIndexMergeDiffs(Owner
, RealURI
, Description
, Desc
.ShortDesc
, ExpectedHashes
,
552 available_patches
[i
], diffs
);
562 // Nothing found, report and return false
563 // Failing here is ok, if we return false later, the full
564 // IndexFile is queued
566 std::clog
<< "Can't find a patch in the index file" << std::endl
;
570 void pkgAcqDiffIndex::Failed(string Message
,pkgAcquire::MethodConfig
* /*Cnf*/)/*{{{*/
573 std::clog
<< "pkgAcqDiffIndex failed: " << Desc
.URI
<< " with " << Message
<< std::endl
574 << "Falling back to normal index file acquire" << std::endl
;
576 new pkgAcqIndex(Owner
, Target
, ExpectedHashes
, MetaIndexParser
);
583 void pkgAcqDiffIndex::Done(string Message
,unsigned long long Size
,HashStringList
const &Hashes
, /*{{{*/
584 pkgAcquire::MethodConfig
*Cnf
)
587 std::clog
<< "pkgAcqDiffIndex::Done(): " << Desc
.URI
<< std::endl
;
589 Item::Done(Message
, Size
, Hashes
, Cnf
);
592 FinalFile
= _config
->FindDir("Dir::State::lists")+URItoFileName(RealURI
);
594 // success in downloading the index
596 FinalFile
+= string(".IndexDiff");
598 std::clog
<< "Renaming: " << DestFile
<< " -> " << FinalFile
600 Rename(DestFile
,FinalFile
);
601 chmod(FinalFile
.c_str(),0644);
602 DestFile
= FinalFile
;
604 if(!ParseDiffIndex(DestFile
))
605 return Failed("", NULL
);
613 // AcqIndexDiffs::AcqIndexDiffs - Constructor /*{{{*/
614 // ---------------------------------------------------------------------
615 /* The package diff is added to the queue. one object is constructed
616 * for each diff and the index
618 pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire
*Owner
,
619 string URI
,string URIDesc
,string ShortDesc
,
620 HashStringList
const &ExpectedHashes
,
622 vector
<DiffInfo
> diffs
)
623 : Item(Owner
, ExpectedHashes
), RealURI(URI
),
624 available_patches(diffs
), ServerSha1(ServerSha1
)
627 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
628 DestFile
+= URItoFileName(URI
);
630 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
632 Description
= URIDesc
;
634 Desc
.ShortDesc
= ShortDesc
;
636 if(available_patches
.empty() == true)
638 // we are done (yeah!)
644 State
= StateFetchDiff
;
649 void pkgAcqIndexDiffs::Failed(string Message
,pkgAcquire::MethodConfig
* /*Cnf*/)/*{{{*/
652 std::clog
<< "pkgAcqIndexDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
653 << "Falling back to normal index file acquire" << std::endl
;
654 new pkgAcqIndex(Owner
, RealURI
, Description
,Desc
.ShortDesc
, HashSums());
658 // Finish - helper that cleans the item out of the fetcher queue /*{{{*/
659 void pkgAcqIndexDiffs::Finish(bool allDone
)
661 // we restore the original name, this is required, otherwise
662 // the file will be cleaned
665 DestFile
= _config
->FindDir("Dir::State::lists");
666 DestFile
+= URItoFileName(RealURI
);
668 if(HashSums().usable() && !HashSums().VerifyFile(DestFile
))
670 RenameOnError(HashSumMismatch
);
675 // this is for the "real" finish
680 std::clog
<< "\n\nallDone: " << DestFile
<< "\n" << std::endl
;
685 std::clog
<< "Finishing: " << Desc
.URI
<< std::endl
;
692 bool pkgAcqIndexDiffs::QueueNextDiff() /*{{{*/
695 // calc sha1 of the just patched file
696 string FinalFile
= _config
->FindDir("Dir::State::lists");
697 FinalFile
+= URItoFileName(RealURI
);
699 FileFd
fd(FinalFile
, FileFd::ReadOnly
);
702 string local_sha1
= string(SHA1
.Result());
704 std::clog
<< "QueueNextDiff: "
705 << FinalFile
<< " (" << local_sha1
<< ")"<<std::endl
;
707 // final file reached before all patches are applied
708 if(local_sha1
== ServerSha1
)
714 // remove all patches until the next matching patch is found
715 // this requires the Index file to be ordered
716 for(vector
<DiffInfo
>::iterator I
=available_patches
.begin();
717 available_patches
.empty() == false &&
718 I
!= available_patches
.end() &&
719 I
->sha1
!= local_sha1
;
722 available_patches
.erase(I
);
725 // error checking and falling back if no patch was found
726 if(available_patches
.empty() == true)
732 // queue the right diff
733 Desc
.URI
= RealURI
+ ".diff/" + available_patches
[0].file
+ ".gz";
734 Desc
.Description
= Description
+ " " + available_patches
[0].file
+ string(".pdiff");
735 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
736 DestFile
+= URItoFileName(RealURI
+ ".diff/" + available_patches
[0].file
);
739 std::clog
<< "pkgAcqIndexDiffs::QueueNextDiff(): " << Desc
.URI
<< std::endl
;
746 void pkgAcqIndexDiffs::Done(string Message
,unsigned long long Size
, HashStringList
const &Hashes
, /*{{{*/
747 pkgAcquire::MethodConfig
*Cnf
)
750 std::clog
<< "pkgAcqIndexDiffs::Done(): " << Desc
.URI
<< std::endl
;
752 Item::Done(Message
, Size
, Hashes
, Cnf
);
755 FinalFile
= _config
->FindDir("Dir::State::lists")+URItoFileName(RealURI
);
757 // success in downloading a diff, enter ApplyDiff state
758 if(State
== StateFetchDiff
)
761 // rred excepts the patch as $FinalFile.ed
762 Rename(DestFile
,FinalFile
+".ed");
765 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
767 State
= StateApplyDiff
;
769 Desc
.URI
= "rred:" + FinalFile
;
776 // success in download/apply a diff, queue next (if needed)
777 if(State
== StateApplyDiff
)
779 // remove the just applied patch
780 available_patches
.erase(available_patches
.begin());
781 unlink((FinalFile
+ ".ed").c_str());
786 std::clog
<< "Moving patched file in place: " << std::endl
787 << DestFile
<< " -> " << FinalFile
<< std::endl
;
789 Rename(DestFile
,FinalFile
);
790 chmod(FinalFile
.c_str(),0644);
792 // see if there is more to download
793 if(available_patches
.empty() == false) {
794 new pkgAcqIndexDiffs(Owner
, RealURI
, Description
, Desc
.ShortDesc
,
795 HashSums(), ServerSha1
, available_patches
);
802 // AcqIndexMergeDiffs::AcqIndexMergeDiffs - Constructor /*{{{*/
803 pkgAcqIndexMergeDiffs::pkgAcqIndexMergeDiffs(pkgAcquire
*Owner
,
804 string
const &URI
, string
const &URIDesc
,
805 string
const &ShortDesc
, HashStringList
const &ExpectedHashes
,
806 DiffInfo
const &patch
,
807 std::vector
<pkgAcqIndexMergeDiffs
*> const * const allPatches
)
808 : Item(Owner
, ExpectedHashes
), RealURI(URI
),
809 patch(patch
),allPatches(allPatches
), State(StateFetchDiff
)
812 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
813 DestFile
+= URItoFileName(URI
);
815 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
817 Description
= URIDesc
;
819 Desc
.ShortDesc
= ShortDesc
;
821 Desc
.URI
= RealURI
+ ".diff/" + patch
.file
+ ".gz";
822 Desc
.Description
= Description
+ " " + patch
.file
+ string(".pdiff");
823 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
824 DestFile
+= URItoFileName(RealURI
+ ".diff/" + patch
.file
);
827 std::clog
<< "pkgAcqIndexMergeDiffs: " << Desc
.URI
<< std::endl
;
832 void pkgAcqIndexMergeDiffs::Failed(string Message
,pkgAcquire::MethodConfig
* /*Cnf*/)/*{{{*/
835 std::clog
<< "pkgAcqIndexMergeDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
;
840 // check if we are the first to fail, otherwise we are done here
841 State
= StateDoneDiff
;
842 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
843 I
!= allPatches
->end(); ++I
)
844 if ((*I
)->State
== StateErrorDiff
)
847 // first failure means we should fallback
848 State
= StateErrorDiff
;
849 std::clog
<< "Falling back to normal index file acquire" << std::endl
;
850 new pkgAcqIndex(Owner
, RealURI
, Description
,Desc
.ShortDesc
,
854 void pkgAcqIndexMergeDiffs::Done(string Message
,unsigned long long Size
,HashStringList
const &Hashes
, /*{{{*/
855 pkgAcquire::MethodConfig
*Cnf
)
858 std::clog
<< "pkgAcqIndexMergeDiffs::Done(): " << Desc
.URI
<< std::endl
;
860 Item::Done(Message
,Size
,Hashes
,Cnf
);
862 string
const FinalFile
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
864 if (State
== StateFetchDiff
)
866 // rred expects the patch as $FinalFile.ed.$patchname.gz
867 Rename(DestFile
, FinalFile
+ ".ed." + patch
.file
+ ".gz");
869 // check if this is the last completed diff
870 State
= StateDoneDiff
;
871 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
872 I
!= allPatches
->end(); ++I
)
873 if ((*I
)->State
!= StateDoneDiff
)
876 std::clog
<< "Not the last done diff in the batch: " << Desc
.URI
<< std::endl
;
880 // this is the last completed diff, so we are ready to apply now
881 State
= StateApplyDiff
;
884 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
887 Desc
.URI
= "rred:" + FinalFile
;
892 // success in download/apply all diffs, clean up
893 else if (State
== StateApplyDiff
)
895 // see if we really got the expected file
896 if(ExpectedHashes
.usable() && !ExpectedHashes
.VerifyFile(DestFile
))
898 RenameOnError(HashSumMismatch
);
902 // move the result into place
904 std::clog
<< "Moving patched file in place: " << std::endl
905 << DestFile
<< " -> " << FinalFile
<< std::endl
;
906 Rename(DestFile
, FinalFile
);
907 chmod(FinalFile
.c_str(), 0644);
909 // otherwise lists cleanup will eat the file
910 DestFile
= FinalFile
;
912 // ensure the ed's are gone regardless of list-cleanup
913 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
914 I
!= allPatches
->end(); ++I
)
916 std::string patch
= FinalFile
+ ".ed." + (*I
)->patch
.file
+ ".gz";
917 unlink(patch
.c_str());
923 std::clog
<< "allDone: " << DestFile
<< "\n" << std::endl
;
927 // AcqIndex::AcqIndex - Constructor /*{{{*/
928 // ---------------------------------------------------------------------
929 /* The package file is added to the queue and a second class is
930 instantiated to fetch the revision file */
931 pkgAcqIndex::pkgAcqIndex(pkgAcquire
*Owner
,
932 string URI
,string URIDesc
,string ShortDesc
,
933 HashStringList
const &ExpectedHashes
, string comprExt
)
934 : Item(Owner
, ExpectedHashes
), RealURI(URI
), Target(0),
937 if(comprExt
.empty() == true)
939 // autoselect the compression method
940 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
941 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
942 comprExt
.append(*t
).append(" ");
943 if (comprExt
.empty() == false)
944 comprExt
.erase(comprExt
.end()-1);
946 CompressionExtension
= comprExt
;
950 Init(URI
, URIDesc
, ShortDesc
);
952 pkgAcqIndex::pkgAcqIndex(pkgAcquire
*Owner
, IndexTarget
const * const Target
,
953 HashStringList
const &ExpectedHashes
, indexRecords
*MetaIndexParser
)
954 : Item(Owner
, ExpectedHashes
), RealURI(Target
->URI
)
956 // autoselect the compression method
957 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
958 CompressionExtension
= "";
959 if (ExpectedHashes
.usable())
961 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
962 if (*t
== "uncompressed" || MetaIndexParser
->Exists(string(Target
->MetaKey
).append(".").append(*t
)) == true)
963 CompressionExtension
.append(*t
).append(" ");
967 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
968 CompressionExtension
.append(*t
).append(" ");
970 if (CompressionExtension
.empty() == false)
971 CompressionExtension
.erase(CompressionExtension
.end()-1);
973 // only verify non-optional targets, see acquire-item.h for a FIXME
974 // to make this more flexible
975 if (Target
->IsOptional())
980 // we need this in Init()
981 this->Target
= Target
;
982 this->MetaIndexParser
= MetaIndexParser
;
984 Init(Target
->URI
, Target
->Description
, Target
->ShortDesc
);
987 // AcqIndex::Init - defered Constructor /*{{{*/
988 void pkgAcqIndex::Init(string
const &URI
, string
const &URIDesc
, string
const &ShortDesc
) {
989 Decompression
= false;
992 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
993 DestFile
+= URItoFileName(URI
);
995 std::string
const comprExt
= CompressionExtension
.substr(0, CompressionExtension
.find(' '));
997 if (comprExt
== "uncompressed")
1001 MetaKey
= string(Target
->MetaKey
);
1005 Desc
.URI
= URI
+ '.' + comprExt
;
1007 MetaKey
= string(Target
->MetaKey
) + '.' + comprExt
;
1010 // load the filesize
1013 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(MetaKey
);
1015 FileSize
= Record
->Size
;
1018 Desc
.Description
= URIDesc
;
1020 Desc
.ShortDesc
= ShortDesc
;
1025 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
1026 // ---------------------------------------------------------------------
1027 /* The only header we use is the last-modified header. */
1028 string
pkgAcqIndex::Custom600Headers() const
1030 string Final
= _config
->FindDir("Dir::State::lists");
1031 Final
+= URItoFileName(RealURI
);
1032 if (_config
->FindB("Acquire::GzipIndexes",false))
1035 string msg
= "\nIndex-File: true";
1036 // FIXME: this really should use "IndexTarget::IsOptional()" but that
1037 // seems to be difficult without breaking ABI
1038 if (ShortDesc().find("Translation") != 0)
1039 msg
+= "\nFail-Ignore: true";
1041 if (stat(Final
.c_str(),&Buf
) == 0)
1042 msg
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1047 void pkgAcqIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
1049 size_t const nextExt
= CompressionExtension
.find(' ');
1050 if (nextExt
!= std::string::npos
)
1052 CompressionExtension
= CompressionExtension
.substr(nextExt
+1);
1053 Init(RealURI
, Desc
.Description
, Desc
.ShortDesc
);
1057 // on decompression failure, remove bad versions in partial/
1058 if (Decompression
&& Erase
) {
1059 string s
= _config
->FindDir("Dir::State::lists") + "partial/";
1060 s
.append(URItoFileName(RealURI
));
1064 Item::Failed(Message
,Cnf
);
1067 // AcqIndex::Done - Finished a fetch /*{{{*/
1068 // ---------------------------------------------------------------------
1069 /* This goes through a number of states.. On the initial fetch the
1070 method could possibly return an alternate filename which points
1071 to the uncompressed version of the file. If this is so the file
1072 is copied into the partial directory. In all other cases the file
1073 is decompressed with a gzip uri. */
1074 void pkgAcqIndex::Done(string Message
,unsigned long long Size
,HashStringList
const &Hashes
,
1075 pkgAcquire::MethodConfig
*Cfg
)
1077 Item::Done(Message
,Size
,Hashes
,Cfg
);
1079 if (Decompression
== true)
1081 if (ExpectedHashes
.usable() && ExpectedHashes
!= Hashes
)
1083 RenameOnError(HashSumMismatch
);
1084 printHashSumComparision(RealURI
, ExpectedHashes
, Hashes
);
1088 /* Verify the index file for correctness (all indexes must
1089 * have a Package field) (LP: #346386) (Closes: #627642) */
1092 FileFd
fd(DestFile
, FileFd::ReadOnly
);
1093 // Only test for correctness if the file is not empty (empty is ok)
1094 if (fd
.FileSize() > 0)
1097 pkgTagFile
tag(&fd
);
1099 // all our current indexes have a field 'Package' in each section
1100 if (_error
->PendingError() == true || tag
.Step(sec
) == false || sec
.Exists("Package") == false)
1102 RenameOnError(InvalidFormat
);
1108 // Done, move it into position
1109 string FinalFile
= _config
->FindDir("Dir::State::lists");
1110 FinalFile
+= URItoFileName(RealURI
);
1111 Rename(DestFile
,FinalFile
);
1112 chmod(FinalFile
.c_str(),0644);
1114 /* We restore the original name to DestFile so that the clean operation
1116 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1117 DestFile
+= URItoFileName(RealURI
);
1119 // Remove the compressed version.
1121 unlink(DestFile
.c_str());
1129 // Handle the unzipd case
1130 string FileName
= LookupTag(Message
,"Alt-Filename");
1131 if (FileName
.empty() == false)
1133 // The files timestamp matches
1134 if (StringToBool(LookupTag(Message
,"Alt-IMS-Hit"),false) == true)
1136 Decompression
= true;
1138 DestFile
+= ".decomp";
1139 Desc
.URI
= "copy:" + FileName
;
1145 FileName
= LookupTag(Message
,"Filename");
1146 if (FileName
.empty() == true)
1149 ErrorText
= "Method gave a blank filename";
1152 std::string
const compExt
= CompressionExtension
.substr(0, CompressionExtension
.find(' '));
1154 // The files timestamp matches
1155 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true) {
1156 if (_config
->FindB("Acquire::GzipIndexes",false) && compExt
== "gz")
1157 // Update DestFile for .gz suffix so that the clean operation keeps it
1162 if (FileName
== DestFile
)
1169 // If we enable compressed indexes and already have gzip, keep it
1170 if (_config
->FindB("Acquire::GzipIndexes",false) && compExt
== "gz" && !Local
) {
1171 string FinalFile
= _config
->FindDir("Dir::State::lists");
1172 FinalFile
+= URItoFileName(RealURI
) + ".gz";
1173 Rename(DestFile
,FinalFile
);
1174 chmod(FinalFile
.c_str(),0644);
1176 // Update DestFile for .gz suffix so that the clean operation keeps it
1177 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1178 DestFile
+= URItoFileName(RealURI
) + ".gz";
1182 // get the binary name for your used compression type
1183 decompProg
= _config
->Find(string("Acquire::CompressionTypes::").append(compExt
),"");
1184 if(decompProg
.empty() == false);
1185 else if(compExt
== "uncompressed")
1186 decompProg
= "copy";
1188 _error
->Error("Unsupported extension: %s", compExt
.c_str());
1192 Decompression
= true;
1193 DestFile
+= ".decomp";
1194 Desc
.URI
= decompProg
+ ":" + FileName
;
1197 // FIXME: this points to a c++ string that goes out of scope
1198 Mode
= decompProg
.c_str();
1201 // AcqIndexTrans::pkgAcqIndexTrans - Constructor /*{{{*/
1202 // ---------------------------------------------------------------------
1203 /* The Translation file is added to the queue */
1204 pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire
*Owner
,
1205 string URI
,string URIDesc
,string ShortDesc
)
1206 : pkgAcqIndex(Owner
, URI
, URIDesc
, ShortDesc
, HashStringList(), "")
1209 pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire
*Owner
, IndexTarget
const * const Target
,
1210 HashStringList
const &ExpectedHashes
, indexRecords
*MetaIndexParser
)
1211 : pkgAcqIndex(Owner
, Target
, ExpectedHashes
, MetaIndexParser
)
1213 // load the filesize
1214 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(string(Target
->MetaKey
));
1216 FileSize
= Record
->Size
;
1219 // AcqIndexTrans::Custom600Headers - Insert custom request headers /*{{{*/
1220 // ---------------------------------------------------------------------
1221 string
pkgAcqIndexTrans::Custom600Headers() const
1223 string Final
= _config
->FindDir("Dir::State::lists");
1224 Final
+= URItoFileName(RealURI
);
1227 if (stat(Final
.c_str(),&Buf
) != 0)
1228 return "\nFail-Ignore: true\nIndex-File: true";
1229 return "\nFail-Ignore: true\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1232 // AcqIndexTrans::Failed - Silence failure messages for missing files /*{{{*/
1233 // ---------------------------------------------------------------------
1235 void pkgAcqIndexTrans::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1237 size_t const nextExt
= CompressionExtension
.find(' ');
1238 if (nextExt
!= std::string::npos
)
1240 CompressionExtension
= CompressionExtension
.substr(nextExt
+1);
1241 Init(RealURI
, Desc
.Description
, Desc
.ShortDesc
);
1246 if (Cnf
->LocalOnly
== true ||
1247 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1256 Item::Failed(Message
,Cnf
);
1259 pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire
*Owner
, /*{{{*/
1260 string URI
,string URIDesc
,string ShortDesc
,
1261 string MetaIndexURI
, string MetaIndexURIDesc
,
1262 string MetaIndexShortDesc
,
1263 const vector
<IndexTarget
*>* IndexTargets
,
1264 indexRecords
* MetaIndexParser
) :
1265 Item(Owner
, HashStringList()), RealURI(URI
), MetaIndexURI(MetaIndexURI
),
1266 MetaIndexURIDesc(MetaIndexURIDesc
), MetaIndexShortDesc(MetaIndexShortDesc
),
1267 MetaIndexParser(MetaIndexParser
), IndexTargets(IndexTargets
)
1269 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1270 DestFile
+= URItoFileName(URI
);
1272 // remove any partial downloaded sig-file in partial/.
1273 // it may confuse proxies and is too small to warrant a
1274 // partial download anyway
1275 unlink(DestFile
.c_str());
1278 Desc
.Description
= URIDesc
;
1280 Desc
.ShortDesc
= ShortDesc
;
1283 string Final
= _config
->FindDir("Dir::State::lists");
1284 Final
+= URItoFileName(RealURI
);
1285 if (RealFileExists(Final
) == true)
1287 // File was already in place. It needs to be re-downloaded/verified
1288 // because Release might have changed, we do give it a different
1289 // name than DestFile because otherwise the http method will
1290 // send If-Range requests and there are too many broken servers
1291 // out there that do not understand them
1292 LastGoodSig
= DestFile
+".reverify";
1293 Rename(Final
,LastGoodSig
);
1296 // we expect the indextargets + one additional Release file
1297 ExpectedAdditionalItems
= IndexTargets
->size() + 1;
1302 pkgAcqMetaSig::~pkgAcqMetaSig() /*{{{*/
1304 // if the file was never queued undo file-changes done in the constructor
1305 if (QueueCounter
== 1 && Status
== StatIdle
&& FileSize
== 0 && Complete
== false &&
1306 LastGoodSig
.empty() == false)
1308 string
const Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1309 if (RealFileExists(Final
) == false && RealFileExists(LastGoodSig
) == true)
1310 Rename(LastGoodSig
, Final
);
1315 // pkgAcqMetaSig::Custom600Headers - Insert custom request headers /*{{{*/
1316 // ---------------------------------------------------------------------
1317 /* The only header we use is the last-modified header. */
1318 string
pkgAcqMetaSig::Custom600Headers() const
1321 if (stat(LastGoodSig
.c_str(),&Buf
) != 0)
1322 return "\nIndex-File: true";
1324 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1327 void pkgAcqMetaSig::Done(string Message
,unsigned long long Size
, HashStringList
const &Hashes
,
1328 pkgAcquire::MethodConfig
*Cfg
)
1330 Item::Done(Message
, Size
, Hashes
, Cfg
);
1332 string FileName
= LookupTag(Message
,"Filename");
1333 if (FileName
.empty() == true)
1336 ErrorText
= "Method gave a blank filename";
1340 if (FileName
!= DestFile
)
1342 // We have to copy it into place
1344 Desc
.URI
= "copy:" + FileName
;
1351 // at this point pkgAcqMetaIndex takes over
1352 ExpectedAdditionalItems
= 0;
1354 // put the last known good file back on i-m-s hit (it will
1355 // be re-verified again)
1356 // Else do nothing, we have the new file in DestFile then
1357 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
1358 Rename(LastGoodSig
, DestFile
);
1360 // queue a pkgAcqMetaIndex to be verified against the sig we just retrieved
1361 new pkgAcqMetaIndex(Owner
, MetaIndexURI
, MetaIndexURIDesc
,
1362 MetaIndexShortDesc
, DestFile
, IndexTargets
,
1367 void pkgAcqMetaSig::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)/*{{{*/
1369 string Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1371 // at this point pkgAcqMetaIndex takes over
1372 ExpectedAdditionalItems
= 0;
1374 // if we get a network error we fail gracefully
1375 if(Status
== StatTransientNetworkError
)
1377 Item::Failed(Message
,Cnf
);
1378 // move the sigfile back on transient network failures
1379 if(FileExists(LastGoodSig
))
1380 Rename(LastGoodSig
,Final
);
1382 // set the status back to , Item::Failed likes to reset it
1383 Status
= pkgAcquire::Item::StatTransientNetworkError
;
1387 // Delete any existing sigfile when the acquire failed
1388 unlink(Final
.c_str());
1390 // queue a pkgAcqMetaIndex with no sigfile
1391 new pkgAcqMetaIndex(Owner
, MetaIndexURI
, MetaIndexURIDesc
, MetaIndexShortDesc
,
1392 "", IndexTargets
, MetaIndexParser
);
1394 if (Cnf
->LocalOnly
== true ||
1395 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1404 Item::Failed(Message
,Cnf
);
1407 pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire
*Owner
, /*{{{*/
1408 string URI
,string URIDesc
,string ShortDesc
,
1410 const vector
<IndexTarget
*>* IndexTargets
,
1411 indexRecords
* MetaIndexParser
) :
1412 Item(Owner
, HashStringList()), RealURI(URI
), SigFile(SigFile
), IndexTargets(IndexTargets
),
1413 MetaIndexParser(MetaIndexParser
), AuthPass(false), IMSHit(false)
1415 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1416 DestFile
+= URItoFileName(URI
);
1419 Desc
.Description
= URIDesc
;
1421 Desc
.ShortDesc
= ShortDesc
;
1424 // we expect more item
1425 ExpectedAdditionalItems
= IndexTargets
->size();
1430 // pkgAcqMetaIndex::Custom600Headers - Insert custom request headers /*{{{*/
1431 // ---------------------------------------------------------------------
1432 /* The only header we use is the last-modified header. */
1433 string
pkgAcqMetaIndex::Custom600Headers() const
1435 string Final
= _config
->FindDir("Dir::State::lists");
1436 Final
+= URItoFileName(RealURI
);
1439 if (stat(Final
.c_str(),&Buf
) != 0)
1440 return "\nIndex-File: true";
1442 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1445 void pkgAcqMetaIndex::Done(string Message
,unsigned long long Size
,HashStringList
const &Hashes
, /*{{{*/
1446 pkgAcquire::MethodConfig
*Cfg
)
1448 Item::Done(Message
,Size
,Hashes
,Cfg
);
1450 // MetaIndexes are done in two passes: one to download the
1451 // metaindex with an appropriate method, and a second to verify it
1452 // with the gpgv method
1454 if (AuthPass
== true)
1458 // all cool, move Release file into place
1463 RetrievalDone(Message
);
1465 // Still more retrieving to do
1470 // There was no signature file, so we are finished. Download
1471 // the indexes and do only hashsum verification if possible
1472 MetaIndexParser
->Load(DestFile
);
1473 QueueIndexes(false);
1477 // FIXME: move this into pkgAcqMetaClearSig::Done on the next
1480 // if we expect a ClearTextSignature (InRelase), ensure that
1481 // this is what we get and if not fail to queue a
1482 // Release/Release.gpg, see #346386
1483 if (SigFile
== DestFile
&& !StartsWithGPGClearTextSignature(DestFile
))
1485 Failed(Message
, Cfg
);
1489 // There was a signature file, so pass it to gpgv for
1491 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1492 std::cerr
<< "Metaindex acquired, queueing gpg verification ("
1493 << SigFile
<< "," << DestFile
<< ")\n";
1495 Desc
.URI
= "gpgv:" + SigFile
;
1502 if (Complete
== true)
1504 string FinalFile
= _config
->FindDir("Dir::State::lists");
1505 FinalFile
+= URItoFileName(RealURI
);
1506 if (SigFile
== DestFile
)
1507 SigFile
= FinalFile
;
1508 Rename(DestFile
,FinalFile
);
1509 chmod(FinalFile
.c_str(),0644);
1510 DestFile
= FinalFile
;
1514 void pkgAcqMetaIndex::RetrievalDone(string Message
) /*{{{*/
1516 // We have just finished downloading a Release file (it is not
1519 string FileName
= LookupTag(Message
,"Filename");
1520 if (FileName
.empty() == true)
1523 ErrorText
= "Method gave a blank filename";
1527 if (FileName
!= DestFile
)
1530 Desc
.URI
= "copy:" + FileName
;
1535 // make sure to verify against the right file on I-M-S hit
1536 IMSHit
= StringToBool(LookupTag(Message
,"IMS-Hit"),false);
1539 string FinalFile
= _config
->FindDir("Dir::State::lists");
1540 FinalFile
+= URItoFileName(RealURI
);
1541 if (SigFile
== DestFile
)
1543 SigFile
= FinalFile
;
1544 // constructor of pkgAcqMetaClearSig moved it out of the way,
1545 // now move it back in on IMS hit for the 'old' file
1546 string
const OldClearSig
= DestFile
+ ".reverify";
1547 if (RealFileExists(OldClearSig
) == true)
1548 Rename(OldClearSig
, FinalFile
);
1550 DestFile
= FinalFile
;
1555 void pkgAcqMetaIndex::AuthDone(string Message
) /*{{{*/
1557 // At this point, the gpgv method has succeeded, so there is a
1558 // valid signature from a key in the trusted keyring. We
1559 // perform additional verification of its contents, and use them
1560 // to verify the indexes we are about to download
1562 if (!MetaIndexParser
->Load(DestFile
))
1564 Status
= StatAuthError
;
1565 ErrorText
= MetaIndexParser
->ErrorText
;
1569 if (!VerifyVendor(Message
))
1574 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1575 std::cerr
<< "Signature verification succeeded: "
1576 << DestFile
<< std::endl
;
1578 // Download further indexes with verification
1581 // is it a clearsigned MetaIndex file?
1582 if (DestFile
== SigFile
)
1585 // Done, move signature file into position
1586 string VerifiedSigFile
= _config
->FindDir("Dir::State::lists") +
1587 URItoFileName(RealURI
) + ".gpg";
1588 Rename(SigFile
,VerifiedSigFile
);
1589 chmod(VerifiedSigFile
.c_str(),0644);
1592 void pkgAcqMetaIndex::QueueIndexes(bool verify
) /*{{{*/
1595 /* Reject invalid, existing Release files (LP: #346386) (Closes: #627642)
1596 * FIXME: Disabled; it breaks unsigned repositories without hashes */
1597 if (!verify
&& FileExists(DestFile
) && !MetaIndexParser
->Load(DestFile
))
1600 ErrorText
= MetaIndexParser
->ErrorText
;
1604 bool transInRelease
= false;
1606 std::vector
<std::string
> const keys
= MetaIndexParser
->MetaKeys();
1607 for (std::vector
<std::string
>::const_iterator k
= keys
.begin(); k
!= keys
.end(); ++k
)
1608 // FIXME: Feels wrong to check for hardcoded string here, but what should we do else…
1609 if (k
->find("Translation-") != std::string::npos
)
1611 transInRelease
= true;
1616 // at this point the real Items are loaded in the fetcher
1617 ExpectedAdditionalItems
= 0;
1619 for (vector
<IndexTarget
*>::const_iterator Target
= IndexTargets
->begin();
1620 Target
!= IndexTargets
->end();
1623 HashStringList ExpectedIndexHashes
;
1624 const indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup((*Target
)->MetaKey
);
1625 bool compressedAvailable
= false;
1628 if ((*Target
)->IsOptional() == true)
1630 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
1631 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
1632 if (MetaIndexParser
->Exists((*Target
)->MetaKey
+ "." + *t
) == true)
1634 compressedAvailable
= true;
1638 else if (verify
== true)
1640 Status
= StatAuthError
;
1641 strprintf(ErrorText
, _("Unable to find expected entry '%s' in Release file (Wrong sources.list entry or malformed file)"), (*Target
)->MetaKey
.c_str());
1647 ExpectedIndexHashes
= Record
->Hashes
;
1648 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1650 std::cerr
<< "Queueing: " << (*Target
)->URI
<< std::endl
1651 << "Expected Hash:" << std::endl
;
1652 for (HashStringList::const_iterator hs
= ExpectedIndexHashes
.begin(); hs
!= ExpectedIndexHashes
.end(); ++hs
)
1653 std::cerr
<< "\t- " << hs
->toStr() << std::endl
;
1654 std::cerr
<< "For: " << Record
->MetaKeyFilename
<< std::endl
;
1656 if (verify
== true && ExpectedIndexHashes
.empty() == true && (*Target
)->IsOptional() == false)
1658 Status
= StatAuthError
;
1659 strprintf(ErrorText
, _("Unable to find hash sum for '%s' in Release file"), (*Target
)->MetaKey
.c_str());
1664 if ((*Target
)->IsOptional() == true)
1666 if ((*Target
)->IsSubIndex() == true)
1667 new pkgAcqSubIndex(Owner
, (*Target
)->URI
, (*Target
)->Description
,
1668 (*Target
)->ShortDesc
, ExpectedIndexHashes
);
1669 else if (transInRelease
== false || Record
!= NULL
|| compressedAvailable
== true)
1671 if (_config
->FindB("Acquire::PDiffs",true) == true && transInRelease
== true &&
1672 MetaIndexParser
->Exists((*Target
)->MetaKey
+ ".diff/Index") == true)
1673 new pkgAcqDiffIndex(Owner
, *Target
, ExpectedIndexHashes
, MetaIndexParser
);
1675 new pkgAcqIndexTrans(Owner
, *Target
, ExpectedIndexHashes
, MetaIndexParser
);
1680 /* Queue Packages file (either diff or full packages files, depending
1681 on the users option) - we also check if the PDiff Index file is listed
1682 in the Meta-Index file. Ideal would be if pkgAcqDiffIndex would test this
1683 instead, but passing the required info to it is to much hassle */
1684 if(_config
->FindB("Acquire::PDiffs",true) == true && (verify
== false ||
1685 MetaIndexParser
->Exists((*Target
)->MetaKey
+ ".diff/Index") == true))
1686 new pkgAcqDiffIndex(Owner
, *Target
, ExpectedIndexHashes
, MetaIndexParser
);
1688 new pkgAcqIndex(Owner
, *Target
, ExpectedIndexHashes
, MetaIndexParser
);
1692 bool pkgAcqMetaIndex::VerifyVendor(string Message
) /*{{{*/
1694 string::size_type pos
;
1696 // check for missing sigs (that where not fatal because otherwise we had
1699 string msg
= _("There is no public key available for the "
1700 "following key IDs:\n");
1701 pos
= Message
.find("NO_PUBKEY ");
1702 if (pos
!= std::string::npos
)
1704 string::size_type start
= pos
+strlen("NO_PUBKEY ");
1705 string Fingerprint
= Message
.substr(start
, Message
.find("\n")-start
);
1706 missingkeys
+= (Fingerprint
);
1708 if(!missingkeys
.empty())
1709 _error
->Warning("%s", (msg
+ missingkeys
).c_str());
1711 string Transformed
= MetaIndexParser
->GetExpectedDist();
1713 if (Transformed
== "../project/experimental")
1715 Transformed
= "experimental";
1718 pos
= Transformed
.rfind('/');
1719 if (pos
!= string::npos
)
1721 Transformed
= Transformed
.substr(0, pos
);
1724 if (Transformed
== ".")
1729 if (_config
->FindB("Acquire::Check-Valid-Until", true) == true &&
1730 MetaIndexParser
->GetValidUntil() > 0) {
1731 time_t const invalid_since
= time(NULL
) - MetaIndexParser
->GetValidUntil();
1732 if (invalid_since
> 0)
1733 // TRANSLATOR: The first %s is the URL of the bad Release file, the second is
1734 // the time since then the file is invalid - formated in the same way as in
1735 // the download progress display (e.g. 7d 3h 42min 1s)
1736 return _error
->Error(
1737 _("Release file for %s is expired (invalid since %s). "
1738 "Updates for this repository will not be applied."),
1739 RealURI
.c_str(), TimeToStr(invalid_since
).c_str());
1742 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1744 std::cerr
<< "Got Codename: " << MetaIndexParser
->GetDist() << std::endl
;
1745 std::cerr
<< "Expecting Dist: " << MetaIndexParser
->GetExpectedDist() << std::endl
;
1746 std::cerr
<< "Transformed Dist: " << Transformed
<< std::endl
;
1749 if (MetaIndexParser
->CheckDist(Transformed
) == false)
1751 // This might become fatal one day
1752 // Status = StatAuthError;
1753 // ErrorText = "Conflicting distribution; expected "
1754 // + MetaIndexParser->GetExpectedDist() + " but got "
1755 // + MetaIndexParser->GetDist();
1757 if (!Transformed
.empty())
1759 _error
->Warning(_("Conflicting distribution: %s (expected %s but got %s)"),
1760 Desc
.Description
.c_str(),
1761 Transformed
.c_str(),
1762 MetaIndexParser
->GetDist().c_str());
1769 // pkgAcqMetaIndex::Failed - no Release file present or no signature file present /*{{{*/
1770 // ---------------------------------------------------------------------
1772 void pkgAcqMetaIndex::Failed(string Message
,pkgAcquire::MethodConfig
* /*Cnf*/)
1774 if (AuthPass
== true)
1776 // gpgv method failed, if we have a good signature
1777 string LastGoodSigFile
= _config
->FindDir("Dir::State::lists").append("partial/").append(URItoFileName(RealURI
));
1778 if (DestFile
!= SigFile
)
1779 LastGoodSigFile
.append(".gpg");
1780 LastGoodSigFile
.append(".reverify");
1782 if(FileExists(LastGoodSigFile
))
1784 string VerifiedSigFile
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1785 if (DestFile
!= SigFile
)
1786 VerifiedSigFile
.append(".gpg");
1787 Rename(LastGoodSigFile
, VerifiedSigFile
);
1788 Status
= StatTransientNetworkError
;
1789 _error
->Warning(_("An error occurred during the signature "
1790 "verification. The repository is not updated "
1791 "and the previous index files will be used. "
1792 "GPG error: %s: %s\n"),
1793 Desc
.Description
.c_str(),
1794 LookupTag(Message
,"Message").c_str());
1795 RunScripts("APT::Update::Auth-Failure");
1797 } else if (LookupTag(Message
,"Message").find("NODATA") != string::npos
) {
1798 /* Invalid signature file, reject (LP: #346386) (Closes: #627642) */
1799 _error
->Error(_("GPG error: %s: %s"),
1800 Desc
.Description
.c_str(),
1801 LookupTag(Message
,"Message").c_str());
1804 _error
->Warning(_("GPG error: %s: %s"),
1805 Desc
.Description
.c_str(),
1806 LookupTag(Message
,"Message").c_str());
1808 // gpgv method failed
1809 ReportMirrorFailure("GPGFailure");
1812 /* Always move the meta index, even if gpgv failed. This ensures
1813 * that PackageFile objects are correctly filled in */
1814 if (FileExists(DestFile
)) {
1815 string FinalFile
= _config
->FindDir("Dir::State::lists");
1816 FinalFile
+= URItoFileName(RealURI
);
1817 /* InRelease files become Release files, otherwise
1818 * they would be considered as trusted later on */
1819 if (SigFile
== DestFile
) {
1820 RealURI
= RealURI
.replace(RealURI
.rfind("InRelease"), 9,
1822 FinalFile
= FinalFile
.replace(FinalFile
.rfind("InRelease"), 9,
1824 SigFile
= FinalFile
;
1826 Rename(DestFile
,FinalFile
);
1827 chmod(FinalFile
.c_str(),0644);
1829 DestFile
= FinalFile
;
1832 // No Release file was present, or verification failed, so fall
1833 // back to queueing Packages files without verification
1834 QueueIndexes(false);
1837 pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire
*Owner
, /*{{{*/
1838 string
const &URI
, string
const &URIDesc
, string
const &ShortDesc
,
1839 string
const &MetaIndexURI
, string
const &MetaIndexURIDesc
, string
const &MetaIndexShortDesc
,
1840 string
const &MetaSigURI
, string
const &MetaSigURIDesc
, string
const &MetaSigShortDesc
,
1841 const vector
<IndexTarget
*>* IndexTargets
,
1842 indexRecords
* MetaIndexParser
) :
1843 pkgAcqMetaIndex(Owner
, URI
, URIDesc
, ShortDesc
, "", IndexTargets
, MetaIndexParser
),
1844 MetaIndexURI(MetaIndexURI
), MetaIndexURIDesc(MetaIndexURIDesc
), MetaIndexShortDesc(MetaIndexShortDesc
),
1845 MetaSigURI(MetaSigURI
), MetaSigURIDesc(MetaSigURIDesc
), MetaSigShortDesc(MetaSigShortDesc
)
1849 // index targets + (worst case:) Release/Release.gpg
1850 ExpectedAdditionalItems
= IndexTargets
->size() + 2;
1853 // keep the old InRelease around in case of transistent network errors
1854 string
const Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1855 if (RealFileExists(Final
) == true)
1857 string
const LastGoodSig
= DestFile
+ ".reverify";
1858 Rename(Final
,LastGoodSig
);
1862 pkgAcqMetaClearSig::~pkgAcqMetaClearSig() /*{{{*/
1864 // if the file was never queued undo file-changes done in the constructor
1865 if (QueueCounter
== 1 && Status
== StatIdle
&& FileSize
== 0 && Complete
== false)
1867 string
const Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1868 string
const LastGoodSig
= DestFile
+ ".reverify";
1869 if (RealFileExists(Final
) == false && RealFileExists(LastGoodSig
) == true)
1870 Rename(LastGoodSig
, Final
);
1874 // pkgAcqMetaClearSig::Custom600Headers - Insert custom request headers /*{{{*/
1875 // ---------------------------------------------------------------------
1876 // FIXME: this can go away once the InRelease file is used widely
1877 string
pkgAcqMetaClearSig::Custom600Headers() const
1879 string Final
= _config
->FindDir("Dir::State::lists");
1880 Final
+= URItoFileName(RealURI
);
1883 if (stat(Final
.c_str(),&Buf
) != 0)
1885 Final
= DestFile
+ ".reverify";
1886 if (stat(Final
.c_str(),&Buf
) != 0)
1887 return "\nIndex-File: true\nFail-Ignore: true\n";
1890 return "\nIndex-File: true\nFail-Ignore: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1893 void pkgAcqMetaClearSig::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
1895 // we failed, we will not get additional items from this method
1896 ExpectedAdditionalItems
= 0;
1898 if (AuthPass
== false)
1900 // Remove the 'old' InRelease file if we try Release.gpg now as otherwise
1901 // the file will stay around and gives a false-auth impression (CVE-2012-0214)
1902 string FinalFile
= _config
->FindDir("Dir::State::lists");
1903 FinalFile
.append(URItoFileName(RealURI
));
1904 if (FileExists(FinalFile
))
1905 unlink(FinalFile
.c_str());
1907 new pkgAcqMetaSig(Owner
,
1908 MetaSigURI
, MetaSigURIDesc
, MetaSigShortDesc
,
1909 MetaIndexURI
, MetaIndexURIDesc
, MetaIndexShortDesc
,
1910 IndexTargets
, MetaIndexParser
);
1911 if (Cnf
->LocalOnly
== true ||
1912 StringToBool(LookupTag(Message
, "Transient-Failure"), false) == false)
1916 pkgAcqMetaIndex::Failed(Message
, Cnf
);
1919 // AcqArchive::AcqArchive - Constructor /*{{{*/
1920 // ---------------------------------------------------------------------
1921 /* This just sets up the initial fetch environment and queues the first
1923 pkgAcqArchive::pkgAcqArchive(pkgAcquire
*Owner
,pkgSourceList
*Sources
,
1924 pkgRecords
*Recs
,pkgCache::VerIterator
const &Version
,
1925 string
&StoreFilename
) :
1926 Item(Owner
, HashStringList()), Version(Version
), Sources(Sources
), Recs(Recs
),
1927 StoreFilename(StoreFilename
), Vf(Version
.FileList()),
1930 Retries
= _config
->FindI("Acquire::Retries",0);
1932 if (Version
.Arch() == 0)
1934 _error
->Error(_("I wasn't able to locate a file for the %s package. "
1935 "This might mean you need to manually fix this package. "
1936 "(due to missing arch)"),
1937 Version
.ParentPkg().FullName().c_str());
1941 /* We need to find a filename to determine the extension. We make the
1942 assumption here that all the available sources for this version share
1943 the same extension.. */
1944 // Skip not source sources, they do not have file fields.
1945 for (; Vf
.end() == false; ++Vf
)
1947 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
1952 // Does not really matter here.. we are going to fail out below
1953 if (Vf
.end() != true)
1955 // If this fails to get a file name we will bomb out below.
1956 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
1957 if (_error
->PendingError() == true)
1960 // Generate the final file name as: package_version_arch.foo
1961 StoreFilename
= QuoteString(Version
.ParentPkg().Name(),"_:") + '_' +
1962 QuoteString(Version
.VerStr(),"_:") + '_' +
1963 QuoteString(Version
.Arch(),"_:.") +
1964 "." + flExtension(Parse
.FileName());
1967 // check if we have one trusted source for the package. if so, switch
1968 // to "TrustedOnly" mode - but only if not in AllowUnauthenticated mode
1969 bool const allowUnauth
= _config
->FindB("APT::Get::AllowUnauthenticated", false);
1970 bool const debugAuth
= _config
->FindB("Debug::pkgAcquire::Auth", false);
1971 bool seenUntrusted
= false;
1972 for (pkgCache::VerFileIterator i
= Version
.FileList(); i
.end() == false; ++i
)
1974 pkgIndexFile
*Index
;
1975 if (Sources
->FindIndex(i
.File(),Index
) == false)
1978 if (debugAuth
== true)
1979 std::cerr
<< "Checking index: " << Index
->Describe()
1980 << "(Trusted=" << Index
->IsTrusted() << ")" << std::endl
;
1982 if (Index
->IsTrusted() == true)
1985 if (allowUnauth
== false)
1989 seenUntrusted
= true;
1992 // "allow-unauthenticated" restores apts old fetching behaviour
1993 // that means that e.g. unauthenticated file:// uris are higher
1994 // priority than authenticated http:// uris
1995 if (allowUnauth
== true && seenUntrusted
== true)
1999 if (QueueNext() == false && _error
->PendingError() == false)
2000 _error
->Error(_("Can't find a source to download version '%s' of '%s'"),
2001 Version
.VerStr(), Version
.ParentPkg().FullName(false).c_str());
2004 // AcqArchive::QueueNext - Queue the next file source /*{{{*/
2005 // ---------------------------------------------------------------------
2006 /* This queues the next available file version for download. It checks if
2007 the archive is already available in the cache and stashs the MD5 for
2009 bool pkgAcqArchive::QueueNext()
2011 for (; Vf
.end() == false; ++Vf
)
2013 // Ignore not source sources
2014 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
2017 // Try to cross match against the source list
2018 pkgIndexFile
*Index
;
2019 if (Sources
->FindIndex(Vf
.File(),Index
) == false)
2022 // only try to get a trusted package from another source if that source
2024 if(Trusted
&& !Index
->IsTrusted())
2027 // Grab the text package record
2028 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2029 if (_error
->PendingError() == true)
2032 string PkgFile
= Parse
.FileName();
2033 ExpectedHashes
= Parse
.Hashes();
2035 if (PkgFile
.empty() == true)
2036 return _error
->Error(_("The package index files are corrupted. No Filename: "
2037 "field for package %s."),
2038 Version
.ParentPkg().Name());
2040 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
2041 Desc
.Description
= Index
->ArchiveInfo(Version
);
2043 Desc
.ShortDesc
= Version
.ParentPkg().FullName(true);
2045 // See if we already have the file. (Legacy filenames)
2046 FileSize
= Version
->Size
;
2047 string FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile
);
2049 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2051 // Make sure the size matches
2052 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2057 StoreFilename
= DestFile
= FinalFile
;
2061 /* Hmm, we have a file and its size does not match, this means it is
2062 an old style mismatched arch */
2063 unlink(FinalFile
.c_str());
2066 // Check it again using the new style output filenames
2067 FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
2068 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2070 // Make sure the size matches
2071 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2076 StoreFilename
= DestFile
= FinalFile
;
2080 /* Hmm, we have a file and its size does not match, this shouldn't
2082 unlink(FinalFile
.c_str());
2085 DestFile
= _config
->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename
);
2087 // Check the destination file
2088 if (stat(DestFile
.c_str(),&Buf
) == 0)
2090 // Hmm, the partial file is too big, erase it
2091 if ((unsigned long long)Buf
.st_size
> Version
->Size
)
2092 unlink(DestFile
.c_str());
2094 PartialSize
= Buf
.st_size
;
2097 // Disables download of archives - useful if no real installation follows,
2098 // e.g. if we are just interested in proposed installation order
2099 if (_config
->FindB("Debug::pkgAcqArchive::NoQueue", false) == true)
2104 StoreFilename
= DestFile
= FinalFile
;
2118 // AcqArchive::Done - Finished fetching /*{{{*/
2119 // ---------------------------------------------------------------------
2121 void pkgAcqArchive::Done(string Message
,unsigned long long Size
, HashStringList
const &CalcHashes
,
2122 pkgAcquire::MethodConfig
*Cfg
)
2124 Item::Done(Message
, Size
, CalcHashes
, Cfg
);
2127 if (Size
!= Version
->Size
)
2129 RenameOnError(SizeMismatch
);
2133 // FIXME: could this empty() check impose *any* sort of security issue?
2134 if(ExpectedHashes
.usable() && ExpectedHashes
!= CalcHashes
)
2136 RenameOnError(HashSumMismatch
);
2137 printHashSumComparision(DestFile
, ExpectedHashes
, CalcHashes
);
2141 // Grab the output filename
2142 string FileName
= LookupTag(Message
,"Filename");
2143 if (FileName
.empty() == true)
2146 ErrorText
= "Method gave a blank filename";
2152 // Reference filename
2153 if (FileName
!= DestFile
)
2155 StoreFilename
= DestFile
= FileName
;
2160 // Done, move it into position
2161 string FinalFile
= _config
->FindDir("Dir::Cache::Archives");
2162 FinalFile
+= flNotDir(StoreFilename
);
2163 Rename(DestFile
,FinalFile
);
2165 StoreFilename
= DestFile
= FinalFile
;
2169 // AcqArchive::Failed - Failure handler /*{{{*/
2170 // ---------------------------------------------------------------------
2171 /* Here we try other sources */
2172 void pkgAcqArchive::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
2174 ErrorText
= LookupTag(Message
,"Message");
2176 /* We don't really want to retry on failed media swaps, this prevents
2177 that. An interesting observation is that permanent failures are not
2179 if (Cnf
->Removable
== true &&
2180 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2182 // Vf = Version.FileList();
2183 while (Vf
.end() == false) ++Vf
;
2184 StoreFilename
= string();
2185 Item::Failed(Message
,Cnf
);
2189 if (QueueNext() == false)
2191 // This is the retry counter
2193 Cnf
->LocalOnly
== false &&
2194 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2197 Vf
= Version
.FileList();
2198 if (QueueNext() == true)
2202 StoreFilename
= string();
2203 Item::Failed(Message
,Cnf
);
2207 // AcqArchive::IsTrusted - Determine whether this archive comes from a trusted source /*{{{*/
2208 // ---------------------------------------------------------------------
2209 APT_PURE
bool pkgAcqArchive::IsTrusted() const
2214 // AcqArchive::Finished - Fetching has finished, tidy up /*{{{*/
2215 // ---------------------------------------------------------------------
2217 void pkgAcqArchive::Finished()
2219 if (Status
== pkgAcquire::Item::StatDone
&&
2222 StoreFilename
= string();
2225 // AcqFile::pkgAcqFile - Constructor /*{{{*/
2226 // ---------------------------------------------------------------------
2227 /* The file is added to the queue */
2228 pkgAcqFile::pkgAcqFile(pkgAcquire
*Owner
,string URI
, HashStringList
const &Hashes
,
2229 unsigned long long Size
,string Dsc
,string ShortDesc
,
2230 const string
&DestDir
, const string
&DestFilename
,
2232 Item(Owner
, Hashes
), IsIndexFile(IsIndexFile
)
2234 Retries
= _config
->FindI("Acquire::Retries",0);
2236 if(!DestFilename
.empty())
2237 DestFile
= DestFilename
;
2238 else if(!DestDir
.empty())
2239 DestFile
= DestDir
+ "/" + flNotDir(URI
);
2241 DestFile
= flNotDir(URI
);
2245 Desc
.Description
= Dsc
;
2248 // Set the short description to the archive component
2249 Desc
.ShortDesc
= ShortDesc
;
2251 // Get the transfer sizes
2254 if (stat(DestFile
.c_str(),&Buf
) == 0)
2256 // Hmm, the partial file is too big, erase it
2257 if ((Size
> 0) && (unsigned long long)Buf
.st_size
> Size
)
2258 unlink(DestFile
.c_str());
2260 PartialSize
= Buf
.st_size
;
2266 // AcqFile::Done - Item downloaded OK /*{{{*/
2267 // ---------------------------------------------------------------------
2269 void pkgAcqFile::Done(string Message
,unsigned long long Size
,HashStringList
const &CalcHashes
,
2270 pkgAcquire::MethodConfig
*Cnf
)
2272 Item::Done(Message
,Size
,CalcHashes
,Cnf
);
2275 if(ExpectedHashes
.usable() && ExpectedHashes
!= CalcHashes
)
2277 RenameOnError(HashSumMismatch
);
2278 printHashSumComparision(DestFile
, ExpectedHashes
, CalcHashes
);
2282 string FileName
= LookupTag(Message
,"Filename");
2283 if (FileName
.empty() == true)
2286 ErrorText
= "Method gave a blank filename";
2292 // The files timestamp matches
2293 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
2296 // We have to copy it into place
2297 if (FileName
!= DestFile
)
2300 if (_config
->FindB("Acquire::Source-Symlinks",true) == false ||
2301 Cnf
->Removable
== true)
2303 Desc
.URI
= "copy:" + FileName
;
2308 // Erase the file if it is a symlink so we can overwrite it
2310 if (lstat(DestFile
.c_str(),&St
) == 0)
2312 if (S_ISLNK(St
.st_mode
) != 0)
2313 unlink(DestFile
.c_str());
2317 if (symlink(FileName
.c_str(),DestFile
.c_str()) != 0)
2319 ErrorText
= "Link to " + DestFile
+ " failure ";
2326 // AcqFile::Failed - Failure handler /*{{{*/
2327 // ---------------------------------------------------------------------
2328 /* Here we try other sources */
2329 void pkgAcqFile::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
2331 ErrorText
= LookupTag(Message
,"Message");
2333 // This is the retry counter
2335 Cnf
->LocalOnly
== false &&
2336 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2343 Item::Failed(Message
,Cnf
);
2346 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
2347 // ---------------------------------------------------------------------
2348 /* The only header we use is the last-modified header. */
2349 string
pkgAcqFile::Custom600Headers() const
2352 return "\nIndex-File: true";